This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH ARC 3/8] GAS: new ARC port


New ARC implementation. Please review.

Claudiu

2015-09-01  Claudiu Zissulescu  <claziss@synopsys.com>

        * config/tc-arc.c: Revamped file for ARC support.
        * config/tc-arc.h: Likewise.
        * doc/as.texinfo: Add new ARC options.
        * doc/c-arc.texi: Likewise.


---
 gas/config/tc-arc.c | 4219 +++++++++++++++++++++++++++++++++------------------
 gas/config/tc-arc.h |  173 ++-
 gas/configure.tgt   |   10 +-
 gas/doc/as.texinfo  |   12 +-
 gas/doc/c-arc.texi  |  529 ++++---
 5 files changed, 3197 insertions(+), 1746 deletions(-)

diff --git a/gas/config/tc-arc.c b/gas/config/tc-arc.c
index 4806ed8..789864a 100644
--- a/gas/config/tc-arc.c
+++ b/gas/config/tc-arc.c
@@ -1,6 +1,7 @@
 /* tc-arc.c -- Assembler for the ARC
    Copyright (C) 1994-2015 Free Software Foundation, Inc.
-   Contributed by Doug Evans (dje@cygnus.com).
+
+   Contributor: Claudiu Zissulescu <claziss@synopsys.com>
 
    This file is part of GAS, the GNU Assembler.
 
@@ -20,62 +21,63 @@
    02110-1301, USA.  */
 
 #include "as.h"
+#include "subsegs.h"
 #include "struc-symbol.h"
+#include "dwarf2dbg.h"
 #include "safe-ctype.h"
-#include "subsegs.h"
+
 #include "opcode/arc.h"
-#include "../opcodes/arc-ext.h"
 #include "elf/arc.h"
-#include "dwarf2dbg.h"
 
-const struct suffix_classes
-{
-  char *name;
-  int  len;
-} suffixclass[] =
-{
-  { "SUFFIX_COND|SUFFIX_FLAG",23 },
-  { "SUFFIX_FLAG", 11 },
-  { "SUFFIX_COND", 11 },
-  { "SUFFIX_NONE", 11 }
-};
+/**************************************************************************/
+/* Defines								  */
+/**************************************************************************/
 
-#define MAXSUFFIXCLASS (sizeof (suffixclass) / sizeof (struct suffix_classes))
+#define MAX_FLAG_NAME_LENGHT 3
+#define MAX_INSN_FIXUPS      2
+#define MAX_CONSTR_STR       20
 
-const struct syntax_classes
-{
-  char *name;
-  int  len;
-  int  s_class;
-} syntaxclass[] =
-{
-  { "SYNTAX_3OP|OP1_MUST_BE_IMM", 26, SYNTAX_3OP|OP1_MUST_BE_IMM|SYNTAX_VALID },
-  { "OP1_MUST_BE_IMM|SYNTAX_3OP", 26, OP1_MUST_BE_IMM|SYNTAX_3OP|SYNTAX_VALID },
-  { "SYNTAX_2OP|OP1_IMM_IMPLIED", 26, SYNTAX_2OP|OP1_IMM_IMPLIED|SYNTAX_VALID },
-  { "OP1_IMM_IMPLIED|SYNTAX_2OP", 26, OP1_IMM_IMPLIED|SYNTAX_2OP|SYNTAX_VALID },
-  { "SYNTAX_3OP",                 10, SYNTAX_3OP|SYNTAX_VALID },
-  { "SYNTAX_2OP",                 10, SYNTAX_2OP|SYNTAX_VALID }
-};
+#ifdef DEBUG
+# define pr_debug(fmt, args...) fprintf (stderr, fmt, ##args)
+#else
+# define pr_debug(fmt, args...)
+#endif
+
+#define MAJOR_OPCODE(x)  (((x) & 0xF8000000) >> 27)
+#define SUB_OPCODE(x)	 (((x) & 0x003F0000) >> 16)
+#define LP_INSN(x)	 ((MAJOR_OPCODE (x) == 0x4) &&	\
+			  (SUB_OPCODE (x) == 0x28))
 
-#define MAXSYNTAXCLASS (sizeof (syntaxclass) / sizeof (struct syntax_classes))
+/* Equal to MAX_PRECISION in atof-ieee.c.  */
+#define MAX_LITTLENUMS 6
 
-/* This array holds the chars that always start a comment.  If the
-   pre-processor is disabled, these aren't very useful.  */
+/**************************************************************************/
+/* Macros								  */
+/**************************************************************************/
+
+#define regno(x)		((x) & 0x3F)
+#define is_ir_num(x)		(((x) & ~0x3F) == 0)
+#define is_code_density_p(op)   (((op)->subclass == CD1 || (op)->subclass == CD2))
+#define is_br_jmp_insn_p(op)    (((op)->class == BRANCH || (op)->class == JUMP))
+#define is_kernel_insn_p(op)    (((op)->class == KERNEL))
+
+/**************************************************************************/
+/* Generic assembler global variables which must be defined by all	  */
+/* targets.								  */
+/**************************************************************************/
+
+/* Characters which always start a comment.  */
 const char comment_chars[] = "#;";
 
-/* This array holds the chars that only start a comment at the beginning of
-   a line.  If the line seems to have the form '# 123 filename'
-   .line and .file directives will appear in the pre-processed output */
-/* Note that input_file.c hand checks for '#' at the beginning of the
-   first line of the input file.  This is because the compiler outputs
-   #NO_APP at the beginning of its output.  */
-/* Also note that comments started like this one will always
-   work if '/' isn't otherwise defined.  */
+/* Characters which start a comment at the beginning of a line.  */
 const char line_comment_chars[] = "#";
 
-const char line_separator_chars[] = "";
+/* Characters which may be used to separate multiple commands on a
+   single line.  */
+const char line_separator_chars[] = "`";
 
-/* Chars that can be used to separate mant from exp in floating point nums.  */
+/* Characters which are used to indicate an exponent in a floating
+   point number.  */
 const char EXP_CHARS[] = "eE";
 
 /* Chars that mean this number is a floating point constant
@@ -87,1807 +89,3052 @@ extern int target_big_endian;
 const char *arc_target_format = DEFAULT_TARGET_FORMAT;
 static int byte_order = DEFAULT_BYTE_ORDER;
 
-static segT arcext_section;
+extern int arc_get_mach (char *);
 
-/* One of bfd_mach_arc_n.  */
-static int arc_mach_type = bfd_mach_arc_6;
+/* Forward declaration.  */
+static void arc_lcomm (int);
+static void arc_option (int);
+static void arc_extra_reloc (int);
 
-/* Non-zero if the cpu type has been explicitly specified.  */
-static int mach_type_specified_p = 0;
+const pseudo_typeS md_pseudo_table[] =
+  {
+    /* Make sure that .word is 32 bits.  */
+    { "word", cons, 4 },
+
+    { "align",   s_align_bytes, 0 }, /* Defaulting is invalid (0).  */
+    { "lcomm",   arc_lcomm, 0 },
+    { "lcommon", arc_lcomm, 0 },
+    { "cpu",     arc_option, 0 },
 
-/* Non-zero if opcode tables have been initialized.
-   A .option command must appear before any instructions.  */
-static int cpu_tables_init_p = 0;
+    { "tls_gd_ld",   arc_extra_reloc, BFD_RELOC_ARC_TLS_GD_LD },
+    { "tls_gd_call", arc_extra_reloc, BFD_RELOC_ARC_TLS_GD_CALL },
+
+    { NULL, NULL, 0 }
+  };
 
-static struct hash_control *arc_suffix_hash = NULL;
-
 const char *md_shortopts = "";
 
 enum options
-{
-  OPTION_EB = OPTION_MD_BASE,
-  OPTION_EL,
-  OPTION_ARC5,
-  OPTION_ARC6,
-  OPTION_ARC7,
-  OPTION_ARC8,
-  OPTION_ARC
-};
+  {
+    OPTION_EB = OPTION_MD_BASE,
+    OPTION_EL,
+
+    OPTION_ARC600,
+    OPTION_ARC601,
+    OPTION_ARC700,
+    OPTION_ARCEM,
+    OPTION_ARCHS,
+
+    OPTION_MCPU,
+    OPTION_CD,
+
+    /* The following options are deprecated and provided here only for
+       compatibility reasons.  */
+    OPTION_USER_MODE,
+    OPTION_LD_EXT_MASK,
+    OPTION_SWAP,
+    OPTION_NORM,
+    OPTION_BARREL_SHIFT,
+    OPTION_MIN_MAX,
+    OPTION_NO_MPY,
+    OPTION_EA,
+    OPTION_MUL64,
+    OPTION_SIMD,
+    OPTION_SPFP,
+    OPTION_DPFP,
+    OPTION_XMAC_D16,
+    OPTION_XMAC_24,
+    OPTION_DSP_PACKA,
+    OPTION_CRC,
+    OPTION_DVBF,
+    OPTION_TELEPHONY,
+    OPTION_XYMEMORY,
+    OPTION_LOCK,
+    OPTION_SWAPE,
+    OPTION_RTSC,
+    OPTION_FPUDA
+  };
 
 struct option md_longopts[] =
-{
-  { "EB", no_argument, NULL, OPTION_EB },
-  { "EL", no_argument, NULL, OPTION_EL },
-  { "marc5", no_argument, NULL, OPTION_ARC5 },
-  { "pre-v6", no_argument, NULL, OPTION_ARC5 },
-  { "marc6", no_argument, NULL, OPTION_ARC6 },
-  { "marc7", no_argument, NULL, OPTION_ARC7 },
-  { "marc8", no_argument, NULL, OPTION_ARC8 },
-  { "marc", no_argument, NULL, OPTION_ARC },
-  { NULL, no_argument, NULL, 0 }
-};
+  {
+    { "EB",		no_argument,	   NULL, OPTION_EB },
+    { "EL",		no_argument,	   NULL, OPTION_EL },
+    { "mcpu",		required_argument, NULL, OPTION_MCPU },
+    { "mA6",		no_argument,	   NULL, OPTION_ARC600 },
+    { "mARC600",	no_argument,	   NULL, OPTION_ARC600 },
+    { "mARC601",	no_argument,	   NULL, OPTION_ARC601 },
+    { "mARC700",	no_argument,	   NULL, OPTION_ARC700 },
+    { "mA7",		no_argument,	   NULL, OPTION_ARC700 },
+    { "mEM",		no_argument,	   NULL, OPTION_ARCEM },
+    { "mHS",		no_argument,	   NULL, OPTION_ARCHS },
+    { "mcode-density",	no_argument,	   NULL, OPTION_CD },
+
+    /* The following options are deprecated and provided here only for
+       compatibility reasons.  */
+    { "mav2em", no_argument, NULL, OPTION_ARCEM },
+    { "mav2hs", no_argument, NULL, OPTION_ARCHS },
+    { "muser-mode-only", no_argument, NULL, OPTION_USER_MODE },
+    { "mld-extension-reg-mask", required_argument, NULL, OPTION_LD_EXT_MASK },
+    { "mswap", no_argument, NULL, OPTION_SWAP },
+    { "mnorm", no_argument, NULL, OPTION_NORM },
+    { "mbarrel-shifter", no_argument, NULL, OPTION_BARREL_SHIFT },
+    { "mbarrel_shifter", no_argument, NULL, OPTION_BARREL_SHIFT },
+    { "mmin-max", no_argument, NULL, OPTION_MIN_MAX },
+    { "mmin_max", no_argument, NULL, OPTION_MIN_MAX },
+    { "mno-mpy", no_argument, NULL, OPTION_NO_MPY },
+    { "mea", no_argument, NULL, OPTION_EA },
+    { "mEA", no_argument, NULL, OPTION_EA },
+    { "mmul64", no_argument, NULL, OPTION_MUL64 },
+    { "msimd", no_argument, NULL, OPTION_SIMD},
+    { "mspfp", no_argument, NULL, OPTION_SPFP},
+    { "mspfp-compact", no_argument, NULL, OPTION_SPFP},
+    { "mspfp_compact", no_argument, NULL, OPTION_SPFP},
+    { "mspfp-fast", no_argument, NULL, OPTION_SPFP},
+    { "mspfp_fast", no_argument, NULL, OPTION_SPFP},
+    { "mdpfp", no_argument, NULL, OPTION_DPFP},
+    { "mdpfp-compact", no_argument, NULL, OPTION_DPFP},
+    { "mdpfp_compact", no_argument, NULL, OPTION_DPFP},
+    { "mdpfp-fast", no_argument, NULL, OPTION_DPFP},
+    { "mdpfp_fast", no_argument, NULL, OPTION_DPFP},
+    { "mmac-d16", no_argument, NULL, OPTION_XMAC_D16},
+    { "mmac_d16", no_argument, NULL, OPTION_XMAC_D16},
+    { "mmac-24", no_argument, NULL, OPTION_XMAC_24},
+    { "mmac_24", no_argument, NULL, OPTION_XMAC_24},
+    { "mdsp-packa", no_argument, NULL, OPTION_DSP_PACKA},
+    { "mdsp_packa", no_argument, NULL, OPTION_DSP_PACKA},
+    { "mcrc", no_argument, NULL, OPTION_CRC},
+    { "mdvbf", no_argument, NULL, OPTION_DVBF},
+    { "mtelephony", no_argument, NULL, OPTION_TELEPHONY},
+    { "mxy", no_argument, NULL, OPTION_XYMEMORY},
+    { "mlock", no_argument, NULL, OPTION_LOCK},
+    { "mswape", no_argument, NULL, OPTION_SWAPE},
+    { "mrtsc", no_argument, NULL, OPTION_RTSC},
+    { "mfpuda", no_argument, NULL, OPTION_FPUDA},
+
+    { NULL,		no_argument, NULL, 0 }
+  };
+
 size_t md_longopts_size = sizeof (md_longopts);
 
-#define IS_SYMBOL_OPERAND(o) \
- ((o) == 'b' || (o) == 'c' || (o) == 's' || (o) == 'o' || (o) == 'O')
+/**************************************************************************/
+/* Local data and data types						  */
+/**************************************************************************/
+/* Used since new relocation types are introduced in this
+   file (DUMMY_RELOC_LITUSE_*).  */
+typedef int extended_bfd_reloc_code_real_type;
 
-struct arc_operand_value *get_ext_suffix (char *s);
+struct arc_fixup
+{
+  expressionS exp;
 
-/* Invocation line includes a switch not recognized by the base assembler.
-   See if it's a processor-specific option.  */
+  extended_bfd_reloc_code_real_type reloc;
 
-int
-md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
-{
-  switch (c)
-    {
-    case OPTION_ARC5:
-      arc_mach_type = bfd_mach_arc_5;
-      break;
-    case OPTION_ARC:
-    case OPTION_ARC6:
-      arc_mach_type = bfd_mach_arc_6;
-      break;
-    case OPTION_ARC7:
-      arc_mach_type = bfd_mach_arc_7;
-      break;
-    case OPTION_ARC8:
-      arc_mach_type = bfd_mach_arc_8;
-      break;
-    case OPTION_EB:
-      byte_order = BIG_ENDIAN;
-      arc_target_format = "elf32-bigarc";
-      break;
-    case OPTION_EL:
-      byte_order = LITTLE_ENDIAN;
-      arc_target_format = "elf32-littlearc";
-      break;
-    default:
-      return 0;
-    }
-  return 1;
-}
+  /* index into arc_operands.  */
+  unsigned int opindex;
 
-void
-md_show_usage (FILE *stream)
-{
-  fprintf (stream, "\
-ARC Options:\n\
-  -marc[5|6|7|8]          select processor variant (default arc%d)\n\
-  -EB                     assemble code for a big endian cpu\n\
-  -EL                     assemble code for a little endian cpu\n", arc_mach_type + 5);
-}
+  /* PC-relative, used by internals fixups.  */
+  unsigned char pcrel;
 
-/* This function is called once, at assembler startup time.  It should
-   set up all the tables, etc. that the MD part of the assembler will need.
-   Opcode selection is deferred until later because we might see a .option
-   command.  */
+  /* TRUE if this fixup is for LIMM operand.  */
+  bfd_boolean islong;
+};
 
-void
-md_begin (void)
+struct arc_insn
 {
-  /* The endianness can be chosen "at the factory".  */
-  target_big_endian = byte_order == BIG_ENDIAN;
+  unsigned int insn;
+  int nfixups;
+  struct arc_fixup fixups[MAX_INSN_FIXUPS];
+  long limm;
+  unsigned char short_insn; /* Boolean value: 1 if current insn is short.  */
+  unsigned char has_limm;   /* Boolean value: 1 if limm field is valid.  */
+};
 
-  if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, arc_mach_type))
-    as_warn (_("could not set architecture and machine"));
+/* Structure to hold any last two instructions.  */
+static struct arc_last_insn
+{
+  /* Saved instruction opcode.  */
+  const struct arc_opcode *opcode;
 
-  /* This call is necessary because we need to initialize `arc_operand_map'
-     which may be needed before we see the first insn.  */
-  arc_opcode_init_tables (arc_get_opcode_mach (arc_mach_type,
-					       target_big_endian));
-}
+  unsigned char has_limm;
 
-/* Initialize the various opcode and operand tables.
-   MACH is one of bfd_mach_arc_xxx.  */
+  unsigned char has_delay_slot;
 
-static void
-init_opcode_tables (int mach)
-{
-  int i;
-  char *last;
+} arc_last_insns[2];
 
-  if ((arc_suffix_hash = hash_new ()) == NULL)
-    as_fatal (_("virtual memory exhausted"));
+/* The cpu for which we are generating code.  */
+static unsigned arc_target = ARC_OPCODE_BASE;
+static const char *arc_target_name = "<all>";
+static unsigned arc_features = 0x00;
 
-  if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, mach))
-    as_warn (_("could not set architecture and machine"));
-
-  /* This initializes a few things in arc-opc.c that we need.
-     This must be called before the various arc_xxx_supported fns.  */
-  arc_opcode_init_tables (arc_get_opcode_mach (mach, target_big_endian));
+/* The default architecture.  */
+static int arc_mach_type = bfd_mach_arc_arcv2;
 
-  /* Only put the first entry of each equivalently named suffix in the
-     table.  */
-  last = "";
-  for (i = 0; i < arc_suffixes_count; i++)
-    {
-      if (strcmp (arc_suffixes[i].name, last) != 0)
-	hash_insert (arc_suffix_hash, arc_suffixes[i].name, (void *) (arc_suffixes + i));
-      last = arc_suffixes[i].name;
-    }
+/* Non-zero if the cpu type has been explicitly specified.  */
+static int mach_type_specified_p = 0;
 
-  /* Since registers don't have a prefix, we put them in the symbol table so
-     they can't be used as symbols.  This also simplifies argument parsing as
-     we can let gas parse registers for us.  The recorded register number is
-     the address of the register's entry in arc_reg_names.
+/* The hash table of instruction opcodes.  */
+static struct hash_control *arc_opcode_hash;
 
-     If the register name is already in the table, then the existing
-     definition is assumed to be from an .ExtCoreRegister pseudo-op.  */
+/* The hash table of register symbols.  */
+static struct hash_control *arc_reg_hash;
 
-  for (i = 0; i < arc_reg_names_count; i++)
+/* A table of CPU names and opcode sets.  */
+static const struct cpu_type
+{
+  const char *name;
+  unsigned flags;
+  int mach;
+  unsigned eflags;
+  unsigned features;
+}
+  cpu_types[] =
     {
-      if (symbol_find (arc_reg_names[i].name))
-	continue;
-      /* Use symbol_create here instead of symbol_new so we don't try to
-	 output registers into the object file's symbol table.  */
-      symbol_table_insert (symbol_create (arc_reg_names[i].name,
-					  reg_section,
-					  (valueT) &arc_reg_names[i],
-					  &zero_address_frag));
-    }
+      { "arc600", ARC_OPCODE_ARC600,  bfd_mach_arc_arc600, E_ARC_MACH_ARC600,  0x00}, /* FIXME! update bfd-in2.h */
+      { "arc700", ARC_OPCODE_ARC700,  bfd_mach_arc_arc700, E_ARC_MACH_ARC700,  0x00},
+      { "arcem",  ARC_OPCODE_ARCv2EM, bfd_mach_arc_arcv2,  EF_ARC_CPU_ARCV2EM, 0x00},
+      { "archs",  ARC_OPCODE_ARCv2HS, bfd_mach_arc_arcv2,  EF_ARC_CPU_ARCV2HS, ARC_CD},
+      { "all",    ARC_OPCODE_BASE,    bfd_mach_arc_arcv2,  0x00, 0x00 },
+      { 0, 0, 0, 0, 0 }
+    };
 
-  /* Tell `.option' it's too late.  */
-  cpu_tables_init_p = 1;
-}
-
-/* Insert an operand value into an instruction.
-   If REG is non-NULL, it is a register number and ignore VAL.  */
-
-static arc_insn
-arc_insert_operand (arc_insn insn,
-		    const struct arc_operand *operand,
-		    int mods,
-		    const struct arc_operand_value *reg,
-		    offsetT val,
-		    char *file,
-		    unsigned int line)
+struct arc_flags
 {
-  if (operand->bits != 32)
-    {
-      long min, max;
-      offsetT test;
+  /* Name of the parsed flag.  */
+  char name[MAX_FLAG_NAME_LENGHT+1];
 
-      if ((operand->flags & ARC_OPERAND_SIGNED) != 0)
-	{
-	  if ((operand->flags & ARC_OPERAND_SIGNOPT) != 0)
-	    max = (1 << operand->bits) - 1;
-	  else
-	    max = (1 << (operand->bits - 1)) - 1;
-	  min = - (1 << (operand->bits - 1));
-	}
-      else
-	{
-	  max = (1 << operand->bits) - 1;
-	  min = 0;
-	}
+  /* The code of the parsed flag.  Valid when is not zero.  */
+  unsigned char code;
+};
 
-      if ((operand->flags & ARC_OPERAND_NEGATIVE) != 0)
-	test = - val;
-      else
-	test = val;
+/* Used by the arc_reloc_op table.  Order is important.  */
+#define O_gotoff  O_md1     /* @gotoff relocation.  */
+#define O_gotpc   O_md2     /* @gotpc relocation.  */
+#define O_plt     O_md3     /* @plt relocation.  */
+#define O_sda     O_md4     /* @sda relocation.  */
+#define O_pcl     O_md5     /* @pcl relocation.  */
+#define O_tlsgd   O_md6     /* @tlsgd relocation.  */
+#define O_tlsie   O_md7     /* @tlsie relocation.  */
+#define O_tpoff9  O_md8     /* @tpoff9 relocation.  */
+#define O_tpoff   O_md9     /* @tpoff relocation.  */
+#define O_dtpoff9 O_md10    /* @dtpoff9 relocation.  */
+#define O_dtpoff  O_md11    /* @dtpoff relocation.  */
+#define O_last    O_dtpoff
+
+/* Used to define a bracket as operand in tokens.  */
+#define O_bracket O_md32
+
+/* Dummy relocation, to be sorted out.  */
+#define DUMMY_RELOC_ARC_ENTRY     (BFD_RELOC_UNUSED + 1)
+
+#define USER_RELOC_P(R) ((R) >= O_gotoff && (R) <= O_last)
+
+/* A table to map the spelling of a relocation operand into an appropriate
+   bfd_reloc_code_real_type type.  The table is assumed to be ordered such
+   that op-O_literal indexes into it.  */
+#define ARC_RELOC_TABLE(op)				\
+  (&arc_reloc_op[ ((!USER_RELOC_P (op))			\
+		   ? (abort (), 0)			\
+		   : (int) (op) - (int) O_gotoff) ])
+
+#define DEF(NAME, RELOC, REQ)				\
+  { #NAME, sizeof (#NAME)-1, O_##NAME, RELOC, REQ}
+
+static const struct arc_reloc_op_tag
+{
+  /* String to lookup.  */
+  const char *name;
+  /* Size of the string.  */
+  size_t length;
+  /* Which operator to use.  */
+  operatorT op;
+  extended_bfd_reloc_code_real_type reloc;
+  /* Allows complex relocation expression like identifier@reloc +
+     const.  */
+  unsigned int complex_expr : 1;
+}
+  arc_reloc_op[] =
+    {
+      DEF (gotoff,  BFD_RELOC_ARC_GOTOFF,	 1),
+      DEF (gotpc,   BFD_RELOC_ARC_GOTPC32,	 0),
+      DEF (plt,	    BFD_RELOC_ARC_PLT32,	 0),
+      DEF (sda,	    DUMMY_RELOC_ARC_ENTRY,	 1),
+      DEF (pcl,	    BFD_RELOC_ARC_PC32,		 1),
+      DEF (tlsgd,   BFD_RELOC_ARC_TLS_GD_GOT,	 0),
+      DEF (tlsie,   BFD_RELOC_ARC_TLS_IE_GOT,	 0),
+      DEF (tpoff9,  BFD_RELOC_ARC_TLS_LE_S9,	 0),
+      DEF (tpoff,   BFD_RELOC_ARC_TLS_LE_32,	 0),
+      DEF (dtpoff9, BFD_RELOC_ARC_TLS_DTPOFF_S9, 0),
+      DEF (dtpoff,  BFD_RELOC_ARC_TLS_DTPOFF,	 0),
+    };
 
-      if (test < (offsetT) min || test > (offsetT) max)
-	as_warn_value_out_of_range (_("operand"), test, (offsetT) min, (offsetT) max, file, line);
-    }
+static const int arc_num_reloc_op
+= sizeof (arc_reloc_op) / sizeof (*arc_reloc_op);
+
+/* Flags to set in the elf header.  */
+static flagword arc_eflag = 0x00;
+
+/* Pre-defined "_GLOBAL_OFFSET_TABLE_".  */
+symbolS * GOT_symbol = 0;
+
+/* Set to one when we assemble instructions.  */
+static int assembling_insn = 0;
+
+/**************************************************************************/
+/* Functions declaration                                                  */
+/**************************************************************************/
+
+static void assemble_tokens (const char *, expressionS *, int,
+			     struct arc_flags *, int);
+static const struct arc_opcode *find_opcode_match (const struct arc_opcode *,
+						   expressionS *, int *,
+						   struct arc_flags *, int, int *);
+static void assemble_insn (const struct arc_opcode *, const expressionS *,
+			   int, const struct arc_flags *, int,
+			   struct arc_insn *);
+static void emit_insn (struct arc_insn *);
+static unsigned insert_operand (unsigned, const struct arc_operand *,
+				offsetT, char *, unsigned);
+static const struct arc_opcode *find_special_case_flag (const char *opname,
+							int *nflgs,
+							struct arc_flags *pflags);
+static const struct arc_opcode *find_special_case (const char *opname,
+						   int *nflgs, struct arc_flags *pflags,
+						   expressionS *, int *);
+static const struct arc_opcode *find_special_case_pseudo (const char *,
+							  int *,
+							  expressionS *,
+							  int *,
+							  struct arc_flags *);
+
+/**************************************************************************/
+/* Functions implementation                                               */
+/**************************************************************************/
+
+/* Like md_number_to_chars but used for limms.  The 4-byte limm value,
+   is encoded as 'middle-endian' for a little-endian target. FIXME!
+   this function is used for regular 4 byte instructions as well.  */
 
-  if (operand->insert)
+static void
+md_number_to_chars_midend (char *buf,
+			   valueT val,
+			   int n)
+{
+  if (n == 4)
     {
-      const char *errmsg;
-
-      errmsg = NULL;
-      insn = (*operand->insert) (insn, operand, mods, reg, (long) val, &errmsg);
-      if (errmsg != (const char *) NULL)
-	as_warn ("%s", errmsg);
+      md_number_to_chars (buf,     (val & 0xffff0000) >> 16, 2);
+      md_number_to_chars (buf + 2, (val & 0xffff), 2);
     }
   else
-    insn |= (((long) val & ((1 << operand->bits) - 1))
-	     << operand->shift);
-
-  return insn;
+    {
+      md_number_to_chars (buf, val, n);
+    }
 }
 
-/* We need to keep a list of fixups.  We can't simply generate them as
-   we go, because that would require us to first create the frag, and
-   that would screw up references to ``.''.  */
+/* Here ends all the ARCompact extension instruction assembling stuff.  */
 
-struct arc_fixup
+static void
+arc_extra_reloc (int r_type)
 {
-  /* index into `arc_operands'  */
-  int opindex;
-  expressionS exp;
-};
+  char *sym_name, c;
+  symbolS *sym, *lab = NULL;
+
+  if (*input_line_pointer == '@')
+    input_line_pointer++;
+  c = get_symbol_name (&sym_name);
+  sym = symbol_find_or_make (sym_name);
+  restore_line_pointer (c);
+  if (c == ',' && r_type == BFD_RELOC_ARC_TLS_GD_LD)
+    {
+      ++input_line_pointer;
+      char *lab_name;
+      c = get_symbol_name (&lab_name);
+      lab = symbol_find_or_make (lab_name);
+      restore_line_pointer (c);
+    }
+  fixS *fixP
+    = fix_new (frag_now,	/* Which frag?  */
+	       frag_now_fix (),	/* Where in that frag?  */
+	       2,		/* size: 1, 2, or 4 usually.  */
+	       sym,		/* X_add_symbol.  */
+	       0,		/* X_add_number.  */
+	       FALSE,		/* TRUE if PC-relative relocation.  */
+	       r_type		/* Relocation type.  */);
+  fixP->fx_subsy = lab;
+}
 
-#define MAX_FIXUPS 5
+static symbolS *
+arc_lcomm_internal (int ignore ATTRIBUTE_UNUSED,
+		    symbolS *symbolP, addressT size)
+{
+  addressT align = 0;
+  SKIP_WHITESPACE ();
 
-#define MAX_SUFFIXES 5
+  if (*input_line_pointer == ',')
+    {
+      align = parse_align (1);
 
-/* Compute the reloc type of an expression.
-   The possibly modified expression is stored in EXPNEW.
+      if (align == (addressT) -1)
+	return NULL;
+    }
+  else
+    {
+      if (size >= 8)
+	align = 3;
+      else if (size >= 4)
+	align = 2;
+      else if (size >= 2)
+	align = 1;
+      else
+	align = 0;
+    }
 
-   This is used to convert the expressions generated by the %-op's into
-   the appropriate operand type.  It is called for both data in instructions
-   (operands) and data outside instructions (variables, debugging info, etc.).
+  bss_alloc (symbolP, size, align);
+  S_CLEAR_EXTERNAL (symbolP);
 
-   Currently supported %-ops:
+  return symbolP;
+}
 
-   %st(symbol): represented as "symbol >> 2"
-                "st" is short for STatus as in the status register (pc)
+static void
+arc_lcomm (int ignore)
+{
+  symbolS *symbolP = s_comm_internal (ignore, arc_lcomm_internal);
 
-   DEFAULT_TYPE is the type to use if no special processing is required.
+  if (symbolP)
+    symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT;
+}
 
-   DATA_P is non-zero for data or limm values, zero for insn operands.
-   Remember that the opcode "insertion fns" cannot be used on data, they're
-   only for inserting operands into insns.  They also can't be used for limm
-   values as the insertion routines don't handle limm values.  When called for
-   insns we return fudged reloc types (real_value - BFD_RELOC_UNUSED).  When
-   called for data or limm values we use real reloc types.  */
+/* Select the cpu we're assembling for.  */
 
-static int
-get_arc_exp_reloc_type (int data_p,
-			int default_type,
-			expressionS *exp,
-			expressionS *expnew)
+static void
+arc_option (int ignore ATTRIBUTE_UNUSED)
 {
-  /* If the expression is "symbol >> 2" we must change it to just "symbol",
-     as fix_new_exp can't handle it.  Similarly for (symbol - symbol) >> 2.
-     That's ok though.  What's really going on here is that we're using
-     ">> 2" as a special syntax for specifying BFD_RELOC_ARC_B26.  */
+  int mach = -1;
+  char c;
+  char *cpu;
 
-  if (exp->X_op == O_right_shift
-      && exp->X_op_symbol != NULL
-      && exp->X_op_symbol->sy_value.X_op == O_constant
-      && exp->X_op_symbol->sy_value.X_add_number == 2
-      && exp->X_add_number == 0)
-    {
-      if (exp->X_add_symbol != NULL
-	  && (exp->X_add_symbol->sy_value.X_op == O_constant
-	      || exp->X_add_symbol->sy_value.X_op == O_symbol))
-	{
-	  *expnew = *exp;
-	  expnew->X_op = O_symbol;
-	  expnew->X_op_symbol = NULL;
-	  return data_p ? BFD_RELOC_ARC_B26 : arc_operand_map['J'];
-	}
-      else if (exp->X_add_symbol != NULL
-	       && exp->X_add_symbol->sy_value.X_op == O_subtract)
-	{
-	  *expnew = exp->X_add_symbol->sy_value;
-	  return data_p ? BFD_RELOC_ARC_B26 : arc_operand_map['J'];
-	}
-    }
+  c = get_symbol_name (&cpu);
+  mach = arc_get_mach (cpu);
+  restore_line_pointer (c);
 
-  *expnew = *exp;
-  return default_type;
-}
-
-static int
-arc_set_ext_seg (void)
-{
-  if (!arcext_section)
+  if (mach == -1)
+    goto bad_cpu;
+
+  if (!mach_type_specified_p)
     {
-      arcext_section = subseg_new (".arcextmap", 0);
-      bfd_set_section_flags (stdoutput, arcext_section,
-			     SEC_READONLY | SEC_HAS_CONTENTS);
+      arc_mach_type = mach;
+      if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, mach))
+	as_fatal ("could not set architecture and machine");
+
+      mach_type_specified_p = 1;
     }
   else
-    subseg_set (arcext_section, 0);
-  return 1;
+    if (arc_mach_type != mach)
+      as_warn ("Command-line value overrides \".cpu\" directive");
+
+  demand_empty_rest_of_line ();
+
+  return;
+
+ bad_cpu:
+  as_bad ("invalid identifier for \".cpu\"");
+  ignore_rest_of_line ();
 }
 
+/* Smartly print an expression.  */
+
 static void
-arc_extoper (int opertype)
+debug_exp (expressionS *t)
 {
-  char *name;
-  char *mode;
-  char c;
-  char *p;
-  int imode = 0;
-  int number;
-  struct arc_ext_operand_value *ext_oper;
-  symbolS *symbolP;
+  const char *name ATTRIBUTE_UNUSED;
+  const char *namemd ATTRIBUTE_UNUSED;
 
-  segT old_sec;
-  int old_subsec;
+  pr_debug ("debug_exp: ");
 
-  c = get_symbol_name (&name);
-  name = xstrdup (name);
-
-  p = name;
-  while (*p)
+  switch (t->X_op)
     {
-      *p = TOLOWER (*p);
-      p++;
+    default:			name = "unknown";		break;
+    case O_illegal:		name = "O_illegal";		break;
+    case O_absent:		name = "O_absent";		break;
+    case O_constant:		name = "O_constant";		break;
+    case O_symbol:		name = "O_symbol";		break;
+    case O_symbol_rva:		name = "O_symbol_rva";		break;
+    case O_register:		name = "O_register";		break;
+    case O_big:			name = "O_big";			break;
+    case O_uminus:		name = "O_uminus";		break;
+    case O_bit_not:		name = "O_bit_not";		break;
+    case O_logical_not:		name = "O_logical_not";		break;
+    case O_multiply:		name = "O_multiply";		break;
+    case O_divide:		name = "O_divide";		break;
+    case O_modulus:		name = "O_modulus";		break;
+    case O_left_shift:		name = "O_left_shift";		break;
+    case O_right_shift:		name = "O_right_shift";		break;
+    case O_bit_inclusive_or:	name = "O_bit_inclusive_or";	break;
+    case O_bit_or_not:		name = "O_bit_or_not";		break;
+    case O_bit_exclusive_or:	name = "O_bit_exclusive_or";	break;
+    case O_bit_and:		name = "O_bit_and";		break;
+    case O_add:			name = "O_add";			break;
+    case O_subtract:		name = "O_subtract";		break;
+    case O_eq:			name = "O_eq";			break;
+    case O_ne:			name = "O_ne";			break;
+    case O_lt:			name = "O_lt";			break;
+    case O_le:			name = "O_le";			break;
+    case O_ge:			name = "O_ge";			break;
+    case O_gt:			name = "O_gt";			break;
+    case O_logical_and:		name = "O_logical_and";		break;
+    case O_logical_or:		name = "O_logical_or";		break;
+    case O_index:		name = "O_index";		break;
+    case O_bracket:		name = "O_bracket";		break;
     }
 
-  /* just after name is now '\0'  */
-  p = input_line_pointer;
-  (void) restore_line_pointer (c);
-  SKIP_WHITESPACE ();
-
-  if (*input_line_pointer != ',')
+  switch (t->X_md)
     {
-      as_bad (_("expected comma after operand name"));
-      ignore_rest_of_line ();
-      free (name);
-      return;
+    default:			namemd = "unknown";		break;
+    case O_gotoff:		namemd = "O_gotoff";		break;
+    case O_gotpc:		namemd = "O_gotpc";		break;
+    case O_plt:			namemd = "O_plt";		break;
+    case O_sda:			namemd = "O_sda";		break;
+    case O_pcl:			namemd = "O_pcl";		break;
+    case O_tlsgd:		namemd = "O_tlsgd";		break;
+    case O_tlsie:		namemd = "O_tlsie";		break;
+    case O_tpoff9:		namemd = "O_tpoff9";		break;
+    case O_tpoff:		namemd = "O_tpoff";		break;
+    case O_dtpoff9:		namemd = "O_dtpoff9";		break;
+    case O_dtpoff:		namemd = "O_dtpoff";		break;
     }
 
-  input_line_pointer++;		/* skip ','  */
-  number = get_absolute_expression ();
+  pr_debug ("%s (%s, %s, %d, %s)", name,
+	    (t->X_add_symbol) ? S_GET_NAME (t->X_add_symbol) : "--",
+	    (t->X_op_symbol) ? S_GET_NAME (t->X_op_symbol) : "--",
+	    (int) t->X_add_number,
+	    (t->X_md) ? namemd : "--");
+  pr_debug ("\n");
+  fflush (stderr);
+}
 
-  if (number < 0)
-    {
-      as_bad (_("negative operand number %d"), number);
-      ignore_rest_of_line ();
-      free (name);
-      return;
-    }
+/* Parse the arguments to an opcode.  */
 
-  if (opertype)
+static int
+tokenize_arguments (char *str,
+		    expressionS *tok,
+		    int ntok)
+{
+  char *old_input_line_pointer;
+  bfd_boolean saw_comma = FALSE;
+  bfd_boolean saw_arg = FALSE;
+  int brk_lvl = 0;
+  int num_args = 0;
+  const char *p;
+  int i;
+  size_t len;
+  const struct arc_reloc_op_tag *r;
+  expressionS tmpE;
+
+  memset (tok, 0, sizeof (*tok) * ntok);
+
+  /* Save and restore input_line_pointer around this function.  */
+  old_input_line_pointer = input_line_pointer;
+  input_line_pointer = str;
+
+  while (*input_line_pointer)
     {
       SKIP_WHITESPACE ();
-
-      if (*input_line_pointer != ',')
+      switch (*input_line_pointer)
 	{
-	  as_bad (_("expected comma after register-number"));
-	  ignore_rest_of_line ();
-	  free (name);
-	  return;
-	}
+	case '\0':
+	  goto fini;
+
+	case ',':
+	  input_line_pointer++;
+	  if (saw_comma || !saw_arg)
+	    goto err;
+	  saw_comma = TRUE;
+	  break;
 
-      input_line_pointer++;		/* skip ','  */
-      mode = input_line_pointer;
+	case '}':
+	case ']':
+	  ++input_line_pointer;
+	  --brk_lvl;
+	  if (!saw_arg)
+	    goto err;
+	  tok->X_op = O_bracket;
+	  ++tok;
+	  ++num_args;
+	  break;
 
-      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
+	case '{':
+	case '[':
+	  input_line_pointer++;
+	  if (brk_lvl)
+	    goto err;
+	  ++brk_lvl;
+	  tok->X_op = O_bracket;
+	  ++tok;
+	  ++num_args;
+	  break;
+
+	case '@':
+	  /* We have labels, function names and relocations, all
+	     starting with @ symbol.  Sort them out.  */
+	  if (saw_arg && !saw_comma)
+	    goto err;
+
+	  /* Parse @label.  */
+	  tok->X_op = O_symbol;
+	  tok->X_md = O_absent;
+	  expression (tok);
+	  if (*input_line_pointer != '@')
+	    goto normalsymbol; /* this is not a relocation.  */
+
+	  /* A relocation opernad has the following form
+	     @identifier@relocation_type.  The identifier is already
+	     in tok!  */
+	  if (tok->X_op != O_symbol)
 	    {
-	      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;
-		}
+	      as_bad (_("No valid label relocation operand"));
+	      goto err;
 	    }
-	}
-      SKIP_WHITESPACE ();
-      if (1 == opertype)
-	{
-	  if (*input_line_pointer != ',')
+
+	  /* Parse @relocation_type.  */
+	  memset (&tmpE, 0, sizeof (tmpE));
+	  tmpE.X_op = O_symbol;
+	  expression (&tmpE);
+
+	  if (tmpE.X_op != O_symbol)
 	    {
-	      as_bad (_("expected comma after register-mode"));
-	      ignore_rest_of_line ();
-	      free (name);
-	      return;
+	      as_bad (_("No relocation operand"));
+	      goto err;
 	    }
+	  p = S_GET_NAME (tmpE.X_add_symbol);
+	  len = strlen (p);
 
-	  input_line_pointer++;		/* skip ','  */
+	  /* Go through known relocation and try to find a match.  */
+	  r = &arc_reloc_op[0];
+	  for (i = arc_num_reloc_op - 1; i >= 0; i--, r++)
+	    if (len == r->length && memcmp (p, r->name, len) == 0)
+	      break;
 
-	  if (!strncmp (input_line_pointer, "cannot_shortcut", 15))
+	  if (i < 0)
 	    {
-	      imode |= arc_get_noshortcut_flag ();
-	      input_line_pointer += 15;
+	      as_bad (_("Unknown relocation operand: @%s"), p);
+	      goto err;
 	    }
-	  else
+	  tok->X_md = r->op;
+	  tok->X_add_number = tmpE.X_add_number;
+	  if (tmpE.X_add_number && !r->complex_expr)
 	    {
-	      if (strncmp (input_line_pointer, "can_shortcut", 12))
-		{
-		  as_bad (_("shortcut designator invalid"));
-		  ignore_rest_of_line ();
-		  free (name);
-		  return;
-		}
-	      else
+	      as_bad (_("Complex relocation operand."));
+	      goto err;
+	    }
+
+	  /* Extra check for TLS: base.  */
+	  if (*input_line_pointer == '@')
+	    {
+	      symbolS *base;
+	      if (tok->X_op_symbol != NULL
+		  || tok->X_op != O_symbol)
 		{
-		  input_line_pointer += 12;
+		  as_bad (_("Unable to parse this reloc"));
+		  goto err;
 		}
+	      input_line_pointer++;
+	      char *sym_name;
+	      char c = get_symbol_name (&sym_name);
+	      base = symbol_find_or_make (sym_name);
+	      tok->X_op = O_subtract;
+	      tok->X_op_symbol = base;
+	      restore_line_pointer (c);
 	    }
+
+	  debug_exp (tok);
+
+	  saw_comma = FALSE;
+	  saw_arg = TRUE;
+	  tok++;
+	  num_args++;
+	  break;
+
+	case '%':
+	  /* Can be a register.  */
+	  ++input_line_pointer;
+	  /* Fall through.  */
+	default:
+
+	  if (saw_arg && !saw_comma)
+	    goto err;
+
+	  tok->X_op = O_absent;
+	  expression (tok);
+
+	normalsymbol:
+	  debug_exp (tok);
+
+	  if (tok->X_op == O_illegal || tok->X_op == O_absent)
+	    goto err;
+
+	  saw_comma = FALSE;
+	  saw_arg = TRUE;
+	  tok++;
+	  num_args++;
+	  break;
 	}
     }
 
-  if ((opertype == 1) && number > 60)
+ fini:
+  if (saw_comma || brk_lvl)
+    goto err;
+  input_line_pointer = old_input_line_pointer;
+
+  return num_args;
+
+ err:
+  if (brk_lvl)
+    as_bad (_("Brackets in operand field incorrect"));
+  else if (saw_comma)
+    as_bad (_("extra comma"));
+  else if (!saw_arg)
+    as_bad (_("missing argument"));
+  else
+    as_bad (_("missing comma or colon"));
+  input_line_pointer = old_input_line_pointer;
+  return -1;
+}
+
+/* Parse the flags to a structure.  */
+
+static int
+tokenize_flags (const char *str,
+		struct arc_flags flags[],
+		int nflg)
+{
+  char *old_input_line_pointer;
+  bfd_boolean saw_flg = FALSE;
+  bfd_boolean saw_dot = FALSE;
+  int num_flags  = 0;
+  size_t flgnamelen;
+
+  memset (flags, 0, sizeof (*flags) * nflg);
+
+  /* Save and restore input_line_pointer around this function.  */
+  old_input_line_pointer = input_line_pointer;
+  input_line_pointer = (char *) str;
+
+  while (*input_line_pointer)
     {
-      as_bad (_("core register value (%d) too large"), number);
-      ignore_rest_of_line ();
-      free (name);
+      switch (*input_line_pointer)
+	{
+	case ' ':
+	case '\0':
+	  goto fini;
+
+	case '.':
+	  input_line_pointer++;
+	  if (saw_dot)
+	    goto err;
+	  saw_dot = TRUE;
+	  saw_flg = FALSE;
+	  break;
+
+	default:
+	  if (saw_flg && !saw_dot)
+	    goto err;
+
+	  if (num_flags >= nflg)
+	    goto err;
+
+	  flgnamelen = strspn (input_line_pointer, "abcdefghilmnopqrstvwxz");
+	  if (flgnamelen > MAX_FLAG_NAME_LENGHT)
+	    goto err;
+
+	  memcpy (flags->name, input_line_pointer, flgnamelen);
+
+	  input_line_pointer += flgnamelen;
+	  flags++;
+	  saw_dot = FALSE;
+	  saw_flg = TRUE;
+	  num_flags++;
+	  break;
+	}
+    }
+
+ fini:
+  input_line_pointer = old_input_line_pointer;
+  return num_flags;
+
+ err:
+  if (saw_dot)
+    as_bad (_("extra dot"));
+  else if (!saw_flg)
+    as_bad (_("unrecognized flag"));
+  else
+    as_bad (_("failed to parse flags"));
+  input_line_pointer = old_input_line_pointer;
+  return -1;
+}
+
+/* The public interface to the instruction assembler.  */
+
+void
+md_assemble (char *str)
+{
+  char *opname;
+  expressionS tok[MAX_INSN_ARGS];
+  int ntok, nflg;
+  size_t opnamelen;
+  struct arc_flags flags[MAX_INSN_FLGS];
+
+  /* Split off the opcode.  */
+  opnamelen = strspn (str, "abcdefghijklmnopqrstuvwxyz_0123468");
+  opname = xmalloc (opnamelen + 1);
+  memcpy (opname, str, opnamelen);
+  opname[opnamelen] = '\0';
+
+  /* Signalize we are assmbling the instructions.  */
+  assembling_insn = 1;
+
+  /* Tokenize the flags.  */
+  if ((nflg = tokenize_flags (str + opnamelen, flags, MAX_INSN_FLGS)) == -1)
+    {
+      as_bad (_("syntax error"));
       return;
     }
 
-  if ((opertype == 0) && number > 31)
+  /* Scan up to the end of the mnemonic which must end in space or end
+     of string.  */
+  str += opnamelen;
+  for (; *str != '\0'; str++)
+    if (*str == ' ')
+      break;
+
+  /* Tokenize the rest of the line.  */
+  if ((ntok = tokenize_arguments (str, tok, MAX_INSN_ARGS)) < 0)
     {
-      as_bad (_("condition code value (%d) too large"), number);
-      ignore_rest_of_line ();
-      free (name);
+      as_bad (_("syntax error"));
       return;
     }
 
-  ext_oper = (struct arc_ext_operand_value *)
-      xmalloc (sizeof (struct arc_ext_operand_value));
+  /* Finish it off.  */
+  assemble_tokens (opname, tok, ntok, flags, nflg);
+  assembling_insn = 0;
+}
+
+/* Callback to insert a register into the hash table.  */
 
-  if (opertype)
+static void
+declare_register (char *name,
+		  int number)
+{
+  const char *err;
+  symbolS *regS = symbol_create (name, reg_section,
+				 number, &zero_address_frag);
+
+  err = hash_insert (arc_reg_hash, S_GET_NAME (regS), (void *) regS);
+  if (err)
+    as_fatal ("Inserting \"%s\" into register table failed: %s",
+	      name, err);
+}
+
+/* Construct symbols for each of the general registers.  */
+
+static void
+declare_register_set (void)
+{
+  int i;
+  for (i = 0; i < 32; ++i)
     {
-      /* If the symbol already exists, point it at the new definition.  */
-      if ((symbolP = symbol_find (name)))
-	{
-	  if (S_GET_SEGMENT (symbolP) == reg_section)
-	    S_SET_VALUE (symbolP, (valueT) &ext_oper->operand);
-	  else
-	    {
-	      as_bad (_("attempt to override symbol: %s"), name);
-	      ignore_rest_of_line ();
-	      free (name);
-	      free (ext_oper);
-	      return;
-	    }
-	}
-      else
+      char name[7];
+
+      sprintf (name, "r%d", i);
+      declare_register (name, i);
+      if ((i & 0x01) == 0)
 	{
-	  /* If its not there, add it.  */
-	  symbol_table_insert (symbol_create (name, reg_section,
-					      (valueT) &ext_oper->operand,
-					      &zero_address_frag));
+	  sprintf (name, "r%dr%d", i, i+1);
+	  declare_register (name, i);
 	}
     }
+}
 
-  ext_oper->operand.name  = name;
-  ext_oper->operand.value = number;
-  ext_oper->operand.type  = arc_operand_type (opertype);
-  ext_oper->operand.flags = imode;
+/* Port-specific assembler initialization.  This function is called
+   once, at assembler startup time.  */
 
-  ext_oper->next = arc_ext_operands;
-  arc_ext_operands = ext_oper;
+void
+md_begin (void)
+{
+  unsigned int i;
 
-  /* OK, now that we know what this operand is, put a description in
-     the arc extension section of the output file.  */
+  /* The endianness can be chosen "at the factory".  */
+  target_big_endian = byte_order == BIG_ENDIAN;
 
-  old_sec    = now_seg;
-  old_subsec = now_subseg;
+  if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, arc_mach_type))
+    as_warn (_("could not set architecture and machine"));
 
-  arc_set_ext_seg ();
+  /* Set elf header flags.  */
+  bfd_set_private_flags (stdoutput, arc_eflag);
 
-  switch (opertype)
+  /* Set up a hash table for the instructions.  */
+  arc_opcode_hash = hash_new ();
+  if (arc_opcode_hash == NULL)
+    as_fatal (_("Virtual memory exhausted"));
+
+  /* Initialize the hash table with the insns.  */
+  for (i = 0; i < arc_num_opcodes;)
     {
-    case 0:
-      p = frag_more (1);
-      *p = 3 + strlen (name) + 1;
-      p = frag_more (1);
-      *p = EXT_COND_CODE;
-      p = frag_more (1);
-      *p = number;
-      p = frag_more (strlen (name) + 1);
-      strcpy (p, name);
-      break;
-    case 1:
-      p = frag_more (1);
-      *p = 3 + strlen (name) + 1;
-      p = frag_more (1);
-      *p = EXT_CORE_REGISTER;
-      p = frag_more (1);
-      *p = number;
-      p = frag_more (strlen (name) + 1);
-      strcpy (p, name);
-      break;
-    case 2:
-      p = frag_more (1);
-      *p = 6 + strlen (name) + 1;
-      p = frag_more (1);
-      *p = EXT_AUX_REGISTER;
-      p = frag_more (1);
-      *p = number >> 24 & 0xff;
-      p = frag_more (1);
-      *p = number >> 16 & 0xff;
-      p = frag_more (1);
-      *p = number >>  8 & 0xff;
-      p = frag_more (1);
-      *p = number       & 0xff;
-      p = frag_more (strlen (name) + 1);
-      strcpy (p, name);
-      break;
-    default:
-      as_bad (_("invalid opertype"));
-      ignore_rest_of_line ();
-      free (name);
-      return;
-      break;
+      const char *name, *retval;
+
+      name = arc_opcodes[i].name;
+      retval = hash_insert (arc_opcode_hash, name, (void *) &arc_opcodes[i]);
+      if (retval)
+	as_fatal (_("internal error: can't hash opcode '%s': %s"),
+		  name, retval);
+
+      while (++i < arc_num_opcodes
+	     && (arc_opcodes[i].name == name
+		 || !strcmp (arc_opcodes[i].name, name)))
+	continue;
     }
 
-  subseg_set (old_sec, old_subsec);
+  /* Register declaration.  */
+  arc_reg_hash = hash_new ();
+  if (arc_reg_hash == NULL)
+    as_fatal (_("Virtual memory exhausted"));
 
-  /* Enter all registers into the symbol table.  */
+  declare_register_set ();
+  declare_register ("gp", 26);
+  declare_register ("fp", 27);
+  declare_register ("sp", 28);
+  declare_register ("ilink", 29);
+  declare_register ("ilink1", 29);
+  declare_register ("ilink2", 30);
+  declare_register ("blink", 31);
 
-  demand_empty_rest_of_line ();
+  declare_register ("mlo", 57);
+  declare_register ("mmid", 58);
+  declare_register ("mhi", 59);
+
+  declare_register ("acc1", 56);
+  declare_register ("acc2", 57);
+
+  declare_register ("lp_count", 60);
+  declare_register ("pcl", 63);
+
+  /* Initialize the last instructions.  */
+  memset (&arc_last_insns[0], 0, sizeof (arc_last_insns));
 }
 
-static void
-arc_extinst (int ignore ATTRIBUTE_UNUSED)
+/* Write a value out to the object file, using the appropriate
+   endianness.  */
+
+void
+md_number_to_chars (char *buf,
+		    valueT val,
+		    int n)
 {
-  char syntax[129];
-  char *name;
-  char *p;
-  char c;
-  int suffixcode = -1;
-  int opcode, subopcode;
-  int i;
-  int s_class = 0;
-  int name_len;
-  struct arc_opcode *ext_op;
+  if (target_big_endian)
+    number_to_chars_bigendian (buf, val, n);
+  else
+    number_to_chars_littleendian (buf, val, n);
+}
 
-  segT old_sec;
-  int old_subsec;
+/* Round up a section size to the appropriate boundary.  */
 
-  c = get_symbol_name (&name);
-  name = xstrdup (name);
-  strcpy (syntax, name);
-  name_len = strlen (name);
+valueT
+md_section_align (segT segment,
+		  valueT size)
+{
+  int align = bfd_get_section_alignment (stdoutput, segment);
 
-  /* just after name is now '\0'  */
-  p = input_line_pointer;
-  (void) restore_line_pointer (c);
+  return ((size + (1 << align) - 1) & (-1 << align));
+}
 
-  SKIP_WHITESPACE ();
+/* The location from which a PC relative jump should be calculated,
+   given a PC relative reloc.  */
 
-  if (*input_line_pointer != ',')
-    {
-      as_bad (_("expected comma after operand name"));
-      ignore_rest_of_line ();
-      return;
-    }
+long
+md_pcrel_from_section (fixS *fixP,
+		       segT sec)
+{
+  offsetT base = fixP->fx_where + fixP->fx_frag->fr_address;
 
-  input_line_pointer++;		/* skip ','  */
-  opcode = get_absolute_expression ();
+  pr_debug ("pcrel_from_section, fx_offset = %d\n", (int) fixP->fx_offset);
 
-  SKIP_WHITESPACE ();
+  if (fixP->fx_addsy != (symbolS *) NULL
+      && (!S_IS_DEFINED (fixP->fx_addsy)
+	  || S_GET_SEGMENT (fixP->fx_addsy) != sec))
+    {
+      pr_debug ("Unknown pcrel symbol: %s\n", S_GET_NAME (fixP->fx_addsy));
 
-  if (*input_line_pointer != ',')
+      /* The symbol is undefined (or is defined but not in this section).
+	 Let the linker figure it out.  */
+      return 0;
+    }
+
+  if ((int) fixP->fx_r_type < 0)
     {
-      as_bad (_("expected comma after opcode"));
-      ignore_rest_of_line ();
-      return;
+      /* these are the "internal" relocations.  Align them to
+	 32 bit boundary (PCL), for the moment.  */
+      base &= ~3;
     }
+  else
+    {
+      switch (fixP->fx_r_type)
+	{
+	case BFD_RELOC_ARC_PC32:
+	  /* The hardware calculates relative to the start of the
+	     insn, but this relocation is relative to location of the
+	     LIMM, compensate.  TIP: the base always needs to be
+	     substracted by 4 as we do not support this type of PCrel
+	     relocation for short instructions.  */
+	  base -= fixP->fx_where - fixP->fx_dot_value;
+	  gas_assert ((fixP->fx_where - fixP->fx_dot_value) == 4);
+	  /* Fall through.  */
+	case BFD_RELOC_ARC_PLT32:
+	case BFD_RELOC_ARC_S25H_PCREL_PLT:
+	case BFD_RELOC_ARC_S21H_PCREL_PLT:
+	case BFD_RELOC_ARC_S25W_PCREL_PLT:
+	case BFD_RELOC_ARC_S21W_PCREL_PLT:
+
+	case BFD_RELOC_ARC_S21H_PCREL:
+	case BFD_RELOC_ARC_S25H_PCREL:
+	case BFD_RELOC_ARC_S13_PCREL:
+	case BFD_RELOC_ARC_S21W_PCREL:
+	case BFD_RELOC_ARC_S25W_PCREL:
+	  base &= ~3;
+	  break;
+	default:
+	  as_bad_where (fixP->fx_file, fixP->fx_line,
+			_("unhandled reloc %s in md_pcrel_from_section"),
+		  bfd_get_reloc_code_name (fixP->fx_r_type));
+	  break;
+	}
+    }
+
+  pr_debug ("pcrel from %x + %lx = %x, symbol: %s (%x)\n",
+	    fixP->fx_frag->fr_address, fixP->fx_where, base,
+	    fixP->fx_addsy ? S_GET_NAME (fixP->fx_addsy) : "(null)",
+	    fixP->fx_addsy ? S_GET_VALUE (fixP->fx_addsy) : 0);
+
+  return base;
+}
 
-  input_line_pointer++;		/* skip ','  */
-  subopcode = get_absolute_expression ();
+/* Given a BFD relocation find the coresponding operand.  */
 
-  if (subopcode < 0)
+static const struct arc_operand *
+find_operand_for_reloc (extended_bfd_reloc_code_real_type reloc)
+{
+  unsigned i;
+
+  for (i = 0; i < arc_num_operands; i++)
+    if (arc_operands[i].default_reloc == reloc)
+      return  &arc_operands[i];
+  return NULL;
+}
+
+/* Apply a fixup to the object code.  At this point all symbol values
+   should be fully resolved, and we attempt to completely resolve the
+   reloc.  If we can not do that, we determine the correct reloc code
+   and put it back in the fixup.  To indicate that a fixup has been
+   eliminated, set fixP->fx_done.  */
+
+void
+md_apply_fix (fixS *fixP,
+	      valueT *valP,
+	      segT seg)
+{
+  char * const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
+  valueT value = *valP;
+  unsigned insn = 0;
+  symbolS *fx_addsy, *fx_subsy;
+  offsetT fx_offset;
+  segT add_symbol_segment = absolute_section;
+  segT sub_symbol_segment = absolute_section;
+  const struct arc_operand *operand = NULL;
+  extended_bfd_reloc_code_real_type reloc;
+
+  pr_debug ("%s:%u: apply_fix: r_type=%d (%s) value=0x%lX offset=0x%lX\n",
+	    fixP->fx_file, fixP->fx_line, fixP->fx_r_type,
+	    ((int) fixP->fx_r_type < 0) ? "Internal":
+	    bfd_get_reloc_code_name (fixP->fx_r_type), value,
+	    fixP->fx_offset);
+
+  fx_addsy = fixP->fx_addsy;
+  fx_subsy = fixP->fx_subsy;
+  fx_offset = 0;
+
+  if (fx_addsy)
     {
-      as_bad (_("negative subopcode %d"), subopcode);
-      ignore_rest_of_line ();
-      return;
+      add_symbol_segment = S_GET_SEGMENT (fx_addsy);
     }
 
-  if (subopcode)
+  if (fx_subsy
+      && fixP->fx_r_type != BFD_RELOC_ARC_TLS_DTPOFF
+      && fixP->fx_r_type != BFD_RELOC_ARC_TLS_DTPOFF_S9
+      && fixP->fx_r_type != BFD_RELOC_ARC_TLS_GD_LD)
     {
-      if (3 != opcode)
+      resolve_symbol_value (fx_subsy);
+      sub_symbol_segment = S_GET_SEGMENT (fx_subsy);
+
+      if (sub_symbol_segment == absolute_section)
 	{
-	  as_bad (_("subcode value found when opcode not equal 0x03"));
-	  ignore_rest_of_line ();
-	  return;
+	  /* The symbol is really a constant.  */
+	  fx_offset -= S_GET_VALUE (fx_subsy);
+	  fx_subsy = NULL;
 	}
       else
 	{
-	  if (subopcode < 0x09 || subopcode == 0x3f)
-	    {
-	      as_bad (_("invalid subopcode %d"), subopcode);
-	      ignore_rest_of_line ();
-	      return;
-	    }
+	  as_bad_where (fixP->fx_file, fixP->fx_line,
+			_("can't resolve `%s' {%s section} - `%s' {%s section}"),
+			fx_addsy ? S_GET_NAME (fx_addsy) : "0",
+			segment_name (add_symbol_segment),
+			S_GET_NAME (fx_subsy),
+			segment_name (sub_symbol_segment));
+	  return;
 	}
     }
 
-  SKIP_WHITESPACE ();
-
-  if (*input_line_pointer != ',')
+  if (fx_addsy
+      && !S_IS_WEAK (fx_addsy))
     {
-      as_bad (_("expected comma after subopcode"));
-      ignore_rest_of_line ();
-      return;
+      if (add_symbol_segment == seg
+	  && fixP->fx_pcrel)
+	{
+	  value += S_GET_VALUE (fx_addsy);
+	  value -= md_pcrel_from_section (fixP, seg);
+	  fx_addsy = NULL;
+	  fixP->fx_pcrel = FALSE;
+	}
+      else if (add_symbol_segment == absolute_section)
+	{
+	  value = fixP->fx_offset;
+	  fx_offset += S_GET_VALUE (fixP->fx_addsy);
+	  fx_addsy = NULL;
+	  fixP->fx_pcrel = FALSE;
+	}
     }
 
-  input_line_pointer++;		/* skip ','  */
+  if (!fx_addsy)
+    fixP->fx_done = TRUE;
 
-  for (i = 0; i < (int) MAXSUFFIXCLASS; i++)
+  if (fixP->fx_pcrel)
     {
-      if (!strncmp (suffixclass[i].name,input_line_pointer, suffixclass[i].len))
+      if (fx_addsy
+	  && ((S_IS_DEFINED (fx_addsy)
+	       && S_GET_SEGMENT (fx_addsy) != seg)
+	      || S_IS_WEAK (fx_addsy)))
+	value += md_pcrel_from_section (fixP, seg);
+
+      switch (fixP->fx_r_type)
 	{
-	  suffixcode = i;
-	  input_line_pointer += suffixclass[i].len;
+	case BFD_RELOC_ARC_32_ME:
+	  /* This is a pc-relative value in a LIMM.  Adjust it to the
+	     address of the instruction not to the address of the
+	     LIMM.  Note: it is not anylonger valid this afirmation as
+	     the linker consider ARC_PC32 a fixup to entire 64 bit
+	     insn.  */
+	  fixP->fx_offset += fixP->fx_frag->fr_address;
+	  /* Fall through.  */
+	case BFD_RELOC_32:
+	  fixP->fx_r_type = BFD_RELOC_ARC_PC32;
+	  /* Fall through.  */
+	case BFD_RELOC_ARC_PC32:
+	  //fixP->fx_offset += fixP->fx_where - fixP->fx_dot_value;
+	  break;
+	default:
+	  if ((int) fixP->fx_r_type < 0)
+	    as_fatal (_("PC relative relocation not allowed for (internal) type %d"),
+		      fixP->fx_r_type);
 	  break;
 	}
     }
 
-  if (-1 == suffixcode)
+  pr_debug ("%s:%u: apply_fix: r_type=%d (%s) value=0x%lX offset=0x%lX\n",
+	    fixP->fx_file, fixP->fx_line, fixP->fx_r_type,
+	    ((int) fixP->fx_r_type < 0) ? "Internal":
+	    bfd_get_reloc_code_name (fixP->fx_r_type), value,
+	    fixP->fx_offset);
+
+  if (!fixP->fx_done)
+    return;
+
+  /* Addjust the value if we have a constant.  */
+  value += fx_offset;
+
+  /* For hosts with longs bigger than 32-bits make sure that the top
+     bits of a 32-bit negative value read in by the parser are set,
+     so that the correct comparisons are made.  */
+  if (value & 0x80000000)
+    value |= (-1L << 31);
+
+  reloc = fixP->fx_r_type;
+  switch (reloc)
     {
-      as_bad (_("invalid suffix class"));
-      ignore_rest_of_line ();
+    case BFD_RELOC_8:
+    case BFD_RELOC_16:
+    case BFD_RELOC_24:
+    case BFD_RELOC_32:
+    case BFD_RELOC_64:
+      md_number_to_chars (fixpos, value, fixP->fx_size);
       return;
-    }
 
-  SKIP_WHITESPACE ();
+    case BFD_RELOC_ARC_GOTPC32:
+      /* I cannot fix an GOTPC relocation because I need to relax it
+	 from ld rx,[pcl,@sym@gotpc] to add rx,pcl,@sym@gotpc.  */
+      as_bad (_("Unsupported operation on reloc"));
+      return;
+    case BFD_RELOC_ARC_GOTOFF:
+    case BFD_RELOC_ARC_32_ME:
+    case BFD_RELOC_ARC_PC32:
+      md_number_to_chars_midend (fixpos, value, fixP->fx_size);
+      return;
 
-  if (*input_line_pointer != ',')
-    {
-      as_bad (_("expected comma after suffix class"));
-      ignore_rest_of_line ();
+    case BFD_RELOC_ARC_PLT32:
+      md_number_to_chars_midend (fixpos, value, fixP->fx_size);
       return;
-    }
 
-  input_line_pointer++;		/* skip ','  */
+    case BFD_RELOC_ARC_S25H_PCREL_PLT:
+      reloc = BFD_RELOC_ARC_S25W_PCREL;
+      goto solve_plt;
+
+    case BFD_RELOC_ARC_S21H_PCREL_PLT:
+      reloc = BFD_RELOC_ARC_S21H_PCREL;
+      goto solve_plt;
+
+    case BFD_RELOC_ARC_S25W_PCREL_PLT:
+      reloc = BFD_RELOC_ARC_S25W_PCREL;
+      goto solve_plt;
+
+    case BFD_RELOC_ARC_S21W_PCREL_PLT:
+      reloc = BFD_RELOC_ARC_S21W_PCREL;
+
+    case BFD_RELOC_ARC_S25W_PCREL:
+    case BFD_RELOC_ARC_S21W_PCREL:
+    case BFD_RELOC_ARC_S21H_PCREL:
+    case BFD_RELOC_ARC_S25H_PCREL:
+    case BFD_RELOC_ARC_S13_PCREL:
+    solve_plt:
+      operand = find_operand_for_reloc (reloc);
+      gas_assert (operand);
+      break;
 
-  for (i = 0; i < (int) MAXSYNTAXCLASS; i++)
-    {
-      if (!strncmp (syntaxclass[i].name,input_line_pointer, syntaxclass[i].len))
+    case BFD_RELOC_ARC_TLS_DTPOFF:
+    case BFD_RELOC_ARC_TLS_LE_32:
+      if (fixP->fx_done)
 	{
-	  s_class = syntaxclass[i].s_class;
-	  input_line_pointer += syntaxclass[i].len;
-	  break;
+	  gas_assert (!fixP->fx_addsy);
+	  gas_assert (!fixP->fx_subsy);
+	  md_number_to_chars_midend (fixpos, value, fixP->fx_size);
+	  return;
 	}
-    }
+      else
+	{
+	  value = fixP->fx_offset;
+	  fixP->fx_offset = 0;
+	}
+      /* Fall through.  */
+    case BFD_RELOC_ARC_TLS_GD_GOT:
+    case BFD_RELOC_ARC_TLS_IE_GOT:
+      S_SET_THREAD_LOCAL (fixP->fx_addsy);
+      md_number_to_chars_midend (fixpos, value, fixP->fx_size);
+      return;
 
-  if (0 == (SYNTAX_VALID & s_class))
-    {
-      as_bad (_("invalid syntax class"));
-      ignore_rest_of_line ();
+    case BFD_RELOC_ARC_TLS_GD_LD:
+      gas_assert (!fixP->fx_offset);
+      if (fixP->fx_subsy)
+	fixP->fx_offset
+	  = (S_GET_VALUE (fixP->fx_subsy)
+	     - fixP->fx_frag->fr_address- fixP->fx_where);
+      fixP->fx_subsy = NULL;
+      /* Fall through.  */
+    case BFD_RELOC_ARC_TLS_GD_CALL:
+      /* These two relocs are there just to allow ld to change the tls
+	 model for this symbol, by patching the code.  */
+      /* Fall through.  */
+      /* The offset - and scale, if any - will be installed by the
+	 linker.  */
+      gas_assert (!fixP->fx_done);
+      S_SET_THREAD_LOCAL (fixP->fx_addsy);
       return;
+
+    case BFD_RELOC_ARC_TLS_LE_S9:
+    case BFD_RELOC_ARC_TLS_DTPOFF_S9:
+      as_bad (_("TLS_*_S9 relocs are not supported yet"));
+      break;
+
+    default:
+      {
+	if ((int) fixP->fx_r_type >= 0)
+	  as_fatal (_("unhandled relocation type %s"),
+		    bfd_get_reloc_code_name (fixP->fx_r_type));
+
+	/* The rest of these fixups needs to be completely resolved as
+	   constants.  */
+	if (fixP->fx_addsy != 0
+	    && S_GET_SEGMENT (fixP->fx_addsy) != absolute_section)
+	  as_bad_where (fixP->fx_file, fixP->fx_line,
+			_("non-absolute expression in constant field"));
+
+	gas_assert (-(int) fixP->fx_r_type < (int) arc_num_operands);
+	operand = &arc_operands[-(int) fixP->fx_r_type];
+	break;
+      }
     }
 
-  if ((0x3 == opcode) & (s_class & SYNTAX_3OP))
+  if (target_big_endian)
     {
-      as_bad (_("opcode 0x3 and SYNTAX_3OP invalid"));
-      ignore_rest_of_line ();
-      return;
+      switch (fixP->fx_size)
+	{
+	case 4:
+	  insn = bfd_getb32 (fixpos);
+	  break;
+	case 2:
+	  insn = bfd_getb16 (fixpos);
+	  break;
+	default:
+	  as_bad_where (fixP->fx_file, fixP->fx_line,
+			_("unknown fixup size"));
+	}
     }
-
-  switch (suffixcode)
+  else
     {
-    case 0:
-      strcat (syntax, "%.q%.f ");
-      break;
-    case 1:
-      strcat (syntax, "%.f ");
-      break;
-    case 2:
-      strcat (syntax, "%.q ");
-      break;
-    case 3:
-      strcat (syntax, " ");
-      break;
-    default:
-      as_bad (_("unknown suffix class"));
-      ignore_rest_of_line ();
-      return;
-      break;
-    };
+      insn = 0;
+      switch (fixP->fx_size)
+	{
+	case 4:
+	  insn = bfd_getl16 (fixpos) << 16 | bfd_getl16 (fixpos + 2);
+	  break;
+	case 2:
+	  insn = bfd_getl16 (fixpos);
+	  break;
+	default:
+	  as_bad_where (fixP->fx_file, fixP->fx_line,
+			_("unknown fixup size"));
+	}
+    }
 
-  strcat (syntax, ((opcode == 0x3) ? "%a,%b" : ((s_class & SYNTAX_3OP) ? "%a,%b,%c" : "%b,%c")));
-  if (suffixcode < 2)
-    strcat (syntax, "%F");
-  strcat (syntax, "%S%L");
-
-  ext_op = (struct arc_opcode *) xmalloc (sizeof (struct arc_opcode));
-  ext_op->syntax = xstrdup (syntax);
-
-  ext_op->mask  = I (-1) | ((0x3 == opcode) ? C (-1) : 0);
-  ext_op->value = I (opcode) | ((0x3 == opcode) ? C (subopcode) : 0);
-  ext_op->flags = s_class;
-  ext_op->next_asm = arc_ext_opcodes;
-  ext_op->next_dis = arc_ext_opcodes;
-  arc_ext_opcodes = ext_op;
-
-  /* OK, now that we know what this inst is, put a description in the
-     arc extension section of the output file.  */
-
-  old_sec    = now_seg;
-  old_subsec = now_subseg;
-
-  arc_set_ext_seg ();
-
-  p = frag_more (1);
-  *p = 5 + name_len + 1;
-  p = frag_more (1);
-  *p = EXT_INSTRUCTION;
-  p = frag_more (1);
-  *p = opcode;
-  p = frag_more (1);
-  *p = subopcode;
-  p = frag_more (1);
-  *p = (s_class & (OP1_MUST_BE_IMM | OP1_IMM_IMPLIED) ? IGNORE_FIRST_OPD : 0);
-  p = frag_more (name_len);
-  strncpy (p, syntax, name_len);
-  p = frag_more (1);
-  *p = '\0';
-
-  subseg_set (old_sec, old_subsec);
+  insn = insert_operand (insn, operand, (offsetT) value,
+			 fixP->fx_file, fixP->fx_line);
 
-  demand_empty_rest_of_line ();
+  md_number_to_chars_midend (fixpos, insn, fixP->fx_size);
 }
 
-static void
-arc_common (int localScope)
+/* Prepare machine-dependent frags for relaxation.
+
+   Called just before relaxation starts.  Any symbol that is now undefined
+   will not become defined.
+
+   Return the correct fr_subtype in the frag.
+
+   Return the initial "guess for fr_var" to caller.  The guess for fr_var
+   is *actually* the growth beyond fr_fix.  Whatever we do to grow fr_fix
+   or fr_var contributes to our returned value.
+
+   Although it may not be explicit in the frag, pretend
+   fr_var starts with a value.  */
+
+int
+md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED,
+			       segT segment ATTRIBUTE_UNUSED)
 {
-  char *name;
-  char c;
-  char *p;
-  int align, size;
-  symbolS *symbolP;
-
-  c = get_symbol_name (&name);
-  /* just after name is now '\0'  */
-  p = input_line_pointer;
-  (void) restore_line_pointer (c);
-  SKIP_WHITESPACE ();
+  int growth = 4;
 
-  if (*input_line_pointer != ',')
-    {
-      as_bad (_("expected comma after symbol name"));
-      ignore_rest_of_line ();
-      return;
-    }
+  fragP->fr_var = 4;
+  pr_debug ("%s:%d: md_estimate_size_before_relax: %d\n",
+	   fragP->fr_file, fragP->fr_line, growth);
 
-  input_line_pointer++;		/* skip ','  */
-  size = get_absolute_expression ();
+  as_fatal (_("md_estimate_size_before_relax\n"));
+  return growth;
+}
 
-  if (size < 0)
-    {
-      as_bad (_("negative symbol length"));
-      ignore_rest_of_line ();
-      return;
-    }
+/* Translate internal representation of relocation info to BFD target
+   format.  */
 
-  *p = 0;
-  symbolP = symbol_find_or_make (name);
-  *p = c;
+arelent *
+tc_gen_reloc (asection *section ATTRIBUTE_UNUSED,
+	      fixS *fixP)
+{
+  arelent *reloc;
+  bfd_reloc_code_real_type code;
 
-  if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP))
-    {
-      as_bad (_("ignoring attempt to re-define symbol"));
-      ignore_rest_of_line ();
-      return;
-    }
-  if (((int) S_GET_VALUE (symbolP) != 0) \
-      && ((int) S_GET_VALUE (symbolP) != size))
+  reloc = (arelent *) xmalloc (sizeof (* reloc));
+  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
+  reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
+
+  /* Make sure none of our internal relocations make it this far.
+     They'd better have been fully resolved by this point.  */
+  gas_assert ((int) fixP->fx_r_type > 0);
+
+  code = fixP->fx_r_type;
+
+  /* if we have something like add gp, pcl,
+     _GLOBAL_OFFSET_TABLE_@gotpc.  */
+  if (code == BFD_RELOC_ARC_GOTPC32
+      && GOT_symbol
+      && fixP->fx_addsy == GOT_symbol)
+    code = BFD_RELOC_ARC_GOTPC;
+
+  reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
+  if (reloc->howto == NULL)
     {
-      as_warn (_("length of symbol \"%s\" already %ld, ignoring %d"),
-	       S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size);
+      as_bad_where (fixP->fx_file, fixP->fx_line,
+		    _("cannot represent `%s' relocation in object file"),
+		    bfd_get_reloc_code_name (code));
+      return NULL;
     }
-  gas_assert (symbolP->sy_frag == &zero_address_frag);
 
-  /* Now parse the alignment field.  This field is optional for
-     local and global symbols. Default alignment is zero.  */
-  if (*input_line_pointer == ',')
+  if (!fixP->fx_pcrel != !reloc->howto->pc_relative)
+    as_fatal (_("internal error? cannot generate `%s' relocation"),
+	      bfd_get_reloc_code_name (code));
+
+  gas_assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
+
+  if (code == BFD_RELOC_ARC_TLS_DTPOFF
+      || code ==  BFD_RELOC_ARC_TLS_DTPOFF_S9)
     {
-      input_line_pointer++;
-      align = get_absolute_expression ();
-      if (align < 0)
+      asymbol *sym
+	= fixP->fx_subsy ? symbol_get_bfdsym (fixP->fx_subsy) : NULL;
+      /* We just want to store a 24 bit index, but we have to wait
+	 till after write_contents has been called via
+	 bfd_map_over_sections before we can get the index from
+	 _bfd_elf_symbol_from_bfd_symbol.  Thus, the write_relocs
+	 function is elf32-arc.c has to pick up the slack.
+	 Unfortunately, this leads to problems with hosts that have
+	 pointers wider than long (bfd_vma).  There would be various
+	 ways to handle this, all error-prone :-(  */
+      reloc->addend = (bfd_vma) sym;
+      if ((asymbol *) reloc->addend != sym)
 	{
-	  align = 0;
-	  as_warn (_("assuming symbol alignment of zero"));
+	  as_bad ("Can't store pointer\n");
+	  return NULL;
 	}
     }
   else
-    align = 0;
+    reloc->addend = fixP->fx_offset;
 
-  if (localScope != 0)
-    {
-      segT old_sec;
-      int old_subsec;
-      char *pfrag;
-
-      old_sec    = now_seg;
-      old_subsec = now_subseg;
-      record_alignment (bss_section, align);
-      subseg_set (bss_section, 0);  /* ??? subseg_set (bss_section, 1); ???  */
-
-      if (align)
-	/* Do alignment.  */
-	frag_align (align, 0, 0);
-
-      /* Detach from old frag.  */
-      if (S_GET_SEGMENT (symbolP) == bss_section)
-	symbolP->sy_frag->fr_symbol = NULL;
-
-      symbolP->sy_frag = frag_now;
-      pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP,
-			(offsetT) size, (char *) 0);
-      *pfrag = 0;
-
-      S_SET_SIZE       (symbolP, size);
-      S_SET_SEGMENT    (symbolP, bss_section);
-      S_CLEAR_EXTERNAL (symbolP);
-      symbol_get_obj (symbolP)->local = 1;
-      subseg_set (old_sec, old_subsec);
-    }
-  else
-    {
-      S_SET_VALUE    (symbolP, (valueT) size);
-      S_SET_ALIGN    (symbolP, align);
-      S_SET_EXTERNAL (symbolP);
-      S_SET_SEGMENT  (symbolP, bfd_com_section_ptr);
-    }
+  return reloc;
+}
 
-  symbolP->bsym->flags |= BSF_OBJECT;
+/* Perform post-processing of machine-dependent frags after relaxation.
+   Called after relaxation is finished.
+   In:	Address of frag.
+   fr_type == rs_machine_dependent.
+   fr_subtype is what the address relaxed to.
 
-  demand_empty_rest_of_line ();
-}
-
-/* Select the cpu we're assembling for.  */
+   Out: Any fixS:s and constants are set up.  */
 
-static void
-arc_option (int ignore ATTRIBUTE_UNUSED)
+void
+md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
+		 segT segment ATTRIBUTE_UNUSED,
+		 fragS *fragP ATTRIBUTE_UNUSED)
 {
-  extern int arc_get_mach (char *);
-  int mach;
-  char c;
-  char *cpu;
+  pr_debug ("%s:%d: md_convert_frag, subtype: %d, fix: %d, var: %d\n",
+	    fragP->fr_file, fragP->fr_line,
+	    fragP->fr_subtype, fragP->fr_fix, fragP->fr_var);
+  abort ();
+}
 
-  c = get_symbol_name (&cpu);
-  mach = arc_get_mach (cpu);
-  (void) restore_line_pointer (c);
+/* We have no need to default values of symbols.  We could catch
+   register names here, but that is handled by inserting them all in
+   the symbol table to begin with.  */
 
-  /* If an instruction has already been seen, it's too late.  */
-  if (cpu_tables_init_p)
+symbolS *
+md_undefined_symbol (char *name)
+{
+  /* The arc abi demands that a GOT[0] should be referencible as
+     [pc+_DYNAMIC@gotpc].  Hence we convert a _DYNAMIC@gotpc to a
+     GOTPC reference to _GLOBAL_OFFSET_TABLE_.  */
+  if (((*name == '_')
+       && (*(name+1) == 'G')
+       && (strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0))
+      || ((*name == '_')
+	  && (*(name+1) == 'D')
+	  && (strcmp (name, DYNAMIC_STRUCT_NAME) == 0)))
     {
-      as_bad (_("\".option\" directive must appear before any instructions"));
-      ignore_rest_of_line ();
-      return;
-    }
-
-  if (mach == -1)
-    goto bad_cpu;
+      if (!GOT_symbol)
+	{
+	  if (symbol_find (name))
+	    as_bad ("GOT already in symbol table");
 
-  if (mach_type_specified_p && mach != arc_mach_type)
-    {
-      as_bad (_("\".option\" directive conflicts with initial definition"));
-      ignore_rest_of_line ();
-      return;
+	  GOT_symbol = symbol_new (GLOBAL_OFFSET_TABLE_NAME, undefined_section,
+				   (valueT) 0, &zero_address_frag);
+	};
+      return GOT_symbol;
     }
-  else
-    {
-      /* The cpu may have been selected on the command line.  */
-      if (mach != arc_mach_type)
-	as_warn (_("\".option\" directive overrides command-line (default) value"));
-      arc_mach_type = mach;
-      if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, mach))
-	as_fatal (_("could not set architecture and machine"));
-      mach_type_specified_p = 1;
-    }
-  demand_empty_rest_of_line ();
-  return;
-
- bad_cpu:
-  as_bad (_("invalid identifier for \".option\""));
-  ignore_rest_of_line ();
+  return NULL;
 }
-
+
+/* Turn a string in input_line_pointer into a floating point constant
+   of type type, and store the appropriate bytes in *litP.  The number
+   of LITTLENUMS emitted is stored in *sizeP.  An error message is
+   returned, or NULL on OK.  */
+
 char *
-md_atof (int type, char *litP, int *sizeP)
+md_atof (int type,
+	 char *litP,
+	 int *sizeP)
 {
-  return ieee_md_atof (type, litP, sizeP, TRUE);
+  return ieee_md_atof (type, litP, sizeP, target_big_endian);
 }
 
-/* Write a value out to the object file, using the appropriate
-   endianness.  */
+/* Called for any expression that can not be recognized.  When the
+   function is called, `input_line_pointer' will point to the start of
+   the expression.  */
 
 void
-md_number_to_chars (char *buf, valueT val, int n)
+md_operand (expressionS *expressionP ATTRIBUTE_UNUSED)
 {
-  if (target_big_endian)
-    number_to_chars_bigendian (buf, val, n);
-  else
-    number_to_chars_littleendian (buf, val, n);
+  char *p = input_line_pointer;
+  if (*p == '@')
+    {
+      input_line_pointer++;
+      expressionP->X_op = O_symbol;
+      expression (expressionP);
+    }
 }
 
-/* Round up a section size to the appropriate boundary.  */
+/* This function is called from the function 'expression', it attempts
+   to parse special names (in our case register names).  It fills in
+   the expression with the identified register.  It returns 1 if it is
+   a register and 0 otherwise.  */
 
-valueT
-md_section_align (segT segment, valueT size)
+int
+arc_parse_name (const char *name,
+		struct expressionS *e)
 {
-  int align = bfd_get_section_alignment (stdoutput, segment);
+  struct symbol *sym;
 
-  return ((size + (1 << align) - 1) & (-1 << align));
+  if (!assembling_insn)
+    return 0;
+
+  /* Handle only registers.  */
+  if (e->X_op != O_absent)
+    return 0;
+
+  sym = hash_find (arc_reg_hash, name);
+  if (sym)
+    {
+      e->X_op = O_register;
+      e->X_add_number = S_GET_VALUE (sym);
+      return 1;
+    }
+  return 0;
 }
 
-/* We don't have any form of relaxing.  */
+/* md_parse_option
+   Invocation line includes a switch not recognized by the base assembler.
+   See if it's a processor-specific option.
+
+   New options (supported) are:
+
+   -mcpu=<cpu name>		 Assemble for selected processor
+   -EB/-mbig-endian		 Big-endian
+   -EL/-mlittle-endian		 Little-endian
+
+   The following CPU names are recognized:
+   arc700, av2em, av2hs.  */
 
 int
-md_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED,
-			       asection *seg ATTRIBUTE_UNUSED)
+md_parse_option (int c,
+		 char *arg ATTRIBUTE_UNUSED)
 {
-  as_fatal (_("relaxation not supported\n"));
+  int cpu_flags = EF_ARC_CPU_GENERIC;
+
+  switch (c)
+    {
+    case OPTION_ARC600:
+    case OPTION_ARC601:
+      return md_parse_option (OPTION_MCPU, "arc600");
+
+    case OPTION_ARC700:
+      return md_parse_option (OPTION_MCPU, "arc700");
+
+    case OPTION_ARCEM:
+      return md_parse_option (OPTION_MCPU, "arcem");
+
+    case OPTION_ARCHS:
+      return md_parse_option (OPTION_MCPU, "archs");
+
+    case OPTION_MCPU:
+      {
+	int i;
+	char *s = alloca (strlen (arg) + 1);
+
+	{
+	  char *t = s;
+	  char *arg1 = arg;
+
+	  do
+	    *t = TOLOWER (*arg1++);
+	  while (*t++);
+	}
+
+	for (i = 0; cpu_types[i].name; ++i)
+	  {
+	    if (!strcmp (cpu_types[i].name, s))
+	      {
+		arc_target      = cpu_types[i].flags;
+		arc_target_name = cpu_types[i].name;
+		arc_features    = cpu_types[i].features;
+		arc_mach_type   = cpu_types[i].mach;
+		cpu_flags       = cpu_types[i].eflags;
+
+		mach_type_specified_p = 1;
+		break;
+	      }
+	  }
+
+	if (!cpu_types[i].name)
+	  {
+	    as_fatal (_("unknown architecture: %s\n"), arg);
+	  }
+	break;
+      }
+
+    case OPTION_EB:
+      arc_target_format = "elf32-bigarc";
+      byte_order = BIG_ENDIAN;
+      break;
+
+    case OPTION_EL:
+      arc_target_format = "elf32-littlearc";
+      byte_order = LITTLE_ENDIAN;
+      break;
+
+    case OPTION_CD:
+      /* This option has an effect only on ARC EM.  */
+      if (arc_target & ARC_OPCODE_ARCv2EM)
+	arc_features |= ARC_CD;
+      break;
+
+    case OPTION_USER_MODE:
+    case OPTION_LD_EXT_MASK:
+    case OPTION_SWAP:
+    case OPTION_NORM:
+    case OPTION_BARREL_SHIFT:
+    case OPTION_MIN_MAX:
+    case OPTION_NO_MPY:
+    case OPTION_EA:
+    case OPTION_MUL64:
+    case OPTION_SIMD:
+    case OPTION_SPFP:
+    case OPTION_DPFP:
+    case OPTION_XMAC_D16:
+    case OPTION_XMAC_24:
+    case OPTION_DSP_PACKA:
+    case OPTION_CRC:
+    case OPTION_DVBF:
+    case OPTION_TELEPHONY:
+    case OPTION_XYMEMORY:
+    case OPTION_LOCK:
+    case OPTION_SWAPE:
+    case OPTION_RTSC:
+    case OPTION_FPUDA:
+      /* dummy options.  */
+
+    default:
+      break;
+    }
+
+  if (cpu_flags != EF_ARC_CPU_GENERIC)
+    arc_eflag = (arc_eflag & ~EF_ARC_MACH_MSK) | cpu_flags;
+
   return 1;
 }
 
-/* Convert a machine dependent frag.  We never generate these.  */
-
 void
-md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
-		 asection *sec ATTRIBUTE_UNUSED,
-		 fragS *fragp ATTRIBUTE_UNUSED)
+md_show_usage (FILE *stream)
 {
-  abort ();
+  fprintf (stream, _("ARC-specific assembler options:\n"));
+
+  fprintf (stream, "  -mcpu=<cpu name>\t  assemble for CPU <cpu name>\n");
+  fprintf (stream, "  -mcode-density\t  enable code density option for ARC EM\n");
+
+  fprintf (stream, _("\
+  -EB                     assemble code for a big-endian cpu\n"));
+  fprintf (stream, _("\
+  -EL                     assemble code for a little-endian cpu\n"));
 }
 
 static void
-arc_code_symbol (expressionS *expressionP)
+preprocess_operands (const struct arc_opcode *opcode,
+		     expressionS *tok,
+		     int ntok)
 {
-  if (expressionP->X_op == O_symbol && expressionP->X_add_number == 0)
-    {
-      expressionS two;
-
-      expressionP->X_op = O_right_shift;
-      expressionP->X_add_symbol->sy_value.X_op = O_constant;
-      two.X_op = O_constant;
-      two.X_add_symbol = two.X_op_symbol = NULL;
-      two.X_add_number = 2;
-      expressionP->X_op_symbol = make_expr_symbol (&two);
-    }
-  /* Allow %st(sym1-sym2)  */
-  else if (expressionP->X_op == O_subtract
-	   && expressionP->X_add_symbol != NULL
-	   && expressionP->X_op_symbol != NULL
-	   && expressionP->X_add_number == 0)
+  int i;
+  size_t len;
+  const char *p;
+  unsigned j;
+  const struct arc_aux_reg *auxr;
+
+  for (i = 0; i < ntok; i++)
     {
-      expressionS two;
-
-      expressionP->X_add_symbol = make_expr_symbol (expressionP);
-      expressionP->X_op = O_right_shift;
-      two.X_op = O_constant;
-      two.X_add_symbol = two.X_op_symbol = NULL;
-      two.X_add_number = 2;
-      expressionP->X_op_symbol = make_expr_symbol (&two);
+      switch (tok[i].X_op)
+	{
+	case O_illegal:
+	case O_absent:
+	  break; /* Throw and error.  */
+
+	case O_symbol:
+	  if (opcode->class != AUXREG)
+	    break;
+	  /* Convert the symbol to a constant if possible.  */
+	  p = S_GET_NAME (tok[i].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)
+	      {
+		tok[i].X_op = O_constant;
+		tok[i].X_add_number = auxr->address;
+		break;
+	      }
+	  break;
+	default:
+	  break;
+	}
     }
-  else
-    as_bad (_("expression too complex code symbol"));
 }
 
-/* Parse an operand that is machine-specific.
-
-   The ARC has a special %-op to adjust addresses so they're usable in
-   branches.  The "st" is short for the STatus register.
-   ??? Later expand this to take a flags value too.
+/* Given an opcode name, pre-tockenized set of argumenst and the
+   opcode flags, take it all the way through emission.  */
 
-   ??? We can't create new expression types so we map the %-op's onto the
-   existing syntax.  This means that the user could use the chosen syntax
-   to achieve the same effect.  */
-
-void
-md_operand (expressionS *expressionP)
+static void
+assemble_tokens (const char *opname,
+		 expressionS *tok,
+		 int ntok,
+		 struct arc_flags *pflags,
+		 int nflgs)
 {
-  char *p = input_line_pointer;
+  int found_something = 0;
+  const struct arc_opcode *opcode;
+  int cpumatch = 1;
 
-  if (*p != '%')
-    return;
+  /* Search opcodes.  */
+  opcode = (const struct arc_opcode *) hash_find (arc_opcode_hash, opname);
 
-  if (strncmp (p, "%st(", 4) == 0)
+  /* Couldn't find opcode conventional way, try special cases.  */
+  if (!opcode)
+    opcode = find_special_case (opname, &nflgs, pflags, tok, &ntok);
+
+  if (opcode)
     {
-      input_line_pointer += 4;
-      expression (expressionP);
-      if (*input_line_pointer != ')')
+      pr_debug ("%s:%d: assemble_tokens: %s trying opcode 0x%08X\n",
+		frag_now->fr_file, frag_now->fr_line, opcode->name,
+		opcode->opcode);
+
+      preprocess_operands (opcode, tok, ntok);
+
+      found_something = 1;
+      opcode = find_opcode_match (opcode, tok, &ntok, pflags, nflgs, &cpumatch);
+      if (opcode)
 	{
-	  as_bad (_("missing ')' in %%-op"));
+	  struct arc_insn insn;
+	  assemble_insn (opcode, tok, ntok, pflags, nflgs, &insn);
+	  emit_insn (&insn);
 	  return;
 	}
-      ++input_line_pointer;
-      arc_code_symbol (expressionP);
     }
-  else
-    {
-      /* It could be a register.  */
-      int i, l;
-      struct arc_ext_operand_value *ext_oper = arc_ext_operands;
-      p++;
 
-      while (ext_oper)
-	{
-	  l = strlen (ext_oper->operand.name);
-	  if (!strncmp (p, ext_oper->operand.name, l) && !ISALNUM (*(p + l)))
-	    {
-	      input_line_pointer += l + 1;
-	      expressionP->X_op = O_register;
-	      expressionP->X_add_number = (offsetT) &ext_oper->operand;
-	      return;
-	    }
-	  ext_oper = ext_oper->next;
-	}
-      for (i = 0; i < arc_reg_names_count; i++)
-	{
-	  l = strlen (arc_reg_names[i].name);
-	  if (!strncmp (p, arc_reg_names[i].name, l) && !ISALNUM (*(p + l)))
-	    {
-	      input_line_pointer += l + 1;
-	      expressionP->X_op = O_register;
-	      expressionP->X_add_number = (offsetT) &arc_reg_names[i];
-	      break;
-	    }
-	}
+  if (found_something)
+    {
+      if (cpumatch)
+	as_bad (_("inappropriate arguments for opcode '%s'"), opname);
+      else
+	as_bad (_("opcode '%s' not supported for target %s"), opname,
+		arc_target_name);
     }
+  else
+    as_bad (_("unknown opcode '%s'"), opname);
 }
 
-/* We have no need to default values of symbols.
-   We could catch register names here, but that is handled by inserting
-   them all in the symbol table to begin with.  */
+/* Used to find special case opcode.  */
 
-symbolS *
-md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
+static const struct arc_opcode *
+find_special_case (const char *opname,
+		   int *nflgs,
+		   struct arc_flags *pflags,
+		   expressionS *tok,
+		   int *ntok)
 {
-  return 0;
-}
-
-/* Functions concerning expressions.  */
+  const struct arc_opcode *opcode;
 
-/* Parse a .byte, .word, etc. expression.
+  opcode = find_special_case_pseudo (opname, ntok, tok, nflgs, pflags);
 
-   Values for the status register are specified with %st(label).
-   `label' will be right shifted by 2.  */
+  if (opcode == NULL)
+    opcode = find_special_case_flag (opname, nflgs, pflags);
 
-bfd_reloc_code_real_type
-arc_parse_cons_expression (expressionS *exp,
-			   unsigned int nbytes ATTRIBUTE_UNUSED)
+  return opcode;
+}
+
+/* Swap operand tokens.  */
+
+static void
+swap_operand (expressionS *operand_array,
+	      unsigned source,
+	      unsigned destination)
 {
-  char *p = input_line_pointer;
-  int code_symbol_fix = 0;
+  expressionS cpy_operand;
+  expressionS *src_operand;
+  expressionS *dst_operand;
+  size_t size;
 
-  for (; ! is_end_of_line[(unsigned char) *p]; p++)
-    if (*p == '@' && !strncmp (p, "@h30", 4))
-      {
-	code_symbol_fix = 1;
-	strcpy (p, ";   ");
-      }
-  expression_and_evaluate (exp);
-  if (code_symbol_fix)
-    {
-      arc_code_symbol (exp);
-      input_line_pointer = p;
-    }
-  return BFD_RELOC_NONE;
+  if (source == destination)
+    return;
+
+  src_operand = &operand_array[source];
+  dst_operand = &operand_array[destination];
+  size = sizeof (expressionS);
+
+  /* Make copy of operand to swap with and swap.  */
+  memcpy (&cpy_operand, dst_operand, size);
+  memcpy (dst_operand, src_operand, size);
+  memcpy (src_operand, &cpy_operand, size);
 }
 
-/* Record a fixup for a cons expression.  */
+/* Check if *op matches *tok type.
+   Returns 0 if they don't match, 1 if they match.  */
 
-void
-arc_cons_fix_new (fragS *frag,
-		  int where,
-		  int nbytes,
-		  expressionS *exp,
-		  bfd_reloc_code_real_type r ATTRIBUTE_UNUSED)
+static int
+pseudo_operand_match (const expressionS *tok,
+		      const struct arc_operand_operation *op)
 {
-  if (nbytes == 4)
-    {
-      int reloc_type;
-      expressionS exptmp;
+  offsetT min, max, val;
+  int ret;
+  const struct arc_operand *operand_real = &arc_operands[op->operand_idx];
 
-      /* This may be a special ARC reloc (eg: %st()).  */
-      reloc_type = get_arc_exp_reloc_type (1, BFD_RELOC_32, exp, &exptmp);
-      fix_new_exp (frag, where, nbytes, &exptmp, 0,
-                   (enum bfd_reloc_code_real) reloc_type);
-    }
-  else
+  ret = 0;
+  switch (tok->X_op)
     {
-      fix_new_exp (frag, where, nbytes, exp, 0,
-		   nbytes == 2 ? BFD_RELOC_16
-		   : nbytes == 8 ? BFD_RELOC_64
-		   : BFD_RELOC_32);
+    case O_constant:
+      if (operand_real->bits == 32 && (operand_real->flags & ARC_OPERAND_LIMM))
+	ret = 1;
+      else if (!(operand_real->flags & ARC_OPERAND_IR))
+	{
+	  val = tok->X_add_number;
+	  if (operand_real->flags & ARC_OPERAND_SIGNED)
+	    {
+	      max = (1 << (operand_real->bits - 1)) - 1;
+	      min = -(1 << (operand_real->bits - 1));
+	    }
+	  else
+	    {
+	      max = (1 << operand_real->bits) - 1;
+	      min = 0;
+	    }
+	  if (min <= val && val <= max)
+	    ret = 1;
+	}
+      break;
+
+    case O_symbol:
+      /* Handle all symbols as long immediates or signed 9.  */
+      if (operand_real->flags & ARC_OPERAND_LIMM ||
+	  ((operand_real->flags & ARC_OPERAND_SIGNED) && operand_real->bits == 9))
+	ret = 1;
+      break;
+
+    case O_register:
+      if (operand_real->flags & ARC_OPERAND_IR)
+	ret = 1;
+      break;
+
+    case O_bracket:
+      if (operand_real->flags & ARC_OPERAND_BRAKET)
+	ret = 1;
+      break;
+
+    default:
+      /* Unknown.  */
+      break;
     }
+  return ret;
 }
-
-/* Functions concerning relocs.  */
 
-/* The location from which a PC relative jump should be calculated,
-   given a PC relative reloc.  */
+/* Find pseudo instruction in array.  */
 
-long
-md_pcrel_from (fixS *fixP)
+static const struct arc_pseudo_insn *
+find_pseudo_insn (const char *opname,
+		  int ntok,
+		  const expressionS *tok)
 {
-  /* Return the address of the delay slot.  */
-  return fixP->fx_frag->fr_address + fixP->fx_where + fixP->fx_size;
+  const struct arc_pseudo_insn *pseudo_insn = NULL;
+  const struct arc_operand_operation *op;
+  unsigned int i;
+  int j;
+
+  for (i = 0; i < arc_num_pseudo_insn; ++i)
+    {
+      pseudo_insn = &arc_pseudo_insns[i];
+      if (strcmp (pseudo_insn->mnemonic_p, opname) == 0)
+	{
+	  op = pseudo_insn->operand;
+	  for (j = 0; j < ntok; ++j)
+	    if (!pseudo_operand_match (&tok[j], &op[j]))
+	      break;
+
+	  /* Found the right instruction.  */
+	  if (j == ntok)
+	    return pseudo_insn;
+	}
+    }
+  return NULL;
 }
 
-/* Apply a fixup to the object code.  This is called for all the
-   fixups we generated by the call to fix_new_exp, above.  In the call
-   above we used a reloc code which was the largest legal reloc code
-   plus the operand index.  Here we undo that to recover the operand
-   index.  At this point all symbol values should be fully resolved,
-   and we attempt to completely resolve the reloc.  If we can not do
-   that, we determine the correct reloc code and put it back in the fixup.  */
+/* Assumes the expressionS *tok is of sufficient size.  */
 
-void
-md_apply_fix (fixS *fixP, valueT * valP, segT seg)
+static const struct arc_opcode *
+find_special_case_pseudo (const char *opname,
+			  int *ntok,
+			  expressionS *tok,
+			  int *nflgs,
+			  struct arc_flags *pflags)
 {
-  valueT value = * valP;
+  const struct arc_pseudo_insn *pseudo_insn = NULL;
+  const struct arc_operand_operation *operand_pseudo;
+  const struct arc_operand *operand_real;
+  unsigned i;
+  char construct_operand[MAX_CONSTR_STR];
 
-  if (fixP->fx_addsy == (symbolS *) NULL)
-    fixP->fx_done = 1;
+  /* Find whether opname is in pseudo instruction array.  */
+  pseudo_insn = find_pseudo_insn (opname, *ntok, tok);
 
-  else if (fixP->fx_pcrel)
-    {
-      /* Hack around bfd_install_relocation brain damage.  */
-      if (S_GET_SEGMENT (fixP->fx_addsy) != seg)
-	value += md_pcrel_from (fixP);
-    }
+  if (pseudo_insn == NULL)
+    return NULL;
 
-  /* We can't actually support subtracting a symbol.  */
-  if (fixP->fx_subsy != NULL)
-    as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
+  /* Handle flag, Limited to one flag at the moment.  */
+  if (pseudo_insn->flag_r != NULL)
+    *nflgs += tokenize_flags (pseudo_insn->flag_r, &pflags[*nflgs],
+			      MAX_INSN_FLGS - *nflgs);
 
-  if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
+  /* Handle operand operations.  */
+  for (i = 0; i < pseudo_insn->operand_cnt; ++i)
     {
-      int opindex;
-      const struct arc_operand *operand;
-      char *where;
-      arc_insn insn;
-
-      opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
+      operand_pseudo = &pseudo_insn->operand[i];
+      operand_real = &arc_operands[operand_pseudo->operand_idx];
 
-      operand = &arc_operands[opindex];
+      if (operand_real->flags & ARC_OPERAND_BRAKET &&
+	  !operand_pseudo->needs_insert)
+	continue;
 
-      /* Fetch the instruction, insert the fully resolved operand
-	 value, and stuff the instruction back again.  */
-      where = fixP->fx_frag->fr_literal + fixP->fx_where;
-      if (target_big_endian)
-	insn = bfd_getb32 ((unsigned char *) where);
-      else
-	insn = bfd_getl32 ((unsigned char *) where);
-      insn = arc_insert_operand (insn, operand, -1, NULL, (offsetT) value,
-				 fixP->fx_file, fixP->fx_line);
-      if (target_big_endian)
-	bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
-      else
-	bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
+      /* Has to be inserted (i.e. this token does not exist yet).  */
+      if (operand_pseudo->needs_insert)
+	{
+	  if (operand_real->flags & ARC_OPERAND_BRAKET)
+	    {
+	      tok[i].X_op = O_bracket;
+	      ++(*ntok);
+	      continue;
+	    }
 
-      if (fixP->fx_done)
-	/* Nothing else to do here.  */
-	return;
+	  /* Check if operand is a register or constant and handle it
+	     by type.  */
+	  if (operand_real->flags & ARC_OPERAND_IR)
+	    snprintf (construct_operand, MAX_CONSTR_STR, "r%d",
+		      operand_pseudo->count);
+	  else
+	    snprintf (construct_operand, MAX_CONSTR_STR, "%d",
+		      operand_pseudo->count);
 
-      /* Determine a BFD reloc value based on the operand information.
-	 We are only prepared to turn a few of the operands into relocs.
-	 !!! Note that we can't handle limm values here.  Since we're using
-	 implicit addends the addend must be inserted into the instruction,
-	 however, the opcode insertion routines currently do nothing with
-	 limm values.  */
-      if (operand->fmt == 'B')
-	{
-	  gas_assert ((operand->flags & ARC_OPERAND_RELATIVE_BRANCH) != 0
-		  && operand->bits == 20
-		  && operand->shift == 7);
-	  fixP->fx_r_type = BFD_RELOC_ARC_B22_PCREL;
-	}
-      else if (operand->fmt == 'J')
-	{
-	  gas_assert ((operand->flags & ARC_OPERAND_ABSOLUTE_BRANCH) != 0
-		  && operand->bits == 24
-		  && operand->shift == 32);
-	  fixP->fx_r_type = BFD_RELOC_ARC_B26;
+	  tokenize_arguments (construct_operand, &tok[i], 1);
+	  ++(*ntok);
 	}
-      else if (operand->fmt == 'L')
-	{
-	  gas_assert ((operand->flags & ARC_OPERAND_LIMM) != 0
-		  && operand->bits == 32
-		  && operand->shift == 32);
-	  fixP->fx_r_type = BFD_RELOC_32;
-	}
-      else
+
+      else if (operand_pseudo->count)
 	{
-	  as_bad_where (fixP->fx_file, fixP->fx_line,
-			_("unresolved expression that must be resolved"));
-	  fixP->fx_done = 1;
-	  return;
+	  /* Operand number has to be adjusted accordingly (by operand
+	     type).  */
+	  switch (tok[i].X_op)
+	    {
+	    case O_constant:
+	      tok[i].X_add_number += operand_pseudo->count;
+	      break;
+
+	    case O_symbol:
+	      break;
+
+	    default:
+	      /* Ignored.  */
+	      break;
+	    }
 	}
     }
-  else
+
+  /* Swap operands if necessary.  Only supports one swap at the
+     moment.  */
+  for (i = 0; i < pseudo_insn->operand_cnt; ++i)
     {
-      switch (fixP->fx_r_type)
-	{
-	case BFD_RELOC_8:
-	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			      value, 1);
-	  break;
-	case BFD_RELOC_16:
-	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			      value, 2);
-	  break;
-	case BFD_RELOC_32:
-	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			      value, 4);
-	  break;
-	case BFD_RELOC_ARC_B26:
-	  /* If !fixP->fx_done then `value' is an implicit addend.
-	     We must shift it right by 2 in this case as well because the
-	     linker performs the relocation and then adds this in (as opposed
-	     to adding this in and then shifting right by 2).  */
-	  value >>= 2;
-	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			      value, 4);
-	  break;
-	default:
-	  abort ();
-	}
+      operand_pseudo = &pseudo_insn->operand[i];
+
+      if (operand_pseudo->swap_operand_idx == i)
+	continue;
+
+      swap_operand (tok, i, operand_pseudo->swap_operand_idx);
+
+      /* Prevent a swap back later by breaking out.  */
+      break;
     }
-}
 
-/* Translate internal representation of relocation info to BFD target
-   format.  */
+  return (const struct arc_opcode *)
+    hash_find (arc_opcode_hash,	pseudo_insn->mnemonic_r);
+}
 
-arelent *
-tc_gen_reloc (asection *section ATTRIBUTE_UNUSED,
-	      fixS *fixP)
+static const struct arc_opcode *
+find_special_case_flag (const char *opname,
+			int *nflgs,
+			struct arc_flags *pflags)
 {
-  arelent *reloc;
-
-  reloc = (arelent *) xmalloc (sizeof (arelent));
-  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  unsigned int i;
+  const char *flagnm;
+  unsigned flag_idx, flag_arr_idx;
+  size_t flaglen, oplen;
+  const struct arc_flag_special *arc_flag_special_opcode;
+  const struct arc_opcode *opcode;
 
-  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
-  reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
-  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
-  if (reloc->howto == (reloc_howto_type *) NULL)
+  /* Search for special case instruction.  */
+  for (i = 0; i < arc_num_flag_special; i++)
     {
-      as_bad_where (fixP->fx_file, fixP->fx_line,
-		    _("internal error: can't export reloc type %d (`%s')"),
-		    fixP->fx_r_type,
-		    bfd_get_reloc_code_name (fixP->fx_r_type));
-      return NULL;
+      arc_flag_special_opcode = &arc_flag_special_cases[i];
+      oplen = strlen (arc_flag_special_opcode->name);
+
+      if (strncmp (opname, arc_flag_special_opcode->name, oplen) != 0)
+	continue;
+
+      /* Found a potential special case instruction, now test for
+	 flags.  */
+      for (flag_arr_idx = 0;; ++flag_arr_idx)
+	{
+	  flag_idx = arc_flag_special_opcode->flags[flag_arr_idx];
+	  if (flag_idx == 0)
+	    break;  /* End of array, nothing found.  */
+
+	  flagnm = arc_flag_operands[flag_idx].name;
+	  flaglen = strlen (flagnm);
+	  if (strcmp (opname + oplen, flagnm) == 0)
+	    {
+	      opcode = (const struct arc_opcode *)
+		hash_find (arc_opcode_hash,
+			   arc_flag_special_opcode->name);
+
+	      if (*nflgs + 1 > MAX_INSN_FLGS)
+		break;
+	      memcpy (pflags[*nflgs].name, flagnm, flaglen);
+	      pflags[*nflgs].name[flaglen] = '\0';
+	      (*nflgs)++;
+	      return opcode;
+	    }
+	}
     }
+  return NULL;
+}
 
-  gas_assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
+/* Check whether a symbol involves a register.  */
 
-  /* Set addend to account for PC being advanced one insn before the
-     target address is computed.  */
+static int
+contains_register (symbolS *sym)
+{
+  if (sym)
+  {
+    expressionS *ex = symbol_get_value_expression (sym);
+    return ((O_register == ex->X_op)
+	    && !contains_register (ex->X_add_symbol)
+	    && !contains_register (ex->X_op_symbol));
+  }
+  else
+    return 0;
+}
 
-  reloc->addend = (fixP->fx_pcrel ? -4 : 0);
+/* Returns the register number within a symbol.  */
 
-  return reloc;
+static int
+get_register (symbolS *sym)
+{
+  if (!contains_register (sym))
+    return -1;
+
+  expressionS *ex = symbol_get_value_expression (sym);
+  return regno (ex->X_add_number);
 }
 
-const pseudo_typeS md_pseudo_table[] =
+/* Allocates a tok entry.  */
+
+static int
+allocate_tok (expressionS *tok, int ntok, int cidx)
 {
-  { "align", s_align_bytes, 0 }, /* Defaulting is invalid (0).  */
-  { "comm", arc_common, 0 },
-  { "common", arc_common, 0 },
-  { "lcomm", arc_common, 1 },
-  { "lcommon", arc_common, 1 },
-  { "2byte", cons, 2 },
-  { "half", cons, 2 },
-  { "short", cons, 2 },
-  { "3byte", cons, 3 },
-  { "4byte", cons, 4 },
-  { "word", cons, 4 },
-  { "option", arc_option, 0 },
-  { "cpu", arc_option, 0 },
-  { "block", s_space, 0 },
-  { "extcondcode", arc_extoper, 0 },
-  { "extcoreregister", arc_extoper, 1 },
-  { "extauxregister", arc_extoper, 2 },
-  { "extinstruction", arc_extinst, 0 },
-  { NULL, 0, 0 },
-};
+  if (ntok > MAX_INSN_ARGS - 2)
+    return 0; /* No space left.  */
 
-/* This routine is called for each instruction to be assembled.  */
+  if (cidx > ntok)
+    return 0; /* Incorect args.  */
 
-void
-md_assemble (char *str)
+  memcpy (&tok[ntok+1], &tok[ntok], sizeof (*tok));
+
+  if (cidx == ntok)
+    return 1; /* Success.  */
+  return allocate_tok (tok, ntok - 1, cidx);
+}
+
+/* Return true if a RELOC is generic.  A generic reloc is PC-rel of a
+   simple ME relocation (e.g. RELOC_ARC_32_ME, BFD_RELOC_ARC_PC32.  */
+
+static bfd_boolean
+generic_reloc_p (extended_bfd_reloc_code_real_type reloc)
 {
-  const struct arc_opcode *opcode;
-  const struct arc_opcode *std_opcode;
-  struct arc_opcode *ext_opcode;
-  char *start;
-  const char *last_errmsg = 0;
-  arc_insn insn;
-  static int init_tables_p = 0;
-
-  /* Opcode table initialization is deferred until here because we have to
-     wait for a possible .option command.  */
-  if (!init_tables_p)
+  if (!reloc)
+    return FALSE;
+
+  switch (reloc)
     {
-      init_opcode_tables (arc_mach_type);
-      init_tables_p = 1;
+    case BFD_RELOC_ARC_SDA_LDST:
+    case BFD_RELOC_ARC_SDA_LDST1:
+    case BFD_RELOC_ARC_SDA_LDST2:
+    case BFD_RELOC_ARC_SDA16_LD:
+    case BFD_RELOC_ARC_SDA16_LD1:
+    case BFD_RELOC_ARC_SDA16_LD2:
+    case BFD_RELOC_ARC_SDA16_ST2:
+    case BFD_RELOC_ARC_SDA32_ME:
+      return FALSE;
+    default:
+      break;
     }
+  return TRUE;
+}
 
-  /* Skip leading white space.  */
-  while (ISSPACE (*str))
-    str++;
+/* Search forward through all variants of an opcode looking for a
+   syntax match.  */
 
-  /* The instructions are stored in lists hashed by the first letter (though
-     we needn't care how they're hashed).  Get the first in the list.  */
+static const struct arc_opcode *
+find_opcode_match (const struct arc_opcode *first_opcode,
+		   expressionS *tok,
+		   int *pntok,
+		   struct arc_flags *first_pflag,
+		   int nflgs,
+		   int *pcpumatch)
+{
+  const struct arc_opcode *opcode = first_opcode;
+  int ntok = *pntok;
+  int got_cpu_match = 0;
+  expressionS bktok[MAX_INSN_ARGS];
+  int bkntok;
 
-  ext_opcode = arc_ext_opcodes;
-  std_opcode = arc_opcode_lookup_asm (str);
+  memcpy (bktok, tok, MAX_INSN_ARGS * sizeof (*tok));
+  bkntok = ntok;
 
-  /* Keep looking until we find a match.  */
-  start = str;
-  for (opcode = (ext_opcode ? ext_opcode : std_opcode);
-       opcode != NULL;
-       opcode = (ARC_OPCODE_NEXT_ASM (opcode)
-		 ? ARC_OPCODE_NEXT_ASM (opcode)
-		 : (ext_opcode ? ext_opcode = NULL, std_opcode : NULL)))
+  do
     {
-      int past_opcode_p, fc, num_suffixes;
-      int fix_up_at = 0;
-      char *syn;
-      struct arc_fixup fixups[MAX_FIXUPS];
-      /* Used as a sanity check.  If we need a limm reloc, make sure we ask
-	 for an extra 4 bytes from frag_more.  */
-      int limm_reloc_p;
-      int ext_suffix_p;
-      const struct arc_operand_value *insn_suffixes[MAX_SUFFIXES];
-
-      /* Is this opcode supported by the selected cpu?  */
-      if (! arc_opcode_supported (opcode))
-	continue;
+      const unsigned char *opidx;
+      const unsigned char *flgidx;
+      int tokidx = 0;
+      const expressionS *t;
+
+      pr_debug ("%s:%d: find_opcode_match: trying opcode 0x%08X ",
+		frag_now->fr_file, frag_now->fr_line, opcode->opcode);
+
+      /* Don't match opcodes that don't exist on this
+	 architecture.  */
+      if (!(opcode->cpu & arc_target))
+	goto match_failed;
 
-      /* Scan the syntax string.  If it doesn't match, try the next one.  */
-      arc_opcode_init_insert ();
-      insn = opcode->value;
-      fc = 0;
-      past_opcode_p = 0;
-      num_suffixes = 0;
-      limm_reloc_p = 0;
-      ext_suffix_p = 0;
-
-      /* We don't check for (*str != '\0') here because we want to parse
-	 any trailing fake arguments in the syntax string.  */
-      for (str = start, syn = opcode->syntax; *syn != '\0';)
+      if (is_code_density_p (opcode) && !(arc_features & ARC_CD))
+	goto match_failed;
+
+      got_cpu_match = 1;
+      pr_debug ("cpu ");
+
+      /* Check the operands.  */
+      for (opidx = opcode->operands; *opidx; ++opidx)
 	{
-	  int mods;
-	  const struct arc_operand *operand;
+	  const struct arc_operand *operand = &arc_operands[*opidx];
+
+	  /* Only take input from real operands.  */
+	  if ((operand->flags & ARC_OPERAND_FAKE)
+	      && !(operand->flags & ARC_OPERAND_BRAKET))
+	    continue;
+
+	  /* When we expect input, make sure we have it.  */
+	  if (tokidx >= ntok)
+	    goto match_failed;
 
-	  /* Non operand chars must match exactly.  */
-	  if (*syn != '%' || *++syn == '%')
+	  /* Match operand type with expression type.  */
+	  switch (operand->flags & ARC_OPERAND_TYPECHECK_MASK)
 	    {
-	     if (*str == *syn)
+	    case ARC_OPERAND_IR:
+	      /* Check to be a register.  */
+	      if ((tok[tokidx].X_op != O_register
+		   || !is_ir_num (tok[tokidx].X_add_number))
+		  && !(operand->flags & ARC_OPERAND_IGNORE))
+		goto match_failed;
+
+	      /* If expect duplicate, make sure it is duplicate.  */
+	      if (operand->flags & ARC_OPERAND_DUPLICATE)
 		{
-		  if (*syn == ' ')
-		    past_opcode_p = 1;
-		  ++syn;
-		  ++str;
+		  /* Check for duplicate.  */
+		  if (t->X_op != O_register
+		      || !is_ir_num (t->X_add_number)
+		      || (regno (t->X_add_number) !=
+			  regno (tok[tokidx].X_add_number)))
+		    goto match_failed;
 		}
-	      else
-		break;
-	      continue;
-	    }
 
-	  /* We have an operand.  Pick out any modifiers.  */
-	  mods = 0;
-	  while (ARC_MOD_P (arc_operands[arc_operand_map[(int) *syn]].flags))
-	    {
-	      mods |= arc_operands[arc_operand_map[(int) *syn]].flags & ARC_MOD_BITS;
-	      ++syn;
-	    }
-	  operand = arc_operands + arc_operand_map[(int) *syn];
-	  if (operand->fmt == 0)
-	    as_fatal (_("unknown syntax format character `%c'"), *syn);
-
-	  if (operand->flags & ARC_OPERAND_FAKE)
-	    {
-	      const char *errmsg = NULL;
+	      /* Special handling?  */
 	      if (operand->insert)
 		{
-		  insn = (*operand->insert) (insn, operand, mods, NULL, 0, &errmsg);
-		  if (errmsg != (const char *) NULL)
+		  const char *errmsg = NULL;
+		  (*operand->insert)(0,
+				     regno (tok[tokidx].X_add_number),
+				     &errmsg);
+		  if (errmsg)
 		    {
-		      last_errmsg = errmsg;
-		      if (operand->flags & ARC_OPERAND_ERROR)
+		      if (operand->flags & ARC_OPERAND_IGNORE)
 			{
-			  as_bad ("%s", errmsg);
-			  return;
+			  /* Missing argument, create one.  */
+			  if (!allocate_tok (tok, ntok - 1, tokidx))
+			    goto match_failed;
+
+			  tok[tokidx].X_op = O_absent;
+			  ++ntok;
 			}
-		      else if (operand->flags & ARC_OPERAND_WARN)
-			as_warn ("%s", errmsg);
-		      break;
-		    }
-		  if (limm_reloc_p
-		      && (operand->flags && operand->flags & ARC_OPERAND_LIMM)
-		      && (operand->flags &
-			  (ARC_OPERAND_ABSOLUTE_BRANCH | ARC_OPERAND_ADDRESS)))
-		    {
-		      fixups[fix_up_at].opindex = arc_operand_map[operand->fmt];
+		      else
+			goto match_failed;
 		    }
 		}
-	      ++syn;
-	    }
-	  /* Are we finished with suffixes?  */
-	  else if (!past_opcode_p)
-	    {
-	      int found;
-	      char c;
-	      char *s, *t;
-	      const struct arc_operand_value *suf, *suffix_end;
-	      const struct arc_operand_value *suffix = NULL;
-
-	      if (!(operand->flags & ARC_OPERAND_SUFFIX))
-		abort ();
-
-	      /* If we're at a space in the input string, we want to skip the
-		 remaining suffixes.  There may be some fake ones though, so
-		 just go on to try the next one.  */
-	      if (*str == ' ')
-		{
-		  ++syn;
-		  continue;
-		}
 
-	      s = str;
-	      if (mods & ARC_MOD_DOT)
-		{
-		  if (*s != '.')
-		    break;
-		  ++s;
-		}
-	      else
-		{
-		  /* This can happen in "b.nd foo" and we're currently looking
-		     for "%q" (ie: a condition code suffix).  */
-		  if (*s == '.')
-		    {
-		      ++syn;
-		      continue;
-		    }
-		}
+	      t = &tok[tokidx];
+	      break;
+
+	    case ARC_OPERAND_BRAKET:
+	      /* Check if bracket is also in opcode table as
+		 operand.  */
+	      if (tok[tokidx].X_op != O_bracket)
+		goto match_failed;
+	      break;
 
-	      /* Pick the suffix out and look it up via the hash table.  */
-	      for (t = s; *t && ISALNUM (*t); ++t)
-		continue;
-	      c = *t;
-	      *t = '\0';
-	      if ((suf = get_ext_suffix (s)))
-		ext_suffix_p = 1;
-	      else
-		suf = (const struct arc_operand_value *)
-                    hash_find (arc_suffix_hash, s);
-	      if (!suf)
+	    case ARC_OPERAND_LIMM:
+	    case ARC_OPERAND_SIGNED:
+	    case ARC_OPERAND_UNSIGNED:
+	      switch (tok[tokidx].X_op)
 		{
-		  /* This can happen in "blle foo" and we're currently using
-		     the template "b%q%.n %j".  The "bl" insn occurs later in
-		     the table so "lle" isn't an illegal suffix.  */
-		  *t = c;
+		case O_illegal:
+		case O_absent:
+		case O_register:
+		  goto match_failed;
+
+		case O_bracket:
+		  /* Got an (too) early bracket, check if it is an
+		     ignored operand.  N.B. This procedure works only
+		     when bracket is the last operand!  */
+		  if (!(operand->flags & ARC_OPERAND_IGNORE))
+		    goto match_failed;
+		  /* Insert the missing operand.  */
+		  if (!allocate_tok (tok, ntok - 1, tokidx))
+		    goto match_failed;
+
+		  tok[tokidx].X_op = O_absent;
+		  ++ntok;
 		  break;
-		}
 
-	      /* Is it the right type?  Note that the same character is used
-		 several times, so we have to examine all of them.  This is
-		 relatively efficient as equivalent entries are kept
-		 together.  If it's not the right type, don't increment `str'
-		 so we try the next one in the series.  */
-	      found = 0;
-	      if (ext_suffix_p && arc_operands[suf->type].fmt == *syn)
-		{
-		  /* Insert the suffix's value into the insn.  */
-		  *t = c;
-		  if (operand->insert)
-		    insn = (*operand->insert) (insn, operand,
-					       mods, NULL, suf->value,
-					       NULL);
-		  else
-		    insn |= suf->value << operand->shift;
-		  suffix = suf;
-		  str = t;
-		  found = 1;
-		}
-	      else
-		{
-		  *t = c;
-		  suffix_end = arc_suffixes + arc_suffixes_count;
-		  for (suffix = suf;
-		       suffix < suffix_end && strcmp (suffix->name, suf->name) == 0;
-		       ++suffix)
+		case O_constant:
+		  /* Check the range.  */
+		  if (operand->bits != 32
+		      && !(operand->flags & ARC_OPERAND_NCHK))
 		    {
-		      if (arc_operands[suffix->type].fmt == *syn)
+		      offsetT min, max, val;
+		      val = tok[tokidx].X_add_number;
+
+		      if (operand->flags & ARC_OPERAND_SIGNED)
 			{
-			  /* Insert the suffix's value into the insn.  */
-			  if (operand->insert)
-			    insn = (*operand->insert) (insn, operand,
-						       mods, NULL, suffix->value,
-						       NULL);
-			  else
-			    insn |= suffix->value << operand->shift;
-
-			  str = t;
-			  found = 1;
-			  break;
+			  max = (1 << (operand->bits - 1)) - 1;
+			  min = -(1 << (operand->bits - 1));
+			}
+		      else
+			{
+			  max = (1 << operand->bits) - 1;
+			  min = 0;
 			}
-		    }
-		}
-	      ++syn;
-	      if (!found)
-		/* Wrong type.  Just go on to try next insn entry.  */
-		;
-	      else
-		{
-		  if (num_suffixes == MAX_SUFFIXES)
-		    as_bad (_("too many suffixes"));
-		  else
-		    insn_suffixes[num_suffixes++] = suffix;
-		}
-	    }
-	  else
-	    /* This is either a register or an expression of some kind.  */
-	    {
-	      char *hold;
-	      const struct arc_operand_value *reg = NULL;
-	      long value = 0;
-	      expressionS exp;
-
-	      if (operand->flags & ARC_OPERAND_SUFFIX)
-		abort ();
-
-	      /* Is there anything left to parse?
-		 We don't check for this at the top because we want to parse
-		 any trailing fake arguments in the syntax string.  */
-	      if (is_end_of_line[(unsigned char) *str])
-		break;
 
-	      /* Parse the operand.  */
-	      hold = input_line_pointer;
-	      input_line_pointer = str;
-	      expression (&exp);
-	      str = input_line_pointer;
-	      input_line_pointer = hold;
-
-	      if (exp.X_op == O_illegal)
-		as_bad (_("illegal operand"));
-	      else if (exp.X_op == O_absent)
-		as_bad (_("missing operand"));
-	      else if (exp.X_op == O_constant)
-		value = exp.X_add_number;
-	      else if (exp.X_op == O_register)
-		reg = (struct arc_operand_value *) exp.X_add_number;
-#define IS_REG_DEST_OPERAND(o) ((o) == 'a')
-	      else if (IS_REG_DEST_OPERAND (*syn))
-		as_bad (_("symbol as destination register"));
-	      else
-		{
-		  if (!strncmp (str, "@h30", 4))
-		    {
-		      arc_code_symbol (&exp);
-		      str += 4;
+		      if (val < min || val > max)
+			goto match_failed;
+
+		      /* Check alignmets.  */
+		      if ((operand->flags & ARC_OPERAND_ALIGNED32)
+			  && (val & 0x03))
+			goto match_failed;
+
+		      if ((operand->flags & ARC_OPERAND_ALIGNED16)
+			  && (val & 0x01))
+			goto match_failed;
 		    }
-		  /* We need to generate a fixup for this expression.  */
-		  if (fc >= MAX_FIXUPS)
-		    as_fatal (_("too many fixups"));
-		  fixups[fc].exp = exp;
-		  /* We don't support shimm relocs. break here to force
-		     the assembler to output a limm.  */
-#define IS_REG_SHIMM_OFFSET(o) ((o) == 'd')
-		  if (IS_REG_SHIMM_OFFSET (*syn))
-		    break;
-		  /* If this is a register constant (IE: one whose
-		     register value gets stored as 61-63) then this
-		     must be a limm.  */
-		  /* ??? This bit could use some cleaning up.
-		     Referencing the format chars like this goes
-		     against style.  */
-		  if (IS_SYMBOL_OPERAND (*syn))
+		  else if (operand->flags & ARC_OPERAND_NCHK)
 		    {
-		      const char *junk;
-		      limm_reloc_p = 1;
-		      /* Save this, we don't yet know what reloc to use.  */
-		      fix_up_at = fc;
-		      /* Tell insert_reg we need a limm.  This is
-			 needed because the value at this point is
-			 zero, a shimm.  */
-		      /* ??? We need a cleaner interface than this.  */
-		      (*arc_operands[arc_operand_map['Q']].insert)
-			(insn, operand, mods, reg, 0L, &junk);
+		      if (operand->insert)
+			{
+			  const char *errmsg = NULL;
+			  (*operand->insert)(0,
+					     tok[tokidx].X_add_number,
+					     &errmsg);
+			  if (errmsg)
+			    goto match_failed;
+			}
+		      else
+			goto match_failed;
 		    }
-		  else
-		    fixups[fc].opindex = arc_operand_map[(int) *syn];
-		  ++fc;
-		  value = 0;
-		}
+		  break;
 
-	      /* Insert the register or expression into the instruction.  */
-	      if (operand->insert)
-		{
-		  const char *errmsg = NULL;
-		  insn = (*operand->insert) (insn, operand, mods,
-					     reg, (long) value, &errmsg);
-		  if (errmsg != (const char *) NULL)
+		case O_subtract:
+		  /* Check if it is register range.  */
+		  if ((tok[tokidx].X_add_number == 0)
+		      && contains_register (tok[tokidx].X_add_symbol)
+		      && contains_register (tok[tokidx].X_op_symbol))
 		    {
-		      last_errmsg = errmsg;
-		      if (operand->flags & ARC_OPERAND_ERROR)
+		      int regs;
+		      regs = get_register (tok[tokidx].X_add_symbol);
+		      regs <<= 16;
+		      regs |= get_register (tok[tokidx].X_op_symbol);
+		      if (operand->insert)
 			{
-			  as_bad ("%s", errmsg);
-			  return;
+			  const char *errmsg = NULL;
+			  (*operand->insert)(0,
+					     regs,
+					     &errmsg);
+			  if (errmsg)
+			    goto match_failed;
 			}
-		      else if (operand->flags & ARC_OPERAND_WARN)
-			as_warn ("%s", errmsg);
+		      else
+			goto match_failed;
+		      break;
+		    }
+		default:
+		  if (operand->default_reloc == 0)
+		    goto match_failed; /* The operand needs relocation.  */
+
+		  /* Relocs requiring long immediate. FIXME! make it
+		     generic and move it to a function.  */
+		  switch (tok[tokidx].X_md)
+		    {
+		    case O_gotoff:
+		    case O_gotpc:
+		    case O_pcl:
+		    case O_tpoff:
+		    case O_dtpoff:
+		    case O_tlsgd:
+		    case O_tlsie:
+		      if (!(operand->flags & ARC_OPERAND_LIMM))
+			goto match_failed;
+		    case O_absent:
+		      if (!generic_reloc_p (operand->default_reloc))
+			goto match_failed;
+		    default:
 		      break;
 		    }
+		  break;
+		}
+	      /* If expect duplicate, make sure it is duplicate.  */
+	      if (operand->flags & ARC_OPERAND_DUPLICATE)
+		{
+		  if (t->X_op == O_illegal
+		      || t->X_op == O_absent
+		      || t->X_op == O_register
+		      || (t->X_add_number != tok[tokidx].X_add_number))
+		    goto match_failed;
 		}
-	      else
-		insn |= (value & ((1 << operand->bits) - 1)) << operand->shift;
+	      t = &tok[tokidx];
+	      break;
+
+	    default:
+	      /* Everything else should have been fake.  */
+	      abort ();
+	    }
+
+	  ++tokidx;
+	}
+      pr_debug ("opr ");
+
+      /* Check the flags.  Iterate over the valid flag classes.  */
+      int lnflg = nflgs;
+
+      for (flgidx = opcode->flags; *flgidx && lnflg; ++flgidx)
+	{
+	  /* Get a valid flag class.  */
+	  const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
+	  const unsigned *flgopridx;
+
+	  for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
+	    {
+	      const struct arc_flag_operand *flg_operand;
+	      struct arc_flags *pflag = first_pflag;
+	      int i;
 
-	      ++syn;
+	      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))
+		    {
+		      /*TODO: Check if it is duplicated.  */
+		      pflag->code = *flgopridx;
+		      lnflg--;
+		      break; /* goto next flag class and parsed flag.  */
+		    }
+		}
 	    }
 	}
+      /* Did I check all the parsed flags?  */
+      if (lnflg)
+	goto match_failed;
 
-      /* If we're at the end of the syntax string, we're done.  */
-      /* FIXME: try to move this to a separate function.  */
-      if (*syn == '\0')
+      pr_debug ("flg");
+      /* Possible match -- did we use all of our input?  */
+      if (tokidx == ntok)
 	{
-	  int i;
-	  char *f;
-	  long limm, limm_p;
+	  *pntok = ntok;
+	  pr_debug ("\n");
+	  return opcode;
+	}
 
-	  /* For the moment we assume a valid `str' can only contain blanks
-	     now.  IE: We needn't try again with a longer version of the
-	     insn and it is assumed that longer versions of insns appear
-	     before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
+    match_failed:;
+      pr_debug ("\n");
+      /* Restore the original parameters.  */
+      memcpy (tok, bktok, MAX_INSN_ARGS * sizeof (*tok));
+      ntok = bkntok;
+    }
+  while (++opcode - arc_opcodes < (int) arc_num_opcodes
+	 && !strcmp (opcode->name, first_opcode->name));
 
-	  while (ISSPACE (*str))
-	    ++str;
+  if (*pcpumatch)
+    *pcpumatch = got_cpu_match;
 
-	  if (!is_end_of_line[(unsigned char) *str])
-	    as_bad (_("junk at end of line: `%s'"), str);
+  return NULL;
+}
 
-	  /* Is there a limm value?  */
-	  limm_p = arc_opcode_limm_p (&limm);
+/* Find the proper relocation for the given opcode.  */
 
-	  /* Perform various error and warning tests.  */
+static extended_bfd_reloc_code_real_type
+find_reloc (const char *name,
+	    const char *opcodename,
+	    const struct arc_flags *pflags,
+	    int nflg,
+	    extended_bfd_reloc_code_real_type reloc)
+{
+  unsigned int i;
+  int j;
+  bfd_boolean found_flag;
+  extended_bfd_reloc_code_real_type ret = BFD_RELOC_UNUSED;
 
-	  {
-	    static int in_delay_slot_p = 0;
-	    static int prev_insn_needs_cc_nop_p = 0;
-	    /* delay slot type seen */
-	    int delay_slot_type = ARC_DELAY_NONE;
-	    /* conditional execution flag seen */
-	    int conditional = 0;
-	    /* 1 if condition codes are being set */
-	    int cc_set_p = 0;
-	    /* 1 if conditional branch, including `b' "branch always" */
-	    int cond_branch_p = opcode->flags & ARC_OPCODE_COND_BRANCH;
-
-	    for (i = 0; i < num_suffixes; ++i)
+  for (i = 0; i < arc_num_equiv_tab; i++)
+    {
+      const struct arc_reloc_equiv_tab *r = &arc_reloc_equiv[i];
+
+      /* Find the entry.  */
+      if (strcmp (name, r->name))
+	continue;
+      if (r->mnemonic && (strcmp (r->mnemonic, opcodename)))
+	continue;
+      if (r->flagcode)
+	{
+	  if (!nflg)
+	    continue;
+	  found_flag = FALSE;
+	  for (j = 0; j < nflg; j++)
+	    if (pflags[i].code == r->flagcode)
 	      {
-		switch (arc_operands[insn_suffixes[i]->type].fmt)
-		  {
-		  case 'n':
-		    delay_slot_type = insn_suffixes[i]->value;
-		    break;
-		  case 'q':
-		    conditional = insn_suffixes[i]->value;
-		    break;
-		  case 'f':
-		    cc_set_p = 1;
-		    break;
-		  }
+		found_flag = TRUE;
+		break;
 	      }
+	  if (!found_flag)
+	    continue;
+	}
 
-	    /* Putting an insn with a limm value in a delay slot is supposed to
-	       be legal, but let's warn the user anyway.  Ditto for 8 byte
-	       jumps with delay slots.  */
-	    if (in_delay_slot_p && limm_p)
-	      as_warn (_("8 byte instruction in delay slot"));
-	    if (delay_slot_type != ARC_DELAY_NONE
-		&& limm_p && arc_insn_not_jl (insn)) /* except for jl  addr */
-	      as_warn (_("8 byte jump instruction with delay slot"));
-	    in_delay_slot_p = (delay_slot_type != ARC_DELAY_NONE) && !limm_p;
-
-	    /* Warn when a conditional branch immediately follows a set of
-	       the condition codes.  Note that this needn't be done if the
-	       insn that sets the condition codes uses a limm.  */
-	    if (cond_branch_p && conditional != 0 /* 0 = "always" */
-		&& prev_insn_needs_cc_nop_p && arc_mach_type == bfd_mach_arc_5)
-	      as_warn (_("conditional branch follows set of flags"));
-	    prev_insn_needs_cc_nop_p =
-	      /* FIXME: ??? not required:
-		 (delay_slot_type != ARC_DELAY_NONE) &&  */
-	      cc_set_p && !limm_p;
-	  }
+      if (reloc != r->oldreloc)
+	continue;
+      /* Found it.  */
+      ret = r->newreloc;
+      break;
+    }
+
+  if (ret == BFD_RELOC_UNUSED)
+    as_bad (_("Unable to find %s relocation for instruction %s"),
+	    name, opcodename);
+  return ret;
+}
+
+/* Turn an opcode description and a set of arguments into
+   an instruction and a fixup.  */
+
+static void
+assemble_insn (const struct arc_opcode *opcode,
+	       const expressionS *tok,
+	       int ntok,
+	       const struct arc_flags *pflags,
+	       int nflg,
+	       struct arc_insn *insn)
+{
+  const expressionS *reloc_exp = NULL;
+  unsigned image;
+  const unsigned char *argidx;
+  int i;
+  int tokidx = 0;
+  unsigned char pcrel = 0;
+  bfd_boolean needGOTSymbol;
+  unsigned char has_delay_slot = 0;
+  extended_bfd_reloc_code_real_type reloc;
+
+  memset (insn, 0, sizeof (*insn));
+  image = opcode->opcode;
+
+  pr_debug ("%s:%d: assemble_insn: %s using opcode %x\n",
+	    frag_now->fr_file, frag_now->fr_line, opcode->name,
+	    opcode->opcode);
+
+  /* Handle operands.  */
+  for (argidx = opcode->operands; *argidx; ++argidx)
+    {
+      const struct arc_operand *operand = &arc_operands[*argidx];
+      const expressionS *t = (const expressionS *) 0;
+
+      if ((operand->flags & ARC_OPERAND_FAKE)
+	  && !(operand->flags & ARC_OPERAND_BRAKET))
+	continue;
 
-	  /* Write out the instruction.
-	     It is important to fetch enough space in one call to `frag_more'.
-	     We use (f - frag_now->fr_literal) to compute where we are and we
-	     don't want frag_now to change between calls.  */
-	  if (limm_p)
+      if (operand->flags & ARC_OPERAND_DUPLICATE)
+	{
+	  /* Duplicate operand, already inserted.  */
+	  tokidx ++;
+	  continue;
+	}
+
+      if (tokidx >= ntok)
+	{
+	  abort ();
+	}
+      else
+	t = &tok[tokidx++];
+
+      /* Regardless if we have a reloc or not mark the instruction
+	 limm if it is the case.  */
+      if (operand->flags & ARC_OPERAND_LIMM)
+	insn->has_limm = 1;
+
+      switch (t->X_op)
+	{
+	case O_register:
+	  image = insert_operand (image, operand, regno (t->X_add_number),
+				  NULL, 0);
+	  break;
+
+	case O_constant:
+	  image = insert_operand (image, operand, t->X_add_number, NULL, 0);
+	  reloc_exp = t;
+	  if (operand->flags & ARC_OPERAND_LIMM)
+	    insn->limm = t->X_add_number;
+	  break;
+
+	case O_bracket:
+	  /* Ignore brackets.  */
+	  break;
+
+	case O_absent:
+	  gas_assert (operand->flags & ARC_OPERAND_IGNORE);
+	  break;
+
+	case O_subtract:
+	  /* Maybe register range.  */
+	  if ((t->X_add_number == 0)
+	      && contains_register (t->X_add_symbol)
+	      && contains_register (t->X_op_symbol))
 	    {
-	      f = frag_more (8);
-	      md_number_to_chars (f, insn, 4);
-	      md_number_to_chars (f + 4, limm, 4);
-	      dwarf2_emit_insn (8);
+	      int regs;
+	      regs = get_register (t->X_add_symbol);
+	      regs <<= 16;
+	      regs |= get_register (t->X_op_symbol);
+	      image = insert_operand (image, operand, regs, NULL, 0);
+	      break;
 	    }
-	  else if (limm_reloc_p)
-	    /* We need a limm reloc, but the tables think we don't.  */
-	    abort ();
-	  else
+
+	default:
+	  /* This operand needs a relocation.  */
+	  needGOTSymbol = FALSE;
+
+	  switch (t->X_md)
 	    {
-	      f = frag_more (4);
-	      md_number_to_chars (f, insn, 4);
-	      dwarf2_emit_insn (4);
+	    case O_plt:
+	      needGOTSymbol = TRUE;
+	      reloc = find_reloc ("plt", opcode->name,
+				  pflags, nflg,
+				  operand->default_reloc);
+	      break;
+
+	    case O_gotoff:
+	    case O_gotpc:
+	      needGOTSymbol = TRUE;
+	      reloc = ARC_RELOC_TABLE (t->X_md)->reloc;
+	      break;
+	    case O_pcl:
+	      reloc = ARC_RELOC_TABLE (t->X_md)->reloc;
+	      if (ARC_SHORT (opcode->mask))
+		as_bad_where (frag_now->fr_file, frag_now->fr_line,
+			      _("Unable to use @pcl relocation for insn %s"),
+			      opcode->name);
+	      break;
+	    case O_sda:
+	      reloc = find_reloc ("sda", opcode->name,
+				  pflags, nflg,
+				  operand->default_reloc);
+	      break;
+	    case O_tlsgd:
+	    case O_tlsie:
+	      needGOTSymbol = TRUE;
+	      /* Fall-through.  */
+
+	    case O_tpoff:
+	    case O_dtpoff:
+	      reloc = ARC_RELOC_TABLE (t->X_md)->reloc;
+	      break;
+
+	    case O_tpoff9: /*FIXME! Check for the conditionality of the insn.  */
+	    case O_dtpoff9: /*FIXME! Check for the conditionality of the insn.  */
+	      as_bad (_("TLS_*_S9 relocs are not supported yet"));
+	      break;
+
+	    default:
+	      /* Just consider the default relocation.  */
+	      reloc = operand->default_reloc;
+	      break;
 	    }
 
-	  /* Create any fixups.  */
-	  for (i = 0; i < fc; ++i)
+	  if (needGOTSymbol && (GOT_symbol == NULL))
+	    GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
+
+	  reloc_exp = t;
+
+#if 0
+	  if (reloc > 0)
 	    {
-	      int op_type, reloc_type;
-	      expressionS exptmp;
-	      const struct arc_operand *operand;
-
-	      /* Create a fixup for this operand.
-		 At this point we do not use a bfd_reloc_code_real_type for
-		 operands residing in the insn, but instead just use the
-		 operand index.  This lets us easily handle fixups for any
-		 operand type, although that is admittedly not a very exciting
-		 feature.  We pick a BFD reloc type in md_apply_fix.
-
-		 Limm values (4 byte immediate "constants") must be treated
-		 normally because they're not part of the actual insn word
-		 and thus the insertion routines don't handle them.  */
-
-	      if (arc_operands[fixups[i].opindex].flags & ARC_OPERAND_LIMM)
-		{
-		  /* Modify the fixup addend as required by the cpu.  */
-		  fixups[i].exp.X_add_number += arc_limm_fixup_adjust (insn);
-		  op_type = fixups[i].opindex;
-		  /* FIXME: can we add this data to the operand table?  */
-		  if (op_type == arc_operand_map['L']
-		      || op_type == arc_operand_map['s']
-		      || op_type == arc_operand_map['o']
-		      || op_type == arc_operand_map['O'])
-		    reloc_type = BFD_RELOC_32;
-		  else if (op_type == arc_operand_map['J'])
-		    reloc_type = BFD_RELOC_ARC_B26;
-		  else
-		    abort ();
-		  reloc_type = get_arc_exp_reloc_type (1, reloc_type,
-						       &fixups[i].exp,
-						       &exptmp);
-		}
-	      else
+	      /* sanity checks.  */
+	      reloc_howto_type *reloc_howto
+		= bfd_reloc_type_lookup (stdoutput,
+					 (bfd_reloc_code_real_type) reloc);
+	      unsigned reloc_bitsize = reloc_howto->bitsize;
+	      if (reloc_howto->rightshift)
+		reloc_bitsize -= reloc_howto->rightshift;
+	      if (reloc_bitsize != operand->bits)
 		{
-		  op_type = get_arc_exp_reloc_type (0, fixups[i].opindex,
-						    &fixups[i].exp, &exptmp);
-		  reloc_type = op_type + (int) BFD_RELOC_UNUSED;
+		  as_bad (_("invalid relocation %s for field"),
+			  bfd_get_reloc_code_name (reloc));
+		  return;
 		}
-	      operand = &arc_operands[op_type];
-	      fix_new_exp (frag_now,
-			   ((f - frag_now->fr_literal)
-			    + (operand->flags & ARC_OPERAND_LIMM ? 4 : 0)), 4,
-			   &exptmp,
-			   (operand->flags & ARC_OPERAND_RELATIVE_BRANCH) != 0,
-			   (bfd_reloc_code_real_type) reloc_type);
 	    }
-	  return;
+#endif
+	  if (insn->nfixups >= MAX_INSN_FIXUPS)
+	    as_fatal (_("too many fixups"));
+
+	  struct arc_fixup *fixup;
+	  fixup = &insn->fixups[insn->nfixups++];
+	  fixup->exp = *t;
+	  fixup->reloc = reloc;
+	  pcrel = (operand->flags & ARC_OPERAND_PCREL) ? 1 : 0;
+	  fixup->pcrel = pcrel;
+	  fixup->islong = (operand->flags & ARC_OPERAND_LIMM) ?
+	    TRUE : FALSE;
+	  break;
 	}
     }
 
-  if (NULL == last_errmsg)
-    as_bad (_("bad instruction `%s'"), start);
+  /* Handle flags.  */
+  for (i = 0; i < nflg; i++)
+    {
+      const struct arc_flag_operand *flg_operand =
+	&arc_flag_operands[pflags[i].code];
+
+      /* Check if the instruction has a delay slot.  */
+      if (!strcmp (flg_operand->name, "d"))
+	has_delay_slot = 1;
+
+      /* There is an exceptional case when we cannot insert a flag
+	 just as it is.  The .T flag must be handled in relation with
+	 the relative address.  */
+      if (!strcmp (flg_operand->name, "t")
+	  || !strcmp (flg_operand->name, "nt"))
+	{
+	  unsigned bitYoperand = 0;
+	  /* FIXME! move selection bbit/brcc in arc-opc.c.  */
+	  if (!strcmp (flg_operand->name, "t"))
+	    if (!strcmp (opcode->name, "bbit0")
+		|| !strcmp (opcode->name, "bbit1"))
+	      bitYoperand = arc_NToperand;
+	    else
+	      bitYoperand = arc_Toperand;
+	  else
+	    if (!strcmp (opcode->name, "bbit0")
+		|| !strcmp (opcode->name, "bbit1"))
+	      bitYoperand = arc_Toperand;
+	    else
+	      bitYoperand = arc_NToperand;
+
+	  gas_assert (reloc_exp != NULL);
+	  if (reloc_exp->X_op == O_constant)
+	    {
+	      /* Check if we have a constant and solved it
+		 immediately.  */
+	      offsetT val = reloc_exp->X_add_number;
+	      image |= insert_operand (image, &arc_operands[bitYoperand],
+				       val, NULL, 0);
+	    }
+	  else
+	    {
+	      struct arc_fixup *fixup;
+
+	      if (insn->nfixups >= MAX_INSN_FIXUPS)
+		as_fatal (_("too many fixups"));
+
+	      fixup = &insn->fixups[insn->nfixups++];
+	      fixup->exp = *reloc_exp;
+	      fixup->reloc = -bitYoperand;
+	      fixup->pcrel = pcrel;
+	      fixup->islong = FALSE;
+	    }
+	}
+      else
+	image |= (flg_operand->code & ((1 << flg_operand->bits) - 1))
+	  << flg_operand->shift;
+    }
+
+  /* Short instruction?  */
+  insn->short_insn = ARC_SHORT (opcode->mask);
+
+  insn->insn = image;
+
+  /* Update last insn status.  */
+  arc_last_insns[1]		   = arc_last_insns[0];
+  arc_last_insns[0].opcode	   = opcode;
+  arc_last_insns[0].has_limm	   = insn->has_limm;
+  arc_last_insns[0].has_delay_slot = has_delay_slot;
+
+  /* Check if the current instruction is legally used.  */
+  if (arc_last_insns[1].has_delay_slot
+      && is_br_jmp_insn_p (arc_last_insns[0].opcode))
+    as_bad_where (frag_now->fr_file, frag_now->fr_line,
+		  _("A jump/branch instruction in delay slot."));
+}
+
+/* Actually output an instruction with its fixup.  */
+
+static void
+emit_insn (struct arc_insn *insn)
+{
+  char *f;
+  int i;
+
+  pr_debug ("Emit insn : 0x%x\n", insn->insn);
+  pr_debug ("\tShort   : 0x%d\n", insn->short_insn);
+  pr_debug ("\tLong imm: 0x%lx\n", insn->limm);
+
+  /* Write out the instruction.  */
+  if (insn->short_insn)
+    {
+      if (insn->has_limm)
+	{
+	  f = frag_more (6);
+	  md_number_to_chars (f, insn->insn, 2);
+	  md_number_to_chars_midend (f + 2, insn->limm, 4);
+	  dwarf2_emit_insn (6);
+	}
+      else
+	{
+	  f = frag_more (2);
+	  md_number_to_chars (f, insn->insn, 2);
+	  dwarf2_emit_insn (2);
+	}
+    }
   else
-    as_bad ("%s", last_errmsg);
+    {
+      if (insn->has_limm)
+	{
+	  f = frag_more (8);
+	  md_number_to_chars_midend (f, insn->insn, 4);
+	  md_number_to_chars_midend (f + 4, insn->limm, 4);
+	  dwarf2_emit_insn (8);
+	}
+      else
+	{
+	  f = frag_more (4);
+	  md_number_to_chars_midend (f, insn->insn, 4);
+	  dwarf2_emit_insn (4);
+	}
+    }
+
+  /* Apply the fixups in order.  */
+  for (i = 0; i < insn->nfixups; i++)
+    {
+      struct arc_fixup *fixup = &insn->fixups[i];
+      int size, pcrel, offset = 0;
+
+      /*FIXME! the reloc size is wrong in the BFD file.  When it will
+	be fixed please delete me.  */
+      size = (insn->short_insn && !fixup->islong) ? 2 : 4;
+
+      if (fixup->islong)
+	offset = (insn->short_insn) ? 2 : 4;
+
+      /* Some fixups are only used internally, thus no howto.  */
+      if ((int) fixup->reloc < 0)
+	{
+	  /*FIXME! the reloc size is wrong in the BFD file.  When it
+	    will be fixed please enable me.
+	    size = (insn->short_insn && !fixup->islong) ? 2 : 4; */
+	  pcrel = fixup->pcrel;
+	}
+      else
+	{
+	  reloc_howto_type *reloc_howto =
+	    bfd_reloc_type_lookup (stdoutput,
+				   (bfd_reloc_code_real_type) fixup->reloc);
+	  gas_assert (reloc_howto);
+	  /*FIXME! the reloc size is wrong in the BFD file.  When it
+	    will be fixed please enable me.
+	    size = bfd_get_reloc_size (reloc_howto); */
+	  pcrel = reloc_howto->pc_relative;
+	}
+
+      pr_debug ("%s:%d: emit_insn: new %s fixup (PCrel:%s) of size %d @ offset %d\n",
+		frag_now->fr_file, frag_now->fr_line,
+		(fixup->reloc < 0) ? "Internal" :
+		bfd_get_reloc_code_name (fixup->reloc),
+		pcrel ? "Y" : "N",
+		size, offset);
+      fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
+		   size, &fixup->exp, pcrel, fixup->reloc);
+
+      /* Check for ZOLs, and update symbol info if any.  */
+      if (LP_INSN (insn->insn))
+	{
+	  gas_assert (fixup->exp.X_add_symbol);
+	  ARC_SET_FLAG (fixup->exp.X_add_symbol, ARC_FLAG_ZOL);
+	}
+    }
+}
+
+/* Insert an operand value into an instruction.  */
+
+static unsigned
+insert_operand (unsigned insn,
+		const struct arc_operand *operand,
+		offsetT val,
+		char *file,
+		unsigned line)
+{
+  offsetT min = 0, max = 0;
+
+  if (operand->bits != 32
+      && !(operand->flags & ARC_OPERAND_NCHK)
+      && !(operand->flags & ARC_OPERAND_FAKE))
+    {
+      if (operand->flags & ARC_OPERAND_SIGNED)
+	{
+	  max = (1 << (operand->bits - 1)) - 1;
+	  min = -(1 << (operand->bits - 1));
+	}
+      else
+	{
+	  max = (1 << operand->bits) - 1;
+	  min = 0;
+	}
+
+      if (val < min || val > max)
+	as_bad_value_out_of_range (_("operand"),
+				   val, min, max, file, line);
+    }
+
+  pr_debug ("insert field: %ld <= %ld <= %ld in 0x%08x\n",
+	    min, val, max, insn);
+
+  if ((operand->flags & ARC_OPERAND_ALIGNED32)
+      && (val & 0x03))
+    as_bad_where (file, line,
+		  _("Unaligned operand. Needs to be 32bit aligned"));
+
+  if ((operand->flags & ARC_OPERAND_ALIGNED16)
+      && (val & 0x01))
+    as_bad_where (file, line,
+		  _("Unaligned operand. Needs to be 16bit aligned"));
+
+  if (operand->insert)
+    {
+      const char *errmsg = NULL;
+
+      insn = (*operand->insert) (insn, val, &errmsg);
+      if (errmsg)
+	as_warn_where (file, line, "%s", errmsg);
+    }
+  else
+    {
+      if (operand->flags & ARC_OPERAND_TRUNCATE)
+	{
+	  if (operand->flags & ARC_OPERAND_ALIGNED32)
+	    val >>= 2;
+	  if (operand->flags & ARC_OPERAND_ALIGNED16)
+	    val >>= 1;
+	}
+      insn |= ((val & ((1 << operand->bits) - 1)) << operand->shift);
+    }
+  return insn;
+}
+
+void
+arc_handle_align (fragS* fragP)
+{
+  if ((fragP)->fr_type == rs_align_code)
+    {
+      char *dest = (fragP)->fr_literal + (fragP)->fr_fix;
+      valueT count = ((fragP)->fr_next->fr_address
+		      - (fragP)->fr_address - (fragP)->fr_fix);
+
+      (fragP)->fr_var = 2;
+
+      if (count & 1)/* Padding in the gap till the next 2-byte
+		       boundary with 0s.  */
+	{
+	  (fragP)->fr_fix++;
+	  *dest++ = 0;
+	}
+      md_number_to_chars (dest, 0x78e0, 2);  /*writing nop_s.  */
+    }
+}
+
+/* Here we decide which fixups can be adjusted to make them relative
+   to the beginning of the section instead of the symbol.  Basically
+   we need to make sure that the dynamic relocations are done
+   correctly, so in some cases we force the original symbol to be
+   used.  */
+
+int
+tc_arc_fix_adjustable (fixS *fixP)
+{
+
+  /* Prevent all adjustments to global symbols.  */
+  if (S_IS_EXTERNAL (fixP->fx_addsy))
+    return 0;
+  if (S_IS_WEAK (fixP->fx_addsy))
+    return 0;
+
+  /* adjust_reloc_syms doesn't know about the GOT.  */
+  switch (fixP->fx_r_type)
+    {
+    case BFD_RELOC_ARC_GOTPC32:
+    case BFD_RELOC_ARC_PLT32:
+    case BFD_RELOC_ARC_S25H_PCREL_PLT:
+    case BFD_RELOC_ARC_S21H_PCREL_PLT:
+    case BFD_RELOC_ARC_S25W_PCREL_PLT:
+    case BFD_RELOC_ARC_S21W_PCREL_PLT:
+      return 0;
+
+    default:
+      break;
+    }
+
+  return 0; /* FIXME! return 1, fix it in the linker.  */
+}
+
+/* Compute the reloc type of an expression EXP.  */
+
+static void
+arc_check_reloc (expressionS *exp,
+		 bfd_reloc_code_real_type *r_type_p)
+{
+  if (*r_type_p == BFD_RELOC_32
+      && exp->X_op == O_subtract
+      && exp->X_op_symbol != NULL
+      && exp->X_op_symbol->bsym->section == now_seg)
+    *r_type_p = BFD_RELOC_ARC_PC32;
+}
+
+
+/* Add expression EXP of SIZE bytes to offset OFF of fragment FRAG.  */
+
+void
+arc_cons_fix_new (fragS *frag,
+		  int off,
+		  int size,
+		  expressionS *exp,
+		  bfd_reloc_code_real_type r_type)
+{
+  r_type = BFD_RELOC_UNUSED;
+
+  switch (size)
+    {
+    case 1:
+      r_type = BFD_RELOC_8;
+      break;
+
+    case 2:
+      r_type = BFD_RELOC_16;
+      break;
+
+    case 3:
+      r_type = BFD_RELOC_24;
+      break;
+
+    case 4:
+      r_type = BFD_RELOC_32;
+      arc_check_reloc (exp, &r_type);
+      break;
+
+    case 8:
+      r_type = BFD_RELOC_64;
+      break;
+
+    default:
+      as_bad (_("unsupported BFD relocation size %u"), size);
+      r_type = BFD_RELOC_UNUSED;
+    }
+
+  fix_new_exp (frag, off, size, exp, 0, r_type);
+}
+
+/* The actual routine that checks the ZOL conditions.  */
+
+static void
+check_zol (symbolS *s)
+{
+  switch (arc_mach_type)
+    {
+    case bfd_mach_arc_arcv2:
+      if (arc_target & ARC_OPCODE_ARCv2EM)
+	return;
+
+      if (is_br_jmp_insn_p (arc_last_insns[0].opcode)
+	  || arc_last_insns[1].has_delay_slot)
+	as_bad (_("Jump/Branch instruction detected at the end of the ZOL label @%s"),
+		S_GET_NAME (s));
+
+      break;
+    case bfd_mach_arc_arc600:
+
+      if (is_kernel_insn_p (arc_last_insns[0].opcode))
+	as_bad (_("Kernel instruction detected at the end of the ZOL label @%s"),
+		S_GET_NAME (s));
+
+      if (arc_last_insns[0].has_limm
+	  && is_br_jmp_insn_p (arc_last_insns[0].opcode))
+	as_bad (_("A jump instruction with long immediate detected at the \
+end of the ZOL label @%s"), S_GET_NAME (s));
+
+      /* Fall through.  */
+    case bfd_mach_arc_arc700:
+      if (arc_last_insns[0].has_delay_slot)
+	as_bad (_("An illegal use of delay slot detected at the end of the ZOL label @%s"),
+		S_GET_NAME (s));
+
+      break;
+    default:
+      break;
+    }
+}
+
+/* If ZOL end check the last two instruction for illegals.  */
+void
+arc_frob_label (symbolS * sym)
+{
+  if (ARC_GET_FLAG (sym) & ARC_FLAG_ZOL)
+    check_zol (sym);
+
+  dwarf2_emit_label (sym);
 }
diff --git a/gas/config/tc-arc.h b/gas/config/tc-arc.h
index 8eda165..beea9db 100644
--- a/gas/config/tc-arc.h
+++ b/gas/config/tc-arc.h
@@ -1,6 +1,7 @@
 /* tc-arc.h - Macros and type defines for the ARC.
-   Copyright (C) 1994-2015 Free Software Foundation, Inc.
-   Contributed by Doug Evans (dje@cygnus.com).
+   Copyright 2014 Free Software Foundation, Inc.
+
+   Contributed by Claudiu Zissulescu (claziss@synopsys.com)
 
    This file is part of GAS, the GNU Assembler.
 
@@ -19,56 +20,170 @@
    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
    02110-1301, USA.  */
 
-#define TC_ARC 1
 
-#define TARGET_BYTES_BIG_ENDIAN 0
+/* By convention, you should define this macro in the `.h' file.  For
+   example, `tc-m68k.h' defines `TC_M68K'.  You might have to use this
+   if it is necessary to add CPU specific code to the object format
+   file.  */
+#define TC_ARC
 
+/* We want local label support.  */
 #define LOCAL_LABELS_FB 1
 
+/* This macro is the BFD architecture to pass to
+   `bfd_set_arch_mach'.  */
 #define TARGET_ARCH bfd_arch_arc
 
+/* `extsym - .' expressions can be emitted using PC-relative
+   relocs.  */
 #define DIFF_EXPR_OK
-#define REGISTER_PREFIX '%'
-
-#ifdef LITTLE_ENDIAN
-#undef LITTLE_ENDIAN
-#endif
 
-#ifdef BIG_ENDIAN
-#undef BIG_ENDIAN
-#endif
+#define REGISTER_PREFIX '%'
 
+#undef  LITTLE_ENDIAN
 #define LITTLE_ENDIAN   1234
 
+#undef  BIG_ENDIAN
 #define BIG_ENDIAN      4321
 
+#ifdef TARGET_BYTES_BIG_ENDIAN
+
+# define DEFAULT_TARGET_FORMAT  "elf32-bigarc"
+# define DEFAULT_BYTE_ORDER     BIG_ENDIAN
+
+#else
+/* You should define this macro to be non-zero if the target is big
+   endian, and zero if the target is little endian.  */
+# define TARGET_BYTES_BIG_ENDIAN 0
+
+# define DEFAULT_TARGET_FORMAT  "elf32-littlearc"
+# define DEFAULT_BYTE_ORDER     LITTLE_ENDIAN
+
+#endif /* TARGET_BYTES_BIG_ENDIAN.  */
+
 /* The endianness of the target format may change based on command
    line arguments.  */
-extern const char * arc_target_format;
-
-#define DEFAULT_TARGET_FORMAT  "elf32-littlearc"
-#define TARGET_FORMAT          arc_target_format
-#define DEFAULT_BYTE_ORDER     LITTLE_ENDIAN
+extern const char *arc_target_format;
+
+/* This macro is the BFD target name to use when creating the output
+   file.  This will normally depend upon the `OBJ_FMT' macro.  */
+#define TARGET_FORMAT arc_target_format
+
+/* `md_short_jump_size'
+   `md_long_jump_size'
+   `md_create_short_jump'
+   `md_create_long_jump'
+
+   If `WORKING_DOT_WORD' is defined, GAS will not do broken word
+   processing (*note Broken words::.).  Otherwise, you should set
+   `md_short_jump_size' to the size of a short jump (a jump that is
+   just long enough to jump around a long jmp) and `md_long_jump_size'
+   to the size of a long jump (a jump that can go anywhere in the
+   function).  You should define `md_create_short_jump' to create a
+   short jump around a long jump, and define `md_create_long_jump' to
+   create a long jump.  */
 #define WORKING_DOT_WORD
-#define LISTING_HEADER         "ARC GAS "
 
-/* The ARC needs to parse reloc specifiers in .word.  */
+#define LISTING_HEADER "ARC GAS "
 
-extern bfd_reloc_code_real_type arc_parse_cons_expression (struct expressionS *,
-							   unsigned);
-#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) \
-  arc_parse_cons_expression (EXP, NBYTES)
+/* The number of bytes to put into a word in a listing.  This affects
+   the way the bytes are clumped together in the listing.  For
+   example, a value of 2 might print `1234 5678' where a value of 1
+   would print `12 34 56 78'.  The default value is 4.  */
+#define LISTING_WORD_SIZE 2
 
-extern void arc_cons_fix_new (struct frag *, int, int, struct expressionS *,
-			      bfd_reloc_code_real_type);
-#define TC_CONS_FIX_NEW(FRAG, WHERE, NBYTES, EXP, RELOC)	\
-  arc_cons_fix_new (FRAG, WHERE, NBYTES, EXP, RELOC)
+/* If you define this macro, it should return the position from which
+   the PC relative adjustment for a PC relative fixup should be made.
+   On many processors, the base of a PC relative instruction is the
+   next instruction, so this macro would return the length of an
+   instruction, plus the address of the PC relative fixup.  The latter
+   can be calculated as fixp->fx_where +
+   fixp->fx_frag->fr_address.  */
+extern long md_pcrel_from_section (struct fix *, segT);
+#define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from_section (FIX, SEC)
+
+/* [ ] is index operator.  */
+#define NEED_INDEX_OPERATOR
 
-#define DWARF2_LINE_MIN_INSN_LENGTH 4
+#define MAX_MEM_FOR_RS_ALIGN_CODE (1+2)
 
-/* Values passed to md_apply_fix don't include the symbol value.  */
+/* HANDLE_ALIGN called after all the assembly has been done,
+   so we can fill in all the rs_align_code type frags with
+   nop instructions.  */
+#define HANDLE_ALIGN(FRAGP)	 arc_handle_align(FRAGP)
+
+/* Values passed to md_apply_fix3 don't include the symbol value.  */
 #define MD_APPLY_SYM_VALUE(FIX) 0
 
 /* No shared lib support, so we don't need to ensure externally
    visible symbols can be overridden.  */
 #define EXTERN_FORCE_RELOC 0
+
+/* You may define this macro to generate a fixup for a data allocation
+   pseudo-op.  */
+#define TC_CONS_FIX_NEW(FRAG, OFF, LEN, EXP, RELOC)	\
+  arc_cons_fix_new ((FRAG), (OFF), (LEN), (EXP), (RELOC))
+
+/* We don't want gas to fixup the following program memory related
+   relocations.  */
+#define TC_VALIDATE_FIX(FIXP,SEG,SKIP)			     \
+  if ((FIXP->fx_r_type == BFD_RELOC_ARC_GOTPC32)	     \
+      && FIXP->fx_addsy != NULL				     \
+      && FIXP->fx_subsy == NULL)			     \
+    {							     \
+      symbol_mark_used_in_reloc (FIXP->fx_addsy);	     \
+      goto SKIP;					     \
+    }
+
+/* BFD_RELOC_ARC_TLS_GD_LD may use fx_subsy to store a label that is
+   later turned into fx_offset.  */
+#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX, SEG) \
+  ((FIX)->fx_r_type == BFD_RELOC_ARC_TLS_GD_LD)
+
+#define TC_VALIDATE_FIX_SUB(FIX, SEG) \
+  ((md_register_arithmetic || (SEG) != reg_section) \
+   && ((FIX)->fx_r_type == BFD_RELOC_GPREL32 \
+       || (FIX)->fx_r_type == BFD_RELOC_GPREL16 \
+       || (FIX)->fx_r_type == BFD_RELOC_ARC_TLS_DTPOFF \
+       || (FIX)->fx_r_type == BFD_RELOC_ARC_TLS_DTPOFF_S9 \
+       || TC_FORCE_RELOCATION_SUB_LOCAL (FIX, SEG)))
+
+/* We use this to mark the end-loop label.  We use this mark for ZOL
+   validity checks.  */
+#define TC_SYMFIELD_TYPE   unsigned int
+#define ARC_GET_FLAG(s)   (*symbol_get_tc (s))
+#define ARC_SET_FLAG(s,v) (*symbol_get_tc (s) |= (v))
+
+/* The symbol is a ZOL's end loop label.  */
+#define ARC_FLAG_ZOL      (1 << 0)
+
+/* We use this hook to check the validity of the last to instructions
+   of a ZOL.  */
+#define tc_frob_label(S)  arc_frob_label (S)
+
+#define GLOBAL_OFFSET_TABLE_NAME "_GLOBAL_OFFSET_TABLE_"
+#define DYNAMIC_STRUCT_NAME "_DYNAMIC"
+
+/* We need to take care of not having section relative fixups for the
+   fixups with respect to Position Independent Code.  */
+#define tc_fix_adjustable(FIX)  tc_arc_fix_adjustable(FIX)
+
+/* This hook is required to parse register names as operands.  */
+#define md_parse_name(name, exp, m, c) arc_parse_name (name, exp)
+
+extern int arc_parse_name (const char *, struct expressionS *);
+extern int tc_arc_fix_adjustable (struct fix *);
+extern void arc_handle_align (fragS* fragP);
+extern void arc_cons_fix_new (fragS *, int, int, expressionS *,
+			      bfd_reloc_code_real_type);
+extern void arc_frob_label (symbolS *);
+
+/* The blink register is r31.  */
+#define DWARF2_DEFAULT_RETURN_COLUMN	31
+/* Registers are generally saved at negative offsets to the CFA.  */
+#define DWARF2_CIE_DATA_ALIGNMENT	(-4)
+
+/* Define the NOPs (the first one is also used by generic code).  */
+#define NOP_OPCODE   0x000078E0
+#define NOP_OPCODE_L 0x264A7000 /* mov 0,0.  */
+
diff --git a/gas/configure.tgt b/gas/configure.tgt
index 00fa104..0b490d4 100644
--- a/gas/configure.tgt
+++ b/gas/configure.tgt
@@ -6,12 +6,12 @@
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
-#
+# 
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
-#
+# 
 # You should have received a copy of the GNU General Public License
 # along with this program; see the file COPYING3.  If not see
 # <http://www.gnu.org/licenses/>.
@@ -50,6 +50,7 @@ case ${cpu} in
   aarch64_be)		cpu_type=aarch64 endian=big ;;
   alpha*)		cpu_type=alpha ;;
   am33_2.0)		cpu_type=mn10300 endian=little ;;
+  arc*eb)		cpu_type=arc endian=big ;;
   arm*be|arm*b)		cpu_type=arm endian=big ;;
   arm*)			cpu_type=arm endian=little ;;
   bfin*)		cpu_type=bfin endian=little ;;
@@ -130,6 +131,7 @@ case ${generic_target} in
   alpha-*-openbsd*)			fmt=elf em=obsd ;;
 
   arc-*-elf*)				fmt=elf ;;
+  arc*-*-linux-uclibc*)			fmt=elf bfd_gas=yes ;;
 
   arm-*-aout)				fmt=aout ;;
   arm-*-coff)				fmt=coff ;;
@@ -352,7 +354,7 @@ case ${generic_target} in
   moxie-*-uclinux)			fmt=elf em=linux ;;
   moxie-*-moxiebox*)                    fmt=elf endian=little ;;
   moxie-*-*)				fmt=elf ;;
-
+    
   mt-*-elf)				fmt=elf bfd_gas=yes ;;
 
   msp430-*-*)				fmt=elf ;;
@@ -461,7 +463,7 @@ case ${generic_target} in
   visium-*-elf)				fmt=elf ;;
 
   xstormy16-*-*)			fmt=elf ;;
-
+  
   xgate-*-*)    			fmt=elf ;;
 
   xtensa*-*-*)				fmt=elf ;;
diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo
index fa3221e..4ed29d1 100644
--- a/gas/doc/as.texinfo
+++ b/gas/doc/as.texinfo
@@ -265,7 +265,9 @@ gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}.
 @ifset ARC
 
 @emph{Target ARC options:}
-   [@b{-marc[5|6|7|8]}]
+   [@b{-mcpu=@var{cpu}}]
+   [@b{-mA6}|@b{-mARC600}|@b{-mARC601}|@b{-mA7}|@b{-mARC700}|@b{-mEM}|@b{-mHS}]
+   [@b{-mcode-density}]
    [@b{-EB}|@b{-EL}]
 @end ifset
 @ifset ARM
@@ -860,14 +862,16 @@ processor.
 
 @c man begin OPTIONS
 @ifset ARC
-The following options are available when @value{AS} is configured for
-an ARC processor.
+The following options are available when @value{AS} is configured for an ARC
+processor.
 
 @table @gcctabopt
-@item -marc[5|6|7|8]
+@item -mcpu=@var{cpu}
 This option selects the core processor variant.
 @item -EB | -EL
 Select either big-endian (-EB) or little-endian (-EL) output.
+@item -mcode-density
+Enable Code Density extenssion instructions.
 @end table
 @end ifset
 
diff --git a/gas/doc/c-arc.texi b/gas/doc/c-arc.texi
index 9fa28e5..f72ecae 100644
--- a/gas/doc/c-arc.texi
+++ b/gas/doc/c-arc.texi
@@ -19,52 +19,54 @@
 @menu
 * ARC Options::              Options
 * ARC Syntax::               Syntax
-* ARC Floating Point::       Floating Point
 * ARC Directives::           ARC Machine Directives
+* ARC Modifiers::            ARC Assembler Modifiers
+* ARC Symbols::              ARC Pre-defined Symbols
 * ARC Opcodes::              Opcodes
 @end menu
 
-
 @node ARC Options
 @section Options
-@cindex ARC options (none)
-@cindex options for ARC (none)
+@cindex ARC options
+@cindex options for ARC
+
+The following options control the type of CPU for which code is
+assembled, and generic constraints on the code generated:
 
 @table @code
 
-@cindex @code{-marc[5|6|7|8]} command line option, ARC
-@item -marc[5|6|7|8]
-This option selects the core processor variant.  Using
-@code{-marc} is the same as @code{-marc@value{ARC_CORE_DEFAULT}}, which
-is also the default.
+@item -mcpu=@var{cpu}
+@cindex @code{-mcpu=@var{cpu}} command line option, ARC
+Set architecture type and register usage for @var{cpu}.  There are
+also shortcut alias options available for backward compatibility and
+convenience.  Supported values for @var{cpu} are
 
 @table @code
+@cindex @code{mA6} command line option, ARC
+@cindex @code{marc600} command line option, ARC
+@item arc600
+Assemble for ARC 600.  Aliases: @code{-mA6}, @code{-mARC600}.
 
-@cindex @code{arc5} arc5, ARC
-@item arc5
-Base instruction set.
+@item arc601
+@cindex @code{mARC601} command line option, ARC
+Assemble for ARC 601.  Alias: @code{-mARC601}.
 
-@cindex @code{arc6} arc6, ARC
-@item arc6
-Jump-and-link (jl) instruction.  No requirement of an instruction between
-setting flags and conditional jump.  For example:
+@item arc700
+@cindex @code{mA7} command line option, ARC
+@cindex @code{mARC700} command line option, ARC
+Assemble for ARC 700.  Aliases: @code{-mA7}, @code{-mARC700}.
 
-@smallexample
-  mov.f r0,r1
-  beq   foo
-@end smallexample
+@item arcem
+@cindex @code{mEM} command line option, ARC
+Assemble for ARC EM.  Aliases: @code{-mEM}
 
-@cindex @code{arc7} arc7, ARC
-@item arc7
-Break (brk) and sleep (sleep) instructions.
-
-@cindex @code{arc8} arc8, ARC
-@item arc8
-Software interrupt (swi) instruction.
+@item archs
+@cindex @code{mHS} command line option, ARC
+Assemble for ARC HS.  Aliases: @code{-mHS}, @code{-mav2hs}.
 
 @end table
 
-Note: the @code{.option} directive can to be used to select a core
+Note: the @code{.cpu} directive can to be used to select a core
 variant from within assembly code.
 
 @cindex @code{-EB} command line option, ARC
@@ -78,6 +80,11 @@ This option specifies that the output generated by the assembler should
 be marked as being encoded for a little-endian processor - this is the
 default.
 
+@cindex @code{-mcode-density} command line option, ARC
+@item -mcode-density
+This option turns on Code Density instructions.  Only valid for ARC EM
+processors.
+
 @end table
 
 @node ARC Syntax
@@ -90,36 +97,211 @@ default.
 @node ARC-Chars
 @subsection Special Characters
 
+@table @code
+@item %
+@cindex register name prefix character, ARC
+@cindex ARC register name prefix character
+A register name can optionally be prefixed by a @samp{%} character.  So
+register @code{%r0} is equivalent to @code{r0} in the assembly code.
+
+@item #
 @cindex line comment character, ARC
 @cindex ARC line comment character
-The presence of a @samp{#} on a line indicates the start of a comment
-that extends to the end of the current line.  Note that if a line
-starts with a @samp{#} character then it can also be a logical line
-number directive (@pxref{Comments}) or a preprocessor
-control command (@pxref{Preprocessing}).
-
+The presence of a @samp{#} character within a line (but not at the
+start of a line) indicates the start of a comment that extends to the
+end of the current line.
+
+@emph{Note:} if a line starts with a @samp{#} character then it can
+also be a logical line number directive (@pxref{Comments}) or a
+preprocessor control command (@pxref{Preprocessing}).
+
+@item @@
+@cindex symbol prefix character, ARC
+@cindex ARC symbol prefix character
+Prefixing an operand with an @samp{@@} specifies that the operand is a
+symbol and not a register.  This is how the assembler disambiguates
+the use of an ARC register name as a symbol.  So the instruction
+@example
+mov r0, @@r0
+@end example
+moves the address of symbol @code{r0} into register @code{r0}.
+
+@item `
 @cindex line separator, ARC
 @cindex statement separator, ARC
 @cindex ARC line separator
-The ARC assembler does not support a line separator character.
+The @samp{`} (backtick) character is used to separate statements on a
+single line.
+
+@cindex line
+@item -
+@cindex C preprocessor macro separator, ARC
+@cindex ARC C preprocessor macro separator
+Used as a separator to obtain a sequence of commands from a C
+preprocessor macro.
+
+@end table
 
 @node ARC-Regs
 @subsection Register Names
 
 @cindex ARC register names
 @cindex register names, ARC
-*TODO*
+The ARC assembler uses the following register names for its core
+registers:
+
+@table @code
+@item r0-r31
+@cindex core general registers, ARC
+@cindex ARC core general registers
+The core general registers.  Registers @code{r26} through @code{r31}
+have special functions, and are usually referred to by those synonyms.
+
+@item gp
+@cindex global pointer, ARC
+@cindex ARC global pointer
+The global pointer and a synonym for @code{r26}.
+
+@item fp
+@cindex frame pointer, ARC
+@cindex ARC frame pointer
+The frame pointer and a synonym for @code{r27}.
+
+@item sp
+@cindex stack pointer, ARC
+@cindex ARC stack pointer
+The stack pointer and a synonym for @code{r28}.
+
+@item ilink1
+@cindex level 1 interrupt link register, ARC
+@cindex ARC level 1 interrupt link register
+For ARC 600 and ARC 700, the level 1 interrupt link register and a
+synonym for @code{r29}.  Not supported for ARCv2.
+
+@item ilink
+@cindex interrupt link register, ARC
+@cindex ARC interrupt link register
+For ARCv2, the interrupt link register and a synonym for @code{r29}.
+Not supported for ARC 600 and ARC 700.
+
+@item ilink2
+@cindex level 2 interrupt link register, ARC
+@cindex ARC level 2 interrupt link register
+For ARC 600 and ARC 700, the level 2 interrupt link register and a
+synonym for @code{r30}.  Not supported for ARC v2.
+
+@item blink
+@cindex link register, ARC
+@cindex ARC link register
+The link register and a synonym for @code{r31}.
+
+@item r32-r59
+@cindex extension core registers, ARC
+@cindex ARC extension core registers
+The extension core registers.
+
+@item lp_count
+@cindex loop counter, ARC
+@cindex ARC loop counter
+The loop count register.
+
+@item pcl
+@cindex word aligned program counter, ARC
+@cindex ARC word aligned program counter
+The word aligned program counter.
+
+@end table
 
+In addition the ARC processor has a large number of @emph{auxiliary
+registers}.  The precise set depends on the extensions being
+supported, but the following baseline set are always defined:
 
-@node ARC Floating Point
-@section Floating Point
+@table @code
+@item identity
+@cindex Processor Identification register, ARC
+@cindex ARC Processor Identification register
+Processor Identification register.  Auxiliary register address 0x4.
+
+@item pc
+@cindex Program Counter, ARC
+@cindex ARC Program Counter
+Program Counter.  Auxiliary register address 0x6.
+
+@item status32
+@cindex Status register, ARC
+@cindex ARC Status register
+Status register.  Auxiliary register address 0x0a.
+
+@item bta
+@cindex Branch Target Address, ARC
+@cindex ARC Branch Target Address
+Branch Target Address.  Auxiliary register address 0x412.
+
+@item ecr
+@cindex Exception Cause Register, ARC
+@cindex ARC Exception Cause Register
+Exception Cause Register.  Auxiliary register address 0x403.
+
+@item int_vector_base
+@cindex Interrupt Vector Base address, ARC
+@cindex ARC Interrupt Vector Base address
+Interrupt Vector Base address.  Auxiliary register address 0x25.
+
+@item status32_p0
+@cindex Stored STATUS32 register on entry to level P0 interrupts, ARC
+@cindex ARC Stored STATUS32 register on entry to level P0 interrupts
+Stored STATUS32 register on entry to level P0 interrupts.  Auxiliary
+register address 0xb.
+
+@item aux_user_sp
+@cindex Saved User Stack Pointer, ARC
+@cindex ARC Saved User Stack Pointer
+Saved User Stack Pointer.  Auxiliary register address 0xd.
+
+@item eret
+@cindex Exception Return Address, ARC
+@cindex ARC Exception Return Address
+Exception Return Address.  Auxiliary register address 0x400.
+
+@item erbta
+@cindex BTA saved on exception entry, ARC
+@cindex ARC BTA saved on exception entry
+BTA saved on exception entry.  Auxiliary register address 0x401.
+
+@item erstatus
+@cindex STATUS32 saved on exception, ARC
+@cindex ARC STATUS32 saved on exception
+STATUS32 saved on exception.  Auxiliary register address 0x402.
+
+@item bcr_ver
+@cindex Build Configuration Registers Version, ARC
+@cindex ARC Build Configuration Registers Version
+Build Configuration Registers Version.  Auxiliary register address 0x60.
+
+@item bta_link_build
+@cindex Build configuration for: BTA Registers, ARC
+@cindex ARC Build configuration for: BTA Registers
+Build configuration for: BTA Registers.  Auxiliary register address 0x63.
+
+@item vecbase_ac_build
+@cindex Build configuration for: Interrupts, ARC
+@cindex ARC Build configuration for: Interrupts
+Build configuration for: Interrupts.  Auxiliary register address 0x68.
+
+@item rf_build
+@cindex Build configuration for: Core Registers, ARC
+@cindex ARC Build configuration for: Core Registers
+Build configuration for: Core Registers.  Auxiliary register address 0x6e.
+
+@item dccm_build
+@cindex DCCM RAM Configuration Register, ARC
+@cindex ARC DCCM RAM Configuration Register
+DCCM RAM Configuration Register.  Auxiliary register address 0xc1.
 
-@cindex floating point, ARC (@sc{ieee})
-@cindex ARC floating point (@sc{ieee})
-The ARC core does not currently have hardware floating point
-support. Software floating point support is provided by @code{GCC}
-and uses @sc{ieee} floating-point numbers.
+@end table
 
+Additional auxiliary register names are defined according to the
+processor architecture version and extensions selected by the options.
 
 @node ARC Directives
 @section ARC Machine Directives
@@ -131,205 +313,106 @@ machine directives:
 
 @table @code
 
-@cindex @code{2byte} directive, ARC
-@item .2byte @var{expressions}
-*TODO*
-
-@cindex @code{3byte} directive, ARC
-@item .3byte @var{expressions}
-*TODO*
-
-@cindex @code{4byte} directive, ARC
-@item .4byte @var{expressions}
-*TODO*
-
-@cindex @code{extAuxRegister} directive, ARC
-@item .extAuxRegister @var{name},@var{address},@var{mode}
-The ARCtangent A4 has extensible auxiliary register space.  The
-auxiliary registers can be defined in the assembler source code by
-using this directive.  The first parameter is the @var{name} of the
-new auxiallry register.  The second parameter is the @var{address} of
-the register in the auxiliary register memory map for the variant of
-the ARC.  The third parameter specifies the @var{mode} in which the
-register can be operated is and it can be one of:
-
+@cindex @code{lcomm} directive
+@item .lcomm @var{symbol} , @var{length}[, @var{alignment}]
+Reserve @var{length} (an absolute expression) bytes for a local common
+denoted by @var{symbol}.  The section and value of @var{symbol} are
+those of the new local common.  The addresses are allocated in the bss
+section, so that at run-time the bytes start off zeroed.  Since
+@var{symbol} is not declared global, it is normally not visible to
+@code{@value{LD}}.  The optional third parameter, @var{alignment},
+specifies the desired alignment of the symbol in the bss section,
+specified as a byte boundary (for example, an alignment of 16 means
+that the least significant 4 bits of the address should be zero).  The
+alignment must be an absolute expression, and it must be a power of
+two.  If no alignment is specified, as will set the alignment to the
+largest power of two less than or equal to the size of the symbol, up
+to a maximum of 16.
+
+@cindex @code{lcommon} directive
+@item .lcommon @var{symbol} , @var{length}[, @var{alignment}]
+The same as @code{lcomm} directive.
+
+@cindex @code{cpu} directive, ARC
+@cindex @code{cpu} directive, ARC
+The @code{.cpu} directive must be followed by the desired core
+version.  Permitted values for CPU are:
 @table @code
-@item r          (readonly)
-@item w          (write only)
-@item r|w        (read or write)
-@end table
-
-For example:
-
-@smallexample
-  .extAuxRegister mulhi,0x12,w
-@end smallexample
+@item ARC600
+Assemble for the ARC600 instruction set.
 
-This specifies an extension auxiliary register called @emph{mulhi}
-which is at address 0x12 in the memory space and which is only
-writable.
+@item ARC700
+Assemble for the ARC700 instruction set.
 
-@cindex @code{extCondCode} directive, ARC
-@item .extCondCode @var{suffix},@var{value}
-The condition codes on the ARCtangent A4 are extensible and can be
-specified by means of this assembler directive.  They are specified
-by the suffix and the value for the condition code.  They can be used to
-specify extra condition codes with any values.  For example:
+@item EM
+Assemble for the ARC EM instruction set.
 
-@smallexample
-  .extCondCode is_busy,0x14
+@item HS
+Assemble for the ARC HS instruction set.
 
-   add.is_busy  r1,r2,r3
-   bis_busy     _main
-@end smallexample
-
-@cindex @code{extCoreRegister} directive, ARC
-@item .extCoreRegister @var{name},@var{regnum},@var{mode},@var{shortcut}
-Specifies an extension core register @var{name} for the application.
-This allows a register @var{name} with a valid @var{regnum} between 0
-and 60, with the following as valid values for @var{mode}
-
-@table @samp
-@item @emph{r}   (readonly)
-@item @emph{w}   (write only)
-@item @emph{r|w} (read or write)
 @end table
 
-
-The other parameter gives a description of the register having a
-@var{shortcut} in the pipeline.  The valid values are:
-
-@table @code
-@item can_shortcut
-@item cannot_shortcut
+Note: the @code{.cpu} directive overrides the command line option
+@code{-mcpu=@var{cpu}}; a warning is emitted when the version is not
+consistent between the two.
 @end table
 
-For example:
-
-@smallexample
-  .extCoreRegister mlo,57,r,can_shortcut
-@end smallexample
-
-This defines an extension core register mlo with the value 57 which
-can shortcut the pipeline.
-
-@cindex @code{extInstruction} directive, ARC
-@item .extInstruction @var{name},@var{opcode},@var{subopcode},@var{suffixclass},@var{syntaxclass}
-The ARCtangent A4 allows the user to specify extension instructions.
-The extension instructions are not macros.  The assembler creates
-encodings for use of these instructions according to the specification
-by the user.  The parameters are:
-
-@itemize @bullet
-@item @var{name}
-Name of the extension instruction
-
-@item @var{opcode}
-Opcode to be used. (Bits 27:31 in the encoding).  Valid values
-0x10-0x1f or 0x03
+@node ARC Modifiers
+@section ARC Assembler Modifiers
 
-@item @var{subopcode}
-Subopcode to be used.  Valid values are from 0x09-0x3f.  However the
-correct value also depends on @var{syntaxclass}
-
-@item @var{suffixclass}
-Determines the kinds of suffixes to be allowed.  Valid values are
-@code{SUFFIX_NONE}, @code{SUFFIX_COND},
-@code{SUFFIX_FLAG} which indicates the absence or presence of
-conditional suffixes and flag setting by the extension instruction.
-It is also possible to specify that an instruction sets the flags and
-is conditional by using @code{SUFFIX_CODE} | @code{SUFFIX_FLAG}.
-
-@item @var{syntaxclass}
-Determines the syntax class for the instruction.  It can have the
-following values:
+The following additional assembler modifiers have been added for
+position-independent code.  These modifiers are available only with
+the ARC 700 and above processors and generate relocation entries,
+which are interpreted by the linker as follows:
 
 @table @code
-@item @code{SYNTAX_2OP}:
-2 Operand Instruction
-@item @code{SYNTAX_3OP}:
-3 Operand Instruction
-@end table
-
-In addition there could be modifiers for the syntax class as described
-below:
-
-@itemize @minus
-Syntax Class Modifiers are:
-
-@item @code{OP1_MUST_BE_IMM}:
-Modifies syntax class SYNTAX_3OP,  specifying that the first operand
-of a three-operand instruction must be an immediate (i.e., the result
-is discarded).  OP1_MUST_BE_IMM is used by bitwise ORing it with
-SYNTAX_3OP as given in the example below.  This could usually be used
-to set the flags using specific instructions and not retain results.
+@item @@pcl(@var{symbol})
+@cindex @@pcl(@var{symbol}), ARC modifier
+Relative distance of @var{symbol}'s from the current program counter
+location.
+
+@item @@gotpc(@var{symbol})
+@cindex @@gotpc(@var{symbol}), ARC modifier
+Relative distance of @var{symbol}'s Global Offset Table entry from the
+current program counter location.
+
+@item @@gotoff(@var{symbol})
+@cindex @@gotoff(@var{symbol}), ARC modifier
+Distance of @var{symbol} from the base of the Global Offset Table.
+
+@item @@plt(@var{symbol})
+@cindex @@plt(@var{symbol}), ARC modifier
+Distance of @var{symbol}'s Procedure Linkage Table entry from the
+current program counter.  This is valid only with branch and link
+instructions and PC-relative calls.
+
+@item @@sda(@var{symbol})
+@cindex @@sda(@var{symbol}), ARC modifier
+Relative distance of @var{symbol} from the base of the Small Data
+Pointer.
 
-@item @code{OP1_IMM_IMPLIED}:
-Modifies syntax class SYNTAX_20P, it specifies that there is an
-implied immediate destination operand which does not appear in the
-syntax.  For example, if the source code contains an instruction like:
-
-@smallexample
-inst r1,r2
-@end smallexample
-
-it really means that the first argument is an implied immediate (that
-is, the result is discarded).  This is the same as though the source
-code were: inst 0,r1,r2.  You use OP1_IMM_IMPLIED by bitwise ORing it
-with SYNTAX_20P.
-
-@end itemize
-@end itemize
-
-For example, defining 64-bit multiplier with immediate operands:
-
-@smallexample
-.extInstruction mp64,0x14,0x0,SUFFIX_COND | SUFFIX_FLAG ,
-                SYNTAX_3OP|OP1_MUST_BE_IMM
-@end smallexample
-
-The above specifies an extension instruction called mp64 which has 3 operands,
-sets the flags, can be used with a condition code, for which the
-first operand is an immediate.  (Equivalent to discarding the result
-of the operation).
-
-@smallexample
- .extInstruction mul64,0x14,0x00,SUFFIX_COND, SYNTAX_2OP|OP1_IMM_IMPLIED
-@end smallexample
-
-This describes a 2 operand instruction with an implicit first
-immediate operand.  The result of this operation would be discarded.
-
-@cindex @code{half} directive, ARC
-@item .half @var{expressions}
-*TODO*
-
-@cindex @code{long} directive, ARC
-@item .long @var{expressions}
-*TODO*
+@end table
 
-@cindex @code{option} directive, ARC
-@item .option @var{arc|arc5|arc6|arc7|arc8}
-The @code{.option} directive must be followed by the desired core
-version. Again @code{arc} is an alias for
-@code{arc@value{ARC_CORE_DEFAULT}}.
+@node ARC Symbols
+@section ARC Pre-defined Symbols
 
-Note: the @code{.option} directive overrides the command line option
-@code{-marc}; a warning is emitted when the version is not consistent
-between the two - even for the implicit default core version
-(arc@value{ARC_CORE_DEFAULT}).
+The following assembler symbols will prove useful when developing
+position-independent code.  These symbols are available only with the
+ARC 700 and above processors.
 
-@cindex @code{short} directive, ARC
-@item .short @var{expressions}
-*TODO*
+@table @code
+@item __GLOBAL_OFFSET_TABLE__
+@cindex __GLOBAL_OFFSET_TABLE__, ARC pre-defined symbol
+Symbol referring to the base of the Global Offset Table.
 
-@cindex @code{word} directive, ARC
-@item .word @var{expressions}
-*TODO*
+@item __DYNAMIC__
+@cindex __DYNAMIC__, ARC pre-defined symbol
+An alias for the Global Offset Table
+@code{Base__GLOBAL_OFFSET_TABLE__}.  It can be used only with
+@code{@@gotpc} modifiers.
 
 @end table
 
-
 @node ARC Opcodes
 @section Opcodes
 
@@ -337,4 +420,4 @@ between the two - even for the implicit default core version
 @cindex opcodes for ARC
 
 For information on the ARC instruction set, see @cite{ARC Programmers
-Reference Manual}, ARC International (www.arc.com)
+Reference Manual}, available where you download the processor IP library.
-- 
1.7.0.4


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]