Replace "link" with "sh_link"
[deliverable/binutils-gdb.git] / opcodes / arc-dis.c
index 516fc225426f438d1da98abe10ba45014633d721..eb8bd670dbe7271581d6b25be4eafe851f164a15 100644 (file)
@@ -1,5 +1,5 @@
 /* Instruction printing code for the ARC.
-   Copyright (C) 1994-2015 Free Software Foundation, Inc.
+   Copyright (C) 1994-2016 Free Software Foundation, Inc.
 
    Contributed by Claudiu Zissulescu (claziss@synopsys.com)
 
@@ -59,9 +59,6 @@ static const char * const regnames[64] =
 #define BITS(word,s,e)  (((word) << (sizeof (word) * 8 - 1 - e)) >>    \
                         (s + (sizeof (word) * 8 - 1 - e)))
 #define OPCODE(word)   (BITS ((word), 27, 31))
-#define FIELDA(word)   (BITS ((word), 21, 26))
-#define FIELDB(word)   (BITS ((word), 15, 20))
-#define FIELDC(word)   (BITS ((word),  9, 14))
 
 #define OPCODE_AC(word)   (BITS ((word), 11, 15))
 
@@ -82,15 +79,13 @@ special_flag_p (const char *opname,
                const char *flgname)
 {
   const struct arc_flag_special *flg_spec;
-  size_t len;
   unsigned i, j, flgidx;
 
   for (i = 0; i < arc_num_flag_special; i++)
     {
       flg_spec = &arc_flag_special_cases[i];
-      len = strlen (flg_spec->name);
 
-      if (strncmp (opname, flg_spec->name, len) != 0)
+      if (strcmp (opname, flg_spec->name))
        continue;
 
       /* Found potential special case instruction.  */
@@ -107,6 +102,213 @@ special_flag_p (const char *opname,
   return 0;
 }
 
+/* Find proper format for the given opcode.  */
+static const struct arc_opcode *
+find_format (const struct arc_opcode *arc_table,
+            unsigned *insn, int insnLen,
+            unsigned isa_mask)
+{
+  unsigned int i = 0;
+  const struct arc_opcode *opcode = NULL;
+  const unsigned char *opidx;
+  const unsigned char *flgidx;
+
+  do {
+    bfd_boolean invalid = FALSE;
+
+    opcode = &arc_table[i++];
+
+    if (ARC_SHORT (opcode->mask) && (insnLen == 2))
+      {
+       if (OPCODE_AC (opcode->opcode) != OPCODE_AC (insn[0]))
+         continue;
+      }
+    else if (!ARC_SHORT (opcode->mask) && (insnLen == 4))
+      {
+       if (OPCODE (opcode->opcode) != OPCODE (insn[0]))
+         continue;
+      }
+    else
+      continue;
+
+    if ((insn[0] ^ opcode->opcode) & opcode->mask)
+      continue;
+
+    if (!(opcode->cpu & isa_mask))
+      continue;
+
+    /* Possible candidate, check the operands.  */
+    for (opidx = opcode->operands; *opidx; opidx++)
+      {
+       int value;
+       const struct arc_operand *operand = &arc_operands[*opidx];
+
+       if (operand->flags & ARC_OPERAND_FAKE)
+         continue;
+
+       if (operand->extract)
+         value = (*operand->extract) (insn[0], &invalid);
+       else
+         value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
+
+       /* Check for LIMM indicator.  If it is there, then make sure
+          we pick the right format.  */
+       if (operand->flags & ARC_OPERAND_IR
+           && !(operand->flags & ARC_OPERAND_LIMM))
+         {
+           if ((value == 0x3E && insnLen == 4)
+               || (value == 0x1E && insnLen == 2))
+             {
+               invalid = TRUE;
+               break;
+             }
+         }
+      }
+
+    /* Check the flags.  */
+    for (flgidx = opcode->flags; *flgidx; flgidx++)
+      {
+       /* Get a valid flag class.  */
+       const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
+       const unsigned *flgopridx;
+       int foundA = 0, foundB = 0;
+       unsigned int value;
+
+       /* Check first the extensions.  */
+       if (cl_flags->class & F_CLASS_EXTEND)
+         {
+           value = (insn[0] & 0x1F);
+           if (arcExtMap_condCodeName (value))
+             continue;
+         }
+       for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
+         {
+           const struct arc_flag_operand *flg_operand =
+             &arc_flag_operands[*flgopridx];
+
+           value = (insn[0] >> flg_operand->shift)
+             & ((1 << flg_operand->bits) - 1);
+           if (value == flg_operand->code)
+             foundA = 1;
+           if (value)
+             foundB = 1;
+         }
+       if (!foundA && foundB)
+         {
+           invalid = TRUE;
+           break;
+         }
+      }
+
+    if (invalid)
+      continue;
+
+    /* The instruction is valid.  */
+    return opcode;
+  } while (opcode->mask);
+
+  return NULL;
+}
+
+static void
+print_flags (const struct arc_opcode *opcode,
+            unsigned *insn,
+            struct disassemble_info *info)
+{
+  const unsigned char *flgidx;
+  unsigned int value;
+
+  /* Now extract and print the flags.  */
+  for (flgidx = opcode->flags; *flgidx; flgidx++)
+    {
+      /* Get a valid flag class.  */
+      const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
+      const unsigned *flgopridx;
+
+      /* Check first the extensions.  */
+      if (cl_flags->class & F_CLASS_EXTEND)
+       {
+         const char *name;
+         value = (insn[0] & 0x1F);
+
+         name = arcExtMap_condCodeName (value);
+         if (name)
+           {
+             (*info->fprintf_func) (info->stream, ".%s", name);
+             continue;
+           }
+       }
+
+      for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
+       {
+         const struct arc_flag_operand *flg_operand =
+           &arc_flag_operands[*flgopridx];
+
+         if (!flg_operand->favail)
+           continue;
+
+         value = (insn[0] >> flg_operand->shift)
+           & ((1 << flg_operand->bits) - 1);
+         if (value == flg_operand->code)
+           {
+              /* FIXME!: print correctly nt/t flag.  */
+             if (!special_flag_p (opcode->name, flg_operand->name))
+               (*info->fprintf_func) (info->stream, ".");
+             else if (info->insn_type == dis_dref)
+               {
+                 switch (flg_operand->name[0])
+                   {
+                   case 'b':
+                     info->data_size = 1;
+                     break;
+                   case 'h':
+                   case 'w':
+                     info->data_size = 2;
+                     break;
+                   default:
+                     info->data_size = 4;
+                     break;
+                   }
+               }
+             (*info->fprintf_func) (info->stream, "%s", flg_operand->name);
+           }
+
+         if (flg_operand->name[0] == 'd'
+             && flg_operand->name[1] == 0)
+           info->branch_delay_insns = 1;
+       }
+    }
+}
+
+static const char *
+get_auxreg (const struct arc_opcode *opcode,
+           int value,
+           unsigned isa_mask)
+{
+  const char *name;
+  unsigned int i;
+  const struct arc_aux_reg *auxr = &arc_aux_regs[0];
+
+  if (opcode->class != AUXREG)
+    return NULL;
+
+  name = arcExtMap_auxRegName (value);
+  if (name)
+    return name;
+
+  for (i = 0; i < arc_num_aux_regs; i++, auxr++)
+    {
+      if (!(auxr->cpu & isa_mask))
+       continue;
+
+      if (auxr->subclass != NONE)
+       return NULL;
+
+      if (auxr->address == value)
+       return auxr->name;
+    }
+  return NULL;
+}
 /* Disassemble ARC instructions.  */
 
 static int
@@ -116,23 +318,25 @@ print_insn_arc (bfd_vma memaddr,
   bfd_byte buffer[4];
   unsigned int lowbyte, highbyte;
   int status;
-  unsigned int i;
   int insnLen = 0;
-  unsigned insn[2], isa_mask;
+  unsigned insn[2] = { 0, 0 };
+  unsigned isa_mask;
   const unsigned char *opidx;
-  const unsigned char *flgidx;
   const struct arc_opcode *opcode;
-  const char *instrName;
-  int flags;
+  const extInstruction_t *einsn;
   bfd_boolean need_comma;
   bfd_boolean open_braket;
-
+  int size;
 
   lowbyte  = ((info->endian == BFD_ENDIAN_LITTLE) ? 1 : 0);
   highbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 0 : 1);
 
   switch (info->mach)
     {
+    case bfd_mach_arc_nps400:
+      isa_mask = ARC_OPCODE_ARC700 | ARC_OPCODE_NPS400;
+      break;
+
     case bfd_mach_arc_arc700:
       isa_mask = ARC_OPCODE_ARC700;
       break;
@@ -147,8 +351,46 @@ print_insn_arc (bfd_vma memaddr,
       break;
     }
 
+  /* This variable may be set by the instruction decoder.  It suggests
+     the number of bytes objdump should display on a single line.  If
+     the instruction decoder sets this, it should always set it to
+     the same value in order to get reasonable looking output.  */
+
+  info->bytes_per_line  = 8;
+
+  /* In the next lines, we set two info variables control the way
+     objdump displays the raw data.  For example, if bytes_per_line is
+     8 and bytes_per_chunk is 4, the output will look like this:
+     00:   00000000 00000000
+     with the chunks displayed according to "display_endian".  */
+
+  if (info->section
+      && !(info->section->flags & SEC_CODE))
+    {
+      /* This is not a CODE section.  */
+      switch (info->section->size)
+       {
+       case 1:
+       case 2:
+       case 4:
+         size = info->section->size;
+         break;
+       default:
+         size = (info->section->size & 0x01) ? 1 : 4;
+         break;
+       }
+      info->bytes_per_chunk = 1;
+      info->display_endian = info->endian;
+    }
+  else
+    {
+      size = 2;
+      info->bytes_per_chunk = 2;
+      info->display_endian = info->endian;
+    }
+
   /* Read the insn into a host word.  */
-  status = (*info->read_memory_func) (memaddr, buffer, 2, info);
+  status = (*info->read_memory_func) (memaddr, buffer, size, info);
   if (status != 0)
     {
       (*info->memory_error_func) (status, memaddr, info);
@@ -158,17 +400,26 @@ print_insn_arc (bfd_vma memaddr,
   if (info->section
       && !(info->section->flags & SEC_CODE))
     {
-      /* Sort of data section, just print a 32 bit number.  */
-      insnLen = 4;
-      status = (*info->read_memory_func) (memaddr + 2, &buffer[2], 2, info);
-      if (status != 0)
+      /* Data section.  */
+      unsigned long data;
+
+      data = bfd_get_bits (buffer, size * 8,
+                          info->display_endian == BFD_ENDIAN_BIG);
+      switch (size)
        {
-         (*info->memory_error_func) (status, memaddr + 2, info);
-         return -1;
+       case 1:
+         (*info->fprintf_func) (info->stream, ".byte\t0x%02lx", data);
+         break;
+       case 2:
+         (*info->fprintf_func) (info->stream, ".short\t0x%04lx", data);
+         break;
+       case 4:
+         (*info->fprintf_func) (info->stream, ".word\t0x%08lx", data);
+         break;
+       default:
+         abort ();
        }
-      insn[0] = ARRANGE_ENDIAN (info, buffer);
-      (*info->fprintf_func) (info->stream, ".long %#08x", insn[0]);
-      return insnLen;
+      return size;
     }
 
   if ((((buffer[lowbyte] & 0xf8) > 0x38)
@@ -195,20 +446,6 @@ print_insn_arc (bfd_vma memaddr,
       insn[0] = ARRANGE_ENDIAN (info, buffer);
     }
 
-  /* This variable may be set by the instruction decoder.  It suggests
-     the number of bytes objdump should display on a single line.  If
-     the instruction decoder sets this, it should always set it to
-     the same value in order to get reasonable looking output.  */
-  info->bytes_per_line  = 8;
-
-  /* The next two variables control the way objdump displays the raw data.
-     For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the
-     output will look like this:
-     00:   00000000 00000000
-     with the chunks displayed according to "display_endian".  */
-  info->bytes_per_chunk = 2;
-  info->display_endian  = info->endian;
-
   /* Set some defaults for the insn info.  */
   info->insn_info_valid    = 1;
   info->branch_delay_insns = 0;
@@ -221,110 +458,40 @@ print_insn_arc (bfd_vma memaddr,
   info->disassembler_needs_relocs = TRUE;
 
   /* Find the first match in the opcode table.  */
-  for (i = 0; i < arc_num_opcodes; i++)
-    {
-      bfd_boolean invalid = FALSE;
-
-      opcode = &arc_opcodes[i];
-
-      if (ARC_SHORT (opcode->mask) && (insnLen == 2))
-       {
-         if (OPCODE_AC (opcode->opcode) != OPCODE_AC (insn[0]))
-           continue;
-       }
-      else if (!ARC_SHORT (opcode->mask) && (insnLen == 4))
-       {
-         if (OPCODE (opcode->opcode) != OPCODE (insn[0]))
-           continue;
-       }
-      else
-       continue;
+  opcode = find_format (arc_opcodes, insn, insnLen, isa_mask);
 
-      if ((insn[0] ^ opcode->opcode) & opcode->mask)
-       continue;
-
-      if (!(opcode->cpu & isa_mask))
-       continue;
-
-      /* Possible candidate, check the operands.  */
-      for (opidx = opcode->operands; *opidx; opidx++)
+  if (!opcode)
+    {
+      /* No instruction found.  Try the extensions.  */
+      einsn = arcExtMap_insn (OPCODE (insn[0]), insn[0]);
+      if (einsn)
        {
-         int value;
-         const struct arc_operand *operand = &arc_operands[*opidx];
-
-         if (operand->flags & ARC_OPERAND_FAKE)
-           continue;
-
-         if (operand->extract)
-           value = (*operand->extract) (insn[0], &invalid);
-         else
-           value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
-
-         /* Check for LIMM indicator.  If it is there, then make sure
-            we pick the right format.  */
-         if (operand->flags & ARC_OPERAND_IR
-             && !(operand->flags & ARC_OPERAND_LIMM))
+         const char *errmsg = NULL;
+         opcode = arcExtMap_genOpcode (einsn, isa_mask, &errmsg);
+         if (opcode == NULL)
            {
-             if ((value == 0x3E && insnLen == 4)
-                 || (value == 0x1E && insnLen == 2))
-               {
-                 invalid = TRUE;
-                 break;
-               }
+             (*info->fprintf_func) (info->stream,
+                                    "An error occured while "
+                                    "generating the extension instruction "
+                                    "operations");
+             return -1;
            }
-       }
 
-      /* Check the flags.  */
-      for (flgidx = opcode->flags; *flgidx; flgidx++)
+         opcode = find_format (opcode, insn, insnLen, isa_mask);
+         assert (opcode != NULL);
+       }
+      else
        {
-         /* Get a valid flag class.  */
-         const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
-         const unsigned *flgopridx;
-         int foundA = 0, foundB = 0;
+         if (insnLen == 2)
+           (*info->fprintf_func) (info->stream, ".long %#04x", insn[0]);
+         else
+           (*info->fprintf_func) (info->stream, ".long %#08x", insn[0]);
 
-         for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
-           {
-             const struct arc_flag_operand *flg_operand = &arc_flag_operands[*flgopridx];
-             unsigned int value;
-
-             value = (insn[0] >> flg_operand->shift) & ((1 << flg_operand->bits) - 1);
-             if (value == flg_operand->code)
-               foundA = 1;
-             if (value)
-               foundB = 1;
-           }
-         if (!foundA && foundB)
-           {
-             invalid = TRUE;
-             break;
-           }
+         info->insn_type = dis_noninsn;
+         return insnLen;
        }
-
-      if (invalid)
-       continue;
-
-      /* The instruction is valid.  */
-      goto found;
     }
 
-  /* No instruction found.  Try the extenssions.  */
-  instrName = arcExtMap_instName (OPCODE (insn[0]), insn[0], &flags);
-  if (instrName)
-    {
-      opcode = &arc_opcodes[0];
-      (*info->fprintf_func) (info->stream, "%s", instrName);
-      goto print_flags;
-    }
-
-  if (insnLen == 2)
-    (*info->fprintf_func) (info->stream, ".long %#04x", insn[0]);
-  else
-    (*info->fprintf_func) (info->stream, ".long %#08x", insn[0]);
-
-  info->insn_type = dis_noninsn;
-  return insnLen;
-
- found:
   /* Print the mnemonic.  */
   (*info->fprintf_func) (info->stream, "%s", opcode->name);
 
@@ -349,52 +516,7 @@ print_insn_arc (bfd_vma memaddr,
 
   pr_debug ("%s: 0x%08x\n", opcode->name, opcode->opcode);
 
- print_flags:
-  /* Now extract and print the flags.  */
-  for (flgidx = opcode->flags; *flgidx; flgidx++)
-    {
-      /* Get a valid flag class.  */
-      const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
-      const unsigned *flgopridx;
-
-      for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
-       {
-         const struct arc_flag_operand *flg_operand = &arc_flag_operands[*flgopridx];
-         unsigned int value;
-
-         if (!flg_operand->favail)
-           continue;
-
-         value = (insn[0] >> flg_operand->shift) & ((1 << flg_operand->bits) - 1);
-         if (value == flg_operand->code)
-           {
-              /* FIXME!: print correctly nt/t flag.  */
-             if (!special_flag_p (opcode->name, flg_operand->name))
-               (*info->fprintf_func) (info->stream, ".");
-             else if (info->insn_type == dis_dref)
-               {
-                 switch (flg_operand->name[0])
-                   {
-                   case 'b':
-                     info->data_size = 1;
-                     break;
-                   case 'h':
-                   case 'w':
-                     info->data_size = 2;
-                     break;
-                   default:
-                     info->data_size = 4;
-                     break;
-                   }
-               }
-             (*info->fprintf_func) (info->stream, "%s", flg_operand->name);
-           }
-
-         if (flg_operand->name[0] == 'd'
-             && flg_operand->name[1] == 0)
-           info->branch_delay_insns = 1;
-       }
-    }
+  print_flags (opcode, insn, info);
 
   if (opcode->operands[0] != 0)
     (*info->fprintf_func) (info->stream, "\t");
@@ -474,17 +596,33 @@ print_insn_arc (bfd_vma memaddr,
       /* Print the operand as directed by the flags.  */
       if (operand->flags & ARC_OPERAND_IR)
        {
+         const char *rname;
+
          assert (value >=0 && value < 64);
-         (*info->fprintf_func) (info->stream, "%s", regnames[value]);
+         rname = arcExtMap_coreRegName (value);
+         if (!rname)
+           rname = regnames[value];
+         (*info->fprintf_func) (info->stream, "%s", rname);
          if (operand->flags & ARC_OPERAND_TRUNCATE)
-           (*info->fprintf_func) (info->stream, "%s", regnames[value+1]);
+           {
+             rname = arcExtMap_coreRegName (value + 1);
+             if (!rname)
+               rname = regnames[value + 1];
+             (*info->fprintf_func) (info->stream, "%s", rname);
+           }
        }
       else if (operand->flags & ARC_OPERAND_LIMM)
        {
-         (*info->fprintf_func) (info->stream, "%#x", insn[1]);
-         if (info->insn_type == dis_branch
-             || info->insn_type == dis_jsr)
-           info->target = (bfd_vma) insn[1];
+         const char *rname = get_auxreg (opcode, insn[1], isa_mask);
+         if (rname && open_braket)
+           (*info->fprintf_func) (info->stream, "%s", rname);
+         else
+           {
+             (*info->fprintf_func) (info->stream, "%#x", insn[1]);
+             if (info->insn_type == dis_branch
+                 || info->insn_type == dis_jsr)
+               info->target = (bfd_vma) insn[1];
+           }
        }
       else if (operand->flags & ARC_OPERAND_PCREL)
        {
@@ -496,16 +634,30 @@ print_insn_arc (bfd_vma memaddr,
          info->target = (bfd_vma) (memaddr & ~3) + value;
        }
       else if (operand->flags & ARC_OPERAND_SIGNED)
-       (*info->fprintf_func) (info->stream, "%d", value);
+       {
+         const char *rname = get_auxreg (opcode, value, isa_mask);
+         if (rname && open_braket)
+           (*info->fprintf_func) (info->stream, "%s", rname);
+         else
+           (*info->fprintf_func) (info->stream, "%d", value);
+       }
       else
-       if (operand->flags & ARC_OPERAND_TRUNCATE
-           && !(operand->flags & ARC_OPERAND_ALIGNED32)
-           && !(operand->flags & ARC_OPERAND_ALIGNED16)
-           && value > 0 && value <= 14)
-         (*info->fprintf_func) (info->stream, "r13-%s",
-                                regnames[13 + value - 1]);
-       else
-         (*info->fprintf_func) (info->stream, "%#x", value);
+       {
+         if (operand->flags & ARC_OPERAND_TRUNCATE
+             && !(operand->flags & ARC_OPERAND_ALIGNED32)
+             && !(operand->flags & ARC_OPERAND_ALIGNED16)
+             && value > 0 && value <= 14)
+           (*info->fprintf_func) (info->stream, "r13-%s",
+                                  regnames[13 + value - 1]);
+         else
+           {
+             const char *rname = get_auxreg (opcode, value, isa_mask);
+             if (rname && open_braket)
+               (*info->fprintf_func) (info->stream, "%s", rname);
+             else
+               (*info->fprintf_func) (info->stream, "%#x", value);
+           }
+       }
 
       need_comma = TRUE;
 
@@ -524,7 +676,9 @@ arc_get_disassembler (bfd *abfd)
 {
   /* Read the extenssion insns and registers, if any.  */
   build_ARC_extmap (abfd);
+#ifdef DEBUG
   dump_ARC_extmap ();
+#endif
 
   return print_insn_arc;
 }
This page took 0.030433 seconds and 4 git commands to generate.