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 4/9] Nios II port, gas support


This patch adds assembler support for Nios II. New test cases will follow separately in part 5.

-Sandra

2013-01-24  Sandra Loosemore  <sandra@codesourcery.com>
            Andrew Jenner <andrew@codesourcery.com>

Based on patches from Altera Corporation.

	gas/
	* Makefile.am (TARGET_CPU_CFILES): Add config/tc-nios2.c.
	(TARGET_CPU_HFILES): Add config/tc-nios2.h.
	* Makefile.in: Regenerated.
	* configure.tgt: Add case for nios2*-linux*.
	* config/obj-elf.c: Conditionally include elf/nios2.h.
	* config/tc-nios2.c: New file.
	* config/tc-nios2.h: New file.
	* doc/Makefile.am (CPU_DOCS): Add c-nios2.texi.
	* doc/Makefile.in: Regenerated.
	* doc/all.texi: Set NIOSII.
	* doc/as.texinfo (Overview): Add Nios II options.
	(Machine Dependencies): Include c-nios2.texi.
	* doc/c-nios2.texi: New file.

Index: gas/Makefile.am
===================================================================
RCS file: /cvs/src/src/gas/Makefile.am,v
retrieving revision 1.204
diff -u -p -r1.204 Makefile.am
--- gas/Makefile.am	10 Jan 2013 09:49:15 -0000	1.204
+++ gas/Makefile.am	22 Jan 2013 18:36:36 -0000
@@ -164,6 +164,7 @@ TARGET_CPU_CFILES = \
 	config/tc-moxie.c \
 	config/tc-msp430.c \
 	config/tc-mt.c \
+	config/tc-nios2.c \
 	config/tc-ns32k.c \
 	config/tc-openrisc.c \
 	config/tc-or32.c \
@@ -234,6 +235,7 @@ TARGET_CPU_HFILES = \
 	config/tc-mn10300.h \
 	config/tc-msp430.h \
 	config/tc-mt.h \
+	config/tc-nios2.h \
 	config/tc-ns32k.h \
 	config/tc-openrisc.h \
 	config/tc-or32.h \
Index: gas/Makefile.in
===================================================================
RCS file: /cvs/src/src/gas/Makefile.in,v
retrieving revision 1.228
diff -u -p -r1.228 Makefile.in
--- gas/Makefile.in	10 Jan 2013 09:49:16 -0000	1.228
+++ gas/Makefile.in	22 Jan 2013 18:36:36 -0000
@@ -433,6 +433,7 @@ TARGET_CPU_CFILES = \
 	config/tc-moxie.c \
 	config/tc-msp430.c \
 	config/tc-mt.c \
+	config/tc-nios2.c \
 	config/tc-ns32k.c \
 	config/tc-openrisc.c \
 	config/tc-or32.c \
@@ -503,6 +504,7 @@ TARGET_CPU_HFILES = \
 	config/tc-mn10300.h \
 	config/tc-msp430.h \
 	config/tc-mt.h \
+	config/tc-nios2.h \
 	config/tc-ns32k.h \
 	config/tc-openrisc.h \
 	config/tc-or32.h \
@@ -855,6 +857,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-moxie.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-msp430.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-mt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-nios2.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-ns32k.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-openrisc.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-or32.Po@am__quote@
@@ -1468,6 +1471,20 @@ tc-mt.obj: config/tc-mt.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-mt.obj `if test -f 'config/tc-mt.c'; then $(CYGPATH_W) 'config/tc-mt.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-mt.c'; fi`
 
+tc-nios2.o: config/tc-nios2.c
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-nios2.o -MD -MP -MF $(DEPDIR)/tc-nios2.Tpo -c -o tc-nios2.o `test -f 'config/tc-nios2.c' || echo '$(srcdir)/'`config/tc-nios2.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/tc-nios2.Tpo $(DEPDIR)/tc-nios2.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='config/tc-nios2.c' object='tc-nios2.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-nios2.o `test -f 'config/tc-nios2.c' || echo '$(srcdir)/'`config/tc-nios2.c
+
+tc-nios2.obj: config/tc-nios2.c
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-nios2.obj -MD -MP -MF $(DEPDIR)/tc-nios2.Tpo -c -o tc-nios2.obj `if test -f 'config/tc-nios2.c'; then $(CYGPATH_W) 'config/tc-nios2.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-nios2.c'; fi`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/tc-nios2.Tpo $(DEPDIR)/tc-nios2.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='config/tc-nios2.c' object='tc-nios2.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-nios2.obj `if test -f 'config/tc-nios2.c'; then $(CYGPATH_W) 'config/tc-nios2.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-nios2.c'; fi`
+
 tc-ns32k.o: config/tc-ns32k.c
 @am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-ns32k.o -MD -MP -MF $(DEPDIR)/tc-ns32k.Tpo -c -o tc-ns32k.o `test -f 'config/tc-ns32k.c' || echo '$(srcdir)/'`config/tc-ns32k.c
 @am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/tc-ns32k.Tpo $(DEPDIR)/tc-ns32k.Po
Index: gas/configure.tgt
===================================================================
RCS file: /cvs/src/src/gas/configure.tgt,v
retrieving revision 1.84
diff -u -p -r1.84 configure.tgt
--- gas/configure.tgt	10 Jan 2013 09:49:16 -0000	1.84
+++ gas/configure.tgt	22 Jan 2013 18:36:36 -0000
@@ -350,6 +350,8 @@ case ${generic_target} in
 
   msp430-*-*)				fmt=elf ;;
 
+  nios2*-linux*)                        fmt=elf em=linux ;;
+
   ns32k-pc532-mach*)			fmt=aout em=pc532mach ;;
   ns32k-pc532-ux*)			fmt=aout em=pc532mach ;;
   ns32k-pc532-lites*)			fmt=aout em=nbsd532 ;;
Index: gas/config/obj-elf.c
===================================================================
RCS file: /cvs/src/src/gas/config/obj-elf.c,v
retrieving revision 1.149
diff -u -p -r1.149 obj-elf.c
--- gas/config/obj-elf.c	9 Nov 2012 18:07:10 -0000	1.149
+++ gas/config/obj-elf.c	22 Jan 2013 18:36:36 -0000
@@ -62,6 +62,10 @@
 #include "elf/mep.h"
 #endif
 
+#ifdef TC_NIOS2
+#include "elf/nios2.h"
+#endif
+
 static void obj_elf_line (int);
 static void obj_elf_size (int);
 static void obj_elf_type (int);
Index: gas/config/tc-nios2.c
===================================================================
RCS file: gas/config/tc-nios2.c
diff -N gas/config/tc-nios2.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gas/config/tc-nios2.c	22 Jan 2013 18:36:37 -0000
@@ -0,0 +1,3067 @@
+/* Altera Nios II assembler.
+   Copyright (C) 2012, 2013 Free Software Foundation, Inc.
+   Contributed by Nigel Gray (ngray@altera.com).
+   Contributed by Mentor Graphics, Inc.
+
+   This file is part of GAS, the GNU Assembler.
+
+   GAS is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GAS 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 GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#include "as.h"
+#include "opcode/nios2.h"
+#include "elf/nios2.h"
+#include "tc-nios2.h"
+#include "bfd.h"
+#include "dwarf2dbg.h"
+#include "subsegs.h"
+#include "safe-ctype.h"
+#include "dw2gencfi.h"
+
+#ifndef OBJ_ELF
+/* We are not supporting any other target so we throw a compile time error.  */
+OBJ_ELF not defined
+#endif
+
+/* We can choose our endianness at run-time, regardless of configuration.  */
+extern int target_big_endian;
+
+/* This array holds the chars that always start a comment.  If the
+   pre-processor is disabled, these aren't very useful.  */
+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 C style comments are always supported.  */
+const char line_comment_chars[] = "#";
+
+/* This array holds machine specific line separator characters.  */
+const char line_separator_chars[] = ";";
+
+/* Chars that can be used to separate mant from exp in floating point nums.  */
+const char EXP_CHARS[] = "eE";
+
+/* Chars that mean this number is a floating point constant.  */
+/* As in 0f12.456 */
+/* or    0d1.2345e12 */
+const char FLT_CHARS[] = "rRsSfFdDxXpP";
+
+/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
+   changed in read.c.  Ideally it shouldn't have to know about it at all,
+   but nothing is ideal around here.  */
+
+/* Machine-dependent command-line options.  */
+
+const char *md_shortopts = "r";
+
+struct option md_longopts[] = {
+#define OPTION_RELAX_ALL (OPTION_MD_BASE + 0)
+  {"relax-all", no_argument, NULL, OPTION_RELAX_ALL},
+#define OPTION_NORELAX (OPTION_MD_BASE + 1)
+  {"no-relax", no_argument, NULL, OPTION_NORELAX},
+#define OPTION_RELAX_SECTION (OPTION_MD_BASE + 2)
+  {"relax-section", no_argument, NULL, OPTION_RELAX_SECTION},
+#define OPTION_EB (OPTION_MD_BASE + 3)
+  {"EB", no_argument, NULL, OPTION_EB},
+#define OPTION_EL (OPTION_MD_BASE + 4)
+  {"EL", no_argument, NULL, OPTION_EL}
+};
+
+size_t md_longopts_size = sizeof (md_longopts);
+
+/* The assembler supports three different relaxation modes, controlled by
+   command-line options.  */
+typedef enum
+{
+  relax_section = 0,
+  relax_none,
+  relax_all
+} relax_optionT;
+
+/* Struct contains all assembler options set with .set.  */
+struct
+{
+  /* .set noat -> noat = 1 allows assembly code to use at without warning
+     and macro expansions generate a warning.
+     .set at -> noat = 0, assembly code using at warn but macro expansions
+     do not generate warnings.  */
+  bfd_boolean noat;
+
+  /* .set nobreak -> nobreak = 1 allows assembly code to use ba,bt without 
+				 warning.
+     .set break -> nobreak = 0, assembly code using ba,bt warns.  */
+  bfd_boolean nobreak;
+
+  /* .cmd line option -relax-all allows all branches and calls to be replaced
+     with longer versions.
+     -no-relax inhibits branch/call conversion.
+     The default value is relax_section, which relaxes branches within
+     a section.  */
+  relax_optionT relax;
+
+} nios2_as_options = {FALSE, FALSE, relax_section};
+
+
+typedef struct nios2_insn_reloc
+{
+  /* Any expression in the instruction is parsed into this field,
+     which is passed to fix_new_exp() to generate a fixup.  */
+  expressionS reloc_expression;
+
+  /* The type of the relocation to be applied.  */
+  bfd_reloc_code_real_type reloc_type;
+
+  /* PC-relative.  */
+  unsigned int reloc_pcrel;
+
+  /* The next relocation to be applied to the instruction.  */
+  struct nios2_insn_reloc *reloc_next;
+} nios2_insn_relocS;
+
+/* This struct is used to hold state when assembling instructions.  */
+typedef struct nios2_insn_info
+{
+  /* Assembled instruction.  */
+  unsigned long insn_code;
+  /* Pointer to the relevant bit of the opcode table.  */
+  const struct nios2_opcode *insn_nios2_opcode;
+  /* After parsing ptrs to the tokens in the instruction fill this array
+     it is terminated with a null pointer (hence the first +1).
+     The second +1 is because in some parts of the code the opcode
+     is not counted as a token, but still placed in this array.  */
+  const char *insn_tokens[NIOS2_MAX_INSN_TOKENS + 1 + 1];
+
+  /* This holds information used to generate fixups
+     and eventually relocations if it is not null.  */
+  nios2_insn_relocS *insn_reloc;
+} nios2_insn_infoS;
+
+/* This struct associates an argument assemble function with
+   an argument syntax string.  Used by the assembler to find out
+   how to parse and assemble a set of instruction operands and 
+   return the instruction field values.  */
+typedef struct nios2_arg_info
+{
+  const char *args;
+  void (*assemble_args_func) (nios2_insn_infoS *insn_info);
+} nios2_arg_infoS;
+
+/* This struct is used to convert Nios II pseudo-ops into the
+   corresponding real op.  */
+typedef struct nios2_ps_insn_info
+{
+  /* Map this pseudo_op... */
+  const char *pseudo_insn;
+
+  /* ...to this real instruction.  */
+  const char *insn;
+
+  /* Call this function to modify the operands....  */
+  void (*arg_modifer_func) (char ** parsed_args, const char *arg, int num,
+			    int start);
+
+  /* ...with these arguments.  */
+  const char *arg_modifier;
+  int num;
+  int index;
+
+  /* If arg_modifier_func allocates new memory, provide this function
+     to free it afterwards.  */
+  void (*arg_cleanup_func) (char **parsed_args, int num, int start);
+} nios2_ps_insn_infoS;
+
+/* Opcode hash table.  */
+static struct hash_control *nios2_opcode_hash = NULL;
+#define nios2_opcode_lookup(NAME) \
+  ((struct nios2_opcode *) hash_find (nios2_opcode_hash, (NAME)))
+
+/* Register hash table.  */
+static struct hash_control *nios2_reg_hash = NULL;
+#define nios2_reg_lookup(NAME) \
+  ((struct nios2_reg *) hash_find (nios2_reg_hash, (NAME)))
+
+/* Parse args hash table.  */
+static struct hash_control *nios2_arg_hash = NULL;
+#define nios2_arg_lookup(NAME) \
+  ((nios2_arg_infoS *) hash_find (nios2_arg_hash, (NAME)))
+
+/* Pseudo-op hash table.  */
+static struct hash_control *nios2_ps_hash = NULL;
+#define nios2_ps_lookup(NAME) \
+  ((nios2_ps_insn_infoS *) hash_find (nios2_ps_hash, (NAME)))
+
+/* The known current alignment of the current section.  */
+static int nios2_current_align;
+static segT nios2_current_align_seg;
+
+static int nios2_auto_align_on = 1;
+
+/* The last seen label in the current section.  This is used to auto-align
+   labels preceeding instructions.  */
+static symbolS *nios2_last_label;
+
+#ifdef OBJ_ELF
+/* Pre-defined "_GLOBAL_OFFSET_TABLE_"  */
+symbolS *GOT_symbol;
+#endif
+
+
+/** Utility routines.  */
+/* Function md_chars_to_number takes the sequence of
+   bytes in buf and returns the corresponding value
+   in an int. n must be 1, 2 or 4.  */
+static valueT
+md_chars_to_number (char *buf, int n)
+{
+  int i;
+  valueT val;
+
+  gas_assert (n == 1 || n == 2 || n == 4);
+
+  val = 0;
+  if (target_big_endian)
+    for (i = 0; i < n; ++i)
+      val = val | ((buf[i] & 0xff) << 8 * (n - (i + 1)));
+  else
+    for (i = 0; i < n; ++i)
+      val = val | ((buf[i] & 0xff) << 8 * i);
+  return val;
+}
+
+
+/* This function turns a C long int, short int or char
+   into the series of bytes that represent the number
+   on the target machine.  */
+void
+md_number_to_chars (char *buf, valueT val, int n)
+{
+  gas_assert (n == 1 || n == 2 || n == 4 || n == 8);
+  if (target_big_endian)
+    number_to_chars_bigendian (buf, val, n);
+  else
+    number_to_chars_littleendian (buf, val, n);
+}
+
+/* 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)
+{
+  int prec;
+  LITTLENUM_TYPE words[4];
+  char *t;
+  int i;
+
+  switch (type)
+    {
+    case 'f':
+      prec = 2;
+      break;
+    case 'd':
+      prec = 4;
+      break;
+    default:
+      *sizeP = 0;
+      return _("bad call to md_atof");
+    }
+
+  t = atof_ieee (input_line_pointer, type, words);
+  if (t)
+    input_line_pointer = t;
+
+  *sizeP = prec * 2;
+
+  if (! target_big_endian)
+    for (i = prec - 1; i >= 0; i--, litP += 2)
+      md_number_to_chars (litP, (valueT) words[i], 2);
+  else
+    for (i = 0; i < prec; i++, litP += 2)
+      md_number_to_chars (litP, (valueT) words[i], 2);
+
+  return NULL;
+}
+
+/* Return true if STR starts with PREFIX, which should be a string literal.  */
+#define strprefix(STR, PREFIX) \
+  (strncmp ((STR), PREFIX, strlen (PREFIX)) == 0)
+
+/* Return true if STR is prefixed with a control register name.  */
+static int
+nios2_control_register_arg_p (const char *str)
+{
+  return (strprefix (str, "ctl")
+	  || strprefix (str, "cpuid")
+	  || strprefix (str, "status")
+	  || strprefix (str, "estatus")
+	  || strprefix (str, "bstatus")
+	  || strprefix (str, "ienable")
+	  || strprefix (str, "ipending")
+	  || strprefix (str, "exception")
+	  || strprefix (str, "pteaddr")
+	  || strprefix (str, "tlbacc")
+	  || strprefix (str, "tlbmisc")
+	  || strprefix (str, "fstatus")
+	  || strprefix (str, "config")
+	  || strprefix (str, "mpubase")
+	  || strprefix (str, "mpuacc")
+	  || strprefix (str, "badaddr"));
+}
+
+/* Return true if STR is prefixed with a special relocation operator.  */
+static int
+nios2_special_relocation_p (const char *str)
+{
+  return (strprefix (str, "%lo")
+	  || strprefix (str, "%hi")
+	  || strprefix (str, "%hiadj")
+	  || strprefix (str, "%gprel")
+	  || strprefix (str, "%got")
+	  || strprefix (str, "%call")
+	  || strprefix (str, "%gotoff_lo")
+	  || strprefix (str, "%gotoff_hiadj")
+	  || strprefix (str, "%tls_gd")
+	  || strprefix (str, "%tls_ldm")
+	  || strprefix (str, "%tls_ldo")
+	  || strprefix (str, "%tls_ie")
+	  || strprefix (str, "%tls_le")
+	  || strprefix (str, "%gotoff"));
+}
+
+/* Checks whether the register name is a coprocessor
+   register - returns TRUE if it is, FALSE otherwise.  */
+static bfd_boolean
+nios2_coproc_reg (const char *reg_name)
+{
+  gas_assert (reg_name != NULL);
+
+  /* Check that we do have a valid register name and that it is a
+     coprocessor register.
+     It must begin with c, not be a control register, and be a valid
+     register name.  */
+  if (strprefix (reg_name, "c")
+      && !strprefix (reg_name, "ctl")
+      && hash_find (nios2_reg_hash, reg_name) != NULL)
+    return TRUE;
+  else
+    return FALSE;
+}
+
+/* nop fill pattern for text section.  */
+static char const nop[4] = { 0x3a, 0x88, 0x01, 0x00 };
+
+/* Handles all machine-dependent alignment needs.  */
+static void
+nios2_align (int log_size, const char *pfill, symbolS *label)
+{
+  int align;
+  long max_alignment = 15;
+
+  /* The front end is prone to changing segments out from under us
+     temporarily when -g is in effect.  */
+  int switched_seg_p = (nios2_current_align_seg != now_seg);
+
+  align = log_size;
+  if (align > max_alignment)
+    {
+      align = max_alignment;
+      as_bad (_("Alignment too large: %d. assumed"), align);
+    }
+  else if (align < 0)
+    {
+      as_warn (_("Alignment negative: 0 assumed"));
+      align = 0;
+    }
+
+  if (align != 0)
+    {
+      if (subseg_text_p (now_seg) && align >= 2)
+	{
+	  /* First, make sure we're on a four-byte boundary, in case
+	     someone has been putting .byte values the text section.  */
+	  if (nios2_current_align < 2 || switched_seg_p)
+	    frag_align (2, 0, 0);
+
+	  /* Now fill in the alignment pattern.  */
+	  if (pfill != NULL)
+	    frag_align_pattern (align, pfill, sizeof nop, 0);
+	  else
+	    frag_align (align, 0, 0);
+	}
+      else
+	frag_align (align, 0, 0);
+
+      if (!switched_seg_p)
+	nios2_current_align = align;
+
+      /* If the last label was in a different section we can't align it.  */
+      if (label != NULL && !switched_seg_p)
+	{
+	  symbolS *sym;
+	  int label_seen = FALSE;
+	  struct frag *old_frag;
+	  valueT old_value;
+	  valueT new_value;
+
+	  gas_assert (S_GET_SEGMENT (label) == now_seg);
+
+	  old_frag = symbol_get_frag (label);
+	  old_value = S_GET_VALUE (label);
+	  new_value = (valueT) frag_now_fix ();
+
+	  /* It is possible to have more than one label at a particular
+	     address, especially if debugging is enabled, so we must
+	     take care to adjust all the labels at this address in this
+	     fragment.  To save time we search from the end of the symbol
+	     list, backwards, since the symbols we are interested in are
+	     almost certainly the ones that were most recently added.
+	     Also to save time we stop searching once we have seen at least
+	     one matching label, and we encounter a label that is no longer
+	     in the target fragment.  Note, this search is guaranteed to
+	     find at least one match when sym == label, so no special case
+	     code is necessary.  */
+	  for (sym = symbol_lastP; sym != NULL; sym = symbol_previous (sym))
+	    if (symbol_get_frag (sym) == old_frag
+		&& S_GET_VALUE (sym) == old_value)
+	      {
+		label_seen = TRUE;
+		symbol_set_frag (sym, frag_now);
+		S_SET_VALUE (sym, new_value);
+	      }
+	    else if (label_seen && symbol_get_frag (sym) != old_frag)
+	      break;
+	}
+      record_alignment (now_seg, align);
+    }
+}
+
+
+/** Support for self-check mode.  */
+
+/* Mode of the assembler.  */
+typedef enum
+{
+  NIOS2_MODE_ASSEMBLE,		/* Ordinary operation.  */
+  NIOS2_MODE_TEST		/* Hidden mode used for self testing.  */
+} NIOS2_MODE;
+
+static NIOS2_MODE nios2_mode = NIOS2_MODE_ASSEMBLE;
+
+/* This function is used to in self-checking mode
+   to check the assembled instruction
+   opcode should be the assembled opcode, and exp_opcode
+   the parsed string representing the expected opcode.  */
+static void
+nios2_check_assembly (unsigned int opcode, const char *exp_opcode)
+{
+  if (nios2_mode == NIOS2_MODE_TEST)
+    {
+      if (exp_opcode == NULL)
+	as_bad (_("expecting opcode string in self test mode"));
+      else if (opcode != strtoul (exp_opcode, NULL, 16))
+	as_bad (_("assembly 0x%08x, expected %s"), opcode, exp_opcode);
+    }
+}
+
+
+/** Support for machine-dependent assembler directives.  */
+/* Handle the .align pseudo-op.  This aligns to a power of two.  It
+   also adjusts any current instruction label.  We treat this the same
+   way the MIPS port does: .align 0 turns off auto alignment.  */
+static void
+s_nios2_align (int ignore ATTRIBUTE_UNUSED)
+{
+  int align;
+  char fill;
+  const char *pfill = NULL;
+  long max_alignment = 15;
+
+  align = get_absolute_expression ();
+  if (align > max_alignment)
+    {
+      align = max_alignment;
+      as_bad (_("Alignment too large: %d. assumed"), align);
+    }
+  else if (align < 0)
+    {
+      as_warn (_("Alignment negative: 0 assumed"));
+      align = 0;
+    }
+
+  if (*input_line_pointer == ',')
+    {
+      input_line_pointer++;
+      fill = get_absolute_expression ();
+      pfill = (const char *) &fill;
+    }
+  else if (subseg_text_p (now_seg))
+    pfill = (const char *) &nop;
+  else
+    {
+      pfill = NULL;
+      nios2_last_label = NULL;
+    }
+
+  if (align != 0)
+    {
+      nios2_auto_align_on = 1;
+      nios2_align (align, pfill, nios2_last_label);
+      nios2_last_label = NULL;
+    }
+  else
+    nios2_auto_align_on = 0;
+
+  demand_empty_rest_of_line ();
+}
+
+/* Handle the .text pseudo-op.  This is like the usual one, but it
+   clears the saved last label and resets known alignment.  */
+static void
+s_nios2_text (int i)
+{
+  s_text (i);
+  nios2_last_label = NULL;
+  nios2_current_align = 0;
+  nios2_current_align_seg = now_seg;
+}
+
+/* Handle the .data pseudo-op.  This is like the usual one, but it
+   clears the saved last label and resets known alignment.  */
+static void
+s_nios2_data (int i)
+{
+  s_data (i);
+  nios2_last_label = NULL;
+  nios2_current_align = 0;
+  nios2_current_align_seg = now_seg;
+}
+
+/* Handle the .section pseudo-op.  This is like the usual one, but it
+   clears the saved last label and resets known alignment.  */
+static void
+s_nios2_section (int ignore)
+{
+  obj_elf_section (ignore);
+  nios2_last_label = NULL;
+  nios2_current_align = 0;
+  nios2_current_align_seg = now_seg;
+}
+
+/* Explicitly unaligned cons.  */
+static void
+s_nios2_ucons (int nbytes)
+{
+  int hold;
+  hold = nios2_auto_align_on;
+  nios2_auto_align_on = 0;
+  cons (nbytes);
+  nios2_auto_align_on = hold;
+}
+
+/* Handle the .sdata directive.  */
+static void
+s_nios2_sdata (int ignore ATTRIBUTE_UNUSED)
+{
+  get_absolute_expression ();  /* Ignored.  */
+  subseg_new (".sdata", 0);
+  demand_empty_rest_of_line ();
+}
+
+/* .set sets assembler options eg noat/at and is also used
+   to set symbol values (.equ, .equiv ).  */
+static void
+s_nios2_set (int equiv)
+{
+  char *directive = input_line_pointer;
+  char delim = get_symbol_end ();
+  char *endline = input_line_pointer;
+  *endline = delim;
+
+  /* We only want to handle ".set XXX" if the
+     user has tried ".set XXX, YYY" they are not
+     trying a directive.  This prevents
+     us from polluting the name space.  */
+  SKIP_WHITESPACE ();
+  if (is_end_of_line[(unsigned char) *input_line_pointer]) 
+    {
+      bfd_boolean done = TRUE;
+      *endline = 0;
+      
+      if (!strcmp (directive, "noat"))
+	  nios2_as_options.noat = TRUE;
+      else if (!strcmp (directive, "at"))
+	  nios2_as_options.noat = FALSE;
+      else if (!strcmp (directive, "nobreak"))
+	  nios2_as_options.nobreak = TRUE;
+      else if (!strcmp (directive, "break"))
+	  nios2_as_options.nobreak = FALSE;
+      else if (!strcmp (directive, "norelax"))
+	  nios2_as_options.relax = relax_none;
+      else if (!strcmp (directive, "relaxsection"))
+	  nios2_as_options.relax = relax_section;
+      else if (!strcmp (directive, "relaxall"))
+	  nios2_as_options.relax = relax_all;
+      else
+	done = FALSE;
+	
+      if (done)
+	{
+	  *endline = delim;
+	  demand_empty_rest_of_line ();
+	  return;
+	}
+    }
+
+  /* If we fall through to here, either we have ".set XXX, YYY"
+     or we have ".set XXX" where XXX is unknown or we have 
+     a syntax error.  */
+  input_line_pointer = directive;
+  *endline = delim;
+  s_set (equiv);
+}
+
+/* Machine-dependent assembler directives.
+   Format of each entry is:
+   { "directive", handler_func, param }  */
+const pseudo_typeS md_pseudo_table[] = {
+  {"align", s_nios2_align, 0},
+  {"text", s_nios2_text, 0},
+  {"data", s_nios2_data, 0},
+  {"section", s_nios2_section, 0},
+  {"section.s", s_nios2_section, 0},
+  {"sect", s_nios2_section, 0},
+  {"sect.s", s_nios2_section, 0},
+  /* .dword and .half are included for compatibility with MIPS.  */
+  {"dword", cons, 8},
+  {"half", cons, 2},
+  /* NIOS2 native word size is 4 bytes, so we override
+     the GAS default of 2.  */
+  {"word", cons, 4},
+  /* Explicitly unaligned directives.  */
+  {"2byte", s_nios2_ucons, 2},
+  {"4byte", s_nios2_ucons, 4},
+  {"8byte", s_nios2_ucons, 8},
+  {"16byte", s_nios2_ucons, 16},
+#ifdef OBJ_ELF
+  {"sdata", s_nios2_sdata, 0},
+#endif
+  {"set", s_nios2_set, 0},
+  {NULL, NULL, 0}
+};
+
+
+/** Relaxation support. */
+
+/* We support two relaxation modes:  a limited PC-relative mode with
+   -relax-section (the default), and an absolute jump mode with -relax-all.
+
+   Nios II PC-relative branch instructions only support 16-bit offsets.
+   And, there's no good way to add a 32-bit constant to the PC without
+   using two registers.
+  
+   To deal with this, for the pc-relative relaxation mode we convert
+     br label
+   into a series of 16-bit adds, like:
+     nextpc at
+     addi at, at, 32767
+     ...
+     addi at, at, remainder
+     jmp at
+
+   Similarly, conditional branches are converted from
+     b(condition) r, s, label
+   into a series like:
+     b(opposite condition) r, s, skip
+     nextpc at
+     addi at, at, 32767
+     ...
+     addi at, at, remainder
+     jmp at
+     skip:
+
+   The compiler can do a better job, either by converting the branch
+   directly into a JMP (going through the GOT for PIC) or by allocating
+   a second register for the 32-bit displacement.
+
+   For the -relax-all relaxation mode, the conversions are
+     movhi at, %hi(symbol+offset)
+     ori at, %lo(symbol+offset)
+     jmp at
+   and
+     b(opposite condition), r, s, skip
+     movhi at, %hi(symbol+offset)
+     ori at, %lo(symbol+offset)
+     jmp at
+     skip:
+   respectively.
+*/
+
+/* Arbitrarily limit the number of addis we can insert; we need to be able
+   to specify the maximum growth size for each frag that contains a
+   relaxable branch.  There's no point in specifying a huge number here
+   since that means the assembler needs to allocate that much extra
+   memory for every branch, and almost no real code will ever need it.
+   Plus, as already noted a better solution is to just use a jmp, or
+   allocate a second register to hold a 32-bit displacement.
+   FIXME:  Rather than making this a constant, it could be controlled by
+   a command-line argument.  */
+#define RELAX_MAX_ADDI 32
+
+/* The fr_subtype field represents the target-specific relocation state.
+   It has type relax_substateT (unsigned int).  We use it to track the
+   number of addis necessary, plus a bit to track whether this is a
+   conditional branch.
+   Regardless of the smaller RELAX_MAX_ADDI limit, we reserve 16 bits
+   in the fr_subtype to encode the number of addis so that the whole
+   theoretically-valid range is representable.
+   For the -relax-all mode, N = 0 represents an in-range branch and N = 1
+   represents a branch that needs to be relaxed.  */
+#define UBRANCH (0 << 16)
+#define CBRANCH (1 << 16)
+#define IS_CBRANCH(SUBTYPE) ((SUBTYPE) & CBRANCH)
+#define IS_UBRANCH(SUBTYPE) (!IS_CBRANCH (SUBTYPE))
+#define UBRANCH_SUBTYPE(N) (UBRANCH | (N))
+#define CBRANCH_SUBTYPE(N) (CBRANCH | (N))
+#define SUBTYPE_ADDIS(SUBTYPE) ((SUBTYPE) & 0xffff)
+
+/* For the -relax-section mode, unconditional branches require 2 extra i
+   nstructions besides the addis, conditional branches require 3.  */
+#define UBRANCH_ADDIS_TO_SIZE(N) (((N) + 2) * 4)
+#define CBRANCH_ADDIS_TO_SIZE(N) (((N) + 3) * 4)
+
+/* For the -relax-all mode, unconditional branches require 3 instructions
+   and conditional branches require 4.  */
+#define UBRANCH_JUMP_SIZE 12
+#define CBRANCH_JUMP_SIZE 16
+
+/* Maximum sizes of relaxation sequences.  */
+#define UBRANCH_MAX_SIZE \
+  (nios2_as_options.relax == relax_all		\
+   ? UBRANCH_JUMP_SIZE				\
+   : UBRANCH_ADDIS_TO_SIZE (RELAX_MAX_ADDI))
+#define CBRANCH_MAX_SIZE \
+  (nios2_as_options.relax == relax_all		\
+   ? CBRANCH_JUMP_SIZE				\
+   : CBRANCH_ADDIS_TO_SIZE (RELAX_MAX_ADDI))
+
+/* Register number of AT, the assembler temporary.  */
+#define AT_REGNUM 1
+
+/* Determine how many bytes are required to represent the sequence
+   indicated by SUBTYPE.  */
+static int
+nios2_relax_subtype_size (relax_substateT subtype)
+{
+  int n = SUBTYPE_ADDIS (subtype);
+  if (n == 0)
+    /* Regular conditional/unconditional branch instruction.  */
+    return 4;
+  else if (nios2_as_options.relax == relax_all)
+    return (IS_CBRANCH (subtype) ? CBRANCH_JUMP_SIZE : UBRANCH_JUMP_SIZE);
+  else if (IS_CBRANCH (subtype))
+    return CBRANCH_ADDIS_TO_SIZE (n);
+  else
+    return UBRANCH_ADDIS_TO_SIZE (n);
+}
+
+/* Estimate size of fragp before relaxation.
+   This could also examine the offset in fragp and adjust
+   fragp->fr_subtype, but we will do that in nios2_relax_frag anyway.  */
+int
+md_estimate_size_before_relax (fragS *fragp, segT segment ATTRIBUTE_UNUSED)
+{
+  return nios2_relax_subtype_size (fragp->fr_subtype);
+}
+
+/* Implement md_relax_frag, returning the change in size of the frag.  */
+long
+nios2_relax_frag (segT segment, fragS *fragp, long stretch)
+{
+  addressT target = fragp->fr_offset;
+  relax_substateT subtype = fragp->fr_subtype;
+  symbolS *symbolp = fragp->fr_symbol;
+
+  if (symbolp)
+    {
+      fragS *sym_frag = symbol_get_frag (symbolp);
+      offsetT offset;
+      int n;
+
+      target += S_GET_VALUE (symbolp);
+
+      /* See comments in write.c:relax_frag about handling of stretch.  */
+      if (stretch != 0
+	  && sym_frag->relax_marker != fragp->relax_marker)
+	{
+	  if (stretch < 0 || sym_frag->region == fragp->region)
+	    target += stretch;
+	  else if (target < fragp->fr_address)
+	    target = fragp->fr_next->fr_address + stretch;
+	}
+
+      /* We subtract 4 because all pc relative branches are
+	 from the next instruction.  */
+      offset = target - fragp->fr_address - fragp->fr_fix - 4;
+      if (offset >= -32768 && offset <= 32764)
+	/* Fits in PC-relative branch.  */
+	n = 0;
+      else if (nios2_as_options.relax == relax_all)
+	/* Convert to jump.  */
+	n = 1;
+      else if (nios2_as_options.relax == relax_section
+	       && S_GET_SEGMENT (symbolp) == segment
+	       && S_IS_DEFINED (symbolp))
+	/* Attempt a PC-relative relaxation on a branch to a defined
+	   symbol in the same segment.  */
+	{
+	  /* The relaxation for conditional branches is offset by 4
+	     bytes because we insert the inverted branch around the
+	     sequence.  */
+	  if (IS_CBRANCH (subtype))
+	    offset = offset - 4;
+	  if (offset > 0)
+	    n = offset / 32767 + 1;
+	  else
+	    n = offset / -32768 + 1;
+
+	  /* Bail out immediately if relaxation has failed.  If we try to
+	     defer the diagnostic to md_convert_frag, some pathological test
+	     cases (e.g. gcc/testsuite/gcc.c-torture/compile/20001226-1.c)
+	     apparently never converge.  By returning 0 here we could pretend
+	     to the caller that nothing has changed, but that leaves things
+	     in an inconsistent state when we get to md_convert_frag.  */
+	  if (n > RELAX_MAX_ADDI)
+	    {
+	      as_bad_where (fragp->fr_file, fragp->fr_line,
+			    _("branch offset out of range\n"));
+	      as_fatal (_("branch relaxation failed\n"));
+	    }
+	}
+      else
+	/* We cannot handle this case, diagnose overflow later.  */
+	return 0;
+
+      if (IS_CBRANCH (subtype))
+	fragp->fr_subtype = CBRANCH_SUBTYPE (n);
+      else
+	fragp->fr_subtype = UBRANCH_SUBTYPE (n);
+
+      return (nios2_relax_subtype_size (fragp->fr_subtype)
+	      - nios2_relax_subtype_size (subtype));
+    }
+
+  /* If we got here, it's probably an error.  */
+  return 0;
+}
+
+
+/* Complete fragp using the data from the relaxation pass. */
+void
+md_convert_frag (bfd *headers ATTRIBUTE_UNUSED, segT segment ATTRIBUTE_UNUSED,
+		 fragS *fragp)
+{
+  char *buffer = fragp->fr_literal + fragp->fr_fix;
+  relax_substateT subtype = fragp->fr_subtype;
+  int n = SUBTYPE_ADDIS (subtype);
+  addressT target = fragp->fr_offset;
+  symbolS *symbolp = fragp->fr_symbol;
+  offsetT offset;
+  unsigned int addend_mask, addi_mask;
+  offsetT addend, remainder;
+  int i;
+
+  /* If we didn't or can't relax, this is a regular branch instruction.
+     We just need to generate the fixup for the symbol and offset.  */
+  if (n == 0)
+    {
+      fix_new (fragp, fragp->fr_fix, 4, fragp->fr_symbol, fragp->fr_offset, 1,
+	       BFD_RELOC_16_PCREL);
+      fragp->fr_fix += 4;
+      return;
+    }
+
+  /* Replace the cbranch at fr_fix with one that has the opposite condition
+     in order to jump around the block of instructions we'll be adding.  */
+  if (IS_CBRANCH (subtype))
+    {
+      unsigned int br_opcode;
+      int nbytes;
+
+      /* Account for the nextpc and jmp in the pc-relative case, or the two
+	 load instructions and jump in the absolute case.  */
+      if (nios2_as_options.relax == relax_section)
+	nbytes = (n + 2) * 4;
+      else
+	nbytes = 12;
+
+      br_opcode = md_chars_to_number (buffer, 4);
+      switch (br_opcode & OP_MASK_OP)
+	{
+	case OP_MATCH_BEQ:
+	  br_opcode = (br_opcode & ~OP_MASK_OP) | OP_MATCH_BNE;
+	  break;
+	case OP_MATCH_BNE:
+	  br_opcode = (br_opcode & ~OP_MASK_OP) | OP_MATCH_BEQ ;
+	  break;
+	case OP_MATCH_BGE:
+	  br_opcode = (br_opcode & ~OP_MASK_OP) | OP_MATCH_BLT ;
+	  break;
+	case OP_MATCH_BGEU:
+	  br_opcode = (br_opcode & ~OP_MASK_OP) | OP_MATCH_BLTU ;
+	  break;
+	case OP_MATCH_BLT:
+	  br_opcode = (br_opcode & ~OP_MASK_OP) | OP_MATCH_BGE ;
+	  break;
+	case OP_MATCH_BLTU:
+	  br_opcode = (br_opcode & ~OP_MASK_OP) | OP_MATCH_BGEU ;
+	  break;
+	default:
+	  as_bad_where (fragp->fr_file, fragp->fr_line,
+			_("expecting conditional branch for relaxation\n"));
+	  abort ();
+	}
+
+      br_opcode = br_opcode | (nbytes << OP_SH_IMM16);
+      md_number_to_chars (buffer, br_opcode, 4);
+      fragp->fr_fix += 4;
+      buffer += 4;
+    }
+
+  /* Load at for the PC-relative case.  */
+  if (nios2_as_options.relax == relax_section)
+    {
+      /* Insert the nextpc instruction.  */
+      md_number_to_chars (buffer,
+			  OP_MATCH_NEXTPC | (AT_REGNUM << OP_SH_RRD), 4);
+      fragp->fr_fix += 4;
+      buffer += 4;
+  
+      /* We need to know whether the offset is positive or negative.  */
+      target += S_GET_VALUE (symbolp);
+      offset = target - fragp->fr_address - fragp->fr_fix;
+      if (offset > 0)
+	addend = 32767;
+      else
+	addend = -32768;
+      addend_mask = (((unsigned int)addend) & 0xffff) << OP_SH_IMM16;
+
+      /* Insert n-1 addi instructions.  */
+      addi_mask = (OP_MATCH_ADDI
+		   | (AT_REGNUM << OP_SH_IRD)
+		   | (AT_REGNUM << OP_SH_IRS));
+      for (i = 0; i < n - 1; i ++)
+	{
+	  md_number_to_chars (buffer, addi_mask | addend_mask, 4);
+	  fragp->fr_fix += 4;
+	  buffer += 4;
+	}
+
+      /* Insert the last addi instruction to hold the remainder.  */
+      remainder = offset - addend * (n - 1);
+      gas_assert (remainder >= -32768 && remainder <= 32767);
+      addend_mask = (((unsigned int)remainder) & 0xffff) << OP_SH_IMM16;
+      md_number_to_chars (buffer, addi_mask | addend_mask, 4);
+      fragp->fr_fix += 4;
+      buffer += 4;
+    }
+
+  /* Load at for the absolute case.  */
+  else
+    {
+      md_number_to_chars (buffer, OP_MATCH_ORHI | 0x00400000, 4);
+      fix_new (fragp, fragp->fr_fix, 4, fragp->fr_symbol, fragp->fr_offset,
+	       0, BFD_RELOC_NIOS2_HI16);
+      fragp->fr_fix += 4;
+      buffer += 4;
+      md_number_to_chars (buffer, OP_MATCH_ORI | 0x08400000, 4);
+      fix_new (fragp, fragp->fr_fix, 4, fragp->fr_symbol, fragp->fr_offset,
+	       0, BFD_RELOC_NIOS2_LO16);
+      fragp->fr_fix += 4;
+      buffer += 4;
+    }
+
+  /* Insert the jmp instruction.  */
+  md_number_to_chars (buffer, OP_MATCH_JMP | (AT_REGNUM << OP_SH_RRS), 4);
+  fragp->fr_fix += 4;
+  buffer += 4;
+}
+
+
+/** Fixups and overflow checking.  */
+
+/* Check a fixup for overflow. */
+static bfd_boolean
+nios2_check_overflow (valueT fixup, reloc_howto_type *howto)
+{
+  /* Apply the rightshift before checking for overflow.  */
+  fixup = ((signed)fixup) >> howto->rightshift;
+
+  /* Check for overflow - return TRUE if overflow, FALSE if not.  */
+  switch (howto->complain_on_overflow)
+    {
+    case complain_overflow_dont:
+      break;
+    case complain_overflow_bitfield:
+      if ((fixup >> howto->bitsize) != 0
+	  && ((signed) fixup >> howto->bitsize) != -1)
+	return TRUE;
+      break;
+    case complain_overflow_signed:
+      if ((fixup & 0x80000000) > 0)
+	{
+	  /* Check for negative overflow.  */
+	  if ((signed) fixup < ((signed) 0x80000000 >> howto->bitsize))
+	    return TRUE;
+	}
+      else
+	{
+	  /* Check for positive overflow.  */
+	  if (fixup >= ((unsigned) 1 << (howto->bitsize - 1)))
+	    return TRUE;
+	}
+      break;
+    case complain_overflow_unsigned:
+      if ((fixup >> howto->bitsize) != 0)
+	return TRUE;
+      break;
+    default:
+      as_bad (_("error checking for overflow - broken assembler"));
+      break;
+    }
+  return FALSE;
+}
+
+/* Emit diagnostic for fixup overflow.  */
+static void
+nios2_diagnose_overflow (valueT fixup, reloc_howto_type *howto,
+			 fixS *fixP, valueT value)
+{
+  if (fixP->fx_r_type == BFD_RELOC_8
+      || fixP->fx_r_type == BFD_RELOC_16
+      || fixP->fx_r_type == BFD_RELOC_32)
+    /* These relocs are against data, not instructions.  */
+    as_bad_where (fixP->fx_file, fixP->fx_line,
+		  _("immediate value 0x%x truncated to 0x%x"),
+		  (unsigned int) fixup,
+		  (unsigned int) (~(~(valueT) 0 << howto->bitsize) & fixup));
+  else
+    {
+      /* What opcode is the instruction?  This will determine
+	 whether we check for overflow in immediate values
+	 and what error message we get.  */
+      const struct nios2_opcode *opcode;
+      enum overflow_type overflow_msg_type;
+      unsigned int range_min;
+      unsigned int range_max;
+      unsigned int address;
+      gas_assert (fixP->fx_size == 4);
+      opcode = nios2_find_opcode_hash (value);
+      gas_assert (opcode);
+      overflow_msg_type = opcode->overflow_msg;
+      switch (overflow_msg_type)
+	{
+	case call_target_overflow:
+	  range_min
+	    = ((fixP->fx_frag->fr_address + fixP->fx_where) & 0xf0000000);
+	  range_max = range_min + 0x0fffffff;
+	  address = fixup | range_min;
+	  
+	  as_bad_where (fixP->fx_file, fixP->fx_line,
+			_("call target address 0x%08x out of range 0x%08x to 0x%08x"),
+			address, range_min, range_max);
+	  break;
+	case branch_target_overflow:
+	  as_bad_where (fixP->fx_file, fixP->fx_line,
+			_("branch offset %d out of range %d to %d"),
+			(int)fixup, -32768, 32767);
+	  break;
+	case address_offset_overflow:
+	  as_bad_where (fixP->fx_file, fixP->fx_line,
+			_("%s offset %d out of range %d to %d"),
+			opcode->name, (int)fixup, -32768, 32767);
+	  break;
+	case signed_immed16_overflow:
+	  as_bad_where (fixP->fx_file, fixP->fx_line,
+			_("immediate value %d out of range %d to %d"),
+			(int)fixup, -32768, 32767);
+	  break;
+	case unsigned_immed16_overflow:
+	  as_bad_where (fixP->fx_file, fixP->fx_line,
+			_("immediate value %u out of range %u to %u"),
+			(unsigned int)fixup, 0, 65535);
+	  break;
+	case unsigned_immed5_overflow:
+	  as_bad_where (fixP->fx_file, fixP->fx_line,
+			_("immediate value %u out of range %u to %u"),
+			(unsigned int)fixup, 0, 31);
+	  break;
+	case custom_opcode_overflow:
+	  as_bad_where (fixP->fx_file, fixP->fx_line,
+			_("custom instruction opcode %u out of range %u to %u"),
+			(unsigned int)fixup, 0, 255);
+	  break;
+	default:
+	  as_bad_where (fixP->fx_file, fixP->fx_line,
+			_("overflow in immediate argument"));
+	  break;
+	}
+    }
+}
+
+/* Apply a fixup to the object file.  */
+void
+md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
+{
+  /* Assert that the fixup is one we can handle.  */
+  gas_assert (fixP != NULL && valP != NULL
+	      && (fixP->fx_r_type == BFD_RELOC_8
+		  || fixP->fx_r_type == BFD_RELOC_16
+		  || fixP->fx_r_type == BFD_RELOC_32
+		  || fixP->fx_r_type == BFD_RELOC_64
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_S16
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_U16
+		  || fixP->fx_r_type == BFD_RELOC_16_PCREL
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL26
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_IMM5
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_CACHE_OPX
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_IMM6
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_IMM8
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_HI16
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_LO16
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_HIADJ16
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_GPREL
+		  || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+		  || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_UJMP
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_CJMP
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_CALLR
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_ALIGN
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_GOT16
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL16
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_GOTOFF_LO
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_GOTOFF_HA
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_TLS_GD16
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_TLS_LDM16
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_TLS_LDO16
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_TLS_IE16
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_TLS_LE16
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_GOTOFF
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_TLS_DTPREL
+		  /* Add other relocs here as we generate them.  */
+		  ));
+
+  if (fixP->fx_r_type == BFD_RELOC_64)
+    {
+      /* We may reach here due to .8byte directives, but we never output
+	 BFD_RELOC_64; it must be resolved.  */      
+      if (fixP->fx_addsy != NULL)
+	as_bad_where (fixP->fx_file, fixP->fx_line,
+		      _("cannot create 64-bit relocation"));
+      else
+	{
+	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+			      *valP, 8);
+	  fixP->fx_done = 1;
+	}
+      return;
+    }
+
+  /* The value passed in valP can be the value of a fully
+     resolved expression, or it can be the value of a partially
+     resolved expression.  In the former case, both fixP->fx_addsy
+     and fixP->fx_subsy are NULL, and fixP->fx_offset == *valP, and
+     we can fix up the instruction that fixP relates to.
+     In the latter case, one or both of fixP->fx_addsy and
+     fixP->fx_subsy are not NULL, and fixP->fx_offset may or may not
+     equal *valP.  We don't need to check for fixP->fx_subsy being null
+     because the generic part of the assembler generates an error if
+     it is not an absolute symbol.  */
+  if (fixP->fx_addsy != NULL)
+    /* Partially resolved expression.  */
+    {
+      fixP->fx_addnumber = fixP->fx_offset;
+      fixP->fx_done = 0;
+
+      switch (fixP->fx_r_type)
+        {
+        case BFD_RELOC_NIOS2_TLS_GD16:
+        case BFD_RELOC_NIOS2_TLS_LDM16:
+        case BFD_RELOC_NIOS2_TLS_LDO16:
+        case BFD_RELOC_NIOS2_TLS_IE16:
+        case BFD_RELOC_NIOS2_TLS_LE16:
+        case BFD_RELOC_NIOS2_TLS_DTPMOD:
+        case BFD_RELOC_NIOS2_TLS_DTPREL:
+        case BFD_RELOC_NIOS2_TLS_TPREL:
+          S_SET_THREAD_LOCAL (fixP->fx_addsy);
+	  break;
+	default:
+	  break;
+        }
+    }
+  else
+    /* Fully resolved fixup.  */
+    {
+      reloc_howto_type *howto
+	= bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
+
+      if (howto == NULL)
+	as_bad_where (fixP->fx_file, fixP->fx_line,
+		      _("relocation is not supported"));
+      else
+	{
+	  valueT fixup = *valP;
+	  valueT value;
+	  char *buf;
+
+	  /* If this is a pc-relative relocation, we need to
+	     subtract the current offset within the object file
+	     FIXME : for some reason fixP->fx_pcrel isn't 1 when it should be
+	     so I'm using the howto structure instead to determine this.  */
+	  if (howto->pc_relative == 1)
+	    fixup = fixup - (fixP->fx_frag->fr_address + fixP->fx_where + 4);
+
+	  /* Get the instruction or data to be fixed up.  */
+	  buf = fixP->fx_frag->fr_literal + fixP->fx_where;
+	  value = md_chars_to_number (buf, fixP->fx_size);
+
+	  /* Check for overflow, emitting a diagnostic if necessary.  */
+	  if (nios2_check_overflow (fixup, howto))
+	    nios2_diagnose_overflow (fixup, howto, fixP, value);
+
+	  /* Apply the right shift.  */
+	  fixup = ((signed)fixup) >> howto->rightshift;
+
+	  /* Truncate the fixup to right size.  */
+	  switch (fixP->fx_r_type)
+	    {
+	    case BFD_RELOC_NIOS2_HI16:
+	      fixup = (fixup >> 16) & 0xFFFF;
+	      break;
+	    case BFD_RELOC_NIOS2_LO16:
+	      fixup = fixup & 0xFFFF;
+	      break;
+	    case BFD_RELOC_NIOS2_HIADJ16:
+	      fixup = ((fixup >> 16) & 0xFFFF) + ((fixup >> 15) & 0x01);
+	      break;
+	    default:
+	      fixup = (fixup << (32 - howto->bitsize)) >> (32 - howto->bitsize);
+	      break;
+	    }
+
+	  /* Fix up the instruction.  */
+	  value = (value & ~howto->dst_mask) | (fixup << howto->bitpos);
+	  md_number_to_chars (buf, value, fixP->fx_size);
+	}
+
+      fixP->fx_done = 1;
+    }
+
+  if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT)
+    {
+      fixP->fx_done = 0;
+      if (fixP->fx_addsy
+	  && !S_IS_DEFINED (fixP->fx_addsy) && !S_IS_WEAK (fixP->fx_addsy))
+	S_SET_WEAK (fixP->fx_addsy);
+    }
+  else if (fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+    fixP->fx_done = 0;
+}
+
+
+
+/** Instruction parsing support. */
+
+/* Special relocation directive strings.  */
+
+struct nios2_special_relocS
+{
+  const char *string;
+  bfd_reloc_code_real_type reloc_type;
+};
+
+struct nios2_special_relocS nios2_special_reloc[] = {
+  {"%hiadj", BFD_RELOC_NIOS2_HIADJ16},
+  {"%hi", BFD_RELOC_NIOS2_HI16},
+  {"%lo", BFD_RELOC_NIOS2_LO16},
+  {"%gprel", BFD_RELOC_NIOS2_GPREL},
+  {"%call", BFD_RELOC_NIOS2_CALL16},
+  {"%gotoff_lo", BFD_RELOC_NIOS2_GOTOFF_LO},
+  {"%gotoff_hiadj", BFD_RELOC_NIOS2_GOTOFF_HA},
+  {"%tls_gd", BFD_RELOC_NIOS2_TLS_GD16},
+  {"%tls_ldm", BFD_RELOC_NIOS2_TLS_LDM16},
+  {"%tls_ldo", BFD_RELOC_NIOS2_TLS_LDO16},
+  {"%tls_ie", BFD_RELOC_NIOS2_TLS_IE16},
+  {"%tls_le", BFD_RELOC_NIOS2_TLS_LE16},
+  {"%gotoff", BFD_RELOC_NIOS2_GOTOFF},
+  {"%got", BFD_RELOC_NIOS2_GOT16}
+};
+
+#define NIOS2_NUM_SPECIAL_RELOCS \
+	(sizeof(nios2_special_reloc)/sizeof(nios2_special_reloc[0]))
+const int nios2_num_special_relocs = NIOS2_NUM_SPECIAL_RELOCS;
+
+/* Creates a new nios2_insn_relocS and returns a pointer to it.  */
+static nios2_insn_relocS *
+nios2_insn_reloc_new (bfd_reloc_code_real_type reloc_type, unsigned int pcrel)
+{
+  nios2_insn_relocS *retval;
+  retval = (nios2_insn_relocS *) malloc (sizeof (nios2_insn_relocS));
+  if (retval == NULL)
+    {
+      as_bad (_("can't create relocation"));
+      abort ();
+    }
+
+  /* Fill out the fields with default values.  */
+  retval->reloc_next = NULL;
+  retval->reloc_type = reloc_type;
+  retval->reloc_pcrel = pcrel;
+  return retval;
+}
+
+/* Frees up memory previously allocated by nios2_insn_reloc_new().  */
+/* FIXME:  this is never called; memory leak?  */
+#if 0
+static void
+nios2_insn_reloc_destroy (nios2_insn_relocS *reloc)
+{
+  gas_assert (reloc != NULL);
+  free (reloc);
+}
+#endif
+
+/* The various nios2_assemble_* functions call this
+   function to generate an expression from a string representing an expression.
+   It then tries to evaluate the expression, and if it can, returns its value.
+   If not, it creates a new nios2_insn_relocS and stores the expression and 
+   reloc_type for future use.  */
+static unsigned long
+nios2_assemble_expression (const char *exprstr,
+			   nios2_insn_infoS *insn,
+			   nios2_insn_relocS *prev_reloc,
+			   bfd_reloc_code_real_type reloc_type,
+			   unsigned int pcrel)
+{
+  nios2_insn_relocS *reloc;
+  char *saved_line_ptr;
+  unsigned short value;
+  int i;
+
+  gas_assert (exprstr != NULL);
+  gas_assert (insn != NULL);
+
+  /* Check for relocation operators.
+     Change the relocation type and advance the ptr to the start of
+     the expression proper. */
+  for (i = 0; i < nios2_num_special_relocs; i++)
+    if (strstr (exprstr, nios2_special_reloc[i].string) != NULL)
+      {
+	reloc_type = nios2_special_reloc[i].reloc_type;
+	exprstr += strlen (nios2_special_reloc[i].string) + 1;
+	
+	/* %lo and %hiadj have different meanings for PC-relative
+	   expressions.  */
+	if (pcrel)
+	  {
+	    if (reloc_type == BFD_RELOC_NIOS2_LO16)
+	      reloc_type = BFD_RELOC_NIOS2_PCREL_LO;
+	    if (reloc_type == BFD_RELOC_NIOS2_HIADJ16)
+	      reloc_type = BFD_RELOC_NIOS2_PCREL_HA;
+	  }
+	
+	break;
+      }
+
+  /* We potentially have a relocation.  */
+  reloc = nios2_insn_reloc_new (reloc_type, pcrel);
+  if (prev_reloc != NULL)
+    prev_reloc->reloc_next = reloc;
+  else
+    insn->insn_reloc = reloc;
+
+  /* Parse the expression string.  */
+  saved_line_ptr = input_line_pointer;
+  input_line_pointer = (char *) exprstr;
+  expression (&reloc->reloc_expression);
+  input_line_pointer = saved_line_ptr;
+
+  /* This is redundant as the fixup will put this into
+     the instruction, but it is included here so that
+     self-test mode (-r) works.  */
+  value = 0;
+  if (nios2_mode == NIOS2_MODE_TEST
+      && reloc->reloc_expression.X_op == O_constant)
+    value = reloc->reloc_expression.X_add_number;
+
+  return (unsigned long) value;
+}
+
+/* Argument assemble functions.
+   All take an instruction argument string, and a pointer
+   to an instruction opcode. Upon return the insn_opcode
+   has the relevant fields filled in to represent the arg
+   string.  The return value is NULL if successful, or
+   an error message if an error was detected.
+
+   The naming conventions for these functions match the args template
+   in the nios2_opcode structure, as documented in include/opcode/nios2.h.
+   For example, nios2_assemble_args_dst is used for instructions with
+   "d,s,t" args.
+   See nios2_arg_info_structs below for the exact correspondence.  */
+
+static void
+nios2_assemble_args_dst (nios2_insn_infoS *insn_info)
+{
+  if (insn_info->insn_tokens[1] != NULL
+      && insn_info->insn_tokens[2] != NULL
+      && insn_info->insn_tokens[3] != NULL)
+    {
+      struct nios2_reg *dst = nios2_reg_lookup (insn_info->insn_tokens[1]);
+      struct nios2_reg *src1 = nios2_reg_lookup (insn_info->insn_tokens[2]);
+      struct nios2_reg *src2 = nios2_reg_lookup (insn_info->insn_tokens[3]);
+
+      if (dst == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[1]);
+      else
+	SET_INSN_FIELD (RRD, insn_info->insn_code, dst->index);
+
+      if (src1 == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[2]);
+      else
+	SET_INSN_FIELD (RRS, insn_info->insn_code, src1->index);
+
+      if (src2 == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[3]);
+      else
+	SET_INSN_FIELD (RRT, insn_info->insn_code, src2->index);
+
+      nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[4]);
+    }
+}
+
+static void
+nios2_assemble_args_tsi (nios2_insn_infoS *insn_info)
+{
+  if (insn_info->insn_tokens[1] != NULL &&
+      insn_info->insn_tokens[2] != NULL && insn_info->insn_tokens[3] != NULL)
+    {
+      struct nios2_reg *dst = nios2_reg_lookup (insn_info->insn_tokens[1]);
+      struct nios2_reg *src1 = nios2_reg_lookup (insn_info->insn_tokens[2]);
+      unsigned int src2
+	= nios2_assemble_expression (insn_info->insn_tokens[3], insn_info,
+				     insn_info->insn_reloc, BFD_RELOC_NIOS2_S16,
+				     0);
+
+      if (dst == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[1]);
+      else
+	SET_INSN_FIELD (IRT, insn_info->insn_code, dst->index);
+
+      if (src1 == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[2]);
+      else
+	SET_INSN_FIELD (IRS, insn_info->insn_code, src1->index);
+
+      SET_INSN_FIELD (IMM16, insn_info->insn_code, src2);
+      nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[4]);
+      SET_INSN_FIELD (IMM16, insn_info->insn_code, 0);
+    }
+}
+
+static void
+nios2_assemble_args_tsu (nios2_insn_infoS *insn_info)
+{
+  if (insn_info->insn_tokens[1] != NULL
+      && insn_info->insn_tokens[2] != NULL
+      && insn_info->insn_tokens[3] != NULL)
+    {
+      struct nios2_reg *dst = nios2_reg_lookup (insn_info->insn_tokens[1]);
+      struct nios2_reg *src1 = nios2_reg_lookup (insn_info->insn_tokens[2]);
+      unsigned int src2
+	= nios2_assemble_expression (insn_info->insn_tokens[3], insn_info,
+				     insn_info->insn_reloc, BFD_RELOC_NIOS2_U16,
+				     0);
+
+      if (dst == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[1]);
+      else
+	SET_INSN_FIELD (IRT, insn_info->insn_code, dst->index);
+
+      if (src1 == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[2]);
+      else
+	SET_INSN_FIELD (IRS, insn_info->insn_code, src1->index);
+
+      SET_INSN_FIELD (IMM16, insn_info->insn_code, src2);
+      nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[4]);
+      SET_INSN_FIELD (IMM16, insn_info->insn_code, 0);
+    }
+}
+
+static void
+nios2_assemble_args_sto (nios2_insn_infoS *insn_info)
+{
+  if (insn_info->insn_tokens[1] != NULL
+      && insn_info->insn_tokens[2] != NULL
+      && insn_info->insn_tokens[3] != NULL)
+    {
+      struct nios2_reg *dst = nios2_reg_lookup (insn_info->insn_tokens[1]);
+      struct nios2_reg *src1 = nios2_reg_lookup (insn_info->insn_tokens[2]);
+      unsigned int src2
+	= nios2_assemble_expression (insn_info->insn_tokens[3], insn_info,
+				     insn_info->insn_reloc, BFD_RELOC_16_PCREL,
+				     1);
+
+      if (dst == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[1]);
+      else
+	SET_INSN_FIELD (IRS, insn_info->insn_code, dst->index);
+
+      if (src1 == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[2]);
+      else
+	SET_INSN_FIELD (IRT, insn_info->insn_code, src1->index);
+
+      SET_INSN_FIELD (IMM16, insn_info->insn_code, src2);
+      nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[4]);
+      SET_INSN_FIELD (IMM16, insn_info->insn_code, 0);
+    }
+}
+
+static void
+nios2_assemble_args_o (nios2_insn_infoS *insn_info)
+{
+  if (insn_info->insn_tokens[1] != NULL)
+    {
+      unsigned long immed
+	= nios2_assemble_expression (insn_info->insn_tokens[1], insn_info,
+				     insn_info->insn_reloc, BFD_RELOC_16_PCREL,
+				     1);
+      SET_INSN_FIELD (IMM16, insn_info->insn_code, immed);
+      nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[2]);
+      SET_INSN_FIELD (IMM16, insn_info->insn_code, 0);
+    }
+}
+
+static void
+nios2_assemble_args_is (nios2_insn_infoS *insn_info)
+{
+  if (insn_info->insn_tokens[1] != NULL && insn_info->insn_tokens[2] != NULL)
+    {
+      struct nios2_reg *addr_src = nios2_reg_lookup (insn_info->insn_tokens[2]);
+      unsigned long immed
+	= nios2_assemble_expression (insn_info->insn_tokens[1], insn_info,
+				     insn_info->insn_reloc, BFD_RELOC_NIOS2_S16,
+				     0);
+
+      SET_INSN_FIELD (IMM16, insn_info->insn_code, immed);
+
+      if (addr_src == NULL)
+	as_bad (_("unknown base register %s"), insn_info->insn_tokens[2]);
+      else
+	SET_INSN_FIELD (RRS, insn_info->insn_code, addr_src->index);
+
+      nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[3]);
+      SET_INSN_FIELD (IMM16, insn_info->insn_code, 0);
+    }
+}
+
+static void
+nios2_assemble_args_m (nios2_insn_infoS *insn_info)
+{
+  if (insn_info->insn_tokens[1] != NULL)
+    {
+      unsigned long immed
+	= nios2_assemble_expression (insn_info->insn_tokens[1], insn_info,
+				     insn_info->insn_reloc,
+				     BFD_RELOC_NIOS2_CALL26, 0);
+
+      SET_INSN_FIELD (IMM26, insn_info->insn_code, immed);
+      nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[2]);
+      SET_INSN_FIELD (IMM26, insn_info->insn_code, 0);
+    }
+}
+
+static void
+nios2_assemble_args_s (nios2_insn_infoS *insn_info)
+{
+  if (insn_info->insn_tokens[1] != NULL)
+    {
+      struct nios2_reg *src = nios2_reg_lookup (insn_info->insn_tokens[1]);
+      if (src == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[1]);
+      else
+	SET_INSN_FIELD (RRS, insn_info->insn_code, src->index);
+
+      nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[2]);
+    }
+}
+
+static void
+nios2_assemble_args_tis (nios2_insn_infoS *insn_info)
+{
+  if (insn_info->insn_tokens[1] != NULL
+      && insn_info->insn_tokens[2] != NULL
+      && insn_info->insn_tokens[3] != NULL)
+    {
+      struct nios2_reg *dst = nios2_reg_lookup (insn_info->insn_tokens[1]);
+      struct nios2_reg *addr_src = nios2_reg_lookup (insn_info->insn_tokens[3]);
+      unsigned long immed
+	= nios2_assemble_expression (insn_info->insn_tokens[2], insn_info,
+				     insn_info->insn_reloc, BFD_RELOC_NIOS2_S16,
+				     0);
+
+      if (addr_src == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[3]);
+      else
+	SET_INSN_FIELD (RRS, insn_info->insn_code, addr_src->index);
+
+      if (dst == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[1]);
+      else
+	SET_INSN_FIELD (RRT, insn_info->insn_code, dst->index);
+
+      SET_INSN_FIELD (IMM16, insn_info->insn_code, immed);
+      nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[4]);
+      SET_INSN_FIELD (IMM16, insn_info->insn_code, 0);
+    }
+}
+
+static void
+nios2_assemble_args_dc (nios2_insn_infoS *insn_info)
+{
+  if (insn_info->insn_tokens[1] != NULL && insn_info->insn_tokens[2] != NULL)
+    {
+      struct nios2_reg *ctl = nios2_reg_lookup (insn_info->insn_tokens[2]);
+      struct nios2_reg *dst = nios2_reg_lookup (insn_info->insn_tokens[1]);
+
+      if (ctl == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[1]);
+      else
+	SET_INSN_FIELD (RCTL, insn_info->insn_code, ctl->index);
+
+      if (dst == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[2]);
+      else
+	SET_INSN_FIELD (RRD, insn_info->insn_code, dst->index);
+
+      nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[3]);
+    }
+}
+
+static void
+nios2_assemble_args_cs (nios2_insn_infoS *insn_info)
+{
+  if (insn_info->insn_tokens[1] != NULL && insn_info->insn_tokens[2] != NULL)
+    {
+      struct nios2_reg *ctl = nios2_reg_lookup (insn_info->insn_tokens[1]);
+      struct nios2_reg *src = nios2_reg_lookup (insn_info->insn_tokens[2]);
+
+      if (ctl == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[1]);
+      else if (ctl->index == 4)
+	as_bad (_("ipending control register (ctl4) is read-only\n"));
+      else
+	SET_INSN_FIELD (RCTL, insn_info->insn_code, ctl->index);
+
+      if (src == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[2]);
+      else
+	SET_INSN_FIELD (RRS, insn_info->insn_code, src->index);
+
+      nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[3]);
+    }
+}
+
+static void
+nios2_assemble_args_ldst (nios2_insn_infoS *insn_info)
+{
+  if (insn_info->insn_tokens[1] != NULL
+      && insn_info->insn_tokens[2] != NULL
+      && insn_info->insn_tokens[3] != NULL
+      && insn_info->insn_tokens[4] != NULL)
+    {
+      unsigned long custom_n
+	= nios2_assemble_expression (insn_info->insn_tokens[1], insn_info,
+				     insn_info->insn_reloc,
+				     BFD_RELOC_NIOS2_IMM8, 0);
+
+      struct nios2_reg *dst = nios2_reg_lookup (insn_info->insn_tokens[2]);
+      struct nios2_reg *src1 = nios2_reg_lookup (insn_info->insn_tokens[3]);
+      struct nios2_reg *src2 = nios2_reg_lookup (insn_info->insn_tokens[4]);
+
+      SET_INSN_FIELD (CUSTOM_N, insn_info->insn_code, custom_n);
+
+      if (dst == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[2]);
+      else
+	SET_INSN_FIELD (RRD, insn_info->insn_code, dst->index);
+
+      if (src1 == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[3]);
+      else
+	SET_INSN_FIELD (RRS, insn_info->insn_code, src1->index);
+
+      if (src2 == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[4]);
+      else
+	SET_INSN_FIELD (RRT, insn_info->insn_code, src2->index);
+
+      /* Set or clear the bits to indicate whether coprocessor registers are 
+ 	 used.  */
+      if (nios2_coproc_reg (insn_info->insn_tokens[2]))
+	SET_INSN_FIELD (CUSTOM_C, insn_info->insn_code, 0);
+      else
+	SET_INSN_FIELD (CUSTOM_C, insn_info->insn_code, 1);
+
+      if (nios2_coproc_reg (insn_info->insn_tokens[3]))
+	SET_INSN_FIELD (CUSTOM_A, insn_info->insn_code, 0);
+      else
+	SET_INSN_FIELD (CUSTOM_A, insn_info->insn_code, 1);
+
+      if (nios2_coproc_reg (insn_info->insn_tokens[4]))
+	SET_INSN_FIELD (CUSTOM_B, insn_info->insn_code, 0);
+      else
+	SET_INSN_FIELD (CUSTOM_B, insn_info->insn_code, 1);
+
+      nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[5]);
+    }
+}
+
+static void
+nios2_assemble_args_none (nios2_insn_infoS *insn_info ATTRIBUTE_UNUSED)
+{
+  /* Nothing to do.  */
+}
+
+static void
+nios2_assemble_args_dsj (nios2_insn_infoS *insn_info)
+{
+  if (insn_info->insn_tokens[1] != NULL
+      && insn_info->insn_tokens[2] != NULL
+      && insn_info->insn_tokens[3] != NULL)
+    {
+      struct nios2_reg *dst = nios2_reg_lookup (insn_info->insn_tokens[1]);
+      struct nios2_reg *src1 = nios2_reg_lookup (insn_info->insn_tokens[2]);
+
+      /* A 5-bit constant expression.  */
+      unsigned int src2 =
+	nios2_assemble_expression (insn_info->insn_tokens[3], insn_info,
+				   insn_info->insn_reloc,
+				   BFD_RELOC_NIOS2_IMM5, 0);
+
+      if (dst == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[1]);
+      else
+	SET_INSN_FIELD (RRD, insn_info->insn_code, dst->index);
+
+      if (src1 == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[2]);
+      else
+	SET_INSN_FIELD (RRS, insn_info->insn_code, src1->index);
+
+      SET_INSN_FIELD (IMM5, insn_info->insn_code, src2);
+      nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[4]);
+      SET_INSN_FIELD (IMM5, insn_info->insn_code, 0);
+    }
+}
+
+static void
+nios2_assemble_args_d (nios2_insn_infoS *insn_info)
+{
+  if (insn_info->insn_tokens[1] != NULL)
+    {
+      struct nios2_reg *dst = nios2_reg_lookup (insn_info->insn_tokens[1]);
+
+      if (dst == NULL)
+	as_bad (_("unknown register %s"), insn_info->insn_tokens[1]);
+      else
+	SET_INSN_FIELD (RRD, insn_info->insn_code, dst->index);
+
+      nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[2]);
+    }
+}
+
+static void
+nios2_assemble_args_b (nios2_insn_infoS *insn_info)
+{
+  unsigned int imm5 = 0;
+
+  if (insn_info->insn_tokens[1] != NULL)
+    {
+      /* A 5-bit constant expression.  */
+      imm5 = nios2_assemble_expression (insn_info->insn_tokens[1],
+					insn_info, insn_info->insn_reloc,
+					BFD_RELOC_NIOS2_IMM5, 0);
+      SET_INSN_FIELD (TRAP_IMM5, insn_info->insn_code, imm5);
+      nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[2]);
+    }
+
+  SET_INSN_FIELD (TRAP_IMM5, insn_info->insn_code, imm5);
+
+  nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[2]);
+}
+
+/* This table associates pointers to functions that parse the arguments to an
+   instruction and fill in the relevant fields of the instruction.  */
+const nios2_arg_infoS nios2_arg_info_structs[] = {
+  /* args, assemble_args_func */
+  {"d,s,t", nios2_assemble_args_dst},
+  {"d,s,t,E", nios2_assemble_args_dst},
+  {"t,s,i", nios2_assemble_args_tsi},
+  {"t,s,i,E", nios2_assemble_args_tsi},
+  {"t,s,u", nios2_assemble_args_tsu},
+  {"t,s,u,E", nios2_assemble_args_tsu},
+  {"s,t,o", nios2_assemble_args_sto},
+  {"s,t,o,E", nios2_assemble_args_sto},
+  {"o", nios2_assemble_args_o},
+  {"o,E", nios2_assemble_args_o},
+  {"s", nios2_assemble_args_s},
+  {"s,E", nios2_assemble_args_s},
+  {"", nios2_assemble_args_none},
+  {"E", nios2_assemble_args_none},
+  {"i(s)", nios2_assemble_args_is},
+  {"i(s)E", nios2_assemble_args_is},
+  {"m", nios2_assemble_args_m},
+  {"m,E", nios2_assemble_args_m},
+  {"t,i(s)", nios2_assemble_args_tis},
+  {"t,i(s)E", nios2_assemble_args_tis},
+  {"d,c", nios2_assemble_args_dc},
+  {"d,c,E", nios2_assemble_args_dc},
+  {"c,s", nios2_assemble_args_cs},
+  {"c,s,E", nios2_assemble_args_cs},
+  {"l,d,s,t", nios2_assemble_args_ldst},
+  {"l,d,s,t,E", nios2_assemble_args_ldst},
+  {"d,s,j", nios2_assemble_args_dsj},
+  {"d,s,j,E", nios2_assemble_args_dsj},
+  {"d", nios2_assemble_args_d},
+  {"d,E", nios2_assemble_args_d},
+  {"b", nios2_assemble_args_b},
+  {"b,E", nios2_assemble_args_b}
+};
+
+#define NIOS2_NUM_ARGS \
+	((sizeof(nios2_arg_info_structs)/sizeof(nios2_arg_info_structs[0])))
+const int nios2_num_arg_info_structs = NIOS2_NUM_ARGS;
+
+/* The function consume_arg takes a pointer into a string
+   of instruction tokens (args) and a pointer into a string
+   representing the expected sequence of tokens and separators.
+   It checks whether the first argument in argstr is of the
+   expected type, throwing an error if it is not, and returns
+   the pointer argstr.  */
+static char *
+nios2_consume_arg (nios2_insn_infoS *insn, char *argstr, const char *parsestr)
+{
+  char *temp;
+  int regno = -1;
+  
+  switch (*parsestr)
+    {
+    case 'c':
+      if (!nios2_control_register_arg_p (argstr))
+	as_bad (_("expecting control register"));
+      break;
+    case 'd':
+    case 's':
+    case 't':
+
+      /* We check to make sure we don't have a control register.  */
+      if (nios2_control_register_arg_p (argstr))
+	as_bad (_("illegal use of control register"));
+
+      /* And whether coprocessor registers are valid here.  */
+      if (nios2_coproc_reg (argstr)
+	  && insn->insn_nios2_opcode->match != OP_MATCH_CUSTOM)
+	as_bad (_("illegal use of coprocessor register\n"));
+
+      /* Extract a register number if the register is of the 
+         form r[0-9]+, if it is a normal register, set
+         regno to its number (0-31), else set regno to -1.  */
+      if (argstr[0] == 'r' && ISDIGIT (argstr[1]))
+        {
+	  char *p = argstr;
+	  
+	  ++p;
+	  regno = 0;
+	  do
+	    {
+	      regno *= 10;
+	      regno += *p - '0';
+	      ++p;
+	    }
+	  while (ISDIGIT (*p));
+	}
+      else
+        regno = -1;
+
+      /* And whether we are using at.  */
+      if (!nios2_as_options.noat
+	  && (regno == 1 || strprefix (argstr, "at")))
+        as_warn (_("Register at (r1) can sometimes be corrupted by assembler "
+                   "optimizations.\n"
+                   "Use .set noat to turn off those optimizations (and this "
+		   "warning)."));
+	
+      /* And whether we are using oci registers.  */
+      if (!nios2_as_options.nobreak
+	  && (regno == 25 || strprefix (argstr, "bt")))
+	as_warn (_("The debugger will corrupt bt (r25). If you don't need to "
+		   "debug this\n"
+	           "code then use .set nobreak to turn off this warning."));
+	
+      if (!nios2_as_options.nobreak
+	  && (regno == 30 || strprefix (argstr, "ba")))
+	as_warn (_("The debugger will corrupt ba (r30). If you don't need to "
+		   "debug this\n"
+	           "code then use .set nobreak to turn off this warning."));
+      break;
+    case 'i':
+    case 'u':
+      if (*argstr == '%')
+	{
+	  if (nios2_special_relocation_p (argstr))
+	    {
+	      /* We zap the parentheses because we don't want them confused
+		 with separators.  */
+	      temp = strchr (argstr, '(');
+	      if (temp != NULL)
+		*temp = ' ';
+	      temp = strchr (argstr, ')');
+	      if (temp != NULL)
+		*temp = ' ';
+	    }
+	  else
+	    as_bad (_("badly formed expression near %s"), argstr);
+	}
+      break;
+    case 'm':
+    case 'j':
+    case 'k':
+    case 'l':
+    case 'b':
+      /* We can't have %hi, %lo or %hiadj here.  */
+      if (*argstr == '%')
+	as_bad (_("badly formed expression near %s"), argstr);
+      break;
+    default:
+      break;
+    }
+
+  return argstr;
+}
+
+/* The function consume_separator takes a pointer into a string
+   of instruction tokens (args) and a pointer into a string representing
+   the expected sequence of tokens and separators.  It finds the first
+   instance of the character pointed to by separator in argstr, and
+   returns a pointer to the next element of argstr, which is the
+   following token in the sequence.  */
+static char *
+nios2_consume_separator (char *argstr, const char *separator)
+{
+  char *p;
+
+  /* If we have a opcode reg, expr(reg) type instruction, and
+   * we are separating the expr from the (reg), we find the last
+   * (, just in case the expression has parentheses.  */
+
+  if (*separator == '(')
+    p = strrchr (argstr, *separator);
+  else
+    p = strchr (argstr, *separator);
+
+  if (p != NULL)
+    *p++ = 0;
+  else
+    as_bad (_("expecting %c near %s"), *separator, argstr);
+  return p;
+}
+
+
+/* The principal argument parsing function which takes a string argstr
+   representing the instruction arguments for insn, and extracts the argument
+   tokens matching parsestr into parsed_args.  */
+static void
+nios2_parse_args (nios2_insn_infoS *insn, char *argstr,
+		  const char *parsestr, char **parsed_args)
+{
+  char *p;
+  char *end = NULL;
+  int i;
+  p = argstr;
+  i = 0;
+  bfd_boolean terminate = FALSE;
+  
+  /* This rest of this function is it too fragile and it mostly works,
+     therefore special case this one.  */
+  if (*parsestr == 0 && argstr != 0)
+    {
+      as_bad (_("too many arguments"));
+      parsed_args[0] = NULL;
+      return;
+    }
+  
+  while (p != NULL && !terminate && i < NIOS2_MAX_INSN_TOKENS)
+    {
+      parsed_args[i] = nios2_consume_arg (insn, p, parsestr);
+      ++parsestr;
+      if (*parsestr != '\0')
+	{
+	  p = nios2_consume_separator (p, parsestr);
+	  ++parsestr;
+	}
+      else
+	{
+	  /* Check that the argument string has no trailing arguments.  */
+	  /* If we've got a %lo etc relocation, we've zapped the parens with 
+ 	     spaces.  */
+	  if (nios2_special_relocation_p (p))
+	    end = strpbrk (p, ",");
+	  else
+	    end = strpbrk (p, " ,");
+
+	  if (end != NULL)
+	    as_bad (_("too many arguments"));
+	}
+
+      if (*parsestr == '\0' || (p != NULL && *p == '\0'))
+	terminate = TRUE;
+      ++i;
+    }
+
+  parsed_args[i] = NULL;
+
+  if (*parsestr != '\0' && insn->insn_nios2_opcode->match != OP_MATCH_BREAK)
+    as_bad (_("missing argument"));
+}
+
+
+
+/** Support for pseudo-op parsing.  These are macro-like opcodes that
+    expand into real insns by suitable fiddling with the operands.  */
+
+/* Append the string modifier to the string contained in the argument at
+   parsed_args[ndx].  */
+static void
+nios2_modify_arg (char **parsed_args, const char *modifier,
+		  int unused ATTRIBUTE_UNUSED, int ndx)
+{
+  char *tmp = parsed_args[ndx];
+
+  parsed_args[ndx]
+    = (char *) malloc (strlen (parsed_args[ndx]) + strlen (modifier) + 1);
+  strcpy (parsed_args[ndx], tmp);
+  strcat (parsed_args[ndx], modifier);
+}
+
+/* Modify parsed_args[ndx] by negating that argument.  */
+static void
+nios2_negate_arg (char **parsed_args, const char *modifier ATTRIBUTE_UNUSED,
+		  int unused ATTRIBUTE_UNUSED, int ndx)
+{
+  char *tmp = parsed_args[ndx];
+
+  parsed_args[ndx]
+    = (char *) malloc (strlen ("~(") + strlen (parsed_args[ndx]) +
+		       strlen (")+1") + 1);
+
+  strcpy (parsed_args[ndx], "~(");
+  strcat (parsed_args[ndx], tmp);
+  strcat (parsed_args[ndx], ")+1");
+}
+
+/* The function nios2_swap_args swaps the pointers at indices index_1 and
+   index_2 in the array parsed_args[] - this is used for operand swapping
+   for comparison operations.  */
+static void
+nios2_swap_args (char **parsed_args, const char *unused ATTRIBUTE_UNUSED,
+		 int index_1, int index_2)
+{
+  char *tmp;
+  gas_assert (index_1 < NIOS2_MAX_INSN_TOKENS
+	      && index_2 < NIOS2_MAX_INSN_TOKENS);
+  tmp = parsed_args[index_1];
+  parsed_args[index_1] = parsed_args[index_2];
+  parsed_args[index_2] = tmp;
+}
+
+/* This function appends the string appnd to the array of strings in
+   parsed_args num times starting at index start in the array.  */
+static void
+nios2_append_arg (char **parsed_args, const char *appnd, int num,
+		  int start)
+{
+  int i, count;
+  char *tmp;
+
+  gas_assert ((start + num) < NIOS2_MAX_INSN_TOKENS);
+
+  if (nios2_mode == NIOS2_MODE_TEST)
+    tmp = parsed_args[start];
+  else
+    tmp = NULL;
+
+  for (i = start, count = num; count > 0; ++i, --count)
+    parsed_args[i] = (char *) appnd;
+
+  gas_assert (i == (start + num));
+  parsed_args[i] = tmp;
+  parsed_args[i + 1] = NULL;
+}
+
+/* This function inserts the string insert num times in the array 
+   parsed_args, starting at the index start.  */
+static void
+nios2_insert_arg (char **parsed_args, const char *insert, int num,
+		  int start)
+{
+  int i, count, from, to;
+
+  gas_assert ((start + num) < NIOS2_MAX_INSN_TOKENS);
+
+  to = start + num;
+  from = start;
+
+  /* Move the existing arguments up to create space.  */
+  for (i = NIOS2_MAX_INSN_TOKENS; i - num >= start; --i)
+    parsed_args[i] = parsed_args[i - num];
+
+  for (i = start, count = num; count > 0; ++i, --count)
+    parsed_args[i] = (char *) insert;
+}
+
+/* Cleanup function to free malloc'ed arg strings.  */
+static void
+nios2_free_arg (char **parsed_args, int num ATTRIBUTE_UNUSED, int start)
+{
+  if (parsed_args[start])
+    {
+      free (parsed_args[start]);
+      parsed_args[start] = NULL;
+    }
+}
+
+/* This function swaps the pseudo-op for a real op.  */
+static nios2_ps_insn_infoS*
+nios2_translate_pseudo_insn (nios2_insn_infoS *insn)
+{
+
+  nios2_ps_insn_infoS *ps_insn;
+
+  /* Find which real insn the pseudo-op transates to and
+     switch the insn_info ptr to point to it.  */
+  ps_insn = nios2_ps_lookup (insn->insn_nios2_opcode->name);
+
+  if (ps_insn != NULL)
+    {
+      insn->insn_nios2_opcode = nios2_opcode_lookup (ps_insn->insn);
+      insn->insn_tokens[0] = insn->insn_nios2_opcode->name;
+      /* Modify the args so they work with the real insn.  */
+      ps_insn->arg_modifer_func ((char **) insn->insn_tokens,
+				 ps_insn->arg_modifier, ps_insn->num,
+				 ps_insn->index);
+    }
+  else
+    /* we cannot recover from this.  */
+    as_fatal (_("unrecognized pseudo-instruction %s"),
+	      ps_insn->pseudo_insn);
+  return ps_insn;
+}
+
+/* Invoke the cleanup handler for pseudo-insn ps_insn on insn.  */
+static void
+nios2_cleanup_pseudo_insn (nios2_insn_infoS *insn,
+			   nios2_ps_insn_infoS *ps_insn)
+{
+  if (ps_insn->arg_cleanup_func)
+    (ps_insn->arg_cleanup_func) ((char **) insn->insn_tokens,
+				 ps_insn->num, ps_insn->index);
+}
+
+const nios2_ps_insn_infoS nios2_ps_insn_info_structs[] = {
+  /* pseudo-op, real-op, arg, arg_modifier_func, num, index, arg_cleanup_func */
+  {"mov", "add", nios2_append_arg, "zero", 1, 3, NULL},
+  {"movi", "addi", nios2_insert_arg, "zero", 1, 2, NULL},
+  {"movhi", "orhi", nios2_insert_arg, "zero", 1, 2, NULL},
+  {"movui", "ori", nios2_insert_arg, "zero", 1, 2, NULL},
+  {"movia", "orhi", nios2_insert_arg, "zero", 1, 2, NULL},
+  {"nop", "add", nios2_append_arg, "zero", 3, 1, NULL},
+  {"bgt", "blt", nios2_swap_args, "", 1, 2, NULL},
+  {"bgtu", "bltu", nios2_swap_args, "", 1, 2, NULL},
+  {"ble", "bge", nios2_swap_args, "", 1, 2, NULL},
+  {"bleu", "bgeu", nios2_swap_args, "", 1, 2, NULL},
+  {"cmpgt", "cmplt", nios2_swap_args, "", 2, 3, NULL},
+  {"cmpgtu", "cmpltu", nios2_swap_args, "", 2, 3, NULL},
+  {"cmple", "cmpge", nios2_swap_args, "", 2, 3, NULL},
+  {"cmpleu", "cmpgeu", nios2_swap_args, "", 2, 3, NULL},
+  {"cmpgti", "cmpgei", nios2_modify_arg, "+1", 0, 3, nios2_free_arg},
+  {"cmpgtui", "cmpgeui", nios2_modify_arg, "+1", 0, 3, nios2_free_arg},
+  {"cmplei", "cmplti", nios2_modify_arg, "+1", 0, 3, nios2_free_arg},
+  {"cmpleui", "cmpltui", nios2_modify_arg, "+1", 0, 3, nios2_free_arg},
+  {"subi", "addi", nios2_negate_arg, "", 0, 3, nios2_free_arg}
+  /* Add further pseudo-ops here.  */
+};
+
+#define NIOS2_NUM_PSEUDO_INSNS \
+	((sizeof(nios2_ps_insn_info_structs)/ \
+	  sizeof(nios2_ps_insn_info_structs[0])))
+const int nios2_num_ps_insn_info_structs = NIOS2_NUM_PSEUDO_INSNS;
+
+
+/** Assembler output support.  */
+
+static int
+can_evaluate_expr (nios2_insn_infoS *insn)
+{
+  /* Remove this check for null and the invalid insn "ori r9, 1234" seg faults. */
+  if (!insn->insn_reloc) 
+    /* ??? Ideally we should do something other than as_fatal here as we can
+       continue to assemble.
+       However this function (actually the output_* functions) should not 
+       have been called in the first place once an illegal instruction had 
+       been encountered.  */
+    as_fatal (_("Invalid instruction encountered, cannot recover. No assembly attempted."));
+
+  if (insn->insn_reloc->reloc_expression.X_op == O_constant)
+    return 1;
+
+  return 0;
+}
+
+static int
+get_expr_value (nios2_insn_infoS *insn)
+{
+  int value = 0;
+
+  if (insn->insn_reloc->reloc_expression.X_op == O_constant)
+    value = insn->insn_reloc->reloc_expression.X_add_number;
+  return value;
+}
+
+/* Output a normal instruction.  */
+static void
+output_insn (nios2_insn_infoS *insn)
+{
+  char *f;
+  nios2_insn_relocS *reloc;
+
+  f = frag_more (4);
+  /* This allocates enough space for the instruction
+     and puts it in the current frag.  */
+  md_number_to_chars (f, insn->insn_code, 4);
+  /* Emit debug info.  */
+  dwarf2_emit_insn (4);
+  /* Create any fixups to be acted on later.  */
+  for (reloc = insn->insn_reloc; reloc != NULL; reloc = reloc->reloc_next)
+    fix_new_exp (frag_now, f - frag_now->fr_literal, 4,
+		 &reloc->reloc_expression, reloc->reloc_pcrel,
+		 reloc->reloc_type);
+}
+
+/* Output an unconditional branch.  */
+static void
+output_ubranch (nios2_insn_infoS *insn)
+{
+  nios2_insn_relocS *reloc = insn->insn_reloc;
+
+  /* If the reloc is NULL, there was an error assembling the branch.  */
+  if (reloc != NULL)
+    {
+      symbolS *symp = reloc->reloc_expression.X_add_symbol;
+      offsetT offset = reloc->reloc_expression.X_add_number;
+      char *f;
+
+      /* Tag dwarf2 debug info to the address at the start of the insn.
+	 We must do it before frag_var() below closes off the frag.  */
+      dwarf2_emit_insn (0);
+
+      /* We create a machine dependent frag which can grow
+         to accommodate the largest possible instruction sequence
+         this may generate.  */
+      f = frag_var (rs_machine_dependent,
+		    UBRANCH_MAX_SIZE, 4, UBRANCH_SUBTYPE (0),
+		    symp, offset, NULL);
+
+      md_number_to_chars (f, insn->insn_code, 4);
+
+      /* We leave fixup generation to md_convert_frag.  */
+    }
+}
+
+/* Output a conditional branch.  */
+static void
+output_cbranch (nios2_insn_infoS *insn)
+{
+  nios2_insn_relocS *reloc = insn->insn_reloc;
+
+  /* If the reloc is NULL, there was an error assembling the branch.  */
+  if (reloc != NULL)
+    {
+      symbolS *symp = reloc->reloc_expression.X_add_symbol;
+      offsetT offset = reloc->reloc_expression.X_add_number;
+      char *f;
+
+      /* Tag dwarf2 debug info to the address at the start of the insn.
+	 We must do it before frag_var() below closes off the frag.  */
+      dwarf2_emit_insn (0);
+
+      /* We create a machine dependent frag which can grow
+         to accommodate the largest possible instruction sequence
+         this may generate.  */
+      f = frag_var (rs_machine_dependent,
+		    CBRANCH_MAX_SIZE, 4, CBRANCH_SUBTYPE (0),
+		    symp, offset, NULL);
+
+      md_number_to_chars (f, insn->insn_code, 4);
+
+      /* We leave fixup generation to md_convert_frag.  */
+    }
+}
+
+/* Output a call sequence.  Since calls are not pc-relative for NIOS2,
+   but are page-relative, we cannot tell at any stage in assembly
+   whether a call will be out of range since a section may be linked
+   at any address.  So if we are relaxing, we convert all call instructions
+   to long call sequences, and rely on the linker to relax them back to
+   short calls.  */
+static void
+output_call (nios2_insn_infoS *insn)
+{
+  /* This allocates enough space for the instruction
+     and puts it in the current frag.  */
+  char *f = frag_more (12);
+  nios2_insn_relocS *reloc = insn->insn_reloc;
+
+  md_number_to_chars (f, OP_MATCH_ORHI | 0x00400000, 4);
+  dwarf2_emit_insn (4);
+  fix_new_exp (frag_now, f - frag_now->fr_literal, 4,
+	       &reloc->reloc_expression, 0, BFD_RELOC_NIOS2_HI16);
+  md_number_to_chars (f + 4, OP_MATCH_ORI | 0x08400000, 4);
+  dwarf2_emit_insn (4);
+  fix_new_exp (frag_now, f - frag_now->fr_literal + 4, 4,
+	       &reloc->reloc_expression, 0, BFD_RELOC_NIOS2_LO16);
+  md_number_to_chars (f + 8, OP_MATCH_CALLR | 0x08000000, 4);
+  dwarf2_emit_insn (4);
+}
+
+/* Output an addi - will silently convert to
+   orhi if rA = r0 and (expr & 0xffff0000) == 0.  */
+static void
+output_addi (nios2_insn_infoS *insn)
+{
+  if (can_evaluate_expr (insn))
+    {
+      int expr_val = get_expr_value (insn);
+      if (GET_INSN_FIELD (RRS, insn->insn_code) == 0
+	  && (expr_val & 0xffff) == 0
+	  && expr_val != 0)
+	{
+	  /* We really want a movhi (orhi) here.  */
+	  insn->insn_code = (insn->insn_code & ~OP_MATCH_ADDI) | OP_MATCH_ORHI;
+	  insn->insn_reloc->reloc_expression.X_add_number =
+	    (insn->insn_reloc->reloc_expression.X_add_number >> 16) & 0xffff;
+	  insn->insn_reloc->reloc_type = BFD_RELOC_NIOS2_U16;
+	}
+    }
+
+  /* Output an instruction.  */
+  output_insn (insn);
+}
+
+static void
+output_andi (nios2_insn_infoS *insn)
+{
+  if (can_evaluate_expr (insn))
+    {
+      int expr_val = get_expr_value (insn);
+      if (expr_val != 0 && (expr_val & 0xffff) == 0)
+	{
+	  /* We really want a movhi (orhi) here.  */
+	  insn->insn_code = (insn->insn_code & ~OP_MATCH_ANDI) | OP_MATCH_ANDHI;
+	  insn->insn_reloc->reloc_expression.X_add_number =
+	    (insn->insn_reloc->reloc_expression.X_add_number >> 16) & 0xffff;
+	  insn->insn_reloc->reloc_type = BFD_RELOC_NIOS2_U16;
+	}
+    }
+
+  /* Output an instruction.  */
+  output_insn (insn);
+}
+
+static void
+output_ori (nios2_insn_infoS *insn)
+{
+  if (can_evaluate_expr (insn))
+    {
+      int expr_val = get_expr_value (insn);
+      if (expr_val != 0 && (expr_val & 0xffff) == 0)
+	{
+	  /* We really want a movhi (orhi) here.  */
+	  insn->insn_code = (insn->insn_code & ~OP_MATCH_ORI) | OP_MATCH_ORHI;
+	  insn->insn_reloc->reloc_expression.X_add_number =
+	    (insn->insn_reloc->reloc_expression.X_add_number >> 16) & 0xffff;
+	  insn->insn_reloc->reloc_type = BFD_RELOC_NIOS2_U16;
+	}
+    }
+
+  /* Output an instruction.  */
+  output_insn (insn);
+}
+
+static void
+output_xori (nios2_insn_infoS *insn)
+{
+  if (can_evaluate_expr (insn))
+    {
+      int expr_val = get_expr_value (insn);
+      if (expr_val != 0 && (expr_val & 0xffff) == 0)
+	{
+	  /* We really want a movhi (orhi) here.  */
+	  insn->insn_code = (insn->insn_code & ~OP_MATCH_XORI) | OP_MATCH_XORHI;
+	  insn->insn_reloc->reloc_expression.X_add_number =
+	    (insn->insn_reloc->reloc_expression.X_add_number >> 16) & 0xffff;
+	  insn->insn_reloc->reloc_type = BFD_RELOC_NIOS2_U16;
+	}
+    }
+
+  /* Output an instruction.  */
+  output_insn (insn);
+}
+
+
+/* Output a movhi/addi pair for the movia pseudo-op.  */
+static void
+output_movia (nios2_insn_infoS *insn)
+{
+  /* This allocates enough space for the instruction
+     and puts it in the current frag.  */
+  char *f = frag_more (8);
+  nios2_insn_relocS *reloc = insn->insn_reloc;
+  unsigned long reg_index = GET_INSN_FIELD (IRT, insn->insn_code);
+
+  /* If the reloc is NULL, there was an error assembling the movia.  */
+  if (reloc != NULL)
+    {
+      md_number_to_chars (f, insn->insn_code, 4);
+      dwarf2_emit_insn (4);
+      md_number_to_chars (f + 4,
+			  (OP_MATCH_ADDI | (reg_index << OP_SH_IRT)
+			   | (reg_index << OP_SH_IRS)),
+			  4);
+      dwarf2_emit_insn (4);
+      fix_new (frag_now, f - frag_now->fr_literal, 4,
+	       reloc->reloc_expression.X_add_symbol,
+	       reloc->reloc_expression.X_add_number, 0,
+	       BFD_RELOC_NIOS2_HIADJ16);
+      fix_new (frag_now, f + 4 - frag_now->fr_literal, 4,
+	       reloc->reloc_expression.X_add_symbol,
+	       reloc->reloc_expression.X_add_number, 0, BFD_RELOC_NIOS2_LO16);
+    }
+}
+
+
+
+/** External interfaces.  */
+
+/* The following functions are called by machine-independent parts of
+   the assembler. */
+int
+md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
+{
+  switch (c)
+    {
+    case 'r':
+      /* Hidden option for self-test mode.  */
+      nios2_mode = NIOS2_MODE_TEST;
+      break;
+    case OPTION_RELAX_ALL:
+      nios2_as_options.relax = relax_all;
+      break;
+    case OPTION_NORELAX:
+      nios2_as_options.relax = relax_none;
+      break;
+    case OPTION_RELAX_SECTION:
+      nios2_as_options.relax = relax_section;
+      break;
+    case OPTION_EB:
+      target_big_endian = 1;
+      break;
+    case OPTION_EL:
+      target_big_endian = 0;
+      break;
+    default:
+      return 0;
+      break;
+    }
+
+  return 1;
+}
+
+/* Implement TARGET_FORMAT.  We can choose to be big-endian or
+   little-endian at runtime based on a switch.  */
+const char *
+nios2_target_format (void)
+{
+  return target_big_endian ? "elf32-bignios2" : "elf32-littlenios2";
+}
+
+/* Machine-dependent usage message. */
+void
+md_show_usage (FILE *stream)
+{
+  fprintf (stream, "        NIOS2 options:\n"
+           "  -relax-all            replace all branch and call "
+           "instructions with jmp and callr sequences\n"
+           "  -relax-section        replace identified out of range "
+           "branches with jmp sequences (default)\n"
+           "  -no-relax             do not replace any branches or calls\n"
+           "  -EB                   force big-endian byte ordering\n"
+           "  -EL                   force little-endian byte ordering\n");
+}
+
+/* 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. */
+void
+md_begin (void)
+{
+  int i;
+  const char *inserted;
+
+  /* Create and fill a hashtable for the Nios II opcodes, registers and 
+     arguments.  */
+  nios2_opcode_hash = hash_new ();
+  nios2_reg_hash = hash_new ();
+  nios2_arg_hash = hash_new ();
+  nios2_ps_hash = hash_new ();
+
+  for (i = 0; i < NUMOPCODES; ++i)
+    {
+      inserted
+	= hash_insert (nios2_opcode_hash, nios2_opcodes[i].name,
+		       (PTR) & nios2_opcodes[i]);
+      if (inserted != NULL)
+	{
+	  fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
+		   nios2_opcodes[i].name, inserted);
+	  /* Probably a memory allocation problem?  Give up now.  */
+	  as_fatal (_("Broken assembler.  No assembly attempted."));
+	}
+    }
+
+  for (i = 0; i < nios2_num_regs; ++i)
+    {
+      inserted
+	= hash_insert (nios2_reg_hash, nios2_regs[i].name,
+		       (PTR) & nios2_regs[i]);
+      if (inserted != NULL)
+	{
+	  fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
+		   nios2_regs[i].name, inserted);
+	  /* Probably a memory allocation problem?  Give up now.  */
+	  as_fatal (_("Broken assembler.  No assembly attempted."));
+	}
+
+    }
+
+  for (i = 0; i < nios2_num_arg_info_structs; ++i)
+    {
+      inserted
+	= hash_insert (nios2_arg_hash, nios2_arg_info_structs[i].args,
+		       (PTR) & nios2_arg_info_structs[i]);
+      if (inserted != NULL)
+	{
+	  fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
+		   nios2_arg_info_structs[i].args, inserted);
+	  /* Probably a memory allocation problem?  Give up now.  */
+	  as_fatal (_("Broken assembler.  No assembly attempted."));
+	}
+    }
+
+  for (i = 0; i < nios2_num_ps_insn_info_structs; ++i)
+    {
+      inserted
+	= hash_insert (nios2_ps_hash, nios2_ps_insn_info_structs[i].pseudo_insn,
+		       (PTR) & nios2_ps_insn_info_structs[i]);
+      if (inserted != NULL)
+	{
+	  fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
+		   nios2_ps_insn_info_structs[i].pseudo_insn, inserted);
+	  /* Probably a memory allocation problem?  Give up now.  */
+	  as_fatal (_("Broken assembler.  No assembly attempted."));
+	}
+    }
+
+  /* Assembler option defaults.  */
+  nios2_as_options.noat = FALSE;
+  nios2_as_options.nobreak = FALSE;
+
+  /* Debug information is incompatible with relaxation.  */
+  if (debug_type != DEBUG_UNSPECIFIED)
+    nios2_as_options.relax = relax_none;
+
+  /* Initialize the alignment data.  */
+  nios2_current_align_seg = now_seg;
+  nios2_last_label = NULL;
+  nios2_current_align = 0;
+}
+
+
+/* Assembles a single line of Nios II assembly language.  */
+void
+md_assemble (char *op_str)
+{
+  char *argstr; 
+  char *op_strdup = NULL;
+  nios2_arg_infoS *arg_info;
+  unsigned long saved_pinfo = 0;
+  nios2_insn_infoS thisinsn;
+  nios2_insn_infoS *insn = &thisinsn;
+
+  /* Make sure we are aligned on a 4-byte boundary.  */
+  if (nios2_current_align < 2)
+    nios2_align (2, NULL, nios2_last_label);
+  else if (nios2_current_align > 2)
+    nios2_current_align = 2;
+  nios2_last_label = NULL;
+
+  /* We don't want to clobber to op_str
+     because we want to be able to use it in messages.  */
+  op_strdup = strdup (op_str);
+  insn->insn_tokens[0] = strtok (op_strdup, " ");
+  argstr = strtok (NULL, "");
+
+  /* Assemble the opcode.  */
+  insn->insn_nios2_opcode = nios2_opcode_lookup (insn->insn_tokens[0]);
+  insn->insn_reloc = NULL;
+
+  if (insn->insn_nios2_opcode != NULL)
+    {
+      nios2_ps_insn_infoS *ps_insn = NULL;
+      /* Set the opcode for the instruction.  */
+      insn->insn_code = insn->insn_nios2_opcode->match;
+
+      /* Parse the arguments pointed to by argstr.  */
+      if (nios2_mode == NIOS2_MODE_ASSEMBLE)
+	nios2_parse_args (insn, argstr, insn->insn_nios2_opcode->args,
+			  (char **) &insn->insn_tokens[1]);
+      else
+	nios2_parse_args (insn, argstr, insn->insn_nios2_opcode->args_test,
+			  (char **) &insn->insn_tokens[1]);
+
+      /* We need to preserve the MOVIA macro as this is clobbered by 
+         translate_pseudo_insn.  */
+      if (insn->insn_nios2_opcode->pinfo == NIOS2_INSN_MACRO_MOVIA)
+	saved_pinfo = NIOS2_INSN_MACRO_MOVIA;
+      /* If the instruction is an pseudo-instruction, we want to replace it 
+         with its real equivalent, and then continue.  */
+      if ((insn->insn_nios2_opcode->pinfo & NIOS2_INSN_MACRO)
+	  == NIOS2_INSN_MACRO)
+	ps_insn = nios2_translate_pseudo_insn (insn);
+
+      /* Find the assemble function, and call it.  */
+      arg_info = nios2_arg_lookup (insn->insn_nios2_opcode->args);
+      if (arg_info != NULL)
+	{
+	  arg_info->assemble_args_func (insn);
+
+	  if (nios2_as_options.relax != relax_none
+	      && !nios2_as_options.noat
+	      && insn->insn_nios2_opcode->pinfo & NIOS2_INSN_UBRANCH)
+	    output_ubranch (insn);
+	  else if (nios2_as_options.relax != relax_none
+		   && !nios2_as_options.noat
+		   && insn->insn_nios2_opcode->pinfo & NIOS2_INSN_CBRANCH)
+	    output_cbranch (insn);
+	  else if (nios2_as_options.relax == relax_all
+		   && !nios2_as_options.noat
+		   && insn->insn_nios2_opcode->pinfo & NIOS2_INSN_CALL
+		   && insn->insn_reloc
+		   && insn->insn_reloc->reloc_type == BFD_RELOC_NIOS2_CALL26)
+	    output_call (insn);
+	  else if (insn->insn_nios2_opcode->pinfo & NIOS2_INSN_ANDI)
+	    output_andi (insn);
+	  else if (insn->insn_nios2_opcode->pinfo & NIOS2_INSN_ORI)
+	    output_ori (insn);
+	  else if (insn->insn_nios2_opcode->pinfo & NIOS2_INSN_XORI)
+	    output_xori (insn);
+	  else if (insn->insn_nios2_opcode->pinfo & NIOS2_INSN_ADDI)
+	    output_addi (insn);
+	  else if (saved_pinfo == NIOS2_INSN_MACRO_MOVIA)
+	    output_movia (insn);
+	  else
+	    output_insn (insn);
+	  if (ps_insn)
+	    nios2_cleanup_pseudo_insn (insn, ps_insn);
+	}
+      else
+	{
+	  /* The assembler is broken.  */
+	  fprintf (stderr,
+		   _("internal error: %s is not a valid argument syntax\n"),
+		   insn->insn_nios2_opcode->args);
+	  /* Probably a memory allocation problem.  Give up now.  */
+	  as_fatal (_("Broken assembler.  No assembly attempted."));
+	}
+    }
+  else
+    /* Unrecognised instruction - error.  */
+    as_bad (_("unrecognised instruction %s"), insn->insn_tokens[0]);
+
+  /* Don't leak memory.  */
+  free (op_strdup);
+}
+
+/* Round up section size.  */
+valueT
+md_section_align (asection *seg ATTRIBUTE_UNUSED, valueT size)
+{
+  /* I think byte alignment is fine here.  */
+  return size;
+}
+
+/* Implement TC_FORCE_RELOCATION.  */
+int
+nios2_force_relocation (fixS *fixp)
+{
+  if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY
+      || fixp->fx_r_type == BFD_RELOC_NIOS2_ALIGN)
+    return 1;
+
+  return generic_force_reloc (fixp);
+}
+
+/* Implement tc_fix_adjustable.  */
+int
+nios2_fix_adjustable (fixS *fixp)
+{
+  if (fixp->fx_addsy == NULL)
+    return 1;
+
+#ifdef OBJ_ELF
+  /* Prevent all adjustments to global symbols.  */
+  if (OUTPUT_FLAVOR == bfd_target_elf_flavour
+      && (S_IS_EXTERNAL (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy)))
+    return 0;
+#endif
+  if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+    return 0;
+
+  /* Preserve relocations against symbols with function type.  */
+  if (symbol_get_bfdsym (fixp->fx_addsy)->flags & BSF_FUNCTION)
+    return 0;
+
+  /* Don't allow symbols to be discarded on GOT related relocs.  */
+  if (fixp->fx_r_type == BFD_RELOC_NIOS2_GOT16
+      || fixp->fx_r_type == BFD_RELOC_NIOS2_CALL16
+      || fixp->fx_r_type == BFD_RELOC_NIOS2_GOTOFF_LO
+      || fixp->fx_r_type == BFD_RELOC_NIOS2_GOTOFF_HA
+      || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_GD16
+      || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_LDM16
+      || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_LDO16
+      || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_IE16
+      || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_LE16
+      || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_DTPMOD
+      || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_DTPREL
+      || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_TPREL
+      || fixp->fx_r_type == BFD_RELOC_NIOS2_GOTOFF)
+    return 0;
+
+  return 1;
+}
+
+/* Implement tc_frob_symbol.  This is called in adjust_reloc_syms;
+   it is used to remove *ABS* references from the symbol table.  */
+int
+nios2_frob_symbol (symbolS *symp)
+{
+  if ((OUTPUT_FLAVOR == bfd_target_elf_flavour
+       && symp == section_symbol (absolute_section))
+      || !S_IS_DEFINED (symp))
+    return 1;
+  else
+    return 0;
+}
+
+/* The function tc_gen_reloc creates a relocation structure for the
+   fixup fixp, and returns a pointer to it.  This structure is passed
+   to bfd_install_relocation so that it can be written to the object
+   file for linking.  */
+arelent *
+tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
+{
+  arelent *reloc = (arelent *) xmalloc (sizeof (arelent));
+  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;
+  reloc->addend = fixp->fx_offset;  /* fixp->fx_addnumber; */
+
+  if (fixp->fx_pcrel)
+    {
+      switch (fixp->fx_r_type)
+	{
+	case BFD_RELOC_16:
+	  fixp->fx_r_type = BFD_RELOC_16_PCREL;
+	  break;
+	case BFD_RELOC_NIOS2_LO16:
+	  fixp->fx_r_type = BFD_RELOC_NIOS2_PCREL_LO;
+	  break;
+	case BFD_RELOC_NIOS2_HIADJ16:
+	  fixp->fx_r_type = BFD_RELOC_NIOS2_PCREL_HA;
+	  break;
+	default:
+	  break;
+	}
+    }
+
+  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
+  if (reloc->howto == NULL)
+    {
+      as_bad_where (fixp->fx_file, fixp->fx_line,
+		    _("can't represent relocation type %s"),
+		    bfd_get_reloc_code_name (fixp->fx_r_type));
+
+      /* Set howto to a garbage value so that we can keep going.  */
+      reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
+      gas_assert (reloc->howto != NULL);
+    }
+  return reloc;
+}
+
+long
+md_pcrel_from (fixS *fixP ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+/* Called just before the assembler exits.  */
+void
+md_end ()
+{
+  /* FIXME - not yet implemented */
+}
+
+/* Under ELF we need to default _GLOBAL_OFFSET_TABLE.
+   Otherwise we have no need to default values of symbols.  */
+symbolS *
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
+{
+#ifdef OBJ_ELF
+  if (name[0] == '_' && name[1] == 'G'
+      && strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0)
+    {
+      if (!GOT_symbol)
+        {
+          if (symbol_find (name))
+            as_bad ("GOT already in the symbol table");
+
+          GOT_symbol = symbol_new (name, undefined_section,
+                                   (valueT) 0, &zero_address_frag);
+        }
+
+      return GOT_symbol;
+    }
+#endif
+
+  return 0;
+}
+
+/* Implement tc_frob_label.  */
+void
+nios2_frob_label (symbolS *lab)
+{
+  /* Emit dwarf information.  */
+  dwarf2_emit_label (lab);
+
+  /* Update the label's address with the current output pointer.  */
+  symbol_set_frag (lab, frag_now);
+  S_SET_VALUE (lab, (valueT) frag_now_fix ());
+
+  /* Record this label for future adjustment after we find out what
+     kind of data it references, and the required alignment therewith.  */
+  nios2_last_label = lab;
+}
+
+/* Implement md_cons_align.  */
+void
+nios2_cons_align (int size)
+{
+  int log_size = 0;
+  const char *pfill = NULL;
+
+  while ((size >>= 1) != 0)
+    ++log_size;
+
+  if (subseg_text_p (now_seg))
+    pfill = (const char *) &nop;
+  else
+    pfill = NULL;
+
+  if (nios2_auto_align_on)
+    nios2_align (log_size, pfill, NULL);
+
+  nios2_last_label = NULL;
+}
+
+/* Map 's' to SHF_NIOS2_GPREL.  */
+/* This is from the Alpha code tc-alpha.c.  */
+int
+nios2_elf_section_letter (int letter, char **ptr_msg)
+{
+  if (letter == 's')
+    return SHF_NIOS2_GPREL;
+
+  *ptr_msg = _("Bad .section directive: want a,s,w,x,M,S,G,T in string");
+  return -1;
+}
+
+/* Map SHF_ALPHA_GPREL to SEC_SMALL_DATA.  */
+/* This is from the Alpha code tc-alpha.c.  */
+flagword
+nios2_elf_section_flags (flagword flags, int attr, int type ATTRIBUTE_UNUSED)
+{
+  if (attr & SHF_NIOS2_GPREL)
+    flags |= SEC_SMALL_DATA;
+  return flags;
+}
+
+/* Implement TC_PARSE_CONS_EXPRESSION to handle %tls_ldo(...) */
+static int nios2_tls_ldo_reloc;
+
+void
+nios2_cons (expressionS *exp, int size)
+{
+  nios2_tls_ldo_reloc = 0;
+
+  SKIP_WHITESPACE ();
+  if (input_line_pointer[0] == '%')
+    {
+      if (strprefix (input_line_pointer + 1, "tls_ldo"))
+	{
+          if (size != 4)
+	    as_bad (_("Illegal operands: %%tls_ldo in %d-byte data field"),
+		    size);
+	  else
+	    {
+	      input_line_pointer += 8;
+              nios2_tls_ldo_reloc = 1;
+	    }
+	}
+      if (nios2_tls_ldo_reloc)
+	{
+	  SKIP_WHITESPACE ();
+	  if (input_line_pointer[0] != '(')
+	    as_bad (_("Illegal operands: %%tls_ldo requires arguments in ()"));
+	  else
+	    {
+	      int c;
+	      char *end = ++input_line_pointer;
+	      int npar = 0;
+
+	      for (c = *end; !is_end_of_line[c]; end++, c = *end)
+		if (c == '(')
+		  npar++;
+		else if (c == ')')
+		  {
+		    if (!npar)
+		      break;
+		    npar--;
+		  }
+
+	      if (c != ')')
+		as_bad (_("Illegal operands: %%tls_ldo requires arguments in ()"));
+	      else
+		{
+		  *end = '\0';
+		  expression (exp);
+		  *end = c;
+		  if (input_line_pointer != end)
+		    as_bad (_("Illegal operands: %%tls_ldo requires arguments in ()"));
+		  else
+		    {
+		      input_line_pointer++;
+		      SKIP_WHITESPACE ();
+		      c = *input_line_pointer;
+		      if (! is_end_of_line[c] && c != ',')
+			as_bad (_("Illegal operands: garbage after %%tls_ldo()"));
+		    }
+		}
+	    }
+	}
+    }
+  if (!nios2_tls_ldo_reloc)
+    expression (exp);
+}
+
+/* Implement TC_CONS_FIX_NEW.  */
+void
+nios2_cons_fix_new (fragS *frag, int where, unsigned int nbytes,
+		    expressionS *exp)
+{
+  bfd_reloc_code_real_type r;
+
+  r = (nbytes == 1 ? BFD_RELOC_8
+       : (nbytes == 2 ? BFD_RELOC_16
+	  : (nbytes == 4 ? BFD_RELOC_32 : BFD_RELOC_64)));
+
+  if (nios2_tls_ldo_reloc)
+    r = BFD_RELOC_NIOS2_TLS_DTPREL;
+
+  fix_new_exp (frag, where, (int) nbytes, exp, 0, r);
+  nios2_tls_ldo_reloc = 0;
+}
+
+/* Implement HANDLE_ALIGN.  */
+void
+nios2_handle_align (fragS *fragp)
+{
+  /* If we are expecting to relax in the linker, then we must output a
+     relocation to tell the linker we are aligning code.  */
+  if (nios2_as_options.relax == relax_all
+      && (fragp->fr_type == rs_align || fragp->fr_type == rs_align_code)
+      && fragp->fr_address + fragp->fr_fix > 0
+      && fragp->fr_offset > 1
+      && now_seg != bss_section)
+    fix_new (fragp, fragp->fr_fix, 0, &abs_symbol, fragp->fr_offset, 0,
+	     BFD_RELOC_NIOS2_ALIGN);
+}
+
+/* Implement tc_regname_to_dw2regnum, to convert REGNAME to a DWARF-2
+   register number.  */
+int
+nios2_regname_to_dw2regnum (char *regname)
+{
+  struct nios2_reg *r = nios2_reg_lookup (regname);
+  if (r == NULL)
+    return -1;
+  return r->index;
+}
+
+/* Implement tc_cfi_frame_initial_instructions, to initialize the DWARF-2
+   unwind information for this procedure.  */
+void
+nios2_frame_initial_instructions (void)
+{
+  cfi_add_CFA_def_cfa (27, 0);
+}
Index: gas/config/tc-nios2.h
===================================================================
RCS file: gas/config/tc-nios2.h
diff -N gas/config/tc-nios2.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gas/config/tc-nios2.h	22 Jan 2013 18:36:37 -0000
@@ -0,0 +1,125 @@
+/* Definitions for Altera Nios II assembler.
+   Copyright (C) 2012, 2013 Free Software Foundation, Inc.
+   Contributed by Nigel Gray (ngray@altera.com).
+   Contributed by Mentor Graphics, Inc.
+
+   This file is part of GAS, the GNU Assembler.
+
+   GAS is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GAS 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 GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#ifndef TC_NIOS2
+#define TC_NIOS2
+
+/* If unspecified, default to little endian.  We can explicitly specify
+ * a big-endian default by configuring with --target=nios2eb-elf.  We
+ * can override the default with the -EB and -EL options.  */
+#ifndef TARGET_BYTES_BIG_ENDIAN
+#define TARGET_BYTES_BIG_ENDIAN 0
+#endif
+
+/* Words are big enough to hold addresses.  */
+#define WORKING_DOT_WORD	1
+
+#ifdef OBJ_ELF
+extern const char *nios2_target_format (void);
+#define TARGET_FORMAT  nios2_target_format ()
+#define TARGET_ARCH    bfd_arch_nios2
+#endif
+
+/* A NIOS2 instruction consists of tokens and separator characters
+   the tokens are things like the instruction name (add, or jmp etc),
+   the register indices ($5, $7 etc), and constant expressions. The
+   separator characters are commas, brackets and space.
+   The instruction name is always separated from other tokens by a space
+   The maximum number of tokens in an instruction is 5 (the instruction name,
+   3 arguments, and a 4th string representing the expected instructin opcode
+   after assembly. The latter is only used when the assemble is running in
+   self test mode, otherwise its presence will generate an error.  */
+#define NIOS2_MAX_INSN_TOKENS	6
+
+/* There are no machine-specific operands so we #define this to nothing.  */
+#define md_operand(x)
+
+/* Function prototypes exported to rest of GAS.  */
+extern void md_assemble (char *op_str);
+extern void md_end (void);
+extern void md_begin (void);
+
+#define TC_FORCE_RELOCATION(fixp) nios2_force_relocation (fixp)
+extern int nios2_force_relocation (struct fix *);
+
+#define tc_fix_adjustable(fixp) nios2_fix_adjustable (fixp)
+extern int nios2_fix_adjustable (struct fix *);
+
+#define tc_frob_label(lab)	     nios2_frob_label (lab)
+extern void nios2_frob_label (symbolS *);
+
+#define tc_frob_symbol(symp, punt)  punt = nios2_frob_symbol (symp) ? 1 : punt
+extern int nios2_frob_symbol (symbolS * symp);
+
+#define md_cons_align(nbytes) nios2_cons_align (nbytes)
+extern void nios2_cons_align (int);
+
+extern void md_convert_frag (bfd * headers, segT sec, fragS * fragP);
+
+/* When relaxing, we need to generate relocations for alignment
+   directives.  */
+#define HANDLE_ALIGN(frag) nios2_handle_align (frag)
+extern void nios2_handle_align (fragS *);
+
+#define md_relax_frag nios2_relax_frag
+extern long nios2_relax_frag (segT segment, fragS * fragP, long stretch);
+
+#ifdef OBJ_ELF
+#define ELF_TC_SPECIAL_SECTIONS \
+  { ".sdata",   SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_NIOS2_GPREL  }, \
+  { ".sbss",    SHT_NOBITS,     SHF_ALLOC + SHF_WRITE + SHF_NIOS2_GPREL  }, \
+  { ".lit4",	SHT_PROGBITS,	SHF_ALLOC + SHF_WRITE + SHF_NIOS2_GPREL  }, \
+  { ".lit8",	SHT_PROGBITS,	SHF_ALLOC + SHF_WRITE + SHF_NIOS2_GPREL  },
+
+/* Processor-specific section directives.  */
+#define md_elf_section_letter		nios2_elf_section_letter
+extern int nios2_elf_section_letter (int, char **);
+#define md_elf_section_flags		nios2_elf_section_flags
+extern flagword nios2_elf_section_flags (flagword, int, int);
+#endif
+
+#define GLOBAL_OFFSET_TABLE_NAME       "_GLOBAL_OFFSET_TABLE_"
+
+#define DIFF_EXPR_OK
+
+/* Nios2 ABI doesn't have 32-bit PCREL relocation, and, as relocations for
+   CFI information will be in section other than .text, we can't use PC-biased
+   relocs.  */
+#define CFI_DIFF_EXPR_OK 0
+
+#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) nios2_cons (EXP, NBYTES)
+extern void nios2_cons (expressionS *exp, int size);
+
+#define TC_CONS_FIX_NEW nios2_cons_fix_new
+extern void nios2_cons_fix_new (struct frag *frag, int where,
+				unsigned int nbytes, struct expressionS *exp);
+
+/* We want .cfi_* pseudo-ops for generating unwind info.  */
+#define TARGET_USE_CFIPOP 1
+#define DWARF2_DEFAULT_RETURN_COLUMN 31
+#define DWARF2_CIE_DATA_ALIGNMENT (-4)
+#define tc_regname_to_dw2regnum nios2_regname_to_dw2regnum
+extern int nios2_regname_to_dw2regnum (char *regname);
+#define tc_cfi_frame_initial_instructions  nios2_frame_initial_instructions
+extern void nios2_frame_initial_instructions (void);
+
+#endif /* TC_NIOS2 */
Index: gas/doc/Makefile.am
===================================================================
RCS file: /cvs/src/src/gas/doc/Makefile.am,v
retrieving revision 1.69
diff -u -p -r1.69 Makefile.am
--- gas/doc/Makefile.am	10 Jan 2013 19:51:55 -0000	1.69
+++ gas/doc/Makefile.am	22 Jan 2013 18:36:37 -0000
@@ -74,6 +74,7 @@ CPU_DOCS = \
 	c-mmix.texi \
 	c-mt.texi \
 	c-msp430.texi \
+	c-nios2.texi \
 	c-ns32k.texi \
 	c-pdp11.texi \
 	c-pj.texi \
Index: gas/doc/Makefile.in
===================================================================
RCS file: /cvs/src/src/gas/doc/Makefile.in,v
retrieving revision 1.121
diff -u -p -r1.121 Makefile.in
--- gas/doc/Makefile.in	10 Jan 2013 19:51:55 -0000	1.121
+++ gas/doc/Makefile.in	22 Jan 2013 18:36:37 -0000
@@ -316,6 +316,7 @@ CPU_DOCS = \
 	c-mmix.texi \
 	c-mt.texi \
 	c-msp430.texi \
+	c-nios2.texi \
 	c-ns32k.texi \
 	c-pdp11.texi \
 	c-pj.texi \
@@ -410,17 +411,17 @@ as.info: as.texinfo $(as_TEXINFOS)
 	fi; \
 	rm -rf $$backupdir; exit $$rc
 
-as.dvi: as.texinfo $(as_TEXINFOS)
+as.dvi: as.texinfo $(as_TEXINFOS) 
 	TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
 	MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
 	$(TEXI2DVI) -o $@ `test -f 'as.texinfo' || echo '$(srcdir)/'`as.texinfo
 
-as.pdf: as.texinfo $(as_TEXINFOS)
+as.pdf: as.texinfo $(as_TEXINFOS) 
 	TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
 	MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
 	$(TEXI2PDF) -o $@ `test -f 'as.texinfo' || echo '$(srcdir)/'`as.texinfo
 
-as.html: as.texinfo $(as_TEXINFOS)
+as.html: as.texinfo $(as_TEXINFOS) 
 	rm -rf $(@:.html=.htp)
 	if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
 	 -o $(@:.html=.htp) `test -f 'as.texinfo' || echo '$(srcdir)/'`as.texinfo; \
Index: gas/doc/all.texi
===================================================================
RCS file: /cvs/src/src/gas/doc/all.texi,v
retrieving revision 1.44
diff -u -p -r1.44 all.texi
--- gas/doc/all.texi	10 Jan 2013 09:49:09 -0000	1.44
+++ gas/doc/all.texi	22 Jan 2013 18:36:37 -0000
@@ -58,6 +58,7 @@
 @set MMIX
 @set MS1
 @set MSP430
+@set NIOSII
 @set NS32K
 @set PDP11
 @set PJ
Index: gas/doc/as.texinfo
===================================================================
RCS file: /cvs/src/src/gas/doc/as.texinfo,v
retrieving revision 1.263
diff -u -p -r1.263 as.texinfo
--- gas/doc/as.texinfo	11 Jan 2013 02:25:33 -0000	1.263
+++ gas/doc/as.texinfo	23 Jan 2013 04:12:20 -0000
@@ -431,6 +431,12 @@ gcc(1), ld(1), and the Info entries for 
    [@b{--no-expand}] [@b{--no-merge-gregs}] [@b{-x}]
    [@b{--linker-allocated-gregs}]
 @end ifset
+@ifset NIOSII
+
+@emph{Target Altera Nios II options:}
+   [@b{-relax-all}] [@b{-relax-section}] [@b{-no-relax}]
+   [@b{-EB}] [@b{-EL}]
+@end ifset
 @ifset PDP11
 
 @emph{Target PDP11 options:}
@@ -1028,6 +1034,24 @@ unit coprocessor.  The default is to ass
 @end table
 @end ifset
 
+@ifset NIOSII
+The following options are available when @value{AS} is configured for
+an Altera Nios II processor.
+
+@table @gcctabopt
+@item -relax-all
+Replace all branch and call instructions with @code{jmp} and @code{callr} sequences.
+@item -relax-section
+Replace identified out-of-range branches with @code{jmp} sequences (default).
+@item -no-relax
+Do not replace any branches or calls.
+@item -EB
+Generate big-endian output.
+@item -EL
+Generate little-endian output (default).
+@end table
+@end ifset
+
 @ifset PDP11
 
 For details about the PDP-11 machine dependent features options,
@@ -7059,6 +7083,9 @@ subject, see the hardware manufacturer's
 @ifset MSP430
 * MSP430-Dependent::		MSP430 Dependent Features
 @end ifset
+@ifset NIOSII
+* NiosII-Dependent::            Altera Nios II Dependent Features
+@end ifset
 @ifset NS32K
 * NS32K-Dependent::		NS32K Dependent Features
 @end ifset
@@ -7270,6 +7297,10 @@ family.
 @include c-msp430.texi
 @end ifset
 
+@ifset NIOSII
+@include c-nios2.texi
+@end ifset
+
 @ifset NS32K
 @include c-ns32k.texi
 @end ifset
Index: gas/doc/c-nios2.texi
===================================================================
RCS file: gas/doc/c-nios2.texi
diff -N gas/doc/c-nios2.texi
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gas/doc/c-nios2.texi	23 Jan 2013 04:06:38 -0000
@@ -0,0 +1,247 @@
+@c Copyright 2012, 2013 Free Software Foundation, Inc.
+@c This is part of the GAS manual.
+@c For copying conditions, see the file as.texinfo.
+@ifset GENERIC
+@page
+@node NiosII-Dependent
+@chapter Nios II Dependent Features
+@end ifset
+@ifclear GENERIC
+@node Machine Dependencies
+@chapter Nios II Dependent Features
+@end ifclear
+
+@cindex Altera Nios II support
+@cindex Nios support
+@cindex Nios II support
+@menu
+* Nios II Options::              Options
+* Nios II Syntax::               Syntax
+* Nios II Relocations::          Relocations
+* Nios II Directives::           Nios II Machine Directives
+* Nios II Opcodes::              Opcodes
+@end menu
+
+@node Nios II Options
+@section Options
+@cindex Nios II options
+@cindex options for Nios II
+
+@table @code
+
+@cindex @code{relax-section} command line option, Nios II
+@item -relax-section
+Replace identified out-of-range branches with PC-relative @code{jmp}
+sequences when possible.  The generated code sequences are suitable
+for use in position-independent code, but there is a practical limit
+on the extended branch range because of the length of the sequences.
+This option is the default.
+
+@cindex @code{relax-all} command line option, Nios II
+@item -relax-all
+Replace branch instructions not determinable to be in range
+and all call instructions with @code{jmp} and @code{callr} sequences
+(respectively).  This option generates absolute relocations against the
+target symbols and is not appropriate for position-independent code.
+
+@cindex @code{no-relax} command line option, Nios II
+@item -no-relax
+Do not replace any branches or calls.
+
+@cindex @code{EB} command line option, Nios II
+@item -EB
+Generate big-endian output.
+
+@cindex @code{EL} command line option, Nios II
+@item -EL
+Generate little-endian output.  This is the default.
+
+@end table
+
+
+@node Nios II Syntax
+@section Syntax
+@menu
+* Nios II Chars::                Special Characters
+@end menu
+
+
+@node Nios II Chars
+@subsection Special Characters
+
+@cindex line comment character, Nios II
+@cindex Nios II line comment character
+@cindex line separator character, Nios II
+@cindex Nios II line separator character
+@samp{#} is the line comment character.
+@samp{;} is the line separator character.
+
+
+@node Nios II Relocations
+@section Nios II Machine Relocations
+
+@cindex machine relocations, Nios II
+@cindex Nios II machine relocations
+
+@table @code
+@cindex @code{hiadj} directive, Nios II
+@item %hiadj(@var{expression})
+Extract the upper 16 bits of @var{expression} and add 
+one if the 15th bit is set. 
+
+The value of @code{%hiadj(@var{expression})} is:
+@smallexample
+((@var{expression} >> 16) & 0xffff) + ((@var{expression} >> 15) & 0x01)
+@end smallexample
+
+The @code{%hiadj} relocation is intended to be used with
+the @code{addi}, @code{ld} or @code{st} instructions
+along with a @code{%lo}, in order to load a 32-bit constant.
+
+@smallexample
+movhi r2, %hiadj(symbol)
+addi r2, r2, %lo(symbol)
+@end smallexample
+
+@cindex @code{hi} directive, Nios II
+@item %hi(@var{expression})
+Extract the upper 16 bits of @var{expression}.
+
+@cindex @code{lo} directive, Nios II
+@item %lo(@var{expression})
+Extract the lower 16 bits of @var{expression}.
+
+@cindex @code{gprel} directive, Nios II
+@item %gprel(@var{expression})
+Subtract the value of the symbol @code{_gp} from
+@var{expression}. 
+
+The intention of the @code{%gprel} relocation is
+to have a fast small area of memory which only
+takes a 16-bit immediate to access.
+
+@smallexample
+	.section .sdata
+fastint:
+	.int 123
+	.section .text
+	ldw r4, %gprel(fastint)(gp)
+@end smallexample
+
+@cindex @code{call} directive, Nios II
+@cindex @code{got} directive, Nios II
+@cindex @code{gotoff} directive, Nios II
+@cindex @code{gotoff_lo} directive, Nios II
+@cindex @code{gotoff_hiadj} directive, Nios II
+@cindex @code{tls_gd} directive, Nios II
+@cindex @code{tls_ie} directive, Nios II
+@cindex @code{tls_le} directive, Nios II
+@cindex @code{tls_ldm} directive, Nios II
+@cindex @code{tls_ldo} directive, Nios II
+@item %call(@var{expression})
+@itemx %got(@var{expression})
+@itemx %gotoff(@var{expression})
+@itemx %gotoff_lo(@var{expression})
+@itemx %gotoff_hiadj(@var{expression})
+@itemx %tls_gd(@var{expression})
+@itemx %tls_ie(@var{expression})
+@itemx %tls_le(@var{expression})
+@itemx %tls_ldm(@var{expression})
+@itemx %tls_ldo(@var{expression})
+
+These relocations support the ABI for Linux Systems documented in the
+@cite{Nios II Processor Reference Handbook}.
+@end table
+
+
+@node Nios II Directives
+@section Nios II Machine Directives
+
+@cindex machine directives, Nios II
+@cindex Nios II machine directives
+
+@table @code
+
+@cindex @code{align} directive, Nios II
+@item .align @var{expression} [, @var{expression}]
+This is the generic @code{.align} directive, however
+this aligns to a power of two.
+
+@cindex @code{half} directive, Nios II
+@item .half @var{expression}
+Create an aligned constant 2 bytes in size.
+
+@cindex @code{word} directive, Nios II
+@item .word @var{expression}
+Create an aligned constant 4 bytes in size.
+
+@cindex @code{dword} directive, Nios II
+@item .dword @var{expression}
+Create an aligned constant 8 bytes in size.
+
+@cindex @code{2byte} directive, Nios II
+@item .2byte @var{expression}
+Create an unaligned constant 2 bytes in size.
+
+@cindex @code{4byte} directive, Nios II
+@item .4byte @var{expression}
+Create an unaligned constant 4 bytes in size.
+
+@cindex @code{8byte} directive, Nios II
+@item .8byte @var{expression}
+Create an unaligned constant 8 bytes in size.
+
+@cindex @code{16byte} directive, Nios II
+@item .16byte @var{expression}
+Create an unaligned constant 16 bytes in size.
+
+@cindex @code{set noat} directive, Nios II
+@item .set noat
+Allows assembly code to use @code{at} register without 
+warning.  Macro or relaxation expansions
+generate warnings.
+
+@cindex @code{set at} directive, Nios II
+@item .set at
+Assembly code using @code{at} register generates
+warnings, and macro expansion and relaxation are
+enabled.
+
+@cindex @code{set nobreak} directive, Nios II
+@item .set nobreak
+Allows assembly code to use @code{ba} and @code{bt}
+registers without warning. 
+
+@cindex @code{set break} directive, Nios II
+@item .set break
+Turns warnings back on for using @code{ba} and @code{bt}
+registers.
+
+@cindex @code{set norelax} directive, Nios II
+@item .set norelax
+Do not replace any branches or calls.
+
+@cindex @code{set relaxsection} directive, Nios II
+@item .set relaxsection
+Replace identified out-of-range branches with 
+@code{jmp} sequences (default).
+
+@cindex @code{set relaxall} directive, Nios II
+@item .set relaxsection
+Replace all branch and call instructions with
+@code{jmp} and @code{callr} sequences.
+
+@cindex @code{set} directive, Nios II
+@item .set @dots{}
+All other @code{.set} are the normal use.
+
+@end table
+
+@node Nios II Opcodes
+@section Opcodes
+
+@cindex Nios II opcodes
+@cindex opcodes for Nios II
+@code{@value{AS}} implements all the standard Nios II opcodes documented in the
+@cite{Nios II Processor Reference Handbook}, including the assembler
+pseudo-instructions.


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