use XNEW and related macros more
[deliverable/binutils-gdb.git] / gas / config / tc-arc.c
index 3aeedb1943aea95cafe049b646066488d4966ed7..28f135b2c783ed1eb737488f37b6ffbebb3759bd 100644 (file)
@@ -140,6 +140,7 @@ static void arc_lcomm (int);
 static void arc_option (int);
 static void arc_extra_reloc (int);
 static void arc_extinsn (int);
+static void arc_extcorereg (int);
 
 const pseudo_typeS md_pseudo_table[] =
 {
@@ -151,7 +152,10 @@ const pseudo_typeS md_pseudo_table[] =
   { "lcommon", arc_lcomm, 0 },
   { "cpu",     arc_option, 0 },
 
-  { "extinstruction", arc_extinsn, 0 },
+  { "extinstruction",  arc_extinsn, 0 },
+  { "extcoreregister", arc_extcorereg, EXT_CORE_REGISTER },
+  { "extauxregister",  arc_extcorereg, EXT_AUX_REGISTER },
+  { "extcondcode",     arc_extcorereg, EXT_COND_CODE },
 
   { "tls_gd_ld",   arc_extra_reloc, BFD_RELOC_ARC_TLS_GD_LD },
   { "tls_gd_call", arc_extra_reloc, BFD_RELOC_ARC_TLS_GD_CALL },
@@ -333,7 +337,9 @@ static const attributes_t suffixclass[] =
 static const attributes_t syntaxclass[] =
 {
   { "SYNTAX_3OP", 10, ARC_SYNTAX_3OP },
-  { "SYNTAX_2OP", 10, ARC_SYNTAX_2OP }
+  { "SYNTAX_2OP", 10, ARC_SYNTAX_2OP },
+  { "SYNTAX_1OP", 10, ARC_SYNTAX_1OP },
+  { "SYNTAX_NOP", 10, ARC_SYNTAX_NOP }
 };
 
 /* Extension instruction syntax classes modifiers.  */
@@ -343,6 +349,21 @@ static const attributes_t syntaxclassmod[] =
   { "OP1_MUST_BE_IMM" , 15, ARC_OP1_MUST_BE_IMM }
 };
 
+/* Extension register type.  */
+typedef struct
+{
+  char *name;
+  int  number;
+  int  imode;
+} extRegister_t;
+
+/* A structure to hold the additional conditional codes.  */
+static struct
+{
+  struct arc_flag_operand *arc_ext_condcode;
+  int size;
+} ext_condcode = { NULL, 0 };
+
 /* Structure to hold an entry in ARC_OPCODE_HASH.  */
 struct arc_opcode_hash_entry
 {
@@ -377,8 +398,8 @@ static unsigned arc_features;
 /* The default architecture.  */
 static int arc_mach_type;
 
-/* Non-zero if the cpu type has been explicitly specified.  */
-static int mach_type_specified_p = 0;
+/* TRUE if the cpu type has been explicitly specified.  */
+static bfd_boolean mach_type_specified_p = FALSE;
 
 /* The hash table of instruction opcodes.  */
 static struct hash_control *arc_opcode_hash;
@@ -386,6 +407,9 @@ static struct hash_control *arc_opcode_hash;
 /* The hash table of register symbols.  */
 static struct hash_control *arc_reg_hash;
 
+/* The hash table of aux register symbols.  */
+static struct hash_control *arc_aux_hash;
+
 /* A table of CPU names and opcode sets.  */
 static const struct cpu_type
 {
@@ -676,7 +700,7 @@ arc_insert_opcode (const struct arc_opcode *opcode)
   entry = hash_find (arc_opcode_hash, name);
   if (entry == NULL)
     {
-      entry = xmalloc (sizeof (*entry));
+      entry = XNEW (struct arc_opcode_hash_entry);
       entry->count = 0;
       entry->opcode = NULL;
 
@@ -686,9 +710,8 @@ arc_insert_opcode (const struct arc_opcode *opcode)
                  name, retval);
     }
 
-  entry->opcode = xrealloc (entry->opcode,
-                           sizeof (const struct arc_opcode *)
-                           * (entry->count + 1));
+  entry->opcode = XRESIZEVEC (const struct arc_opcode *, entry->opcode,
+                             entry->count + 1);
 
   if (entry->opcode == NULL)
     as_fatal (_("Virtual memory exhausted"));
@@ -875,11 +898,18 @@ arc_option (int ignore ATTRIBUTE_UNUSED)
        {
          md_parse_option (OPTION_MCPU, "archs");
        }
+      else if (!strcmp ("NPS400", cpu))
+       {
+         md_parse_option (OPTION_MCPU, "nps400");
+       }
       else
        as_fatal (_("could not find the architecture"));
 
       if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, mach))
        as_fatal (_("could not set architecture and machine"));
+
+      /* Set elf header flags.  */
+      bfd_set_private_flags (stdoutput, arc_eflag);
     }
   else
     if (arc_mach_type != mach)
@@ -1658,31 +1688,23 @@ find_opcode_match (const struct arc_opcode_hash_entry *entry,
                case O_symbol:
                  {
                    const char *p;
-                   size_t len;
                    const struct arc_aux_reg *auxr;
-                   unsigned j;
 
                    if (opcode->class != AUXREG)
                      goto de_fault;
                    p = S_GET_NAME (tok[tokidx].X_add_symbol);
-                   len = strlen (p);
-
-                   auxr = &arc_aux_regs[0];
-                   for (j = 0; j < arc_num_aux_regs; j++, auxr++)
-                     if (len == auxr->length
-                         && strcasecmp (auxr->name, p) == 0
-                          && ((auxr->subclass == NONE)
-                              || check_cpu_feature (auxr->subclass)))
-                       {
-                         /* We modify the token array here, safe in the
-                            knowledge, that if this was the wrong choice
-                            then the original contents will be restored
-                            from BKTOK.  */
-                         tok[tokidx].X_op = O_constant;
-                         tok[tokidx].X_add_number = auxr->address;
-                         ARC_SET_FLAG (tok[tokidx].X_add_symbol, ARC_FLAG_AUX);
-                         break;
-                       }
+
+                   auxr = hash_find (arc_aux_hash, p);
+                   if (auxr)
+                     {
+                       /* We modify the token array here, safe in the
+                          knowledge, that if this was the wrong
+                          choice then the original contents will be
+                          restored from BKTOK.  */
+                       tok[tokidx].X_op = O_constant;
+                       tok[tokidx].X_add_number = auxr->address;
+                       ARC_SET_FLAG (tok[tokidx].X_add_symbol, ARC_FLAG_AUX);
+                     }
 
                    if (tok[tokidx].X_op != O_constant)
                      goto de_fault;
@@ -1809,7 +1831,7 @@ find_opcode_match (const struct arc_opcode_hash_entry *entry,
       /* Setup ready for flag parsing.  */
       lnflg = nflgs;
       for (i = 0; i < nflgs; i++)
-        first_pflag [i].code = 0;
+       first_pflag[i].flgp = NULL;
 
       /* Check the flags.  Iterate over the valid flag classes.  */
       for (flgidx = opcode->flags; *flgidx; ++flgidx)
@@ -1818,31 +1840,57 @@ find_opcode_match (const struct arc_opcode_hash_entry *entry,
          const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
          const unsigned *flgopridx;
          int cl_matches = 0;
+         struct arc_flags *pflag = NULL;
+
+         /* Check for extension conditional codes.  */
+         if (ext_condcode.arc_ext_condcode
+             && cl_flags->class & F_CLASS_EXTEND)
+           {
+             struct arc_flag_operand *pf = ext_condcode.arc_ext_condcode;
+             while (pf->name)
+               {
+                 pflag = first_pflag;
+                 for (i = 0; i < nflgs; i++, pflag++)
+                   {
+                     if (!strcmp (pf->name, pflag->name))
+                       {
+                         if (pflag->flgp != NULL)
+                           goto match_failed;
+                         /* Found it.  */
+                         cl_matches++;
+                         pflag->flgp = pf;
+                         lnflg--;
+                         break;
+                       }
+                   }
+                 pf++;
+               }
+           }
 
          for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
            {
              const struct arc_flag_operand *flg_operand;
-             struct arc_flags *pflag = first_pflag;
 
+             pflag = first_pflag;
              flg_operand = &arc_flag_operands[*flgopridx];
              for (i = 0; i < nflgs; i++, pflag++)
                {
                  /* Match against the parsed flags.  */
                  if (!strcmp (flg_operand->name, pflag->name))
                    {
-                     if (pflag->code != 0)
+                     if (pflag->flgp != NULL)
                        goto match_failed;
                      cl_matches++;
-                     pflag->code = *flgopridx;
+                     pflag->flgp = (struct arc_flag_operand *) flg_operand;
                      lnflg--;
                      break; /* goto next flag class and parsed flag.  */
                    }
                }
            }
 
-         if (cl_flags->class == F_CLASS_REQUIRED && cl_matches == 0)
+         if ((cl_flags->class & F_CLASS_REQUIRED) && cl_matches == 0)
            goto match_failed;
-         if (cl_flags->class == F_CLASS_OPTIONAL && cl_matches > 1)
+         if ((cl_flags->class & F_CLASS_OPTIONAL) && cl_matches > 1)
            goto match_failed;
        }
       /* Did I check all the parsed flags?  */
@@ -2213,9 +2261,7 @@ md_assemble (char *str)
 
   /* Split off the opcode.  */
   opnamelen = strspn (str, "abcdefghijklmnopqrstuvwxyz_0123468");
-  opname = xmalloc (opnamelen + 1);
-  memcpy (opname, str, opnamelen);
-  opname[opnamelen] = '\0';
+  opname = xmemdup0 (str, opnamelen);
 
   /* Signalize we are assmbling the instructions.  */
   assembling_insn = TRUE;
@@ -2345,6 +2391,30 @@ md_begin (void)
 
   /* Initialize the last instructions.  */
   memset (&arc_last_insns[0], 0, sizeof (arc_last_insns));
+
+  /* Aux register declaration.  */
+  arc_aux_hash = hash_new ();
+  if (arc_aux_hash == NULL)
+    as_fatal (_("Virtual memory exhausted"));
+
+  const struct arc_aux_reg *auxr = &arc_aux_regs[0];
+  unsigned int i;
+  for (i = 0; i < arc_num_aux_regs; i++, auxr++)
+    {
+      const char *retval;
+
+      if (!(auxr->cpu & arc_target))
+       continue;
+
+      if ((auxr->subclass != NONE)
+         && !check_cpu_feature (auxr->subclass))
+       continue;
+
+      retval = hash_insert (arc_aux_hash, auxr->name, (void *) auxr);
+      if (retval)
+       as_fatal (_("internal error: can't hash aux register '%s': %s"),
+                 auxr->name, retval);
+    }
 }
 
 /* Write a value out to the object file, using the appropriate
@@ -2866,8 +2936,8 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED,
   arelent *reloc;
   bfd_reloc_code_real_type code;
 
-  reloc = (arelent *) xmalloc (sizeof (* reloc));
-  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  reloc = XNEW (arelent);
+  reloc->sym_ptr_ptr = XNEW (asymbol *);
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
   reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
 
@@ -3092,7 +3162,7 @@ md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED)
     case OPTION_MCPU:
       {
         arc_select_cpu (arg);
-        mach_type_specified_p = 1;
+        mach_type_specified_p = TRUE;
        break;
       }
 
@@ -3631,8 +3701,7 @@ assemble_insn (const struct arc_opcode *opcode,
   /* Handle flags.  */
   for (i = 0; i < nflg; i++)
     {
-      const struct arc_flag_operand *flg_operand =
-       &arc_flag_operands[pflags[i].code];
+      const struct arc_flag_operand *flg_operand = pflags[i].flgp;
 
       /* Check if the instruction has a delay slot.  */
       if (!strcmp (flg_operand->name, "d"))
@@ -4163,13 +4232,15 @@ arc_extinsn (int ignore ATTRIBUTE_UNUSED)
       && (einsn.major != 5) && (einsn.major != 9))
     as_fatal (_("minor opcode not in range [0x00 - 0x3f]"));
 
-  switch (einsn.syntax & (ARC_SYNTAX_3OP | ARC_SYNTAX_2OP))
+  switch (einsn.syntax & ARC_SYNTAX_MASK)
     {
     case ARC_SYNTAX_3OP:
       if (einsn.modsyn & ARC_OP1_IMM_IMPLIED)
        as_fatal (_("Improper use of OP1_IMM_IMPLIED"));
       break;
     case ARC_SYNTAX_2OP:
+    case ARC_SYNTAX_1OP:
+    case ARC_SYNTAX_NOP:
       if (einsn.modsyn & ARC_OP1_MUST_BE_IMM)
        as_fatal (_("Improper use of OP1_MUST_BE_IMM"));
       break;
@@ -4194,6 +4265,249 @@ arc_extinsn (int ignore ATTRIBUTE_UNUSED)
   create_extinst_section (&einsn);
 }
 
+static void
+tokenize_extregister (extRegister_t *ereg, int opertype)
+{
+  char *name;
+  char *mode;
+  char c;
+  char *p;
+  int number, imode = 0;
+  bfd_boolean isCore_p = (opertype == EXT_CORE_REGISTER) ? TRUE : FALSE;
+  bfd_boolean isReg_p  = (opertype == EXT_CORE_REGISTER
+                         || opertype == EXT_AUX_REGISTER) ? TRUE : FALSE;
+
+  /* 1st: get register name.  */
+  SKIP_WHITESPACE ();
+  p = input_line_pointer;
+  c = get_symbol_name (&p);
+
+  name = xstrdup (p);
+  restore_line_pointer (c);
+
+  /* 2nd: get register number.  */
+  SKIP_WHITESPACE ();
+
+  if (*input_line_pointer != ',')
+    {
+      as_bad (_("expected comma after register name"));
+      ignore_rest_of_line ();
+      free (name);
+      return;
+    }
+  input_line_pointer++;
+  number = get_absolute_expression ();
+
+  if (number < 0)
+    {
+      as_bad (_("negative operand number %d"), number);
+      ignore_rest_of_line ();
+      free (name);
+      return;
+    }
+
+  if (isReg_p)
+    {
+      /* 3rd: get register mode.  */
+      SKIP_WHITESPACE ();
+
+      if (*input_line_pointer != ',')
+       {
+         as_bad (_("expected comma after register number"));
+         ignore_rest_of_line ();
+         free (name);
+         return;
+       }
+
+      input_line_pointer++;
+      mode = input_line_pointer;
+
+      if (!strncmp (mode, "r|w", 3))
+       {
+         imode = 0;
+         input_line_pointer += 3;
+       }
+      else if (!strncmp (mode, "r", 1))
+       {
+         imode = ARC_REGISTER_READONLY;
+         input_line_pointer += 1;
+       }
+      else if (strncmp (mode, "w", 1))
+       {
+         as_bad (_("invalid mode"));
+         ignore_rest_of_line ();
+         free (name);
+         return;
+       }
+      else
+       {
+         imode = ARC_REGISTER_WRITEONLY;
+         input_line_pointer += 1;
+       }
+    }
+
+  if (isCore_p)
+    {
+      /* 4th: get core register shortcut.  */
+      SKIP_WHITESPACE ();
+      if (*input_line_pointer != ',')
+       {
+         as_bad (_("expected comma after register mode"));
+         ignore_rest_of_line ();
+         free (name);
+         return;
+       }
+
+      input_line_pointer++;
+
+      if (!strncmp (input_line_pointer, "cannot_shortcut", 15))
+       {
+         imode |= ARC_REGISTER_NOSHORT_CUT;
+         input_line_pointer += 15;
+       }
+      else if (strncmp (input_line_pointer, "can_shortcut", 12))
+       {
+         as_bad (_("shortcut designator invalid"));
+         ignore_rest_of_line ();
+         free (name);
+         return;
+       }
+      else
+       {
+         input_line_pointer += 12;
+       }
+    }
+  demand_empty_rest_of_line ();
+
+  ereg->name = name;
+  ereg->number = number;
+  ereg->imode  = imode;
+}
+
+/* Create an extension register/condition description in the arc
+   extension section of the output file.
+
+   The structure for an instruction is like this:
+   [0]: Length of the record.
+   [1]: Type of the record.
+
+   For core regs and condition codes:
+   [2]: Value.
+   [3]+ Name.
+
+   For auxilirary registers:
+   [2..5]: Value.
+   [6]+ Name
+
+   The sequence is terminated by an empty entry.  */
+
+static void
+create_extcore_section (extRegister_t *ereg, int opertype)
+{
+  segT old_sec   = now_seg;
+  int old_subsec = now_subseg;
+  char *p;
+  int name_len   = strlen (ereg->name);
+
+  arc_set_ext_seg ();
+
+  switch (opertype)
+    {
+    case EXT_COND_CODE:
+    case EXT_CORE_REGISTER:
+      p = frag_more (1);
+      *p = 3 + name_len + 1;
+      p = frag_more (1);
+      *p = opertype;
+      p = frag_more (1);
+      *p = ereg->number;
+      break;
+    case EXT_AUX_REGISTER:
+      p = frag_more (1);
+      *p = 6 + name_len + 1;
+      p = frag_more (1);
+      *p = EXT_AUX_REGISTER;
+      p = frag_more (1);
+      *p = (ereg->number >> 24) & 0xff;
+      p = frag_more (1);
+      *p = (ereg->number >> 16) & 0xff;
+      p = frag_more (1);
+      *p = (ereg->number >>  8) & 0xff;
+      p = frag_more (1);
+      *p = (ereg->number)       & 0xff;
+      break;
+    default:
+      break;
+    }
+
+  p = frag_more (name_len + 1);
+  strcpy (p, ereg->name);
+
+  subseg_set (old_sec, old_subsec);
+}
+
+/* Handler .extCoreRegister pseudo-op.  */
+
+static void
+arc_extcorereg (int opertype)
+{
+  extRegister_t ereg;
+  struct arc_aux_reg *auxr;
+  const char *retval;
+  struct arc_flag_operand *ccode;
+
+  memset (&ereg, 0, sizeof (ereg));
+  tokenize_extregister (&ereg, opertype);
+
+  switch (opertype)
+    {
+    case EXT_CORE_REGISTER:
+      /* Core register.  */
+      if (ereg.number > 60)
+       as_bad (_("core register %s value (%d) too large"), ereg.name,
+               ereg.number);
+      declare_register (ereg.name, ereg.number);
+      break;
+    case EXT_AUX_REGISTER:
+      /* Auxiliary register.  */
+      auxr = XNEW (struct arc_aux_reg);
+      auxr->name = ereg.name;
+      auxr->cpu = arc_target;
+      auxr->subclass = NONE;
+      auxr->address = ereg.number;
+      retval = hash_insert (arc_aux_hash, auxr->name, (void *) auxr);
+      if (retval)
+       as_fatal (_("internal error: can't hash aux register '%s': %s"),
+                 auxr->name, retval);
+      break;
+    case EXT_COND_CODE:
+      /* Condition code.  */
+      if (ereg.number > 31)
+       as_bad (_("condition code %s value (%d) too large"), ereg.name,
+               ereg.number);
+      ext_condcode.size ++;
+      ext_condcode.arc_ext_condcode =
+       XRESIZEVEC (struct arc_flag_operand, ext_condcode.arc_ext_condcode,
+                   ext_condcode.size + 1);
+      if (ext_condcode.arc_ext_condcode == NULL)
+       as_fatal (_("Virtual memory exhausted"));
+
+      ccode = ext_condcode.arc_ext_condcode + ext_condcode.size - 1;
+      ccode->name   = ereg.name;
+      ccode->code   = ereg.number;
+      ccode->bits   = 5;
+      ccode->shift  = 0;
+      ccode->favail = 0; /* not used.  */
+      ccode++;
+      memset (ccode, 0, sizeof (struct arc_flag_operand));
+      break;
+    default:
+      as_bad (_("Unknown extension"));
+      break;
+    }
+  create_extcore_section (&ereg, opertype);
+}
+
 /* Local variables:
    eval: (c-set-style "gnu")
    indent-tabs-mode: t
This page took 0.031123 seconds and 4 git commands to generate.