138889Sjdp/* tc-arc.c -- Assembler for the ARC
2218822Sdim   Copyright 1994, 1995, 1997, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
3218822Sdim   2006  Free Software Foundation, Inc.
438889Sjdp   Contributed by Doug Evans (dje@cygnus.com).
538889Sjdp
638889Sjdp   This file is part of GAS, the GNU Assembler.
738889Sjdp
838889Sjdp   GAS is free software; you can redistribute it and/or modify
938889Sjdp   it under the terms of the GNU General Public License as published by
1038889Sjdp   the Free Software Foundation; either version 2, or (at your option)
1138889Sjdp   any later version.
1238889Sjdp
1338889Sjdp   GAS is distributed in the hope that it will be useful,
1438889Sjdp   but WITHOUT ANY WARRANTY; without even the implied warranty of
1538889Sjdp   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1638889Sjdp   GNU General Public License for more details.
1738889Sjdp
1838889Sjdp   You should have received a copy of the GNU General Public License
1960484Sobrien   along with GAS; see the file COPYING.  If not, write to the Free
20218822Sdim   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
21218822Sdim   02110-1301, USA.  */
2238889Sjdp
2338889Sjdp#include "as.h"
24130561Sobrien#include "struc-symbol.h"
2589857Sobrien#include "safe-ctype.h"
2638889Sjdp#include "subsegs.h"
2738889Sjdp#include "opcode/arc.h"
2885815Sobrien#include "../opcodes/arc-ext.h"
2938889Sjdp#include "elf/arc.h"
3085815Sobrien#include "dwarf2dbg.h"
3138889Sjdp
32218822Sdimconst struct suffix_classes
33218822Sdim{
3485815Sobrien  char *name;
3585815Sobrien  int  len;
36218822Sdim} suffixclass[] =
37218822Sdim{
3885815Sobrien  { "SUFFIX_COND|SUFFIX_FLAG",23 },
3985815Sobrien  { "SUFFIX_FLAG", 11 },
4085815Sobrien  { "SUFFIX_COND", 11 },
4185815Sobrien  { "SUFFIX_NONE", 11 }
4285815Sobrien};
4385815Sobrien
4485815Sobrien#define MAXSUFFIXCLASS (sizeof (suffixclass) / sizeof (struct suffix_classes))
4585815Sobrien
46218822Sdimconst struct syntax_classes
47218822Sdim{
4885815Sobrien  char *name;
4985815Sobrien  int  len;
5085815Sobrien  int  class;
51218822Sdim} syntaxclass[] =
52218822Sdim{
5385815Sobrien  { "SYNTAX_3OP|OP1_MUST_BE_IMM", 26, SYNTAX_3OP|OP1_MUST_BE_IMM|SYNTAX_VALID },
5485815Sobrien  { "OP1_MUST_BE_IMM|SYNTAX_3OP", 26, OP1_MUST_BE_IMM|SYNTAX_3OP|SYNTAX_VALID },
5585815Sobrien  { "SYNTAX_2OP|OP1_IMM_IMPLIED", 26, SYNTAX_2OP|OP1_IMM_IMPLIED|SYNTAX_VALID },
5685815Sobrien  { "OP1_IMM_IMPLIED|SYNTAX_2OP", 26, OP1_IMM_IMPLIED|SYNTAX_2OP|SYNTAX_VALID },
5785815Sobrien  { "SYNTAX_3OP",                 10, SYNTAX_3OP|SYNTAX_VALID },
5885815Sobrien  { "SYNTAX_2OP",                 10, SYNTAX_2OP|SYNTAX_VALID }
5985815Sobrien};
6085815Sobrien
6185815Sobrien#define MAXSYNTAXCLASS (sizeof (syntaxclass) / sizeof (struct syntax_classes))
6285815Sobrien
6338889Sjdp/* This array holds the chars that always start a comment.  If the
6485815Sobrien   pre-processor is disabled, these aren't very useful.  */
6538889Sjdpconst char comment_chars[] = "#;";
6638889Sjdp
6738889Sjdp/* This array holds the chars that only start a comment at the beginning of
6838889Sjdp   a line.  If the line seems to have the form '# 123 filename'
6938889Sjdp   .line and .file directives will appear in the pre-processed output */
7038889Sjdp/* Note that input_file.c hand checks for '#' at the beginning of the
7138889Sjdp   first line of the input file.  This is because the compiler outputs
7285815Sobrien   #NO_APP at the beginning of its output.  */
7338889Sjdp/* Also note that comments started like this one will always
7485815Sobrien   work if '/' isn't otherwise defined.  */
7538889Sjdpconst char line_comment_chars[] = "#";
7638889Sjdp
7738889Sjdpconst char line_separator_chars[] = "";
7838889Sjdp
7985815Sobrien/* Chars that can be used to separate mant from exp in floating point nums.  */
8038889Sjdpconst char EXP_CHARS[] = "eE";
8138889Sjdp
8285815Sobrien/* Chars that mean this number is a floating point constant
8385815Sobrien   As in 0f12.456 or 0d1.2345e12.  */
8438889Sjdpconst char FLT_CHARS[] = "rRsSfFdD";
8538889Sjdp
8638889Sjdp/* Byte order.  */
8738889Sjdpextern int target_big_endian;
8838889Sjdpconst char *arc_target_format = DEFAULT_TARGET_FORMAT;
8938889Sjdpstatic int byte_order = DEFAULT_BYTE_ORDER;
9038889Sjdp
9185815Sobrienstatic segT arcext_section;
9238889Sjdp
9385815Sobrien/* One of bfd_mach_arc_n.  */
9485815Sobrienstatic int arc_mach_type = bfd_mach_arc_6;
9585815Sobrien
9638889Sjdp/* Non-zero if the cpu type has been explicitly specified.  */
9738889Sjdpstatic int mach_type_specified_p = 0;
9838889Sjdp
9938889Sjdp/* Non-zero if opcode tables have been initialized.
10085815Sobrien   A .option command must appear before any instructions.  */
10138889Sjdpstatic int cpu_tables_init_p = 0;
10238889Sjdp
10338889Sjdpstatic struct hash_control *arc_suffix_hash = NULL;
10438889Sjdp
10538889Sjdpconst char *md_shortopts = "";
106218822Sdim
107218822Sdimenum options
108218822Sdim{
109218822Sdim  OPTION_EB = OPTION_MD_BASE,
110218822Sdim  OPTION_EL,
111218822Sdim  OPTION_ARC5,
112218822Sdim  OPTION_ARC6,
113218822Sdim  OPTION_ARC7,
114218822Sdim  OPTION_ARC8,
115218822Sdim  OPTION_ARC
116218822Sdim};
117218822Sdim
118218822Sdimstruct option md_longopts[] =
119218822Sdim{
12085815Sobrien  { "EB", no_argument, NULL, OPTION_EB },
12185815Sobrien  { "EL", no_argument, NULL, OPTION_EL },
12285815Sobrien  { "marc5", no_argument, NULL, OPTION_ARC5 },
12385815Sobrien  { "pre-v6", no_argument, NULL, OPTION_ARC5 },
12485815Sobrien  { "marc6", no_argument, NULL, OPTION_ARC6 },
12585815Sobrien  { "marc7", no_argument, NULL, OPTION_ARC7 },
12685815Sobrien  { "marc8", no_argument, NULL, OPTION_ARC8 },
12785815Sobrien  { "marc", no_argument, NULL, OPTION_ARC },
12838889Sjdp  { NULL, no_argument, NULL, 0 }
12938889Sjdp};
13038889Sjdpsize_t md_longopts_size = sizeof (md_longopts);
13138889Sjdp
13285815Sobrien#define IS_SYMBOL_OPERAND(o) \
13385815Sobrien ((o) == 'b' || (o) == 'c' || (o) == 's' || (o) == 'o' || (o) == 'O')
13438889Sjdp
13585815Sobrienstruct arc_operand_value *get_ext_suffix (char *s);
13685815Sobrien
13785815Sobrien/* Invocation line includes a switch not recognized by the base assembler.
13885815Sobrien   See if it's a processor-specific option.  */
13985815Sobrien
14038889Sjdpint
141218822Sdimmd_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
14238889Sjdp{
14338889Sjdp  switch (c)
14438889Sjdp    {
14585815Sobrien    case OPTION_ARC5:
14685815Sobrien      arc_mach_type = bfd_mach_arc_5;
14785815Sobrien      break;
14885815Sobrien    case OPTION_ARC:
14985815Sobrien    case OPTION_ARC6:
15085815Sobrien      arc_mach_type = bfd_mach_arc_6;
15185815Sobrien      break;
15285815Sobrien    case OPTION_ARC7:
15385815Sobrien      arc_mach_type = bfd_mach_arc_7;
15485815Sobrien      break;
15585815Sobrien    case OPTION_ARC8:
15685815Sobrien      arc_mach_type = bfd_mach_arc_8;
15785815Sobrien      break;
15838889Sjdp    case OPTION_EB:
15938889Sjdp      byte_order = BIG_ENDIAN;
16038889Sjdp      arc_target_format = "elf32-bigarc";
16138889Sjdp      break;
16238889Sjdp    case OPTION_EL:
16338889Sjdp      byte_order = LITTLE_ENDIAN;
16438889Sjdp      arc_target_format = "elf32-littlearc";
16538889Sjdp      break;
16638889Sjdp    default:
16738889Sjdp      return 0;
16838889Sjdp    }
16938889Sjdp  return 1;
17038889Sjdp}
17138889Sjdp
17238889Sjdpvoid
173218822Sdimmd_show_usage (FILE *stream)
17438889Sjdp{
17585815Sobrien  fprintf (stream, "\
17685815SobrienARC Options:\n\
17785815Sobrien  -marc[5|6|7|8]          select processor variant (default arc%d)\n\
17885815Sobrien  -EB                     assemble code for a big endian cpu\n\
17985815Sobrien  -EL                     assemble code for a little endian cpu\n", arc_mach_type + 5);
18038889Sjdp}
18138889Sjdp
18238889Sjdp/* This function is called once, at assembler startup time.  It should
18338889Sjdp   set up all the tables, etc. that the MD part of the assembler will need.
18485815Sobrien   Opcode selection is deferred until later because we might see a .option
18538889Sjdp   command.  */
18638889Sjdp
18738889Sjdpvoid
188218822Sdimmd_begin (void)
18938889Sjdp{
19038889Sjdp  /* The endianness can be chosen "at the factory".  */
19138889Sjdp  target_big_endian = byte_order == BIG_ENDIAN;
19238889Sjdp
19338889Sjdp  if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, arc_mach_type))
19485815Sobrien    as_warn ("could not set architecture and machine");
19538889Sjdp
19685815Sobrien  /* This call is necessary because we need to initialize `arc_operand_map'
19785815Sobrien     which may be needed before we see the first insn.  */
19885815Sobrien  arc_opcode_init_tables (arc_get_opcode_mach (arc_mach_type,
19938889Sjdp					       target_big_endian));
20038889Sjdp}
20138889Sjdp
20238889Sjdp/* Initialize the various opcode and operand tables.
20338889Sjdp   MACH is one of bfd_mach_arc_xxx.  */
204218822Sdim
20538889Sjdpstatic void
206218822Sdiminit_opcode_tables (int mach)
20738889Sjdp{
20885815Sobrien  int i;
20938889Sjdp  char *last;
21038889Sjdp
21138889Sjdp  if ((arc_suffix_hash = hash_new ()) == NULL)
21285815Sobrien    as_fatal ("virtual memory exhausted");
21338889Sjdp
21438889Sjdp  if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, mach))
21585815Sobrien    as_warn ("could not set architecture and machine");
21638889Sjdp
21738889Sjdp  /* This initializes a few things in arc-opc.c that we need.
21838889Sjdp     This must be called before the various arc_xxx_supported fns.  */
21938889Sjdp  arc_opcode_init_tables (arc_get_opcode_mach (mach, target_big_endian));
22038889Sjdp
22138889Sjdp  /* Only put the first entry of each equivalently named suffix in the
22238889Sjdp     table.  */
22338889Sjdp  last = "";
22438889Sjdp  for (i = 0; i < arc_suffixes_count; i++)
22538889Sjdp    {
22638889Sjdp      if (strcmp (arc_suffixes[i].name, last) != 0)
227218822Sdim	hash_insert (arc_suffix_hash, arc_suffixes[i].name, (void *) (arc_suffixes + i));
22838889Sjdp      last = arc_suffixes[i].name;
22938889Sjdp    }
23038889Sjdp
23138889Sjdp  /* Since registers don't have a prefix, we put them in the symbol table so
23238889Sjdp     they can't be used as symbols.  This also simplifies argument parsing as
23338889Sjdp     we can let gas parse registers for us.  The recorded register number is
23485815Sobrien     the address of the register's entry in arc_reg_names.
23585815Sobrien
23685815Sobrien     If the register name is already in the table, then the existing
23785815Sobrien     definition is assumed to be from an .ExtCoreRegister pseudo-op.  */
23885815Sobrien
23938889Sjdp  for (i = 0; i < arc_reg_names_count; i++)
24038889Sjdp    {
24185815Sobrien      if (symbol_find (arc_reg_names[i].name))
24238889Sjdp	continue;
24338889Sjdp      /* Use symbol_create here instead of symbol_new so we don't try to
24438889Sjdp	 output registers into the object file's symbol table.  */
24585815Sobrien      symbol_table_insert (symbol_create (arc_reg_names[i].name,
24685815Sobrien					  reg_section,
247218822Sdim					  (valueT) &arc_reg_names[i],
24885815Sobrien					  &zero_address_frag));
24938889Sjdp    }
25038889Sjdp
25185815Sobrien  /* Tell `.option' it's too late.  */
25238889Sjdp  cpu_tables_init_p = 1;
25338889Sjdp}
25438889Sjdp
25538889Sjdp/* Insert an operand value into an instruction.
25638889Sjdp   If REG is non-NULL, it is a register number and ignore VAL.  */
25738889Sjdp
25838889Sjdpstatic arc_insn
259218822Sdimarc_insert_operand (arc_insn insn,
260218822Sdim		    const struct arc_operand *operand,
261218822Sdim		    int mods,
262218822Sdim		    const struct arc_operand_value *reg,
263218822Sdim		    offsetT val,
264218822Sdim		    char *file,
265218822Sdim		    unsigned int line)
26638889Sjdp{
26738889Sjdp  if (operand->bits != 32)
26838889Sjdp    {
26938889Sjdp      long min, max;
27038889Sjdp      offsetT test;
27138889Sjdp
27238889Sjdp      if ((operand->flags & ARC_OPERAND_SIGNED) != 0)
27338889Sjdp	{
27438889Sjdp	  if ((operand->flags & ARC_OPERAND_SIGNOPT) != 0)
27538889Sjdp	    max = (1 << operand->bits) - 1;
27638889Sjdp	  else
27738889Sjdp	    max = (1 << (operand->bits - 1)) - 1;
27838889Sjdp	  min = - (1 << (operand->bits - 1));
27938889Sjdp	}
28038889Sjdp      else
28138889Sjdp	{
28238889Sjdp	  max = (1 << operand->bits) - 1;
28338889Sjdp	  min = 0;
28438889Sjdp	}
28538889Sjdp
28638889Sjdp      if ((operand->flags & ARC_OPERAND_NEGATIVE) != 0)
28738889Sjdp	test = - val;
28838889Sjdp      else
28938889Sjdp	test = val;
29038889Sjdp
29138889Sjdp      if (test < (offsetT) min || test > (offsetT) max)
292218822Sdim	as_warn_value_out_of_range (_("operand"), test, (offsetT) min, (offsetT) max, file, line);
29338889Sjdp    }
29438889Sjdp
29538889Sjdp  if (operand->insert)
29638889Sjdp    {
29738889Sjdp      const char *errmsg;
29838889Sjdp
29938889Sjdp      errmsg = NULL;
30038889Sjdp      insn = (*operand->insert) (insn, operand, mods, reg, (long) val, &errmsg);
30138889Sjdp      if (errmsg != (const char *) NULL)
30238889Sjdp	as_warn (errmsg);
30338889Sjdp    }
30438889Sjdp  else
30538889Sjdp    insn |= (((long) val & ((1 << operand->bits) - 1))
30638889Sjdp	     << operand->shift);
30738889Sjdp
30838889Sjdp  return insn;
30938889Sjdp}
31038889Sjdp
31138889Sjdp/* We need to keep a list of fixups.  We can't simply generate them as
31238889Sjdp   we go, because that would require us to first create the frag, and
31338889Sjdp   that would screw up references to ``.''.  */
31438889Sjdp
315218822Sdimstruct arc_fixup
316218822Sdim{
31785815Sobrien  /* index into `arc_operands'  */
31838889Sjdp  int opindex;
31938889Sjdp  expressionS exp;
32038889Sjdp};
32138889Sjdp
32238889Sjdp#define MAX_FIXUPS 5
32338889Sjdp
32438889Sjdp#define MAX_SUFFIXES 5
32538889Sjdp
326218822Sdim/* Compute the reloc type of an expression.
327218822Sdim   The possibly modified expression is stored in EXPNEW.
32838889Sjdp
329218822Sdim   This is used to convert the expressions generated by the %-op's into
330218822Sdim   the appropriate operand type.  It is called for both data in instructions
331218822Sdim   (operands) and data outside instructions (variables, debugging info, etc.).
33238889Sjdp
333218822Sdim   Currently supported %-ops:
33438889Sjdp
335218822Sdim   %st(symbol): represented as "symbol >> 2"
336218822Sdim                "st" is short for STatus as in the status register (pc)
33738889Sjdp
338218822Sdim   DEFAULT_TYPE is the type to use if no special processing is required.
33938889Sjdp
340218822Sdim   DATA_P is non-zero for data or limm values, zero for insn operands.
341218822Sdim   Remember that the opcode "insertion fns" cannot be used on data, they're
342218822Sdim   only for inserting operands into insns.  They also can't be used for limm
343218822Sdim   values as the insertion routines don't handle limm values.  When called for
344218822Sdim   insns we return fudged reloc types (real_value - BFD_RELOC_UNUSED).  When
345218822Sdim   called for data or limm values we use real reloc types.  */
34638889Sjdp
347218822Sdimstatic int
348218822Sdimget_arc_exp_reloc_type (int data_p,
349218822Sdim			int default_type,
350218822Sdim			expressionS *exp,
351218822Sdim			expressionS *expnew)
352218822Sdim{
353218822Sdim  /* If the expression is "symbol >> 2" we must change it to just "symbol",
354218822Sdim     as fix_new_exp can't handle it.  Similarly for (symbol - symbol) >> 2.
355218822Sdim     That's ok though.  What's really going on here is that we're using
356218822Sdim     ">> 2" as a special syntax for specifying BFD_RELOC_ARC_B26.  */
35738889Sjdp
358218822Sdim  if (exp->X_op == O_right_shift
359218822Sdim      && exp->X_op_symbol != NULL
360218822Sdim      && exp->X_op_symbol->sy_value.X_op == O_constant
361218822Sdim      && exp->X_op_symbol->sy_value.X_add_number == 2
362218822Sdim      && exp->X_add_number == 0)
36338889Sjdp    {
364218822Sdim      if (exp->X_add_symbol != NULL
365218822Sdim	  && (exp->X_add_symbol->sy_value.X_op == O_constant
366218822Sdim	      || exp->X_add_symbol->sy_value.X_op == O_symbol))
36738889Sjdp	{
368218822Sdim	  *expnew = *exp;
369218822Sdim	  expnew->X_op = O_symbol;
370218822Sdim	  expnew->X_op_symbol = NULL;
371218822Sdim	  return data_p ? BFD_RELOC_ARC_B26 : arc_operand_map['J'];
37238889Sjdp	}
373218822Sdim      else if (exp->X_add_symbol != NULL
374218822Sdim	       && exp->X_add_symbol->sy_value.X_op == O_subtract)
37538889Sjdp	{
376218822Sdim	  *expnew = exp->X_add_symbol->sy_value;
377218822Sdim	  return data_p ? BFD_RELOC_ARC_B26 : arc_operand_map['J'];
37838889Sjdp	}
379218822Sdim    }
38038889Sjdp
381218822Sdim  *expnew = *exp;
382218822Sdim  return default_type;
383218822Sdim}
384218822Sdim
385218822Sdimstatic int
386218822Sdimarc_set_ext_seg (void)
387218822Sdim{
388218822Sdim  if (!arcext_section)
389218822Sdim    {
390218822Sdim      arcext_section = subseg_new (".arcextmap", 0);
391218822Sdim      bfd_set_section_flags (stdoutput, arcext_section,
392218822Sdim			     SEC_READONLY | SEC_HAS_CONTENTS);
39338889Sjdp    }
39485815Sobrien  else
395218822Sdim    subseg_set (arcext_section, 0);
396218822Sdim  return 1;
39738889Sjdp}
398218822Sdim
39938889Sjdpstatic void
400218822Sdimarc_extoper (int opertype)
40138889Sjdp{
40238889Sjdp  char *name;
40385815Sobrien  char *mode;
40438889Sjdp  char c;
40538889Sjdp  char *p;
40685815Sobrien  int imode = 0;
40785815Sobrien  int number;
40885815Sobrien  struct arc_ext_operand_value *ext_oper;
40938889Sjdp  symbolS *symbolP;
41038889Sjdp
41185815Sobrien  segT old_sec;
41285815Sobrien  int old_subsec;
41385815Sobrien
41438889Sjdp  name = input_line_pointer;
41538889Sjdp  c = get_symbol_end ();
41685815Sobrien  name = xstrdup (name);
41785815Sobrien
41885815Sobrien  p = name;
41985815Sobrien  while (*p)
42085815Sobrien    {
42189857Sobrien      *p = TOLOWER (*p);
42285815Sobrien      p++;
42385815Sobrien    }
42485815Sobrien
42585815Sobrien  /* just after name is now '\0'  */
42638889Sjdp  p = input_line_pointer;
42738889Sjdp  *p = c;
42838889Sjdp  SKIP_WHITESPACE ();
42985815Sobrien
43038889Sjdp  if (*input_line_pointer != ',')
43138889Sjdp    {
43285815Sobrien      as_bad ("expected comma after operand name");
43338889Sjdp      ignore_rest_of_line ();
43485815Sobrien      free (name);
43538889Sjdp      return;
43638889Sjdp    }
43785815Sobrien
43885815Sobrien  input_line_pointer++;		/* skip ','  */
43985815Sobrien  number = get_absolute_expression ();
44085815Sobrien
44185815Sobrien  if (number < 0)
44238889Sjdp    {
44385815Sobrien      as_bad ("negative operand number %d", number);
44438889Sjdp      ignore_rest_of_line ();
44585815Sobrien      free (name);
44638889Sjdp      return;
44738889Sjdp    }
44885815Sobrien
44985815Sobrien  if (opertype)
45038889Sjdp    {
45185815Sobrien      SKIP_WHITESPACE ();
45285815Sobrien
45385815Sobrien      if (*input_line_pointer != ',')
45485815Sobrien	{
45585815Sobrien	  as_bad ("expected comma after register-number");
45685815Sobrien	  ignore_rest_of_line ();
45785815Sobrien	  free (name);
45885815Sobrien	  return;
45985815Sobrien	}
46085815Sobrien
46185815Sobrien      input_line_pointer++;		/* skip ','  */
46285815Sobrien      mode = input_line_pointer;
46385815Sobrien
46485815Sobrien      if (!strncmp (mode, "r|w", 3))
46585815Sobrien	{
46685815Sobrien	  imode = 0;
46785815Sobrien	  input_line_pointer += 3;
46885815Sobrien	}
46985815Sobrien      else
47085815Sobrien	{
47185815Sobrien	  if (!strncmp (mode, "r", 1))
47285815Sobrien	    {
47385815Sobrien	      imode = ARC_REGISTER_READONLY;
47485815Sobrien	      input_line_pointer += 1;
47585815Sobrien	    }
47685815Sobrien	  else
47785815Sobrien	    {
47885815Sobrien	      if (strncmp (mode, "w", 1))
47985815Sobrien		{
48085815Sobrien		  as_bad ("invalid mode");
48185815Sobrien		  ignore_rest_of_line ();
48285815Sobrien		  free (name);
48385815Sobrien		  return;
48485815Sobrien		}
48585815Sobrien	      else
48685815Sobrien		{
48785815Sobrien		  imode = ARC_REGISTER_WRITEONLY;
48885815Sobrien		  input_line_pointer += 1;
48985815Sobrien		}
49085815Sobrien	    }
49185815Sobrien	}
49285815Sobrien      SKIP_WHITESPACE ();
49385815Sobrien      if (1 == opertype)
49485815Sobrien	{
49585815Sobrien	  if (*input_line_pointer != ',')
49685815Sobrien	    {
49785815Sobrien	      as_bad ("expected comma after register-mode");
49885815Sobrien	      ignore_rest_of_line ();
49985815Sobrien	      free (name);
50085815Sobrien	      return;
50185815Sobrien	    }
50285815Sobrien
50385815Sobrien	  input_line_pointer++;		/* skip ','  */
50485815Sobrien
50585815Sobrien	  if (!strncmp (input_line_pointer, "cannot_shortcut", 15))
50685815Sobrien	    {
50785815Sobrien	      imode |= arc_get_noshortcut_flag ();
50885815Sobrien	      input_line_pointer += 15;
50985815Sobrien	    }
51085815Sobrien	  else
51185815Sobrien	    {
51285815Sobrien	      if (strncmp (input_line_pointer, "can_shortcut", 12))
51385815Sobrien		{
51485815Sobrien		  as_bad ("shortcut designator invalid");
51585815Sobrien		  ignore_rest_of_line ();
51685815Sobrien		  free (name);
51785815Sobrien		  return;
51885815Sobrien		}
51985815Sobrien	      else
52085815Sobrien		{
52185815Sobrien		  input_line_pointer += 12;
52285815Sobrien		}
52385815Sobrien	    }
52485815Sobrien	}
52585815Sobrien    }
52685815Sobrien
52785815Sobrien  if ((opertype == 1) && number > 60)
52885815Sobrien    {
52985815Sobrien      as_bad ("core register value (%d) too large", number);
53038889Sjdp      ignore_rest_of_line ();
53185815Sobrien      free (name);
53238889Sjdp      return;
53338889Sjdp    }
53485815Sobrien
53585815Sobrien  if ((opertype == 0) && number > 31)
53638889Sjdp    {
53785815Sobrien      as_bad ("condition code value (%d) too large", number);
53885815Sobrien      ignore_rest_of_line ();
53985815Sobrien      free (name);
54085815Sobrien      return;
54185815Sobrien    }
54285815Sobrien
543218822Sdim  ext_oper = xmalloc (sizeof (struct arc_ext_operand_value));
54485815Sobrien
54585815Sobrien  if (opertype)
54685815Sobrien    {
54785815Sobrien      /* If the symbol already exists, point it at the new definition.  */
54885815Sobrien      if ((symbolP = symbol_find (name)))
54938889Sjdp	{
55085815Sobrien	  if (S_GET_SEGMENT (symbolP) == reg_section)
551218822Sdim	    S_SET_VALUE (symbolP, (valueT) &ext_oper->operand);
55285815Sobrien	  else
55385815Sobrien	    {
55485815Sobrien	      as_bad ("attempt to override symbol: %s", name);
55585815Sobrien	      ignore_rest_of_line ();
55685815Sobrien	      free (name);
55785815Sobrien	      free (ext_oper);
55885815Sobrien	      return;
55985815Sobrien	    }
56038889Sjdp	}
56185815Sobrien      else
56285815Sobrien	{
56385815Sobrien	  /* If its not there, add it.  */
56485815Sobrien	  symbol_table_insert (symbol_create (name, reg_section,
565218822Sdim					      (valueT) &ext_oper->operand,
566218822Sdim					      &zero_address_frag));
56785815Sobrien	}
56838889Sjdp    }
56985815Sobrien
57085815Sobrien  ext_oper->operand.name  = name;
57185815Sobrien  ext_oper->operand.value = number;
57285815Sobrien  ext_oper->operand.type  = arc_operand_type (opertype);
57385815Sobrien  ext_oper->operand.flags = imode;
57485815Sobrien
57585815Sobrien  ext_oper->next = arc_ext_operands;
57685815Sobrien  arc_ext_operands = ext_oper;
57785815Sobrien
57885815Sobrien  /* OK, now that we know what this operand is, put a description in
57985815Sobrien     the arc extension section of the output file.  */
58085815Sobrien
58185815Sobrien  old_sec    = now_seg;
58285815Sobrien  old_subsec = now_subseg;
58385815Sobrien
58485815Sobrien  arc_set_ext_seg ();
58585815Sobrien
58685815Sobrien  switch (opertype)
58785815Sobrien    {
58885815Sobrien    case 0:
58985815Sobrien      p = frag_more (1);
59085815Sobrien      *p = 3 + strlen (name) + 1;
59185815Sobrien      p = frag_more (1);
59285815Sobrien      *p = EXT_COND_CODE;
59385815Sobrien      p = frag_more (1);
59485815Sobrien      *p = number;
59585815Sobrien      p = frag_more (strlen (name) + 1);
59685815Sobrien      strcpy (p, name);
59785815Sobrien      break;
59885815Sobrien    case 1:
59985815Sobrien      p = frag_more (1);
60085815Sobrien      *p = 3 + strlen (name) + 1;
60185815Sobrien      p = frag_more (1);
60285815Sobrien      *p = EXT_CORE_REGISTER;
60385815Sobrien      p = frag_more (1);
60485815Sobrien      *p = number;
60585815Sobrien      p = frag_more (strlen (name) + 1);
60685815Sobrien      strcpy (p, name);
60785815Sobrien      break;
60885815Sobrien    case 2:
60985815Sobrien      p = frag_more (1);
61085815Sobrien      *p = 6 + strlen (name) + 1;
61185815Sobrien      p = frag_more (1);
61285815Sobrien      *p = EXT_AUX_REGISTER;
61385815Sobrien      p = frag_more (1);
61485815Sobrien      *p = number >> 24 & 0xff;
61585815Sobrien      p = frag_more (1);
61685815Sobrien      *p = number >> 16 & 0xff;
61785815Sobrien      p = frag_more (1);
61885815Sobrien      *p = number >>  8 & 0xff;
61985815Sobrien      p = frag_more (1);
62085815Sobrien      *p = number       & 0xff;
62185815Sobrien      p = frag_more (strlen (name) + 1);
62285815Sobrien      strcpy (p, name);
62385815Sobrien      break;
62485815Sobrien    default:
62585815Sobrien      as_bad ("invalid opertype");
62685815Sobrien      ignore_rest_of_line ();
62785815Sobrien      free (name);
62885815Sobrien      return;
62985815Sobrien      break;
63085815Sobrien    }
63185815Sobrien
63285815Sobrien  subseg_set (old_sec, old_subsec);
63385815Sobrien
63485815Sobrien  /* Enter all registers into the symbol table.  */
63585815Sobrien
63685815Sobrien  demand_empty_rest_of_line ();
63785815Sobrien}
63885815Sobrien
63985815Sobrienstatic void
640218822Sdimarc_extinst (int ignore ATTRIBUTE_UNUSED)
64185815Sobrien{
642218822Sdim  char syntax[129];
64385815Sobrien  char *name;
64485815Sobrien  char *p;
64585815Sobrien  char c;
64685815Sobrien  int suffixcode = -1;
64785815Sobrien  int opcode, subopcode;
64885815Sobrien  int i;
64985815Sobrien  int class = 0;
65085815Sobrien  int name_len;
65185815Sobrien  struct arc_opcode *ext_op;
65285815Sobrien
65385815Sobrien  segT old_sec;
65485815Sobrien  int old_subsec;
65585815Sobrien
65685815Sobrien  name = input_line_pointer;
65785815Sobrien  c = get_symbol_end ();
65885815Sobrien  name = xstrdup (name);
65985815Sobrien  strcpy (syntax, name);
66085815Sobrien  name_len = strlen (name);
66185815Sobrien
66285815Sobrien  /* just after name is now '\0'  */
66385815Sobrien  p = input_line_pointer;
66485815Sobrien  *p = c;
66585815Sobrien
66685815Sobrien  SKIP_WHITESPACE ();
66785815Sobrien
66838889Sjdp  if (*input_line_pointer != ',')
66938889Sjdp    {
67085815Sobrien      as_bad ("expected comma after operand name");
67138889Sjdp      ignore_rest_of_line ();
67238889Sjdp      return;
67338889Sjdp    }
67485815Sobrien
67585815Sobrien  input_line_pointer++;		/* skip ','  */
67685815Sobrien  opcode = get_absolute_expression ();
67785815Sobrien
67838889Sjdp  SKIP_WHITESPACE ();
67985815Sobrien
68085815Sobrien  if (*input_line_pointer != ',')
68138889Sjdp    {
68285815Sobrien      as_bad ("expected comma after opcode");
68385815Sobrien      ignore_rest_of_line ();
68485815Sobrien      return;
68585815Sobrien    }
68685815Sobrien
68785815Sobrien  input_line_pointer++;		/* skip ','  */
68885815Sobrien  subopcode = get_absolute_expression ();
68985815Sobrien
69085815Sobrien  if (subopcode < 0)
69185815Sobrien    {
69285815Sobrien      as_bad ("negative subopcode %d", subopcode);
69385815Sobrien      ignore_rest_of_line ();
69485815Sobrien      return;
69585815Sobrien    }
69685815Sobrien
69785815Sobrien  if (subopcode)
69885815Sobrien    {
69985815Sobrien      if (3 != opcode)
70038889Sjdp	{
70185815Sobrien	  as_bad ("subcode value found when opcode not equal 0x03");
70285815Sobrien	  ignore_rest_of_line ();
70385815Sobrien	  return;
70438889Sjdp	}
70585815Sobrien      else
70638889Sjdp	{
70785815Sobrien	  if (subopcode < 0x09 || subopcode == 0x3f)
70885815Sobrien	    {
70985815Sobrien	      as_bad ("invalid subopcode %d", subopcode);
71085815Sobrien	      ignore_rest_of_line ();
71185815Sobrien	      return;
71285815Sobrien	    }
71385815Sobrien	}
71485815Sobrien    }
71538889Sjdp
71685815Sobrien  SKIP_WHITESPACE ();
71785815Sobrien
71885815Sobrien  if (*input_line_pointer != ',')
71985815Sobrien    {
72085815Sobrien      as_bad ("expected comma after subopcode");
72185815Sobrien      ignore_rest_of_line ();
72285815Sobrien      return;
72385815Sobrien    }
72485815Sobrien
72585815Sobrien  input_line_pointer++;		/* skip ','  */
72685815Sobrien
72785815Sobrien  for (i = 0; i < (int) MAXSUFFIXCLASS; i++)
72885815Sobrien    {
72985815Sobrien      if (!strncmp (suffixclass[i].name,input_line_pointer, suffixclass[i].len))
73038889Sjdp	{
73185815Sobrien	  suffixcode = i;
73285815Sobrien	  input_line_pointer += suffixclass[i].len;
73385815Sobrien	  break;
73438889Sjdp	}
73538889Sjdp    }
73685815Sobrien
73785815Sobrien  if (-1 == suffixcode)
73838889Sjdp    {
73985815Sobrien      as_bad ("invalid suffix class");
74085815Sobrien      ignore_rest_of_line ();
74185815Sobrien      return;
74285815Sobrien    }
74385815Sobrien
74485815Sobrien  SKIP_WHITESPACE ();
74585815Sobrien
74685815Sobrien  if (*input_line_pointer != ',')
74785815Sobrien    {
74885815Sobrien      as_bad ("expected comma after suffix class");
74985815Sobrien      ignore_rest_of_line ();
75085815Sobrien      return;
75185815Sobrien    }
75285815Sobrien
75385815Sobrien  input_line_pointer++;		/* skip ','  */
75485815Sobrien
75585815Sobrien  for (i = 0; i < (int) MAXSYNTAXCLASS; i++)
75685815Sobrien    {
75785815Sobrien      if (!strncmp (syntaxclass[i].name,input_line_pointer, syntaxclass[i].len))
75838889Sjdp	{
75985815Sobrien	  class = syntaxclass[i].class;
76085815Sobrien	  input_line_pointer += syntaxclass[i].len;
76185815Sobrien	  break;
76238889Sjdp	}
76338889Sjdp    }
76485815Sobrien
76585815Sobrien  if (0 == (SYNTAX_VALID & class))
76685815Sobrien    {
76785815Sobrien      as_bad ("invalid syntax class");
76885815Sobrien      ignore_rest_of_line ();
76985815Sobrien      return;
77085815Sobrien    }
77185815Sobrien
77285815Sobrien  if ((0x3 == opcode) & (class & SYNTAX_3OP))
77385815Sobrien    {
77485815Sobrien      as_bad ("opcode 0x3 and SYNTAX_3OP invalid");
77585815Sobrien      ignore_rest_of_line ();
77685815Sobrien      return;
77785815Sobrien    }
77885815Sobrien
77985815Sobrien  switch (suffixcode)
78085815Sobrien    {
78185815Sobrien    case 0:
78285815Sobrien      strcat (syntax, "%.q%.f ");
78385815Sobrien      break;
78485815Sobrien    case 1:
78585815Sobrien      strcat (syntax, "%.f ");
78685815Sobrien      break;
78785815Sobrien    case 2:
78885815Sobrien      strcat (syntax, "%.q ");
78985815Sobrien      break;
79085815Sobrien    case 3:
79185815Sobrien      strcat (syntax, " ");
79285815Sobrien      break;
79385815Sobrien    default:
79485815Sobrien      as_bad ("unknown suffix class");
79585815Sobrien      ignore_rest_of_line ();
79685815Sobrien      return;
79785815Sobrien      break;
79885815Sobrien    };
79985815Sobrien
80085815Sobrien  strcat (syntax, ((opcode == 0x3) ? "%a,%b" : ((class & SYNTAX_3OP) ? "%a,%b,%c" : "%b,%c")));
80185815Sobrien  if (suffixcode < 2)
80285815Sobrien    strcat (syntax, "%F");
80385815Sobrien  strcat (syntax, "%S%L");
80485815Sobrien
805218822Sdim  ext_op = xmalloc (sizeof (struct arc_opcode));
80685815Sobrien  ext_op->syntax = xstrdup (syntax);
80785815Sobrien
80885815Sobrien  ext_op->mask  = I (-1) | ((0x3 == opcode) ? C (-1) : 0);
80985815Sobrien  ext_op->value = I (opcode) | ((0x3 == opcode) ? C (subopcode) : 0);
81085815Sobrien  ext_op->flags = class;
81185815Sobrien  ext_op->next_asm = arc_ext_opcodes;
81285815Sobrien  ext_op->next_dis = arc_ext_opcodes;
81385815Sobrien  arc_ext_opcodes = ext_op;
81485815Sobrien
81585815Sobrien  /* OK, now that we know what this inst is, put a description in the
81685815Sobrien     arc extension section of the output file.  */
81785815Sobrien
81885815Sobrien  old_sec    = now_seg;
81985815Sobrien  old_subsec = now_subseg;
82085815Sobrien
82185815Sobrien  arc_set_ext_seg ();
82285815Sobrien
82385815Sobrien  p = frag_more (1);
82485815Sobrien  *p = 5 + name_len + 1;
82585815Sobrien  p = frag_more (1);
82685815Sobrien  *p = EXT_INSTRUCTION;
82785815Sobrien  p = frag_more (1);
82885815Sobrien  *p = opcode;
82985815Sobrien  p = frag_more (1);
83085815Sobrien  *p = subopcode;
83185815Sobrien  p = frag_more (1);
83285815Sobrien  *p = (class & (OP1_MUST_BE_IMM | OP1_IMM_IMPLIED) ? IGNORE_FIRST_OPD : 0);
83385815Sobrien  p = frag_more (name_len);
83485815Sobrien  strncpy (p, syntax, name_len);
83585815Sobrien  p = frag_more (1);
83685815Sobrien  *p = '\0';
83785815Sobrien
83885815Sobrien  subseg_set (old_sec, old_subsec);
83985815Sobrien
84038889Sjdp  demand_empty_rest_of_line ();
84185815Sobrien}
84238889Sjdp
84338889Sjdpstatic void
844218822Sdimarc_common (int localScope)
84538889Sjdp{
84685815Sobrien  char *name;
84738889Sjdp  char c;
84885815Sobrien  char *p;
84985815Sobrien  int align, size;
85085815Sobrien  symbolS *symbolP;
85138889Sjdp
85285815Sobrien  name = input_line_pointer;
85385815Sobrien  c = get_symbol_end ();
85485815Sobrien  /* just after name is now '\0'  */
85585815Sobrien  p = input_line_pointer;
85685815Sobrien  *p = c;
85785815Sobrien  SKIP_WHITESPACE ();
85885815Sobrien
85985815Sobrien  if (*input_line_pointer != ',')
86038889Sjdp    {
86185815Sobrien      as_bad ("expected comma after symbol name");
86238889Sjdp      ignore_rest_of_line ();
86338889Sjdp      return;
86438889Sjdp    }
86538889Sjdp
86685815Sobrien  input_line_pointer++;		/* skip ','  */
86785815Sobrien  size = get_absolute_expression ();
86838889Sjdp
86985815Sobrien  if (size < 0)
87085815Sobrien    {
87185815Sobrien      as_bad ("negative symbol length");
87285815Sobrien      ignore_rest_of_line ();
87385815Sobrien      return;
87485815Sobrien    }
87538889Sjdp
87685815Sobrien  *p = 0;
87785815Sobrien  symbolP = symbol_find_or_make (name);
87885815Sobrien  *p = c;
87985815Sobrien
88085815Sobrien  if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP))
88185815Sobrien    {
88285815Sobrien      as_bad ("ignoring attempt to re-define symbol");
88385815Sobrien      ignore_rest_of_line ();
88485815Sobrien      return;
88585815Sobrien    }
88685815Sobrien  if (((int) S_GET_VALUE (symbolP) != 0) \
88785815Sobrien      && ((int) S_GET_VALUE (symbolP) != size))
88885815Sobrien    {
88985815Sobrien      as_warn ("length of symbol \"%s\" already %ld, ignoring %d",
89085815Sobrien	       S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size);
89185815Sobrien    }
89285815Sobrien  assert (symbolP->sy_frag == &zero_address_frag);
89385815Sobrien
89485815Sobrien  /* Now parse the alignment field.  This field is optional for
89585815Sobrien     local and global symbols. Default alignment is zero.  */
89685815Sobrien  if (*input_line_pointer == ',')
89785815Sobrien    {
89885815Sobrien      input_line_pointer++;
89985815Sobrien      align = get_absolute_expression ();
90085815Sobrien      if (align < 0)
90185815Sobrien	{
90285815Sobrien	  align = 0;
90385815Sobrien	  as_warn ("assuming symbol alignment of zero");
90485815Sobrien	}
90585815Sobrien    }
90638889Sjdp  else
90785815Sobrien    align = 0;
90885815Sobrien
90985815Sobrien  if (localScope != 0)
91038889Sjdp    {
91185815Sobrien      segT old_sec;
91285815Sobrien      int old_subsec;
91385815Sobrien      char *pfrag;
91485815Sobrien
91585815Sobrien      old_sec    = now_seg;
91685815Sobrien      old_subsec = now_subseg;
91785815Sobrien      record_alignment (bss_section, align);
91885815Sobrien      subseg_set (bss_section, 0);  /* ??? subseg_set (bss_section, 1); ???  */
91985815Sobrien
92085815Sobrien      if (align)
92185815Sobrien	/* Do alignment.  */
92285815Sobrien	frag_align (align, 0, 0);
92385815Sobrien
92485815Sobrien      /* Detach from old frag.  */
92585815Sobrien      if (S_GET_SEGMENT (symbolP) == bss_section)
92685815Sobrien	symbolP->sy_frag->fr_symbol = NULL;
92785815Sobrien
92885815Sobrien      symbolP->sy_frag = frag_now;
92985815Sobrien      pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP,
93085815Sobrien			(offsetT) size, (char *) 0);
93185815Sobrien      *pfrag = 0;
93285815Sobrien
93385815Sobrien      S_SET_SIZE       (symbolP, size);
93485815Sobrien      S_SET_SEGMENT    (symbolP, bss_section);
93585815Sobrien      S_CLEAR_EXTERNAL (symbolP);
93685815Sobrien      symbolP->local = 1;
93785815Sobrien      subseg_set (old_sec, old_subsec);
93838889Sjdp    }
93985815Sobrien  else
94085815Sobrien    {
94185815Sobrien      S_SET_VALUE    (symbolP, (valueT) size);
94285815Sobrien      S_SET_ALIGN    (symbolP, align);
94385815Sobrien      S_SET_EXTERNAL (symbolP);
94485815Sobrien      S_SET_SEGMENT  (symbolP, bfd_com_section_ptr);
94585815Sobrien    }
94685815Sobrien
94785815Sobrien  symbolP->bsym->flags |= BSF_OBJECT;
94885815Sobrien
94985815Sobrien  demand_empty_rest_of_line ();
95038889Sjdp}
95185815Sobrien
95285815Sobrien/* Select the cpu we're assembling for.  */
95338889Sjdp
95438889Sjdpstatic void
955218822Sdimarc_option (int ignore ATTRIBUTE_UNUSED)
95638889Sjdp{
957218822Sdim  extern int arc_get_mach (char *);
95885815Sobrien  int mach;
95938889Sjdp  char c;
96085815Sobrien  char *cpu;
96138889Sjdp
96285815Sobrien  cpu = input_line_pointer;
96338889Sjdp  c = get_symbol_end ();
96485815Sobrien  mach = arc_get_mach (cpu);
96538889Sjdp  *input_line_pointer = c;
96638889Sjdp
96785815Sobrien  /* If an instruction has already been seen, it's too late.  */
96885815Sobrien  if (cpu_tables_init_p)
96938889Sjdp    {
97085815Sobrien      as_bad ("\".option\" directive must appear before any instructions");
97138889Sjdp      ignore_rest_of_line ();
97238889Sjdp      return;
97338889Sjdp    }
97438889Sjdp
97585815Sobrien  if (mach == -1)
97685815Sobrien    goto bad_cpu;
97785815Sobrien
97885815Sobrien  if (mach_type_specified_p && mach != arc_mach_type)
97938889Sjdp    {
98085815Sobrien      as_bad ("\".option\" directive conflicts with initial definition");
98138889Sjdp      ignore_rest_of_line ();
98238889Sjdp      return;
98338889Sjdp    }
98485815Sobrien  else
98585815Sobrien    {
98685815Sobrien      /* The cpu may have been selected on the command line.  */
98785815Sobrien      if (mach != arc_mach_type)
98885815Sobrien	as_warn ("\".option\" directive overrides command-line (default) value");
98985815Sobrien      arc_mach_type = mach;
99085815Sobrien      if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, mach))
99185815Sobrien	as_fatal ("could not set architecture and machine");
99285815Sobrien      mach_type_specified_p = 1;
99385815Sobrien    }
99485815Sobrien  demand_empty_rest_of_line ();
99585815Sobrien  return;
99638889Sjdp
99785815Sobrien bad_cpu:
99885815Sobrien  as_bad ("invalid identifier for \".option\"");
99985815Sobrien  ignore_rest_of_line ();
100038889Sjdp}
100138889Sjdp
100285815Sobrien/* Turn a string in input_line_pointer into a floating point constant
100385815Sobrien   of type TYPE, and store the appropriate bytes in *LITP.  The number
100485815Sobrien   of LITTLENUMS emitted is stored in *SIZEP.  An error message is
100585815Sobrien   returned, or NULL on OK.  */
100638889Sjdp
100785815Sobrien/* Equal to MAX_PRECISION in atof-ieee.c  */
100838889Sjdp#define MAX_LITTLENUMS 6
100938889Sjdp
101038889Sjdpchar *
1011218822Sdimmd_atof (int type, char *litP, int *sizeP)
101238889Sjdp{
101338889Sjdp  int prec;
101438889Sjdp  LITTLENUM_TYPE words[MAX_LITTLENUMS];
101538889Sjdp  LITTLENUM_TYPE *wordP;
101638889Sjdp  char *t;
101738889Sjdp
101838889Sjdp  switch (type)
101938889Sjdp    {
102038889Sjdp    case 'f':
102138889Sjdp    case 'F':
102238889Sjdp      prec = 2;
102338889Sjdp      break;
102438889Sjdp
102538889Sjdp    case 'd':
102638889Sjdp    case 'D':
102738889Sjdp      prec = 4;
102838889Sjdp      break;
102938889Sjdp
103038889Sjdp    default:
103138889Sjdp      *sizeP = 0;
103285815Sobrien      return "bad call to md_atof";
103338889Sjdp    }
103438889Sjdp
103538889Sjdp  t = atof_ieee (input_line_pointer, type, words);
103638889Sjdp  if (t)
103738889Sjdp    input_line_pointer = t;
103838889Sjdp  *sizeP = prec * sizeof (LITTLENUM_TYPE);
103938889Sjdp  for (wordP = words; prec--;)
104038889Sjdp    {
104138889Sjdp      md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE));
104238889Sjdp      litP += sizeof (LITTLENUM_TYPE);
104338889Sjdp    }
104438889Sjdp
104538889Sjdp  return NULL;
104638889Sjdp}
104738889Sjdp
104838889Sjdp/* Write a value out to the object file, using the appropriate
104938889Sjdp   endianness.  */
105038889Sjdp
105138889Sjdpvoid
1052218822Sdimmd_number_to_chars (char *buf, valueT val, int n)
105338889Sjdp{
105438889Sjdp  if (target_big_endian)
105538889Sjdp    number_to_chars_bigendian (buf, val, n);
105638889Sjdp  else
105738889Sjdp    number_to_chars_littleendian (buf, val, n);
105838889Sjdp}
105938889Sjdp
106085815Sobrien/* Round up a section size to the appropriate boundary.  */
106138889Sjdp
106238889SjdpvalueT
1063218822Sdimmd_section_align (segT segment, valueT size)
106438889Sjdp{
106538889Sjdp  int align = bfd_get_section_alignment (stdoutput, segment);
106638889Sjdp
106738889Sjdp  return ((size + (1 << align) - 1) & (-1 << align));
106838889Sjdp}
106938889Sjdp
107038889Sjdp/* We don't have any form of relaxing.  */
107138889Sjdp
107238889Sjdpint
1073218822Sdimmd_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED,
1074218822Sdim			       asection *seg ATTRIBUTE_UNUSED)
107538889Sjdp{
107685815Sobrien  as_fatal (_("md_estimate_size_before_relax\n"));
107785815Sobrien  return 1;
107838889Sjdp}
107938889Sjdp
108038889Sjdp/* Convert a machine dependent frag.  We never generate these.  */
108138889Sjdp
108238889Sjdpvoid
1083218822Sdimmd_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
1084218822Sdim		 asection *sec ATTRIBUTE_UNUSED,
1085218822Sdim		 fragS *fragp ATTRIBUTE_UNUSED)
108638889Sjdp{
108785815Sobrien  as_fatal (_("md_convert_frag\n"));
108838889Sjdp}
108938889Sjdp
1090218822Sdimstatic void
1091218822Sdimarc_code_symbol (expressionS *expressionP)
109285815Sobrien{
109389857Sobrien  if (expressionP->X_op == O_symbol && expressionP->X_add_number == 0)
109485815Sobrien    {
109585815Sobrien      expressionS two;
1096218822Sdim
109785815Sobrien      expressionP->X_op = O_right_shift;
109885815Sobrien      expressionP->X_add_symbol->sy_value.X_op = O_constant;
109985815Sobrien      two.X_op = O_constant;
110085815Sobrien      two.X_add_symbol = two.X_op_symbol = NULL;
110185815Sobrien      two.X_add_number = 2;
110285815Sobrien      expressionP->X_op_symbol = make_expr_symbol (&two);
110385815Sobrien    }
110485815Sobrien  /* Allow %st(sym1-sym2)  */
110585815Sobrien  else if (expressionP->X_op == O_subtract
110685815Sobrien	   && expressionP->X_add_symbol != NULL
110785815Sobrien	   && expressionP->X_op_symbol != NULL
110885815Sobrien	   && expressionP->X_add_number == 0)
110985815Sobrien    {
111085815Sobrien      expressionS two;
1111218822Sdim
111285815Sobrien      expressionP->X_add_symbol = make_expr_symbol (expressionP);
111385815Sobrien      expressionP->X_op = O_right_shift;
111485815Sobrien      two.X_op = O_constant;
111585815Sobrien      two.X_add_symbol = two.X_op_symbol = NULL;
111685815Sobrien      two.X_add_number = 2;
111785815Sobrien      expressionP->X_op_symbol = make_expr_symbol (&two);
111885815Sobrien    }
111985815Sobrien  else
1120218822Sdim    as_bad ("expression too complex code symbol");
112185815Sobrien}
112285815Sobrien
112338889Sjdp/* Parse an operand that is machine-specific.
112438889Sjdp
112538889Sjdp   The ARC has a special %-op to adjust addresses so they're usable in
112638889Sjdp   branches.  The "st" is short for the STatus register.
112738889Sjdp   ??? Later expand this to take a flags value too.
112838889Sjdp
112938889Sjdp   ??? We can't create new expression types so we map the %-op's onto the
113038889Sjdp   existing syntax.  This means that the user could use the chosen syntax
113185815Sobrien   to achieve the same effect.  */
113238889Sjdp
113385815Sobrienvoid
1134218822Sdimmd_operand (expressionS *expressionP)
113538889Sjdp{
113638889Sjdp  char *p = input_line_pointer;
113738889Sjdp
1138218822Sdim  if (*p != '%')
1139218822Sdim    return;
114038889Sjdp
1141218822Sdim  if (strncmp (p, "%st(", 4) == 0)
1142218822Sdim    {
1143218822Sdim      input_line_pointer += 4;
1144218822Sdim      expression (expressionP);
1145218822Sdim      if (*input_line_pointer != ')')
1146218822Sdim	{
1147218822Sdim	  as_bad ("missing ')' in %%-op");
1148218822Sdim	  return;
1149218822Sdim	}
1150218822Sdim      ++input_line_pointer;
1151218822Sdim      arc_code_symbol (expressionP);
1152218822Sdim    }
1153218822Sdim  else
1154218822Sdim    {
1155218822Sdim      /* It could be a register.  */
1156218822Sdim      int i, l;
1157218822Sdim      struct arc_ext_operand_value *ext_oper = arc_ext_operands;
1158218822Sdim      p++;
1159218822Sdim
1160218822Sdim      while (ext_oper)
1161218822Sdim	{
1162218822Sdim	  l = strlen (ext_oper->operand.name);
1163218822Sdim	  if (!strncmp (p, ext_oper->operand.name, l) && !ISALNUM (*(p + l)))
1164218822Sdim	    {
1165218822Sdim	      input_line_pointer += l + 1;
1166218822Sdim	      expressionP->X_op = O_register;
1167218822Sdim	      expressionP->X_add_number = (offsetT) &ext_oper->operand;
1168218822Sdim	      return;
1169218822Sdim	    }
1170218822Sdim	  ext_oper = ext_oper->next;
1171218822Sdim	}
1172218822Sdim      for (i = 0; i < arc_reg_names_count; i++)
1173218822Sdim	{
1174218822Sdim	  l = strlen (arc_reg_names[i].name);
1175218822Sdim	  if (!strncmp (p, arc_reg_names[i].name, l) && !ISALNUM (*(p + l)))
1176218822Sdim	    {
1177218822Sdim	      input_line_pointer += l + 1;
1178218822Sdim	      expressionP->X_op = O_register;
1179218822Sdim	      expressionP->X_add_number = (offsetT) &arc_reg_names[i];
1180218822Sdim	      break;
1181218822Sdim	    }
1182218822Sdim	}
1183218822Sdim    }
118438889Sjdp}
118538889Sjdp
118638889Sjdp/* We have no need to default values of symbols.
118738889Sjdp   We could catch register names here, but that is handled by inserting
118838889Sjdp   them all in the symbol table to begin with.  */
118938889Sjdp
119038889SjdpsymbolS *
1191218822Sdimmd_undefined_symbol (char *name ATTRIBUTE_UNUSED)
119238889Sjdp{
119338889Sjdp  return 0;
119438889Sjdp}
119538889Sjdp
119638889Sjdp/* Functions concerning expressions.  */
119738889Sjdp
119838889Sjdp/* Parse a .byte, .word, etc. expression.
119938889Sjdp
120038889Sjdp   Values for the status register are specified with %st(label).
120138889Sjdp   `label' will be right shifted by 2.  */
120238889Sjdp
120338889Sjdpvoid
1204218822Sdimarc_parse_cons_expression (expressionS *exp,
1205218822Sdim			   unsigned int nbytes ATTRIBUTE_UNUSED)
120638889Sjdp{
120785815Sobrien  char *p = input_line_pointer;
120885815Sobrien  int code_symbol_fix = 0;
120985815Sobrien
121085815Sobrien  for (; ! is_end_of_line[(unsigned char) *p]; p++)
121185815Sobrien    if (*p == '@' && !strncmp (p, "@h30", 4))
121285815Sobrien      {
121385815Sobrien	code_symbol_fix = 1;
121485815Sobrien	strcpy (p, ";   ");
121585815Sobrien      }
1216218822Sdim  expression_and_evaluate (exp);
121785815Sobrien  if (code_symbol_fix)
121885815Sobrien    {
121985815Sobrien      arc_code_symbol (exp);
122085815Sobrien      input_line_pointer = p;
122185815Sobrien    }
122238889Sjdp}
122338889Sjdp
122438889Sjdp/* Record a fixup for a cons expression.  */
122538889Sjdp
122638889Sjdpvoid
1227218822Sdimarc_cons_fix_new (fragS *frag,
1228218822Sdim		  int where,
1229218822Sdim		  int nbytes,
1230218822Sdim		  expressionS *exp)
123138889Sjdp{
123238889Sjdp  if (nbytes == 4)
123338889Sjdp    {
123438889Sjdp      int reloc_type;
123538889Sjdp      expressionS exptmp;
123638889Sjdp
123738889Sjdp      /* This may be a special ARC reloc (eg: %st()).  */
123838889Sjdp      reloc_type = get_arc_exp_reloc_type (1, BFD_RELOC_32, exp, &exptmp);
123938889Sjdp      fix_new_exp (frag, where, nbytes, &exptmp, 0, reloc_type);
124038889Sjdp    }
124138889Sjdp  else
124238889Sjdp    {
124338889Sjdp      fix_new_exp (frag, where, nbytes, exp, 0,
124438889Sjdp		   nbytes == 2 ? BFD_RELOC_16
124538889Sjdp		   : nbytes == 8 ? BFD_RELOC_64
124638889Sjdp		   : BFD_RELOC_32);
124738889Sjdp    }
124838889Sjdp}
124938889Sjdp
125038889Sjdp/* Functions concerning relocs.  */
125138889Sjdp
125238889Sjdp/* The location from which a PC relative jump should be calculated,
125338889Sjdp   given a PC relative reloc.  */
125438889Sjdp
125585815Sobrienlong
1256218822Sdimmd_pcrel_from (fixS *fixP)
125738889Sjdp{
125838889Sjdp  /* Return the address of the delay slot.  */
125938889Sjdp  return fixP->fx_frag->fr_address + fixP->fx_where + fixP->fx_size;
126038889Sjdp}
126138889Sjdp
126238889Sjdp/* Apply a fixup to the object code.  This is called for all the
126338889Sjdp   fixups we generated by the call to fix_new_exp, above.  In the call
126438889Sjdp   above we used a reloc code which was the largest legal reloc code
126538889Sjdp   plus the operand index.  Here we undo that to recover the operand
126638889Sjdp   index.  At this point all symbol values should be fully resolved,
126738889Sjdp   and we attempt to completely resolve the reloc.  If we can not do
126838889Sjdp   that, we determine the correct reloc code and put it back in the fixup.  */
126938889Sjdp
127089857Sobrienvoid
1271218822Sdimmd_apply_fix (fixS *fixP, valueT * valP, segT seg)
127238889Sjdp{
127389857Sobrien  valueT value = * valP;
127438889Sjdp
127538889Sjdp  if (fixP->fx_addsy == (symbolS *) NULL)
127689857Sobrien    fixP->fx_done = 1;
127789857Sobrien
127838889Sjdp  else if (fixP->fx_pcrel)
127938889Sjdp    {
1280130561Sobrien      /* Hack around bfd_install_relocation brain damage.  */
1281130561Sobrien      if (S_GET_SEGMENT (fixP->fx_addsy) != seg)
128238889Sjdp	value += md_pcrel_from (fixP);
128338889Sjdp    }
128438889Sjdp
1285130561Sobrien  /* We can't actually support subtracting a symbol.  */
1286130561Sobrien  if (fixP->fx_subsy != NULL)
1287130561Sobrien    as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
1288130561Sobrien
128938889Sjdp  if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
129038889Sjdp    {
129138889Sjdp      int opindex;
129238889Sjdp      const struct arc_operand *operand;
129338889Sjdp      char *where;
129438889Sjdp      arc_insn insn;
129538889Sjdp
129638889Sjdp      opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
129738889Sjdp
129838889Sjdp      operand = &arc_operands[opindex];
129938889Sjdp
130038889Sjdp      /* Fetch the instruction, insert the fully resolved operand
130138889Sjdp	 value, and stuff the instruction back again.  */
130238889Sjdp      where = fixP->fx_frag->fr_literal + fixP->fx_where;
130338889Sjdp      if (target_big_endian)
130438889Sjdp	insn = bfd_getb32 ((unsigned char *) where);
130538889Sjdp      else
130638889Sjdp	insn = bfd_getl32 ((unsigned char *) where);
130738889Sjdp      insn = arc_insert_operand (insn, operand, -1, NULL, (offsetT) value,
130838889Sjdp				 fixP->fx_file, fixP->fx_line);
130938889Sjdp      if (target_big_endian)
131038889Sjdp	bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
131138889Sjdp      else
131238889Sjdp	bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
131338889Sjdp
131438889Sjdp      if (fixP->fx_done)
1315218822Sdim	/* Nothing else to do here.  */
1316218822Sdim	return;
131738889Sjdp
131838889Sjdp      /* Determine a BFD reloc value based on the operand information.
131938889Sjdp	 We are only prepared to turn a few of the operands into relocs.
132038889Sjdp	 !!! Note that we can't handle limm values here.  Since we're using
132138889Sjdp	 implicit addends the addend must be inserted into the instruction,
132238889Sjdp	 however, the opcode insertion routines currently do nothing with
132338889Sjdp	 limm values.  */
132438889Sjdp      if (operand->fmt == 'B')
132538889Sjdp	{
132638889Sjdp	  assert ((operand->flags & ARC_OPERAND_RELATIVE_BRANCH) != 0
132738889Sjdp		  && operand->bits == 20
132838889Sjdp		  && operand->shift == 7);
132938889Sjdp	  fixP->fx_r_type = BFD_RELOC_ARC_B22_PCREL;
133038889Sjdp	}
133185815Sobrien      else if (operand->fmt == 'J')
133238889Sjdp	{
133338889Sjdp	  assert ((operand->flags & ARC_OPERAND_ABSOLUTE_BRANCH) != 0
133438889Sjdp		  && operand->bits == 24
133538889Sjdp		  && operand->shift == 32);
133638889Sjdp	  fixP->fx_r_type = BFD_RELOC_ARC_B26;
133738889Sjdp	}
133885815Sobrien      else if (operand->fmt == 'L')
133938889Sjdp	{
134038889Sjdp	  assert ((operand->flags & ARC_OPERAND_LIMM) != 0
134138889Sjdp		  && operand->bits == 32
134238889Sjdp		  && operand->shift == 32);
134338889Sjdp	  fixP->fx_r_type = BFD_RELOC_32;
134438889Sjdp	}
134538889Sjdp      else
134638889Sjdp	{
134738889Sjdp	  as_bad_where (fixP->fx_file, fixP->fx_line,
134885815Sobrien			"unresolved expression that must be resolved");
134938889Sjdp	  fixP->fx_done = 1;
135089857Sobrien	  return;
135138889Sjdp	}
135238889Sjdp    }
135338889Sjdp  else
135438889Sjdp    {
135538889Sjdp      switch (fixP->fx_r_type)
135638889Sjdp	{
135738889Sjdp	case BFD_RELOC_8:
135838889Sjdp	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
135938889Sjdp			      value, 1);
136038889Sjdp	  break;
136138889Sjdp	case BFD_RELOC_16:
136238889Sjdp	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
136338889Sjdp			      value, 2);
136438889Sjdp	  break;
136538889Sjdp	case BFD_RELOC_32:
136638889Sjdp	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
136738889Sjdp			      value, 4);
136838889Sjdp	  break;
136938889Sjdp	case BFD_RELOC_ARC_B26:
137038889Sjdp	  /* If !fixP->fx_done then `value' is an implicit addend.
137138889Sjdp	     We must shift it right by 2 in this case as well because the
137238889Sjdp	     linker performs the relocation and then adds this in (as opposed
137338889Sjdp	     to adding this in and then shifting right by 2).  */
137438889Sjdp	  value >>= 2;
137538889Sjdp	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
137638889Sjdp			      value, 4);
137738889Sjdp	  break;
137838889Sjdp	default:
137938889Sjdp	  abort ();
138038889Sjdp	}
138138889Sjdp    }
138238889Sjdp}
138338889Sjdp
138438889Sjdp/* Translate internal representation of relocation info to BFD target
138538889Sjdp   format.  */
138638889Sjdp
138738889Sjdparelent *
1388218822Sdimtc_gen_reloc (asection *section ATTRIBUTE_UNUSED,
1389218822Sdim	      fixS *fixP)
139038889Sjdp{
139138889Sjdp  arelent *reloc;
139238889Sjdp
1393218822Sdim  reloc = xmalloc (sizeof (arelent));
1394218822Sdim  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
139538889Sjdp
1396218822Sdim  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
139738889Sjdp  reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
139838889Sjdp  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
139938889Sjdp  if (reloc->howto == (reloc_howto_type *) NULL)
140038889Sjdp    {
140138889Sjdp      as_bad_where (fixP->fx_file, fixP->fx_line,
140285815Sobrien		    "internal error: can't export reloc type %d (`%s')",
140385815Sobrien		    fixP->fx_r_type,
140485815Sobrien		    bfd_get_reloc_code_name (fixP->fx_r_type));
140538889Sjdp      return NULL;
140638889Sjdp    }
140738889Sjdp
140838889Sjdp  assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
140938889Sjdp
141085815Sobrien  /* Set addend to account for PC being advanced one insn before the
1411130561Sobrien     target address is computed.  */
141238889Sjdp
141385815Sobrien  reloc->addend = (fixP->fx_pcrel ? -4 : 0);
141485815Sobrien
141538889Sjdp  return reloc;
141638889Sjdp}
1417218822Sdim
1418218822Sdimconst pseudo_typeS md_pseudo_table[] =
1419218822Sdim{
1420218822Sdim  { "align", s_align_bytes, 0 }, /* Defaulting is invalid (0).  */
1421218822Sdim  { "comm", arc_common, 0 },
1422218822Sdim  { "common", arc_common, 0 },
1423218822Sdim  { "lcomm", arc_common, 1 },
1424218822Sdim  { "lcommon", arc_common, 1 },
1425218822Sdim  { "2byte", cons, 2 },
1426218822Sdim  { "half", cons, 2 },
1427218822Sdim  { "short", cons, 2 },
1428218822Sdim  { "3byte", cons, 3 },
1429218822Sdim  { "4byte", cons, 4 },
1430218822Sdim  { "word", cons, 4 },
1431218822Sdim  { "option", arc_option, 0 },
1432218822Sdim  { "cpu", arc_option, 0 },
1433218822Sdim  { "block", s_space, 0 },
1434218822Sdim  { "extcondcode", arc_extoper, 0 },
1435218822Sdim  { "extcoreregister", arc_extoper, 1 },
1436218822Sdim  { "extauxregister", arc_extoper, 2 },
1437218822Sdim  { "extinstruction", arc_extinst, 0 },
1438218822Sdim  { NULL, 0, 0 },
1439218822Sdim};
1440218822Sdim
1441218822Sdim/* This routine is called for each instruction to be assembled.  */
1442218822Sdim
1443218822Sdimvoid
1444218822Sdimmd_assemble (char *str)
1445218822Sdim{
1446218822Sdim  const struct arc_opcode *opcode;
1447218822Sdim  const struct arc_opcode *std_opcode;
1448218822Sdim  struct arc_opcode *ext_opcode;
1449218822Sdim  char *start;
1450218822Sdim  const char *last_errmsg = 0;
1451218822Sdim  arc_insn insn;
1452218822Sdim  static int init_tables_p = 0;
1453218822Sdim
1454218822Sdim  /* Opcode table initialization is deferred until here because we have to
1455218822Sdim     wait for a possible .option command.  */
1456218822Sdim  if (!init_tables_p)
1457218822Sdim    {
1458218822Sdim      init_opcode_tables (arc_mach_type);
1459218822Sdim      init_tables_p = 1;
1460218822Sdim    }
1461218822Sdim
1462218822Sdim  /* Skip leading white space.  */
1463218822Sdim  while (ISSPACE (*str))
1464218822Sdim    str++;
1465218822Sdim
1466218822Sdim  /* The instructions are stored in lists hashed by the first letter (though
1467218822Sdim     we needn't care how they're hashed).  Get the first in the list.  */
1468218822Sdim
1469218822Sdim  ext_opcode = arc_ext_opcodes;
1470218822Sdim  std_opcode = arc_opcode_lookup_asm (str);
1471218822Sdim
1472218822Sdim  /* Keep looking until we find a match.  */
1473218822Sdim  start = str;
1474218822Sdim  for (opcode = (ext_opcode ? ext_opcode : std_opcode);
1475218822Sdim       opcode != NULL;
1476218822Sdim       opcode = (ARC_OPCODE_NEXT_ASM (opcode)
1477218822Sdim		 ? ARC_OPCODE_NEXT_ASM (opcode)
1478218822Sdim		 : (ext_opcode ? ext_opcode = NULL, std_opcode : NULL)))
1479218822Sdim    {
1480218822Sdim      int past_opcode_p, fc, num_suffixes;
1481218822Sdim      int fix_up_at = 0;
1482218822Sdim      char *syn;
1483218822Sdim      struct arc_fixup fixups[MAX_FIXUPS];
1484218822Sdim      /* Used as a sanity check.  If we need a limm reloc, make sure we ask
1485218822Sdim	 for an extra 4 bytes from frag_more.  */
1486218822Sdim      int limm_reloc_p;
1487218822Sdim      int ext_suffix_p;
1488218822Sdim      const struct arc_operand_value *insn_suffixes[MAX_SUFFIXES];
1489218822Sdim
1490218822Sdim      /* Is this opcode supported by the selected cpu?  */
1491218822Sdim      if (! arc_opcode_supported (opcode))
1492218822Sdim	continue;
1493218822Sdim
1494218822Sdim      /* Scan the syntax string.  If it doesn't match, try the next one.  */
1495218822Sdim      arc_opcode_init_insert ();
1496218822Sdim      insn = opcode->value;
1497218822Sdim      fc = 0;
1498218822Sdim      past_opcode_p = 0;
1499218822Sdim      num_suffixes = 0;
1500218822Sdim      limm_reloc_p = 0;
1501218822Sdim      ext_suffix_p = 0;
1502218822Sdim
1503218822Sdim      /* We don't check for (*str != '\0') here because we want to parse
1504218822Sdim	 any trailing fake arguments in the syntax string.  */
1505218822Sdim      for (str = start, syn = opcode->syntax; *syn != '\0';)
1506218822Sdim	{
1507218822Sdim	  int mods;
1508218822Sdim	  const struct arc_operand *operand;
1509218822Sdim
1510218822Sdim	  /* Non operand chars must match exactly.  */
1511218822Sdim	  if (*syn != '%' || *++syn == '%')
1512218822Sdim	    {
1513218822Sdim	     if (*str == *syn)
1514218822Sdim		{
1515218822Sdim		  if (*syn == ' ')
1516218822Sdim		    past_opcode_p = 1;
1517218822Sdim		  ++syn;
1518218822Sdim		  ++str;
1519218822Sdim		}
1520218822Sdim	      else
1521218822Sdim		break;
1522218822Sdim	      continue;
1523218822Sdim	    }
1524218822Sdim
1525218822Sdim	  /* We have an operand.  Pick out any modifiers.  */
1526218822Sdim	  mods = 0;
1527218822Sdim	  while (ARC_MOD_P (arc_operands[arc_operand_map[(int) *syn]].flags))
1528218822Sdim	    {
1529218822Sdim	      mods |= arc_operands[arc_operand_map[(int) *syn]].flags & ARC_MOD_BITS;
1530218822Sdim	      ++syn;
1531218822Sdim	    }
1532218822Sdim	  operand = arc_operands + arc_operand_map[(int) *syn];
1533218822Sdim	  if (operand->fmt == 0)
1534218822Sdim	    as_fatal ("unknown syntax format character `%c'", *syn);
1535218822Sdim
1536218822Sdim	  if (operand->flags & ARC_OPERAND_FAKE)
1537218822Sdim	    {
1538218822Sdim	      const char *errmsg = NULL;
1539218822Sdim	      if (operand->insert)
1540218822Sdim		{
1541218822Sdim		  insn = (*operand->insert) (insn, operand, mods, NULL, 0, &errmsg);
1542218822Sdim		  if (errmsg != (const char *) NULL)
1543218822Sdim		    {
1544218822Sdim		      last_errmsg = errmsg;
1545218822Sdim		      if (operand->flags & ARC_OPERAND_ERROR)
1546218822Sdim			{
1547218822Sdim			  as_bad (errmsg);
1548218822Sdim			  return;
1549218822Sdim			}
1550218822Sdim		      else if (operand->flags & ARC_OPERAND_WARN)
1551218822Sdim			as_warn (errmsg);
1552218822Sdim		      break;
1553218822Sdim		    }
1554218822Sdim		  if (limm_reloc_p
1555218822Sdim		      && (operand->flags && operand->flags & ARC_OPERAND_LIMM)
1556218822Sdim		      && (operand->flags &
1557218822Sdim			  (ARC_OPERAND_ABSOLUTE_BRANCH | ARC_OPERAND_ADDRESS)))
1558218822Sdim		    {
1559218822Sdim		      fixups[fix_up_at].opindex = arc_operand_map[operand->fmt];
1560218822Sdim		    }
1561218822Sdim		}
1562218822Sdim	      ++syn;
1563218822Sdim	    }
1564218822Sdim	  /* Are we finished with suffixes?  */
1565218822Sdim	  else if (!past_opcode_p)
1566218822Sdim	    {
1567218822Sdim	      int found;
1568218822Sdim	      char c;
1569218822Sdim	      char *s, *t;
1570218822Sdim	      const struct arc_operand_value *suf, *suffix_end;
1571218822Sdim	      const struct arc_operand_value *suffix = NULL;
1572218822Sdim
1573218822Sdim	      if (!(operand->flags & ARC_OPERAND_SUFFIX))
1574218822Sdim		abort ();
1575218822Sdim
1576218822Sdim	      /* If we're at a space in the input string, we want to skip the
1577218822Sdim		 remaining suffixes.  There may be some fake ones though, so
1578218822Sdim		 just go on to try the next one.  */
1579218822Sdim	      if (*str == ' ')
1580218822Sdim		{
1581218822Sdim		  ++syn;
1582218822Sdim		  continue;
1583218822Sdim		}
1584218822Sdim
1585218822Sdim	      s = str;
1586218822Sdim	      if (mods & ARC_MOD_DOT)
1587218822Sdim		{
1588218822Sdim		  if (*s != '.')
1589218822Sdim		    break;
1590218822Sdim		  ++s;
1591218822Sdim		}
1592218822Sdim	      else
1593218822Sdim		{
1594218822Sdim		  /* This can happen in "b.nd foo" and we're currently looking
1595218822Sdim		     for "%q" (ie: a condition code suffix).  */
1596218822Sdim		  if (*s == '.')
1597218822Sdim		    {
1598218822Sdim		      ++syn;
1599218822Sdim		      continue;
1600218822Sdim		    }
1601218822Sdim		}
1602218822Sdim
1603218822Sdim	      /* Pick the suffix out and look it up via the hash table.  */
1604218822Sdim	      for (t = s; *t && ISALNUM (*t); ++t)
1605218822Sdim		continue;
1606218822Sdim	      c = *t;
1607218822Sdim	      *t = '\0';
1608218822Sdim	      if ((suf = get_ext_suffix (s)))
1609218822Sdim		ext_suffix_p = 1;
1610218822Sdim	      else
1611218822Sdim		suf = hash_find (arc_suffix_hash, s);
1612218822Sdim	      if (!suf)
1613218822Sdim		{
1614218822Sdim		  /* This can happen in "blle foo" and we're currently using
1615218822Sdim		     the template "b%q%.n %j".  The "bl" insn occurs later in
1616218822Sdim		     the table so "lle" isn't an illegal suffix.  */
1617218822Sdim		  *t = c;
1618218822Sdim		  break;
1619218822Sdim		}
1620218822Sdim
1621218822Sdim	      /* Is it the right type?  Note that the same character is used
1622218822Sdim		 several times, so we have to examine all of them.  This is
1623218822Sdim		 relatively efficient as equivalent entries are kept
1624218822Sdim		 together.  If it's not the right type, don't increment `str'
1625218822Sdim		 so we try the next one in the series.  */
1626218822Sdim	      found = 0;
1627218822Sdim	      if (ext_suffix_p && arc_operands[suf->type].fmt == *syn)
1628218822Sdim		{
1629218822Sdim		  /* Insert the suffix's value into the insn.  */
1630218822Sdim		  *t = c;
1631218822Sdim		  if (operand->insert)
1632218822Sdim		    insn = (*operand->insert) (insn, operand,
1633218822Sdim					       mods, NULL, suf->value,
1634218822Sdim					       NULL);
1635218822Sdim		  else
1636218822Sdim		    insn |= suf->value << operand->shift;
1637218822Sdim		  suffix = suf;
1638218822Sdim		  str = t;
1639218822Sdim		  found = 1;
1640218822Sdim		}
1641218822Sdim	      else
1642218822Sdim		{
1643218822Sdim		  *t = c;
1644218822Sdim		  suffix_end = arc_suffixes + arc_suffixes_count;
1645218822Sdim		  for (suffix = suf;
1646218822Sdim		       suffix < suffix_end && strcmp (suffix->name, suf->name) == 0;
1647218822Sdim		       ++suffix)
1648218822Sdim		    {
1649218822Sdim		      if (arc_operands[suffix->type].fmt == *syn)
1650218822Sdim			{
1651218822Sdim			  /* Insert the suffix's value into the insn.  */
1652218822Sdim			  if (operand->insert)
1653218822Sdim			    insn = (*operand->insert) (insn, operand,
1654218822Sdim						       mods, NULL, suffix->value,
1655218822Sdim						       NULL);
1656218822Sdim			  else
1657218822Sdim			    insn |= suffix->value << operand->shift;
1658218822Sdim
1659218822Sdim			  str = t;
1660218822Sdim			  found = 1;
1661218822Sdim			  break;
1662218822Sdim			}
1663218822Sdim		    }
1664218822Sdim		}
1665218822Sdim	      ++syn;
1666218822Sdim	      if (!found)
1667218822Sdim		/* Wrong type.  Just go on to try next insn entry.  */
1668218822Sdim		;
1669218822Sdim	      else
1670218822Sdim		{
1671218822Sdim		  if (num_suffixes == MAX_SUFFIXES)
1672218822Sdim		    as_bad ("too many suffixes");
1673218822Sdim		  else
1674218822Sdim		    insn_suffixes[num_suffixes++] = suffix;
1675218822Sdim		}
1676218822Sdim	    }
1677218822Sdim	  else
1678218822Sdim	    /* This is either a register or an expression of some kind.  */
1679218822Sdim	    {
1680218822Sdim	      char *hold;
1681218822Sdim	      const struct arc_operand_value *reg = NULL;
1682218822Sdim	      long value = 0;
1683218822Sdim	      expressionS exp;
1684218822Sdim
1685218822Sdim	      if (operand->flags & ARC_OPERAND_SUFFIX)
1686218822Sdim		abort ();
1687218822Sdim
1688218822Sdim	      /* Is there anything left to parse?
1689218822Sdim		 We don't check for this at the top because we want to parse
1690218822Sdim		 any trailing fake arguments in the syntax string.  */
1691218822Sdim	      if (is_end_of_line[(unsigned char) *str])
1692218822Sdim		break;
1693218822Sdim
1694218822Sdim	      /* Parse the operand.  */
1695218822Sdim	      hold = input_line_pointer;
1696218822Sdim	      input_line_pointer = str;
1697218822Sdim	      expression (&exp);
1698218822Sdim	      str = input_line_pointer;
1699218822Sdim	      input_line_pointer = hold;
1700218822Sdim
1701218822Sdim	      if (exp.X_op == O_illegal)
1702218822Sdim		as_bad ("illegal operand");
1703218822Sdim	      else if (exp.X_op == O_absent)
1704218822Sdim		as_bad ("missing operand");
1705218822Sdim	      else if (exp.X_op == O_constant)
1706218822Sdim		value = exp.X_add_number;
1707218822Sdim	      else if (exp.X_op == O_register)
1708218822Sdim		reg = (struct arc_operand_value *) exp.X_add_number;
1709218822Sdim#define IS_REG_DEST_OPERAND(o) ((o) == 'a')
1710218822Sdim	      else if (IS_REG_DEST_OPERAND (*syn))
1711218822Sdim		as_bad ("symbol as destination register");
1712218822Sdim	      else
1713218822Sdim		{
1714218822Sdim		  if (!strncmp (str, "@h30", 4))
1715218822Sdim		    {
1716218822Sdim		      arc_code_symbol (&exp);
1717218822Sdim		      str += 4;
1718218822Sdim		    }
1719218822Sdim		  /* We need to generate a fixup for this expression.  */
1720218822Sdim		  if (fc >= MAX_FIXUPS)
1721218822Sdim		    as_fatal ("too many fixups");
1722218822Sdim		  fixups[fc].exp = exp;
1723218822Sdim		  /* We don't support shimm relocs. break here to force
1724218822Sdim		     the assembler to output a limm.  */
1725218822Sdim#define IS_REG_SHIMM_OFFSET(o) ((o) == 'd')
1726218822Sdim		  if (IS_REG_SHIMM_OFFSET (*syn))
1727218822Sdim		    break;
1728218822Sdim		  /* If this is a register constant (IE: one whose
1729218822Sdim		     register value gets stored as 61-63) then this
1730218822Sdim		     must be a limm.  */
1731218822Sdim		  /* ??? This bit could use some cleaning up.
1732218822Sdim		     Referencing the format chars like this goes
1733218822Sdim		     against style.  */
1734218822Sdim		  if (IS_SYMBOL_OPERAND (*syn))
1735218822Sdim		    {
1736218822Sdim		      const char *junk;
1737218822Sdim		      limm_reloc_p = 1;
1738218822Sdim		      /* Save this, we don't yet know what reloc to use.  */
1739218822Sdim		      fix_up_at = fc;
1740218822Sdim		      /* Tell insert_reg we need a limm.  This is
1741218822Sdim			 needed because the value at this point is
1742218822Sdim			 zero, a shimm.  */
1743218822Sdim		      /* ??? We need a cleaner interface than this.  */
1744218822Sdim		      (*arc_operands[arc_operand_map['Q']].insert)
1745218822Sdim			(insn, operand, mods, reg, 0L, &junk);
1746218822Sdim		    }
1747218822Sdim		  else
1748218822Sdim		    fixups[fc].opindex = arc_operand_map[(int) *syn];
1749218822Sdim		  ++fc;
1750218822Sdim		  value = 0;
1751218822Sdim		}
1752218822Sdim
1753218822Sdim	      /* Insert the register or expression into the instruction.  */
1754218822Sdim	      if (operand->insert)
1755218822Sdim		{
1756218822Sdim		  const char *errmsg = NULL;
1757218822Sdim		  insn = (*operand->insert) (insn, operand, mods,
1758218822Sdim					     reg, (long) value, &errmsg);
1759218822Sdim		  if (errmsg != (const char *) NULL)
1760218822Sdim		    {
1761218822Sdim		      last_errmsg = errmsg;
1762218822Sdim		      if (operand->flags & ARC_OPERAND_ERROR)
1763218822Sdim			{
1764218822Sdim			  as_bad (errmsg);
1765218822Sdim			  return;
1766218822Sdim			}
1767218822Sdim		      else if (operand->flags & ARC_OPERAND_WARN)
1768218822Sdim			as_warn (errmsg);
1769218822Sdim		      break;
1770218822Sdim		    }
1771218822Sdim		}
1772218822Sdim	      else
1773218822Sdim		insn |= (value & ((1 << operand->bits) - 1)) << operand->shift;
1774218822Sdim
1775218822Sdim	      ++syn;
1776218822Sdim	    }
1777218822Sdim	}
1778218822Sdim
1779218822Sdim      /* If we're at the end of the syntax string, we're done.  */
1780218822Sdim      /* FIXME: try to move this to a separate function.  */
1781218822Sdim      if (*syn == '\0')
1782218822Sdim	{
1783218822Sdim	  int i;
1784218822Sdim	  char *f;
1785218822Sdim	  long limm, limm_p;
1786218822Sdim
1787218822Sdim	  /* For the moment we assume a valid `str' can only contain blanks
1788218822Sdim	     now.  IE: We needn't try again with a longer version of the
1789218822Sdim	     insn and it is assumed that longer versions of insns appear
1790218822Sdim	     before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
1791218822Sdim
1792218822Sdim	  while (ISSPACE (*str))
1793218822Sdim	    ++str;
1794218822Sdim
1795218822Sdim	  if (!is_end_of_line[(unsigned char) *str])
1796218822Sdim	    as_bad ("junk at end of line: `%s'", str);
1797218822Sdim
1798218822Sdim	  /* Is there a limm value?  */
1799218822Sdim	  limm_p = arc_opcode_limm_p (&limm);
1800218822Sdim
1801218822Sdim	  /* Perform various error and warning tests.  */
1802218822Sdim
1803218822Sdim	  {
1804218822Sdim	    static int in_delay_slot_p = 0;
1805218822Sdim	    static int prev_insn_needs_cc_nop_p = 0;
1806218822Sdim	    /* delay slot type seen */
1807218822Sdim	    int delay_slot_type = ARC_DELAY_NONE;
1808218822Sdim	    /* conditional execution flag seen */
1809218822Sdim	    int conditional = 0;
1810218822Sdim	    /* 1 if condition codes are being set */
1811218822Sdim	    int cc_set_p = 0;
1812218822Sdim	    /* 1 if conditional branch, including `b' "branch always" */
1813218822Sdim	    int cond_branch_p = opcode->flags & ARC_OPCODE_COND_BRANCH;
1814218822Sdim
1815218822Sdim	    for (i = 0; i < num_suffixes; ++i)
1816218822Sdim	      {
1817218822Sdim		switch (arc_operands[insn_suffixes[i]->type].fmt)
1818218822Sdim		  {
1819218822Sdim		  case 'n':
1820218822Sdim		    delay_slot_type = insn_suffixes[i]->value;
1821218822Sdim		    break;
1822218822Sdim		  case 'q':
1823218822Sdim		    conditional = insn_suffixes[i]->value;
1824218822Sdim		    break;
1825218822Sdim		  case 'f':
1826218822Sdim		    cc_set_p = 1;
1827218822Sdim		    break;
1828218822Sdim		  }
1829218822Sdim	      }
1830218822Sdim
1831218822Sdim	    /* Putting an insn with a limm value in a delay slot is supposed to
1832218822Sdim	       be legal, but let's warn the user anyway.  Ditto for 8 byte
1833218822Sdim	       jumps with delay slots.  */
1834218822Sdim	    if (in_delay_slot_p && limm_p)
1835218822Sdim	      as_warn ("8 byte instruction in delay slot");
1836218822Sdim	    if (delay_slot_type != ARC_DELAY_NONE
1837218822Sdim		&& limm_p && arc_insn_not_jl (insn)) /* except for jl  addr */
1838218822Sdim	      as_warn ("8 byte jump instruction with delay slot");
1839218822Sdim	    in_delay_slot_p = (delay_slot_type != ARC_DELAY_NONE) && !limm_p;
1840218822Sdim
1841218822Sdim	    /* Warn when a conditional branch immediately follows a set of
1842218822Sdim	       the condition codes.  Note that this needn't be done if the
1843218822Sdim	       insn that sets the condition codes uses a limm.  */
1844218822Sdim	    if (cond_branch_p && conditional != 0 /* 0 = "always" */
1845218822Sdim		&& prev_insn_needs_cc_nop_p && arc_mach_type == bfd_mach_arc_5)
1846218822Sdim	      as_warn ("conditional branch follows set of flags");
1847218822Sdim	    prev_insn_needs_cc_nop_p =
1848218822Sdim	      /* FIXME: ??? not required:
1849218822Sdim		 (delay_slot_type != ARC_DELAY_NONE) &&  */
1850218822Sdim	      cc_set_p && !limm_p;
1851218822Sdim	  }
1852218822Sdim
1853218822Sdim	  /* Write out the instruction.
1854218822Sdim	     It is important to fetch enough space in one call to `frag_more'.
1855218822Sdim	     We use (f - frag_now->fr_literal) to compute where we are and we
1856218822Sdim	     don't want frag_now to change between calls.  */
1857218822Sdim	  if (limm_p)
1858218822Sdim	    {
1859218822Sdim	      f = frag_more (8);
1860218822Sdim	      md_number_to_chars (f, insn, 4);
1861218822Sdim	      md_number_to_chars (f + 4, limm, 4);
1862218822Sdim	      dwarf2_emit_insn (8);
1863218822Sdim	    }
1864218822Sdim	  else if (limm_reloc_p)
1865218822Sdim	    /* We need a limm reloc, but the tables think we don't.  */
1866218822Sdim	    abort ();
1867218822Sdim	  else
1868218822Sdim	    {
1869218822Sdim	      f = frag_more (4);
1870218822Sdim	      md_number_to_chars (f, insn, 4);
1871218822Sdim	      dwarf2_emit_insn (4);
1872218822Sdim	    }
1873218822Sdim
1874218822Sdim	  /* Create any fixups.  */
1875218822Sdim	  for (i = 0; i < fc; ++i)
1876218822Sdim	    {
1877218822Sdim	      int op_type, reloc_type;
1878218822Sdim	      expressionS exptmp;
1879218822Sdim	      const struct arc_operand *operand;
1880218822Sdim
1881218822Sdim	      /* Create a fixup for this operand.
1882218822Sdim		 At this point we do not use a bfd_reloc_code_real_type for
1883218822Sdim		 operands residing in the insn, but instead just use the
1884218822Sdim		 operand index.  This lets us easily handle fixups for any
1885218822Sdim		 operand type, although that is admittedly not a very exciting
1886218822Sdim		 feature.  We pick a BFD reloc type in md_apply_fix.
1887218822Sdim
1888218822Sdim		 Limm values (4 byte immediate "constants") must be treated
1889218822Sdim		 normally because they're not part of the actual insn word
1890218822Sdim		 and thus the insertion routines don't handle them.  */
1891218822Sdim
1892218822Sdim	      if (arc_operands[fixups[i].opindex].flags & ARC_OPERAND_LIMM)
1893218822Sdim		{
1894218822Sdim		  /* Modify the fixup addend as required by the cpu.  */
1895218822Sdim		  fixups[i].exp.X_add_number += arc_limm_fixup_adjust (insn);
1896218822Sdim		  op_type = fixups[i].opindex;
1897218822Sdim		  /* FIXME: can we add this data to the operand table?  */
1898218822Sdim		  if (op_type == arc_operand_map['L']
1899218822Sdim		      || op_type == arc_operand_map['s']
1900218822Sdim		      || op_type == arc_operand_map['o']
1901218822Sdim		      || op_type == arc_operand_map['O'])
1902218822Sdim		    reloc_type = BFD_RELOC_32;
1903218822Sdim		  else if (op_type == arc_operand_map['J'])
1904218822Sdim		    reloc_type = BFD_RELOC_ARC_B26;
1905218822Sdim		  else
1906218822Sdim		    abort ();
1907218822Sdim		  reloc_type = get_arc_exp_reloc_type (1, reloc_type,
1908218822Sdim						       &fixups[i].exp,
1909218822Sdim						       &exptmp);
1910218822Sdim		}
1911218822Sdim	      else
1912218822Sdim		{
1913218822Sdim		  op_type = get_arc_exp_reloc_type (0, fixups[i].opindex,
1914218822Sdim						    &fixups[i].exp, &exptmp);
1915218822Sdim		  reloc_type = op_type + (int) BFD_RELOC_UNUSED;
1916218822Sdim		}
1917218822Sdim	      operand = &arc_operands[op_type];
1918218822Sdim	      fix_new_exp (frag_now,
1919218822Sdim			   ((f - frag_now->fr_literal)
1920218822Sdim			    + (operand->flags & ARC_OPERAND_LIMM ? 4 : 0)), 4,
1921218822Sdim			   &exptmp,
1922218822Sdim			   (operand->flags & ARC_OPERAND_RELATIVE_BRANCH) != 0,
1923218822Sdim			   (bfd_reloc_code_real_type) reloc_type);
1924218822Sdim	    }
1925218822Sdim	  return;
1926218822Sdim	}
1927218822Sdim    }
1928218822Sdim
1929218822Sdim  if (NULL == last_errmsg)
1930218822Sdim    as_bad ("bad instruction `%s'", start);
1931218822Sdim  else
1932218822Sdim    as_bad (last_errmsg);
1933218822Sdim}
1934