* gas/config/tc-arm.c (NEON_ENC_TAB): Add vrint entries.
[deliverable/binutils-gdb.git] / opcodes / arm-dis.c
index 74d78cb462162d94ebfd6887cce2fd978b3041d9..60463d16e5211fe30b8a72d486278c77ff98fcca 100644 (file)
@@ -92,7 +92,8 @@ struct opcode16
 
    %c                  print condition code (always bits 28-31 in ARM mode)
    %q                  print shifter argument
-   %u                  print condition code (unconditional in ARM mode)
+   %u                  print condition code (unconditional in ARM mode,
+                          UNPREDICTABLE if not AL in Thumb)
    %A                  print address for ldc/stc/ldf/stf instruction
    %B                  print vstm/vldm register list
    %I                   print cirrus signed shift immediate: bits 0..3|4..6
@@ -101,6 +102,7 @@ struct opcode16
    %Q                  print floating point precision in ldf/stf insn
    %R                  print floating point rounding mode
 
+   %<bitfield>c                print as a condition code (for vsel)
    %<bitfield>r                print as an ARM register
    %<bitfield>R                as %<>r but r15 is UNPREDICTABLE
    %<bitfield>ru        as %<>r but each u register must be unique.
@@ -485,6 +487,20 @@ static const struct opcode32 coprocessor_opcodes[] =
   {FPU_VFP_EXT_FMA, 0x0e900a00, 0x0fb00f50, "vfnms%c.f32\t%y1, %y2, %y0"},
   {FPU_VFP_EXT_FMA, 0x0e900b00, 0x0fb00f50, "vfnms%c.f64\t%z1, %z2, %z0"},
 
+  /* FP v5.  */
+  {FPU_VFP_EXT_ARMV8, 0xfe000a00, 0xff800f00, "vsel%20-21c%u.f32\t%y1, %y2, %y0"},
+  {FPU_VFP_EXT_ARMV8, 0xfe000b00, 0xff800f00, "vsel%20-21c%u.f64\t%z1, %z2, %z0"},
+  {FPU_VFP_EXT_ARMV8, 0xfe800a00, 0xffb00f40, "vmaxnm%u.f32\t%y1, %y2, %y0"},
+  {FPU_VFP_EXT_ARMV8, 0xfe800b00, 0xffb00f40, "vmaxnm%u.f64\t%z1, %z2, %z0"},
+  {FPU_VFP_EXT_ARMV8, 0xfe800a40, 0xffb00f40, "vminnm%u.f32\t%y1, %y2, %y0"},
+  {FPU_VFP_EXT_ARMV8, 0xfe800b40, 0xffb00f40, "vminnm%u.f64\t%z1, %z2, %z0"},
+  {FPU_VFP_EXT_ARMV8, 0xfebc0a40, 0xffbc0f50, "vcvt%16-17?mpna%u.%7?su32.f32\t%y1, %y0"},
+  {FPU_VFP_EXT_ARMV8, 0xfebc0b40, 0xffbc0f50, "vcvt%16-17?mpna%u.%7?su32.f64\t%y1, %z0"},
+  {FPU_VFP_EXT_ARMV8, 0x0eb60a40, 0x0fbe0f50, "vrint%7,16??xzr%c.f32.f32\t%y1, %y0"},
+  {FPU_VFP_EXT_ARMV8, 0x0eb60b40, 0x0fbe0f50, "vrint%7,16??xzr%c.f64.f64\t%z1, %z0"},
+  {FPU_VFP_EXT_ARMV8, 0xfeb80a40, 0xffbc0f50, "vrint%16-17?mpna%u.f32.f32\t%y1, %y0"},
+  {FPU_VFP_EXT_ARMV8, 0xfeb80b40, 0xffbc0f50, "vrint%16-17?mpna%u.f64.f64\t%z1, %z0"},
+
   /* Generic coprocessor instructions.  */
   { 0, SENTINEL_GENERIC_START, 0, "" },
   {ARM_EXT_V5E, 0x0c400000, 0x0ff00000, "mcrr%c\t%8-11d, %4-7d, %12-15R, %16-19r, cr%0-3d"},
@@ -519,6 +535,8 @@ static const struct opcode32 coprocessor_opcodes[] =
    %%                  %
 
    %c                  print condition code
+   %u                  print condition code (unconditional in ARM mode,
+                          UNPREDICTABLE if not AL in Thumb)
    %A                  print v{st,ld}[1234] operands
    %B                  print v{st,ld}[1234] any one operands
    %C                  print v{st,ld}[1234] single->all operands
@@ -564,6 +582,8 @@ static const struct opcode32 neon_opcodes[] =
   {FPU_NEON_EXT_FMA, 0xf2200c10, 0xffa00f10, "vfms%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
 
   /* Two registers, miscellaneous.  */
+  {FPU_NEON_EXT_ARMV8, 0xf3ba0400, 0xffbf0c10, "vrint%7-9?p?m?zaxn%u.f32.f32\t%12-15,22R, %0-3,5R"},
+  {FPU_NEON_EXT_ARMV8, 0xf3bb0000, 0xffbf0c10, "vcvt%8-9?mpna%u.%7?us32.f32\t%12-15,22R, %0-3,5R"},
   {FPU_NEON_EXT_V1, 0xf2880a10, 0xfebf0fd0, "vmovl%c.%24?us8\t%12-15,22Q, %0-3,5D"},
   {FPU_NEON_EXT_V1, 0xf2900a10, 0xfebf0fd0, "vmovl%c.%24?us16\t%12-15,22Q, %0-3,5D"},
   {FPU_NEON_EXT_V1, 0xf2a00a10, 0xfebf0fd0, "vmovl%c.%24?us32\t%12-15,22Q, %0-3,5D"},
@@ -599,6 +619,8 @@ static const struct opcode32 neon_opcodes[] =
   {FPU_NEON_EXT_V1, 0xf3b30600, 0xffb30e10, "vcvt%c.%7-8?usff%18-19Sa.%7-8?ffus%18-19Sa\t%12-15,22R, %0-3,5R"},
 
   /* Three registers of the same length.  */
+  {FPU_NEON_EXT_ARMV8, 0xf3000f10, 0xffa00f10, "vmaxnm%u.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
+  {FPU_NEON_EXT_ARMV8, 0xf3200f10, 0xffa00f10, "vminnm%u.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"},
   {FPU_NEON_EXT_V1, 0xf2000110, 0xffb00f10, "vand%c\t%12-15,22R, %16-19,7R, %0-3,5R"},
   {FPU_NEON_EXT_V1, 0xf2100110, 0xffb00f10, "vbic%c\t%12-15,22R, %16-19,7R, %0-3,5R"},
   {FPU_NEON_EXT_V1, 0xf2200110, 0xffb00f10, "vorr%c\t%12-15,22R, %16-19,7R, %0-3,5R"},
@@ -818,6 +840,7 @@ static const struct opcode32 neon_opcodes[] =
    %P                  print address for pli instruction.
 
    %<bitfield>r                print as an ARM register
+   %<bitfield>T                print as an ARM register + 1
    %<bitfield>R                as %r but r15 is UNPREDICTABLE
    %<bitfield>{r|R}u    as %{r|R} but if matches the other %u field then is UNPREDICTABLE
    %<bitfield>{r|R}U    as %{r|R} but if matches the other %U field then is UNPREDICTABLE
@@ -846,6 +869,24 @@ static const struct opcode32 arm_opcodes[] =
   {ARM_EXT_V3M, 0x00800090, 0x0fa000f0, "%22?sumull%20's%c\t%12-15Ru, %16-19Ru, %0-3R, %8-11R"},
   {ARM_EXT_V3M, 0x00a00090, 0x0fa000f0, "%22?sumlal%20's%c\t%12-15Ru, %16-19Ru, %0-3R, %8-11R"},
 
+  /* V8 instructions.  */
+  {ARM_EXT_V8,   0x0320f005, 0x0fffffff, "sevl"},
+  {ARM_EXT_V8,   0xe1000070, 0xfff000f0, "hlt\t0x%16-19X%12-15X%8-11X%0-3X"},
+  {ARM_EXT_V8,  0x01800e90, 0x0ff00ff0, "strlex%c\t%12-15r, %0-3r, [%16-19R]"},
+  {ARM_EXT_V8,  0x01900e9f, 0x0ff00fff, "ldraex%c\t%12-15r, [%16-19R]"},
+  {ARM_EXT_V8,  0x01a00e90, 0x0ff00ff0, "strlexd%c\t%12-15r, %0-3r, %0-3T, [%16-19R]"},
+  {ARM_EXT_V8,  0x01b00e9f, 0x0ff00fff, "ldraexd%c\t%12-15r, %12-15T, [%16-19R]"},
+  {ARM_EXT_V8,  0x01c00e90, 0x0ff00ff0, "strlexb%c\t%12-15r, %0-3r, [%16-19R]"},
+  {ARM_EXT_V8,  0x01d00e9f, 0x0ff00fff, "ldraexb%c\t%12-15r, [%16-19R]"},
+  {ARM_EXT_V8,  0x01e00e90, 0x0ff00ff0, "strlexh%c\t%12-15r, %0-3r, [%16-19R]"},
+  {ARM_EXT_V8,  0x01f00e9f, 0x0ff00fff, "ldraexh%c\t%12-15r, [%16-19R]"},
+  {ARM_EXT_V8,  0x0180fc90, 0x0ff0fff0, "strl%c\t%0-3r, [%16-19R]"},
+  {ARM_EXT_V8,  0x01900c9f, 0x0ff00fff, "ldra%c\t%12-15r, [%16-19R]"},
+  {ARM_EXT_V8,  0x01c0fc90, 0x0ff0fff0, "strlb%c\t%0-3r, [%16-19R]"},
+  {ARM_EXT_V8,  0x01d00c9f, 0x0ff00fff, "ldrab%c\t%12-15r, [%16-19R]"},
+  {ARM_EXT_V8,  0x01e0fc90, 0x0ff0fff0, "strlh%c\t%0-3r, [%16-19R]"},
+  {ARM_EXT_V8,  0x01f00c9f, 0x0ff00fff, "ldraexh%c\t%12-15r, [%16-19R]"},
+
   /* Virtualization Extension instructions.  */
   {ARM_EXT_VIRT, 0x0160006e, 0x0fffffff, "eret%c"},
   {ARM_EXT_VIRT, 0x01400070, 0x0ff000f0, "hvc%c\t%e"},
@@ -860,6 +901,8 @@ static const struct opcode32 arm_opcodes[] =
   /* V7 instructions.  */
   {ARM_EXT_V7, 0xf450f000, 0xfd70f000, "pli\t%P"},
   {ARM_EXT_V7, 0x0320f0f0, 0x0ffffff0, "dbg%c\t#%0-3d"},
+  {ARM_EXT_V8, 0xf57ff051, 0xfffffff3, "dmb\t%U"},
+  {ARM_EXT_V8, 0xf57ff041, 0xfffffff3, "dsb\t%U"},
   {ARM_EXT_V7, 0xf57ff050, 0xfffffff0, "dmb\t%U"},
   {ARM_EXT_V7, 0xf57ff040, 0xfffffff0, "dsb\t%U"},
   {ARM_EXT_V7, 0xf57ff060, 0xfffffff0, "isb\t%U"},
@@ -1239,6 +1282,10 @@ static const struct opcode16 thumb_opcodes[] =
 {
   /* Thumb instructions.  */
 
+  /* ARM V8 instructions.  */
+  {ARM_EXT_V8,  0xbf50, 0xffff, "sevl%c"},
+  {ARM_EXT_V8,  0xba80, 0xffc0, "hlt\t%0-5x"},
+
   /* ARM V6K no-argument instructions.  */
   {ARM_EXT_V6K, 0xbf00, 0xffff, "nop%c"},
   {ARM_EXT_V6K, 0xbf10, 0xffff, "yield%c"},
@@ -1408,9 +1455,29 @@ static const struct opcode16 thumb_opcodes[] =
    makes heavy use of special-case bit patterns.  */
 static const struct opcode32 thumb32_opcodes[] =
 {
+  /* V8 instructions.  */
+  {ARM_EXT_V8, 0xf3af8005, 0xffffffff, "sevl%c.w"},
+  {ARM_EXT_V8, 0xf78f8000, 0xfffffffc, "dcps%0-1d"},
+  {ARM_EXT_V8, 0xe8c00f8f, 0xfff00fff, "strlb%c\t%12-15r, [%16-19R]"},
+  {ARM_EXT_V8, 0xe8c00f9f, 0xfff00fff, "strlh%c\t%12-15r, [%16-19R]"},
+  {ARM_EXT_V8, 0xe8c00faf, 0xfff00fff, "strl%c\t%12-15r, [%16-19R]"},
+  {ARM_EXT_V8, 0xe8c00fc0, 0xfff00ff0, "strlexb%c\t%0-3r, %12-15r, [%16-19R]"},
+  {ARM_EXT_V8, 0xe8c00fd0, 0xfff00ff0, "strlexh%c\t%0-3r, %12-15r, [%16-19R]"},
+  {ARM_EXT_V8, 0xe8c00fe0, 0xfff00ff0, "strlex%c\t%0-3r, %12-15r, [%16-19R]"},
+  {ARM_EXT_V8, 0xe8c000f0, 0xfff000f0, "strlexd%c\t%0-3r, %12-15r, %8-11r, [%16-19R]"},
+  {ARM_EXT_V8, 0xe8d00f8f, 0xfff00fff, "ldrab%c\t%12-15r, [%16-19R]"},
+  {ARM_EXT_V8, 0xe8d00f9f, 0xfff00fff, "ldrah%c\t%12-15r, [%16-19R]"},
+  {ARM_EXT_V8, 0xe8d00faf, 0xfff00fff, "ldra%c\t%12-15r, [%16-19R]"},
+  {ARM_EXT_V8, 0xe8d00fcf, 0xfff00fff, "ldraexb%c\t%12-15r, [%16-19R]"},
+  {ARM_EXT_V8, 0xe8d00fdf, 0xfff00fff, "ldraexh%c\t%12-15r, [%16-19R]"},
+  {ARM_EXT_V8, 0xe8d00fef, 0xfff00fff, "ldraex%c\t%12-15r, [%16-19R]"},
+  {ARM_EXT_V8, 0xe8d000ff, 0xfff000ff, "ldraexd%c\t%12-15r, %8-11r, [%16-19R]"},
+
   /* V7 instructions.  */
   {ARM_EXT_V7, 0xf910f000, 0xff70f000, "pli%c\t%a"},
   {ARM_EXT_V7, 0xf3af80f0, 0xfffffff0, "dbg%c\t#%0-3d"},
+  {ARM_EXT_V8, 0xf3bf8f51, 0xfffffff3, "dmb%c\t%U"},
+  {ARM_EXT_V8, 0xf3bf8f41, 0xfffffff3, "dsb%c\t%U"},
   {ARM_EXT_V7, 0xf3bf8f50, 0xfffffff0, "dmb%c\t%U"},
   {ARM_EXT_V7, 0xf3bf8f40, 0xfffffff0, "dsb%c\t%U"},
   {ARM_EXT_V7, 0xf3bf8f60, 0xfffffff0, "isb%c\t%U"},
@@ -1692,6 +1759,9 @@ static unsigned int ifthen_next_state;
 /* The address of the insn for which the IT state is valid.  */
 static bfd_vma ifthen_address;
 #define IFTHEN_COND ((ifthen_state >> 4) & 0xf)
+/* Indicates that the current Conditional state is unconditional or outside
+   an IT block.  */
+#define COND_UNCOND 16
 
 \f
 /* Functions.  */
@@ -1870,7 +1940,7 @@ print_insn_coprocessor (bfd_vma pc,
          if (ifthen_state)
            cond = IFTHEN_COND;
          else
-           cond = 16;
+           cond = COND_UNCOND;
        }
       else
        {
@@ -1879,13 +1949,13 @@ print_insn_coprocessor (bfd_vma pc,
          if ((given & 0xf0000000) == 0xf0000000)
            {
              mask |= 0xf0000000;
-             cond = 16;
+             cond = COND_UNCOND;
            }
          else
            {
              cond = (given >> 28) & 0xf;
              if (cond == 0xe)
-               cond = 16;
+               cond = COND_UNCOND;
            }
        }
       
@@ -1979,6 +2049,11 @@ print_insn_coprocessor (bfd_vma pc,
                  }
                  break;
 
+               case 'u':
+                 if (cond != COND_UNCOND)
+                   is_unpredictable = TRUE;
+
+                 /* Fall through.  */
                case 'c':
                  func (stream, "%s", arm_conditional[cond]);
                  break;
@@ -2142,6 +2217,31 @@ print_insn_coprocessor (bfd_vma pc,
                        func (stream, "0x%lx", (value & 0xffffffffUL));
                        break;
 
+                     case 'c':
+                       switch (value)
+                         {
+                         case 0:
+                           func (stream, "eq");
+                           break;
+
+                         case 1:
+                           func (stream, "vs");
+                           break;
+
+                         case 2:
+                           func (stream, "ge");
+                           break;
+
+                         case 3:
+                           func (stream, "gt");
+                           break;
+
+                         default:
+                           func (stream, "??");
+                           break;
+                         }
+                       break;
+
                      case '`':
                        c++;
                        if (value == 0)
@@ -2488,6 +2588,7 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb)
       if ((given & insn->mask) == insn->value)
        {
          signed long value_in_comment = 0;
+         bfd_boolean is_unpredictable = FALSE;
          const char *c;
 
          for (c = insn->assembler; *c; c++)
@@ -2500,6 +2601,11 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb)
                      func (stream, "%%");
                      break;
 
+                   case 'u':
+                     if (thumb && ifthen_state)
+                       is_unpredictable = TRUE;
+
+                     /* Fall through.  */
                    case 'c':
                      if (thumb && ifthen_state)
                        func (stream, "%s", arm_conditional[IFTHEN_COND]);
@@ -2819,7 +2925,7 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb)
                          func (stream, "{d%d-d%d}", regno, regno + num);
                      }
                      break;
-      
+
 
                    case '0': case '1': case '2': case '3': case '4':
                    case '5': case '6': case '7': case '8': case '9':
@@ -2913,6 +3019,9 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb)
          if (value_in_comment > 32 || value_in_comment < -16)
            func (stream, "\t; 0x%lx", value_in_comment);
 
+         if (is_unpredictable)
+           func (stream, UNPREDICTABLE_INSTRUCTION);
+
          return TRUE;
        }
     }
@@ -2965,6 +3074,28 @@ banked_regname (unsigned reg)
     }
 }
 
+/* Return the name of the DMB/DSB option.  */
+static const char *
+data_barrier_option (unsigned option)
+{
+  switch (option & 0xf)
+    {
+    case 0xf: return "sy";
+    case 0xe: return "st";
+    case 0xd: return "ld";
+    case 0xb: return "ish";
+    case 0xa: return "ishst";
+    case 0x9: return "ishld";
+    case 0x7: return "un";
+    case 0x6: return "unst";
+    case 0x5: return "nshld";
+    case 0x3: return "osh";
+    case 0x2: return "oshst";
+    case 0x1: return "oshld";
+    default:  return NULL;
+    }
+}
+
 /* Print one ARM instruction from PC on INFO->STREAM.  */
 
 static void
@@ -3315,20 +3446,11 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info, long given)
                        } 
                      else 
                        {
-                         switch (given & 0xf)
-                           {
-                           case 0xf: func (stream, "sy"); break;
-                           case 0x7: func (stream, "un"); break;
-                           case 0xe: func (stream, "st"); break;
-                           case 0x6: func (stream, "unst"); break;
-                           case 0xb: func (stream, "ish"); break;
-                           case 0xa: func (stream, "ishst"); break;
-                           case 0x3: func (stream, "osh"); break;
-                           case 0x2: func (stream, "oshst"); break;
-                           default:
+                         const char * opt = data_barrier_option (given & 0xf);
+                         if (opt != NULL)
+                           func (stream, "%s", opt);
+                         else
                              func (stream, "#%d", (int) given & 0xf);
-                             break;
-                           }
                        }
                      break;
 
@@ -3347,6 +3469,11 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info, long given)
                              is_unpredictable = TRUE;
                            /* Fall through.  */
                          case 'r':
+                         case 'T':
+                           /* We want register + 1 when decoding T.  */
+                           if (*c == 'T')
+                             ++value;
+
                            if (c[1] == 'u')
                              {
                                /* Eat the 'u' character.  */
@@ -4202,20 +4329,11 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
                  }
                else 
                  {
-                   switch (given & 0xf)
-                     {
-                       case 0xf: func (stream, "sy"); break;
-                       case 0x7: func (stream, "un"); break;
-                       case 0xe: func (stream, "st"); break;
-                       case 0x6: func (stream, "unst"); break;
-                       case 0xb: func (stream, "ish"); break;
-                       case 0xa: func (stream, "ishst"); break;
-                       case 0x3: func (stream, "osh"); break;
-                       case 0x2: func (stream, "oshst"); break;
-                       default:
-                         func (stream, "#%d", (int) given & 0xf);
-                         break;
-                     }
+                   const char * opt = data_barrier_option (given & 0xf);
+                   if (opt != NULL)
+                     func (stream, "%s", opt);
+                   else
+                     func (stream, "#%d", (int) given & 0xf);
                   }
                break;
 
This page took 0.027264 seconds and 4 git commands to generate.