]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - opcodes/arc-dis.c
arc: Put DBNZ instruction to a separate class
[thirdparty/binutils-gdb.git] / opcodes / arc-dis.c
index feb4ca8cbe2b7dc3439d378c1dd5bf154e19b380..16fbc8ab007b2ed8f0ec1b935f0df6caec695b92 100644 (file)
@@ -1,5 +1,5 @@
 /* Instruction printing code for the ARC.
-   Copyright (C) 1994-2018 Free Software Foundation, Inc.
+   Copyright (C) 1994-2024 Free Software Foundation, Inc.
 
    Contributed by Claudiu Zissulescu (claziss@synopsys.com)
 
@@ -61,7 +61,7 @@ struct arc_disassemble_info
   unsigned insn_len;
 
   /* TRUE if we have limm.  */
-  bfd_boolean limm_p;
+  bool limm_p;
 
   /* LIMM value, if exists.  */
   unsigned limm;
@@ -90,7 +90,7 @@ static const char * const regnames[64] =
   "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
   "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",
   "r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55",
-  "r56", "r57", "ACCL", "ACCH", "lp_count", "rezerved", "LIMM", "pcl"
+  "r56", "r57", "r58", "r59", "lp_count", "reserved", "LIMM", "pcl"
 };
 
 static const char * const addrtypenames[ARC_NUM_ADDRTYPES] =
@@ -123,7 +123,7 @@ static linkclass decodelist = NULL;
 static unsigned enforced_isa_mask = ARC_OPCODE_NONE;
 
 /* True if we want to print using only hex numbers.  */
-static bfd_boolean print_hex = FALSE;
+static bool print_hex = false;
 
 /* Macros section.  */
 
@@ -137,24 +137,23 @@ static bfd_boolean print_hex = FALSE;
   (info->endian == BFD_ENDIAN_LITTLE ? bfd_getm32 (bfd_getl32 (buf))   \
    : bfd_getb32 (buf))
 
-#define BITS(word,s,e)  (((word) << (sizeof (word) * 8 - 1 - e)) >>    \
-                        (s + (sizeof (word) * 8 - 1 - e)))
+#define BITS(word,s,e)  (((word) >> (s)) & ((1ull << ((e) - (s)) << 1) - 1))
 #define OPCODE_32BIT_INSN(word)        (BITS ((word), 27, 31))
 
 /* Functions implementation.  */
 
 /* Initialize private data.  */
-static bfd_boolean
+static bool
 init_arc_disasm_info (struct disassemble_info *info)
 {
   struct arc_disassemble_info *arc_infop
-    = calloc (sizeof (*arc_infop), 1);
+    = calloc (1, sizeof (*arc_infop));
 
   if (arc_infop == NULL)
-    return FALSE;
+    return false;
 
   info->private_data = arc_infop;
-  return TRUE;
+  return true;
 }
 
 /* Add a new element to the decode list.  */
@@ -174,15 +173,17 @@ add_to_decodelist (insn_class_t     insn_class,
 /* Return TRUE if we need to skip the opcode from being
    disassembled.  */
 
-static bfd_boolean
+static bool
 skip_this_opcode (const struct arc_opcode *opcode)
 {
   linkclass t = decodelist;
 
   /* Check opcode for major 0x06, return if it is not in.  */
   if (arc_opcode_len (opcode) == 4
-      && OPCODE_32BIT_INSN (opcode->opcode) != 0x06)
-    return FALSE;
+      && (OPCODE_32BIT_INSN (opcode->opcode) != 0x06
+         /* Can be an APEX extensions.  */
+         && OPCODE_32BIT_INSN (opcode->opcode) != 0x07))
+    return false;
 
   /* or not a known truble class.  */
   switch (opcode->insn_class)
@@ -190,20 +191,21 @@ skip_this_opcode (const struct arc_opcode *opcode)
     case FLOAT:
     case DSP:
     case ARITH:
+    case MPY:
       break;
     default:
-      return FALSE;
+      return false;
     }
 
   while (t != NULL)
     {
       if ((t->insn_class == opcode->insn_class)
          && (t->subclass == opcode->subclass))
-       return FALSE;
+       return false;
       t = t->nxt;
     }
 
-  return TRUE;
+  return true;
 }
 
 static bfd_vma
@@ -216,7 +218,7 @@ bfd_getm32 (unsigned int data)
   return value;
 }
 
-static bfd_boolean
+static bool
 special_flag_p (const char *opname,
                const char *flgname)
 {
@@ -238,10 +240,10 @@ special_flag_p (const char *opname,
            break; /* End of the array.  */
 
          if (strcmp (flgname, arc_flag_operands[flgidx].name) == 0)
-           return TRUE;
+           return true;
        }
     }
-  return FALSE;
+  return false;
 }
 
 /* Find opcode from ARC_TABLE given the instruction described by INSN and
@@ -253,19 +255,19 @@ find_format_from_table (struct disassemble_info *info,
                         unsigned long long insn,
                        unsigned int insn_len,
                         unsigned isa_mask,
-                       bfd_boolean *has_limm,
-                       bfd_boolean overlaps)
+                       bool *has_limm,
+                       bool overlaps)
 {
   unsigned int i = 0;
   const struct arc_opcode *opcode = NULL;
   const struct arc_opcode *t_op = NULL;
   const unsigned char *opidx;
   const unsigned char *flgidx;
-  bfd_boolean warn_p = FALSE;
+  bool warn_p = false;
 
   do
     {
-      bfd_boolean invalid = FALSE;
+      bool invalid = false;
 
       opcode = &arc_table[i++];
 
@@ -278,7 +280,7 @@ find_format_from_table (struct disassemble_info *info,
       if ((insn & opcode->mask) != opcode->opcode)
        continue;
 
-      *has_limm = FALSE;
+      *has_limm = false;
 
       /* Possible candidate, check the operands.  */
       for (opidx = opcode->operands; *opidx; opidx++)
@@ -292,7 +294,7 @@ find_format_from_table (struct disassemble_info *info,
          if (operand->extract)
            value = (*operand->extract) (insn, &invalid);
          else
-           value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
+           value = (insn >> operand->shift) & ((1ull << operand->bits) - 1);
 
          /* Check for LIMM indicator.  If it is there, then make sure
             we pick the right format.  */
@@ -303,14 +305,14 @@ find_format_from_table (struct disassemble_info *info,
              if ((value == 0x3E && insn_len == 4)
                  || (value == limmind && insn_len == 2))
                {
-                 invalid = TRUE;
+                 invalid = true;
                  break;
                }
            }
 
          if (operand->flags & ARC_OPERAND_LIMM
              && !(operand->flags & ARC_OPERAND_DUPLICATE))
-           *has_limm = TRUE;
+           *has_limm = true;
        }
 
       /* Check the flags.  */
@@ -349,7 +351,7 @@ find_format_from_table (struct disassemble_info *info,
 
          if (!foundA && foundB)
            {
-             invalid = TRUE;
+             invalid = true;
              break;
            }
        }
@@ -360,7 +362,7 @@ find_format_from_table (struct disassemble_info *info,
       if (insn_len == 4
          && overlaps)
        {
-         warn_p = TRUE;
+         warn_p = true;
          t_op = opcode;
          if (skip_this_opcode (opcode))
            continue;
@@ -373,11 +375,12 @@ find_format_from_table (struct disassemble_info *info,
 
   if (warn_p)
     {
-      info->fprintf_func (info->stream,
-                         _("\nWarning: disassembly may be wrong due to "
-                           "guessed opcode class choice.\n"
-                           "Use -M<class[,class]> to select the correct "
-                           "opcode class(es).\n\t\t\t\t"));
+      info->fprintf_styled_func
+       (info->stream, dis_style_text,
+        _("\nWarning: disassembly may be wrong due to "
+          "guessed opcode class choice.\n"
+          "Use -M<class[,class]> to select the correct "
+          "opcode class(es).\n\t\t\t\t"));
       return t_op;
     }
 
@@ -408,7 +411,7 @@ find_format_from_table (struct disassemble_info *info,
    that calls to OPERAND_ITERATOR_NEXT will iterate over the opcode's
    operands.  */
 
-static bfd_boolean
+static bool
 find_format (bfd_vma                       memaddr,
             unsigned long long            insn,
             unsigned int *                insn_len,
@@ -418,7 +421,7 @@ find_format (bfd_vma                       memaddr,
              struct arc_operand_iterator * iter)
 {
   const struct arc_opcode *opcode = NULL;
-  bfd_boolean needs_limm;
+  bool needs_limm = false;
   const extInstruction_t *einsn, *i;
   unsigned limm = 0;
   struct arc_disassemble_info *arc_infop = info->private_data;
@@ -434,23 +437,25 @@ find_format (bfd_vma                       memaddr,
          opcode = arcExtMap_genOpcode (i, isa_mask, &errmsg);
          if (opcode == NULL)
            {
-             (*info->fprintf_func) (info->stream, "\
-An error occured while generating the extension instruction operations");
+             (*info->fprintf_styled_func)
+               (info->stream, dis_style_text,
+                _("An error occurred while generating "
+                  "the extension instruction operations"));
              *opcode_result = NULL;
-             return FALSE;
+             return false;
            }
 
          opcode = find_format_from_table (info, opcode, insn, *insn_len,
-                                          isa_mask, &needs_limm, FALSE);
+                                          isa_mask, &needs_limm, false);
        }
     }
 
   /* Then, try finding the first match in the opcode table.  */
   if (opcode == NULL)
     opcode = find_format_from_table (info, arc_opcodes, insn, *insn_len,
-                                    isa_mask, &needs_limm, TRUE);
+                                    isa_mask, &needs_limm, true);
 
-  if (needs_limm && opcode != NULL)
+  if (opcode != NULL && needs_limm)
     {
       bfd_byte buffer[4];
       int status;
@@ -480,10 +485,10 @@ An error occured while generating the extension instruction operations");
 
   /* Update private data.  */
   arc_infop->opcode = opcode;
-  arc_infop->limm = (needs_limm) ? limm : 0;
+  arc_infop->limm = limm;
   arc_infop->limm_p = needs_limm;
 
-  return TRUE;
+  return true;
 }
 
 static void
@@ -511,7 +516,8 @@ print_flags (const struct arc_opcode *opcode,
          name = arcExtMap_condCodeName (value);
          if (name)
            {
-             (*info->fprintf_func) (info->stream, ".%s", name);
+             (*info->fprintf_styled_func) (info->stream, dis_style_mnemonic,
+                                           ".%s", name);
              continue;
            }
        }
@@ -542,7 +548,8 @@ print_flags (const struct arc_opcode *opcode,
            {
               /* FIXME!: print correctly nt/t flag.  */
              if (!special_flag_p (opcode->name, flg_operand->name))
-               (*info->fprintf_func) (info->stream, ".");
+               (*info->fprintf_styled_func) (info->stream,
+                                             dis_style_mnemonic, ".");
              else if (info->insn_type == dis_dref)
                {
                  switch (flg_operand->name[0])
@@ -577,7 +584,8 @@ print_flags (const struct arc_opcode *opcode,
              if (cl_flags->flag_class & F_CLASS_WB)
                arc_infop->writeback_mode = flg_operand->code;
 
-             (*info->fprintf_func) (info->stream, "%s", flg_operand->name);
+             (*info->fprintf_styled_func) (info->stream, dis_style_mnemonic,
+                                           "%s", flg_operand->name);
            }
        }
     }
@@ -669,7 +677,7 @@ arc_insn_length (bfd_byte msb, bfd_byte lsb, struct disassemble_info *info)
       break;
 
     default:
-      abort ();
+      return 0;
     }
 }
 
@@ -691,7 +699,7 @@ extract_operand_value (const struct arc_operand *operand,
   else
     {
       if (operand->extract)
-        value = (*operand->extract) (insn, (int *) NULL);
+       value = (*operand->extract) (insn, (bool *) NULL);
       else
         {
           if (operand->flags & ARC_OPERAND_ALIGNED32)
@@ -721,7 +729,7 @@ extract_operand_value (const struct arc_operand *operand,
    into VALUE.  If there is no operand returned then OPERAND and VALUE are
    unchanged.  */
 
-static bfd_boolean
+static bool
 operand_iterator_next (struct arc_operand_iterator *iter,
                        const struct arc_operand **operand,
                        int *value)
@@ -729,14 +737,14 @@ operand_iterator_next (struct arc_operand_iterator *iter,
   if (*iter->opidx == 0)
     {
       *operand = NULL;
-      return FALSE;
+      return false;
     }
 
   *operand = &arc_operands[*iter->opidx];
   *value = extract_operand_value (*operand, iter->insn, iter->limm);
   iter->opidx++;
 
-  return TRUE;
+  return true;
 }
 
 /* Helper for parsing the options.  */
@@ -764,6 +772,23 @@ parse_option (const char *option)
   else if (disassembler_options_cmp (option, "fpuda") == 0)
     add_to_decodelist (FLOAT, DPA);
 
+  else if (disassembler_options_cmp (option, "nps400") == 0)
+    {
+      add_to_decodelist (ACL, NPS400);
+      add_to_decodelist (ARITH, NPS400);
+      add_to_decodelist (BITOP, NPS400);
+      add_to_decodelist (BMU, NPS400);
+      add_to_decodelist (CONTROL, NPS400);
+      add_to_decodelist (DMA, NPS400);
+      add_to_decodelist (DPI, NPS400);
+      add_to_decodelist (MEMORY, NPS400);
+      add_to_decodelist (MISC, NPS400);
+      add_to_decodelist (NET, NPS400);
+      add_to_decodelist (PMU, NPS400);
+      add_to_decodelist (PROTOCOL_DECODE, NPS400);
+      add_to_decodelist (ULTRAIP, NPS400);
+    }
+
   else if (disassembler_options_cmp (option, "fpus") == 0)
     {
       add_to_decodelist (FLOAT, SP);
@@ -775,8 +800,8 @@ parse_option (const char *option)
       add_to_decodelist (FLOAT, DP);
       add_to_decodelist (FLOAT, CVT);
     }
-  else if (CONST_STRNEQ (option, "hex"))
-    print_hex = TRUE;
+  else if (startswith (option, "hex"))
+    print_hex = true;
   else
     /* xgettext:c-format */
     opcodes_error_handler (_("unrecognised disassembler option: %s"), option);
@@ -869,6 +894,7 @@ arc_opcode_to_insn_type (const struct arc_opcode *opcode)
     case BI:
     case BIH:
     case BRCC:
+    case DBNZ:
     case EI:
     case JLI:
     case JUMP:
@@ -921,14 +947,14 @@ print_insn_arc (bfd_vma memaddr,
   unsigned long long insn = 0;
   unsigned isa_mask = ARC_OPCODE_NONE;
   const struct arc_opcode *opcode;
-  bfd_boolean need_comma;
-  bfd_boolean open_braket;
+  bool need_comma;
+  bool open_braket;
   int size;
   const struct arc_operand *operand;
   int value, vpcl;
   struct arc_operand_iterator iter;
   struct arc_disassemble_info *arc_infop;
-  bfd_boolean rpcl = FALSE, rset = FALSE;
+  bool rpcl = false, rset = false;
 
   if (info->disassembler_options)
     {
@@ -989,7 +1015,6 @@ print_insn_arc (bfd_vma memaddr,
      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
@@ -997,7 +1022,6 @@ print_insn_arc (bfd_vma memaddr,
      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))
     {
@@ -1043,22 +1067,40 @@ print_insn_arc (bfd_vma memaddr,
       switch (size)
        {
        case 1:
-         (*info->fprintf_func) (info->stream, ".byte\t0x%02lx", data);
+         (*info->fprintf_styled_func) (info->stream,
+                                       dis_style_assembler_directive,
+                                       ".byte");
+         (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
+         (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
+                                       "0x%02lx", data);
          break;
        case 2:
-         (*info->fprintf_func) (info->stream, ".short\t0x%04lx", data);
+         (*info->fprintf_styled_func) (info->stream,
+                                       dis_style_assembler_directive,
+                                       ".short");
+         (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
+         (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
+                                       "0x%04lx", data);
          break;
        case 4:
-         (*info->fprintf_func) (info->stream, ".word\t0x%08lx", data);
+         (*info->fprintf_styled_func) (info->stream,
+                                       dis_style_assembler_directive,
+                                       ".word");
+         (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
+         (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
+                                       "0x%08lx", data);
          break;
        default:
-         abort ();
+         return -1;
        }
       return size;
     }
 
   insn_len = arc_insn_length (buffer[highbyte], buffer[lowbyte], info);
   pr_debug ("instruction length = %d bytes\n", insn_len);
+  if (insn_len == 0)
+    return -1;
+
   arc_infop = info->private_data;
   arc_infop->insn_len = insn_len;
 
@@ -1111,7 +1153,7 @@ print_insn_arc (bfd_vma memaddr,
 
     default:
       /* There is no instruction whose length is not 2, 4, 6, or 8.  */
-      abort ();
+      return -1;
     }
 
   pr_debug ("instruction value = %llx\n", insn);
@@ -1125,7 +1167,7 @@ print_insn_arc (bfd_vma memaddr,
   info->target2                   = 0;
 
   /* FIXME to be moved in dissasemble_init_for_target.  */
-  info->disassembler_needs_relocs = TRUE;
+  info->disassembler_needs_relocs = true;
 
   /* Find the first match in the opcode table.  */
   if (!find_format (memaddr, insn, &insn_len, isa_mask, info, &opcode, &iter))
@@ -1136,27 +1178,49 @@ print_insn_arc (bfd_vma memaddr,
       switch (insn_len)
        {
        case 2:
-         (*info->fprintf_func) (info->stream, ".shor\t%#04llx",
-                                insn & 0xffff);
+         (*info->fprintf_styled_func) (info->stream,
+                                       dis_style_assembler_directive,
+                                       ".short");
+         (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
+         (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
+                                       "0x%04llx", insn & 0xffff);
          break;
+
        case 4:
-         (*info->fprintf_func) (info->stream, ".word\t%#08llx",
-                                insn & 0xffffffff);
+         (*info->fprintf_styled_func) (info->stream,
+                                       dis_style_assembler_directive,
+                                       ".word");
+         (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
+         (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
+                                       "0x%08llx", insn & 0xffffffff);
          break;
+
        case 6:
-         (*info->fprintf_func) (info->stream, ".long\t%#08llx",
-                                insn & 0xffffffff);
-         (*info->fprintf_func) (info->stream, ".long\t%#04llx",
-                                (insn >> 32) & 0xffff);
+         (*info->fprintf_styled_func) (info->stream,
+                                       dis_style_assembler_directive,
+                                       ".long");
+         (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
+         (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
+                                      "0x%08llx", insn & 0xffffffff);
+         (*info->fprintf_styled_func) (info->stream, dis_style_text, " ");
+         (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
+                                       "0x%04llx", (insn >> 32) & 0xffff);
          break;
+
        case 8:
-         (*info->fprintf_func) (info->stream, ".long\t%#08llx",
-                                insn & 0xffffffff);
-         (*info->fprintf_func) (info->stream, ".long\t%#08llx",
-                                insn >> 32);
+         (*info->fprintf_styled_func) (info->stream,
+                                       dis_style_assembler_directive,
+                                       ".long");
+         (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
+         (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
+                                       "0x%08llx", insn & 0xffffffff);
+         (*info->fprintf_styled_func) (info->stream, dis_style_text, " ");
+         (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
+                                       "0x%08llx", (insn >> 32));
          break;
+
        default:
-         abort ();
+         return -1;
        }
 
       info->insn_type = dis_noninsn;
@@ -1164,7 +1228,8 @@ print_insn_arc (bfd_vma memaddr,
     }
 
   /* Print the mnemonic.  */
-  (*info->fprintf_func) (info->stream, "%s", opcode->name);
+  (*info->fprintf_styled_func) (info->stream, dis_style_mnemonic,
+                               "%s", opcode->name);
 
   /* Preselect the insn class.  */
   info->insn_type = arc_opcode_to_insn_type (opcode);
@@ -1174,10 +1239,10 @@ print_insn_arc (bfd_vma memaddr,
   print_flags (opcode, &insn, info);
 
   if (opcode->operands[0] != 0)
-    (*info->fprintf_func) (info->stream, "\t");
+    (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
 
-  need_comma = FALSE;
-  open_braket = FALSE;
+  need_comma = false;
+  open_braket = false;
   arc_infop->operands_count = 0;
 
   /* Now extract and print the operands.  */
@@ -1187,8 +1252,8 @@ print_insn_arc (bfd_vma memaddr,
     {
       if (open_braket && (operand->flags & ARC_OPERAND_BRAKET))
        {
-         (*info->fprintf_func) (info->stream, "]");
-         open_braket = FALSE;
+         (*info->fprintf_styled_func) (info->stream, dis_style_text, "]");
+         open_braket = false;
          continue;
        }
 
@@ -1203,35 +1268,35 @@ print_insn_arc (bfd_vma memaddr,
 
       if (operand->flags & ARC_OPERAND_COLON)
        {
-         (*info->fprintf_func) (info->stream, ":");
+         (*info->fprintf_styled_func) (info->stream, dis_style_text, ":");
          continue;
        }
 
       if (need_comma)
-       (*info->fprintf_func) (info->stream, ",");
+       (*info->fprintf_styled_func) (info->stream, dis_style_text,",");
 
       if (!open_braket && (operand->flags & ARC_OPERAND_BRAKET))
        {
-         (*info->fprintf_func) (info->stream, "[");
-         open_braket = TRUE;
-         need_comma = FALSE;
+         (*info->fprintf_styled_func) (info->stream, dis_style_text, "[");
+         open_braket = true;
+         need_comma = false;
          continue;
        }
 
-      need_comma = TRUE;
+      need_comma = true;
 
       if (operand->flags & ARC_OPERAND_PCREL)
        {
-         rpcl = TRUE;
+         rpcl = true;
          vpcl = value;
-         rset = TRUE;
+         rset = true;
 
          info->target = (bfd_vma) (memaddr & ~3) + value;
        }
       else if (!(operand->flags & ARC_OPERAND_IR))
        {
          vpcl = value;
-         rset = TRUE;
+         rset = true;
        }
 
       /* Print the operand as directed by the flags.  */
@@ -1243,28 +1308,40 @@ print_insn_arc (bfd_vma memaddr,
          rname = arcExtMap_coreRegName (value);
          if (!rname)
            rname = regnames[value];
-         (*info->fprintf_func) (info->stream, "%s", rname);
+         (*info->fprintf_styled_func) (info->stream, dis_style_register,
+                                       "%s", rname);
+
+         /* Check if we have a double register to print.  */
          if (operand->flags & ARC_OPERAND_TRUNCATE)
            {
-             rname = arcExtMap_coreRegName (value + 1);
-             if (!rname)
-               rname = regnames[value + 1];
-             (*info->fprintf_func) (info->stream, "%s", rname);
+             if ((value & 0x01) == 0)
+               {
+                 rname = arcExtMap_coreRegName (value + 1);
+                 if (!rname)
+                   rname = regnames[value + 1];
+               }
+             else
+               rname = _("\nWarning: illegal use of double register "
+                         "pair.\n");
+             (*info->fprintf_styled_func) (info->stream, dis_style_register,
+                                           "%s", rname);
            }
          if (value == 63)
-           rpcl = TRUE;
+           rpcl = true;
          else
-           rpcl = FALSE;
+           rpcl = false;
        }
       else if (operand->flags & ARC_OPERAND_LIMM)
        {
          const char *rname = get_auxreg (opcode, value, isa_mask);
 
          if (rname && open_braket)
-           (*info->fprintf_func) (info->stream, "%s", rname);
+           (*info->fprintf_styled_func) (info->stream, dis_style_register,
+                                         "%s", rname);
          else
            {
-             (*info->fprintf_func) (info->stream, "%#x", value);
+             (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
+                                           "%#x", value);
              if (info->insn_type == dis_branch
                  || info->insn_type == dis_jsr)
                info->target = (bfd_vma) value;
@@ -1274,21 +1351,25 @@ print_insn_arc (bfd_vma memaddr,
        {
          const char *rname = get_auxreg (opcode, value, isa_mask);
          if (rname && open_braket)
-           (*info->fprintf_func) (info->stream, "%s", rname);
+           (*info->fprintf_styled_func) (info->stream, dis_style_register,
+                                         "%s", rname);
          else
            {
              if (print_hex)
-               (*info->fprintf_func) (info->stream, "%#x", value);
+               (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
+                                             "%#x", value);
              else
-               (*info->fprintf_func) (info->stream, "%d", value);
+               (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
+                                             "%d", value);
            }
        }
       else if (operand->flags & ARC_OPERAND_ADDRTYPE)
        {
          const char *addrtype = get_addrtype (value);
-         (*info->fprintf_func) (info->stream, "%s", addrtype);
+         (*info->fprintf_styled_func) (info->stream, dis_style_address,
+                                       "%s", addrtype);
          /* A colon follow an address type.  */
-         need_comma = FALSE;
+         need_comma = false;
        }
       else
        {
@@ -1301,26 +1382,34 @@ print_insn_arc (bfd_vma memaddr,
              switch (value)
                {
                case 0:
-                 need_comma = FALSE;
+                 need_comma = false;
                  break;
                case 1:
-                 (*info->fprintf_func) (info->stream, "r13");
+                 (*info->fprintf_styled_func) (info->stream,
+                                               dis_style_register, "r13");
                  break;
                default:
-                 (*info->fprintf_func) (info->stream, "r13-%s",
-                                        regnames[13 + value - 1]);
+                 (*info->fprintf_styled_func) (info->stream,
+                                               dis_style_register, "r13");
+                 (*info->fprintf_styled_func) (info->stream,
+                                               dis_style_text, "-");
+                 (*info->fprintf_styled_func) (info->stream,
+                                               dis_style_register, "%s",
+                                               regnames[13 + value - 1]);
                  break;
                }
-             rpcl = FALSE;
-             rset = FALSE;
+             rpcl = false;
+             rset = false;
            }
          else
            {
              const char *rname = get_auxreg (opcode, value, isa_mask);
              if (rname && open_braket)
-               (*info->fprintf_func) (info->stream, "%s", rname);
+               (*info->fprintf_styled_func) (info->stream, dis_style_register,
+                                             "%s", rname);
              else
-               (*info->fprintf_func) (info->stream, "%#x", value);
+               (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
+                                             "%#x", value);
            }
        }
 
@@ -1354,7 +1443,8 @@ print_insn_arc (bfd_vma memaddr,
           the addend is not currently pc-relative.  */
        memaddr = 0;
 
-      (*info->fprintf_func) (info->stream, "\t;");
+      (*info->fprintf_styled_func) (info->stream,
+                                   dis_style_comment_start, "\t;");
       (*info->print_address_func) ((memaddr & ~3) + vpcl, info);
     }
 
@@ -1379,39 +1469,169 @@ arc_get_disassembler (bfd *abfd)
   return print_insn_arc;
 }
 
+/* Indices into option argument vector for options that do require
+   an argument.  Use ARC_OPTION_ARG_NONE for options that don't
+   expect an argument.  */
+typedef enum
+{
+  ARC_OPTION_ARG_NONE = -1,
+  ARC_OPTION_ARG_ARCH,
+  ARC_OPTION_ARG_SIZE
+} arc_option_arg_t;
+
+/* Valid ARC disassembler options.  */
+static struct
+{
+  const char *name;
+  const char *description;
+  arc_option_arg_t arg;
+} arc_options[] =
+{
+  { "cpu=",       N_("Enforce the designated architecture while decoding."),
+                 ARC_OPTION_ARG_ARCH },
+  { "dsp",       N_("Recognize DSP instructions."),
+                 ARC_OPTION_ARG_NONE },
+  { "spfp",      N_("Recognize FPX SP instructions."),
+                 ARC_OPTION_ARG_NONE },
+  { "dpfp",      N_("Recognize FPX DP instructions."),
+                 ARC_OPTION_ARG_NONE },
+  { "quarkse_em", N_("Recognize FPU QuarkSE-EM instructions."),
+                 ARC_OPTION_ARG_NONE },
+  { "fpuda",     N_("Recognize double assist FPU instructions."),
+                 ARC_OPTION_ARG_NONE },
+  { "fpus",      N_("Recognize single precision FPU instructions."),
+                 ARC_OPTION_ARG_NONE },
+  { "fpud",      N_("Recognize double precision FPU instructions."),
+                 ARC_OPTION_ARG_NONE },
+  { "nps400",    N_("Recognize NPS400 instructions."),
+                 ARC_OPTION_ARG_NONE },
+  { "hex",       N_("Use only hexadecimal number to print immediates."),
+                 ARC_OPTION_ARG_NONE }
+};
+
+/* Populate the structure for representing ARC's disassembly options.
+   Such a dynamic initialization is desired, because it makes the maintenance
+   easier and also gdb uses this to enable the "disassembler-option".  */
+
+const disasm_options_and_args_t *
+disassembler_options_arc (void)
+{
+  static disasm_options_and_args_t *opts_and_args;
+
+  if (opts_and_args == NULL)
+    {
+      disasm_option_arg_t *args;
+      disasm_options_t *opts;
+      size_t i;
+      const size_t nr_of_options = ARRAY_SIZE (arc_options);
+      /* There is a null element at the end of CPU_TYPES, therefore
+        NR_OF_CPUS is actually 1 more and that is desired here too.  */
+      const size_t nr_of_cpus = ARRAY_SIZE (cpu_types);
+
+      opts_and_args = XNEW (disasm_options_and_args_t);
+      opts_and_args->args
+       = XNEWVEC (disasm_option_arg_t, ARC_OPTION_ARG_SIZE + 1);
+      opts_and_args->options.name
+       = XNEWVEC (const char *, nr_of_options + 1);
+      opts_and_args->options.description
+       = XNEWVEC (const char *, nr_of_options + 1);
+      opts_and_args->options.arg
+       = XNEWVEC (const disasm_option_arg_t *, nr_of_options + 1);
+
+      /* Populate the arguments for "cpu=" option.  */
+      args = opts_and_args->args;
+      args[ARC_OPTION_ARG_ARCH].name = "ARCH";
+      args[ARC_OPTION_ARG_ARCH].values = XNEWVEC (const char *, nr_of_cpus);
+      for (i = 0; i < nr_of_cpus; ++i)
+       args[ARC_OPTION_ARG_ARCH].values[i] = cpu_types[i].name;
+      args[ARC_OPTION_ARG_SIZE].name = NULL;
+      args[ARC_OPTION_ARG_SIZE].values = NULL;
+
+      /* Populate the options.  */
+      opts = &opts_and_args->options;
+      for (i = 0; i < nr_of_options; ++i)
+       {
+         opts->name[i] = arc_options[i].name;
+         opts->description[i] = arc_options[i].description;
+         if (arc_options[i].arg != ARC_OPTION_ARG_NONE)
+           opts->arg[i] = &args[arc_options[i].arg];
+         else
+           opts->arg[i] = NULL;
+       }
+      opts->name[nr_of_options] = NULL;
+      opts->description[nr_of_options] = NULL;
+      opts->arg[nr_of_options] = NULL;
+    }
+
+  return opts_and_args;
+}
+
+
 void
 print_arc_disassembler_options (FILE *stream)
 {
-  int i;
+  const disasm_options_and_args_t *opts_and_args;
+  const disasm_option_arg_t *args;
+  const disasm_options_t *opts;
+  size_t i, j;
+  size_t max_len = 0;
+
+  opts_and_args = disassembler_options_arc ();
+  opts = &opts_and_args->options;
+  args = opts_and_args->args;
+
+  fprintf (stream, _("\nThe following ARC specific disassembler options are"
+                    " supported for use \nwith the -M switch (multiple"
+                    " options should be separated by commas):\n"));
+
+  /* Find the maximum length for printing options (and their arg name).  */
+  for (i = 0; opts->name[i] != NULL; ++i)
+    {
+      size_t len = strlen (opts->name[i]);
+      len += (opts->arg[i]) ? strlen (opts->arg[i]->name) : 0;
+      max_len = (len > max_len) ? len : max_len;
+    }
 
-  fprintf (stream, _("\n\
-The following ARC specific disassembler options are supported for use \n\
-with -M switch (multiple options should be separated by commas):\n"));
+  /* Print the options, their arg and description, if any.  */
+  for (i = 0, ++max_len; opts->name[i] != NULL; ++i)
+    {
+      fprintf (stream, "  %s", opts->name[i]);
+      if (opts->arg[i] != NULL)
+       fprintf (stream, "%s", opts->arg[i]->name);
+      if (opts->description[i] != NULL)
+       {
+         size_t len = strlen (opts->name[i]);
+         len += (opts->arg[i]) ? strlen (opts->arg[i]->name) : 0;
+         fprintf (stream,
+                  "%*c %s", (int) (max_len - len), ' ', opts->description[i]);
+       }
+      fprintf (stream, _("\n"));
+    }
 
-  /* cpu=... options.  */
-  for (i = 0; cpu_types[i].name; ++i)
+  /* Print the possible values of an argument.  */
+  for (i = 0; args[i].name != NULL; ++i)
     {
-      /* As of now all value CPU values are less than 16 characters.  */
-      fprintf (stream, "  cpu=%-16s\tEnforce %s ISA.\n",
-              cpu_types[i].name, cpu_types[i].isa);
+      size_t len = 3;
+      if (args[i].values == NULL)
+       continue;
+      fprintf (stream, _("\n\
+  For the options above, the following values are supported for \"%s\":\n   "),
+              args[i].name);
+      for (j = 0; args[i].values[j] != NULL; ++j)
+       {
+         fprintf (stream, " %s", args[i].values[j]);
+         len += strlen (args[i].values[j]) + 1;
+         /* reset line if printed too long.  */
+         if (len >= 78)
+           {
+             fprintf (stream, _("\n   "));
+             len = 3;
+           }
+       }
+      fprintf (stream, _("\n"));
     }
 
-  fprintf (stream, _("\
-  dsp             Recognize DSP instructions.\n"));
-  fprintf (stream, _("\
-  spfp            Recognize FPX SP instructions.\n"));
-  fprintf (stream, _("\
-  dpfp            Recognize FPX DP instructions.\n"));
-  fprintf (stream, _("\
-  quarkse_em      Recognize FPU QuarkSE-EM instructions.\n"));
-  fprintf (stream, _("\
-  fpuda           Recognize double assist FPU instructions.\n"));
-  fprintf (stream, _("\
-  fpus            Recognize single precision FPU instructions.\n"));
-  fprintf (stream, _("\
-  fpud            Recognize double precision FPU instructions.\n"));
-  fprintf (stream, _("\
-  hex             Use only hexadecimal number to print immediates.\n"));
+  fprintf (stream, _("\n"));
 }
 
 void arc_insn_decode (bfd_vma addr,
@@ -1428,7 +1648,7 @@ void arc_insn_decode (bfd_vma addr,
   /* There was an error when disassembling, for example memory read error.  */
   if (disasm_func (addr, info) < 0)
     {
-      insn->valid = FALSE;
+      insn->valid = false;
       return;
     }
 
@@ -1441,11 +1661,11 @@ void arc_insn_decode (bfd_vma addr,
   /* Quick exit if memory at this address is not an instruction.  */
   if (info->insn_type == dis_noninsn)
     {
-      insn->valid = FALSE;
+      insn->valid = false;
       return;
     }
 
-  insn->valid = TRUE;
+  insn->valid = true;
 
   opcode = (const struct arc_opcode *) arc_infop->opcode;
   insn->insn_class = opcode->insn_class;