[ARC] Allow CPU to be enforced via disassemble_info options
[deliverable/binutils-gdb.git] / opcodes / arc-dis.c
index 0cf4bff1817bda0b325e8c77b2f50f0b224bfef6..edd0c0735a2510c7eeb6673161c2716592c01076 100644 (file)
@@ -117,6 +117,11 @@ typedef struct skipclass
    disassembling.  */
 static linkclass decodelist = NULL;
 
+/* ISA mask value enforced via disassembler info options.  ARC_OPCODE_NONE
+   value means that no CPU is enforced.  */
+
+static unsigned enforced_isa_mask = ARC_OPCODE_NONE;
+
 /* Macros section.  */
 
 #ifdef DEBUG
@@ -770,6 +775,49 @@ parse_option (const char *option)
     fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option);
 }
 
+#define ARC_CPU_TYPE_A6xx(NAME,EXTRA)                  \
+  { #NAME, ARC_OPCODE_ARC600, "ARC600" }
+#define ARC_CPU_TYPE_A7xx(NAME,EXTRA)                  \
+  { #NAME, ARC_OPCODE_ARC700, "ARC700" }
+#define ARC_CPU_TYPE_AV2EM(NAME,EXTRA)                 \
+  { #NAME,  ARC_OPCODE_ARCv2EM, "ARC EM" }
+#define ARC_CPU_TYPE_AV2HS(NAME,EXTRA)                 \
+  { #NAME,  ARC_OPCODE_ARCv2HS, "ARC HS" }
+#define ARC_CPU_TYPE_NONE                              \
+  { 0, 0, 0 }
+
+/* A table of CPU names and opcode sets.  */
+static const struct cpu_type
+{
+  const char *name;
+  unsigned flags;
+  const char *isa;
+}
+  cpu_types[] =
+{
+  #include "elf/arc-cpu.def"
+};
+
+/* Helper for parsing the CPU options.  Accept any of the ARC architectures
+   values.  OPTION should be a value passed to cpu=.  */
+
+static unsigned
+parse_cpu_option (const char *option)
+{
+  int i;
+
+  for (i = 0; cpu_types[i].name; ++i)
+    {
+      if (!strcasecmp (cpu_types[i].name, option))
+       {
+         return cpu_types[i].flags;
+       }
+    }
+
+  fprintf (stderr, _("Unrecognised disassembler CPU option: %s\n"), option);
+  return ARC_OPCODE_NONE;
+}
+
 /* Go over the options list and parse it.  */
 
 static void
@@ -778,6 +826,12 @@ parse_disassembler_options (const char *options)
   if (options == NULL)
     return;
 
+  /* Disassembler might be reused for difference CPU's, and cpu option set for
+     the first one shouldn't be applied to second (which might not have
+     explicit cpu in its options.  Therefore it is required to reset enforced
+     CPU when new options are being parsed.  */
+  enforced_isa_mask = ARC_OPCODE_NONE;
+
   while (*options)
     {
       /* Skip empty options.  */
@@ -787,7 +841,13 @@ parse_disassembler_options (const char *options)
          continue;
        }
 
-      parse_option (options);
+      /* A CPU option?  Cannot use STRING_COMMA_LEN because strncmp is also a
+        preprocessor macro.  */
+      if (strncmp (options, "cpu=", 4) == 0)
+       /* Strip leading `cpu=`.  */
+       enforced_isa_mask = parse_cpu_option (options + 4);
+      else
+       parse_option (options);
 
       while (*options != ',' && *options != '\0')
        ++ options;
@@ -859,7 +919,7 @@ print_insn_arc (bfd_vma memaddr,
   int status;
   unsigned int insn_len;
   unsigned long long insn = 0;
-  unsigned isa_mask;
+  unsigned isa_mask = ARC_OPCODE_NONE;
   const struct arc_opcode *opcode;
   bfd_boolean need_comma;
   bfd_boolean open_braket;
@@ -867,7 +927,6 @@ print_insn_arc (bfd_vma memaddr,
   const struct arc_operand *operand;
   int value;
   struct arc_operand_iterator iter;
-  Elf_Internal_Ehdr *header = NULL;
   struct arc_disassemble_info *arc_infop;
 
   if (info->disassembler_options)
@@ -885,34 +944,44 @@ print_insn_arc (bfd_vma memaddr,
   highbyte  = ((info->endian == BFD_ENDIAN_LITTLE) ? 1 : 0);
   lowbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 0 : 1);
 
-  if (info->section && info->section->owner)
-    header = elf_elfheader (info->section->owner);
-
-  switch (info->mach)
+  /* Figure out CPU type, unless it was enforced via disassembler options.  */
+  if (enforced_isa_mask == ARC_OPCODE_NONE)
     {
-    case bfd_mach_arc_arc700:
-      isa_mask = ARC_OPCODE_ARC700;
-      break;
+      Elf_Internal_Ehdr *header = NULL;
 
-    case bfd_mach_arc_arc600:
-      isa_mask = ARC_OPCODE_ARC600;
-      break;
+      if (info->section && info->section->owner)
+       header = elf_elfheader (info->section->owner);
 
-    case bfd_mach_arc_arcv2:
-    default:
-      isa_mask = ARC_OPCODE_ARCv2EM;
-      /* TODO: Perhaps remove defitinion of header since it is only used at
-        this location.  */
-      if (header != NULL
-         && (header->e_flags & EF_ARC_MACH_MSK) == EF_ARC_CPU_ARCV2HS)
+      switch (info->mach)
        {
-         isa_mask = ARC_OPCODE_ARCv2HS;
-         /* FPU instructions are not extensions for HS.  */
-         add_to_decodelist (FLOAT, SP);
-         add_to_decodelist (FLOAT, DP);
-         add_to_decodelist (FLOAT, CVT);
+       case bfd_mach_arc_arc700:
+         isa_mask = ARC_OPCODE_ARC700;
+         break;
+
+       case bfd_mach_arc_arc600:
+         isa_mask = ARC_OPCODE_ARC600;
+         break;
+
+       case bfd_mach_arc_arcv2:
+       default:
+         isa_mask = ARC_OPCODE_ARCv2EM;
+         /* TODO: Perhaps remove definition of header since it is only used at
+            this location.  */
+         if (header != NULL
+             && (header->e_flags & EF_ARC_MACH_MSK) == EF_ARC_CPU_ARCV2HS)
+           isa_mask = ARC_OPCODE_ARCv2HS;
+         break;
        }
-      break;
+    }
+  else
+    isa_mask = enforced_isa_mask;
+
+  if (isa_mask == ARC_OPCODE_ARCv2HS)
+    {
+      /* FPU instructions are not extensions for HS.  */
+      add_to_decodelist (FLOAT, SP);
+      add_to_decodelist (FLOAT, DP);
+      add_to_decodelist (FLOAT, CVT);
     }
 
   /* This variable may be set by the instruction decoder.  It suggests
@@ -1278,10 +1347,20 @@ arc_get_disassembler (bfd *abfd)
 void
 print_arc_disassembler_options (FILE *stream)
 {
+  int i;
+
   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"));
 
+  /* cpu=... options.  */
+  for (i = 0; cpu_types[i].name; ++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);
+    }
+
   fprintf (stream, _("\
   dsp             Recognize DSP instructions.\n"));
   fprintf (stream, _("\
This page took 0.025461 seconds and 4 git commands to generate.