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 5/6] Add Visium support to gas


From: Eric Botcazou <ebotcazou@gcc.gnu.org>

gas/ChangeLog

2014-12-03  Eric Botcazou  <ebotcazou@adacore.com>

	* configure.tgt: Add Visium support.
	* Makefile.am (TARGET_CPU_CFILES): Move config/tc-vax.c around
	and add config/tc-visium.c.
	(TARGET_CPU_HFILES): Move config/tc-vax.h around and add
	config/tc-visium.h.
	* Makefile.in: Regenerate.
	* config/tc-visium.c: New file.
	* config/tc-visium.h: Likewise.
	* po/POTFILES.in: Add config/tc-visium.c and config/tc-visium.h.

gas/testsuite/ChangeLog

2014-12-03  Eric Botcazou  <ebotcazou@adacore.com>

	* gas/elf/elf.exp: Skip ifunc-1 for Visium.
	* gas/visium/: New directory.

---
 gas/Makefile.am                         |    6 +-
 gas/Makefile.in                         |   41 +-
 gas/config/tc-visium.c                  | 2328 +++++++++++++++++++++++++++++++
 gas/config/tc-visium.h                  |   79 ++
 gas/configure.tgt                       |    3 +
 gas/po/POTFILES.in                      |    2 +
 gas/testsuite/gas/elf/elf.exp           |    3 +-
 gas/testsuite/gas/visium/allinsn.exp    |    7 +
 gas/testsuite/gas/visium/allinsn_def.d  |  134 ++
 gas/testsuite/gas/visium/allinsn_def.s  |  157 +++
 gas/testsuite/gas/visium/allinsn_gr5.d  |  153 ++
 gas/testsuite/gas/visium/allinsn_gr5.s  |  179 +++
 gas/testsuite/gas/visium/allinsn_gr6.d  |  159 +++
 gas/testsuite/gas/visium/allinsn_gr6.s  |  185 +++
 gas/testsuite/gas/visium/basereg.s      |   20 +
 gas/testsuite/gas/visium/brr-1.d        |   16 +
 gas/testsuite/gas/visium/brr-1.s        |    9 +
 gas/testsuite/gas/visium/brr-2.d        |   18 +
 gas/testsuite/gas/visium/brr-2.s        |    9 +
 gas/testsuite/gas/visium/brr_backward.s |   15 +
 gas/testsuite/gas/visium/brr_forward.s  |   16 +
 gas/testsuite/gas/visium/error.exp      |   35 +
 gas/testsuite/gas/visium/fcmp.s         |   11 +
 gas/testsuite/gas/visium/high-1.d       |   19 +
 gas/testsuite/gas/visium/high-1.s       |   11 +
 gas/testsuite/gas/visium/immed-1.d      |   17 +
 gas/testsuite/gas/visium/immed-1.s      |   10 +
 gas/testsuite/gas/visium/rela-1.d       |   18 +
 gas/testsuite/gas/visium/rela-1.s       |   20 +
 gas/testsuite/gas/visium/visium.exp     |   29 +
 30 files changed, 3694 insertions(+), 15 deletions(-)
 create mode 100644 gas/config/tc-visium.c
 create mode 100644 gas/config/tc-visium.h
 create mode 100644 gas/testsuite/gas/visium/allinsn.exp
 create mode 100644 gas/testsuite/gas/visium/allinsn_def.d
 create mode 100644 gas/testsuite/gas/visium/allinsn_def.s
 create mode 100644 gas/testsuite/gas/visium/allinsn_gr5.d
 create mode 100644 gas/testsuite/gas/visium/allinsn_gr5.s
 create mode 100644 gas/testsuite/gas/visium/allinsn_gr6.d
 create mode 100644 gas/testsuite/gas/visium/allinsn_gr6.s
 create mode 100644 gas/testsuite/gas/visium/basereg.s
 create mode 100644 gas/testsuite/gas/visium/brr-1.d
 create mode 100644 gas/testsuite/gas/visium/brr-1.s
 create mode 100644 gas/testsuite/gas/visium/brr-2.d
 create mode 100644 gas/testsuite/gas/visium/brr-2.s
 create mode 100644 gas/testsuite/gas/visium/brr_backward.s
 create mode 100644 gas/testsuite/gas/visium/brr_forward.s
 create mode 100644 gas/testsuite/gas/visium/error.exp
 create mode 100644 gas/testsuite/gas/visium/fcmp.s
 create mode 100644 gas/testsuite/gas/visium/high-1.d
 create mode 100644 gas/testsuite/gas/visium/high-1.s
 create mode 100644 gas/testsuite/gas/visium/immed-1.d
 create mode 100644 gas/testsuite/gas/visium/immed-1.s
 create mode 100644 gas/testsuite/gas/visium/rela-1.d
 create mode 100644 gas/testsuite/gas/visium/rela-1.s
 create mode 100644 gas/testsuite/gas/visium/visium.exp

diff --git a/gas/Makefile.am b/gas/Makefile.am
index 55c86b2..f65225f 100644
--- a/gas/Makefile.am
+++ b/gas/Makefile.am
@@ -185,8 +185,9 @@ TARGET_CPU_CFILES = \
 	config/tc-tic6x.c \
 	config/tc-tilegx.c \
 	config/tc-tilepro.c \
-	config/tc-vax.c \
 	config/tc-v850.c \
+	config/tc-vax.c \
+	config/tc-visium.c \
 	config/tc-xstormy16.c \
 	config/tc-xc16x.c \
 	config/tc-xgate.c \
@@ -256,8 +257,9 @@ TARGET_CPU_HFILES = \
 	config/tc-tic6x.h \
 	config/tc-tilegx.h \
 	config/tc-tilepro.h \
-	config/tc-vax.h \
 	config/tc-v850.h \
+	config/tc-vax.h \
+	config/tc-visium.h \
 	config/tc-xstormy16.h \
 	config/tc-xc16x.h \
 	config/tc-xgate.h \
diff --git a/gas/Makefile.in b/gas/Makefile.in
index 5dc250f..c7b3597 100644
--- a/gas/Makefile.in
+++ b/gas/Makefile.in
@@ -454,8 +454,9 @@ TARGET_CPU_CFILES = \
 	config/tc-tic6x.c \
 	config/tc-tilegx.c \
 	config/tc-tilepro.c \
-	config/tc-vax.c \
 	config/tc-v850.c \
+	config/tc-vax.c \
+	config/tc-visium.c \
 	config/tc-xstormy16.c \
 	config/tc-xc16x.c \
 	config/tc-xgate.c \
@@ -525,8 +526,9 @@ TARGET_CPU_HFILES = \
 	config/tc-tic6x.h \
 	config/tc-tilegx.h \
 	config/tc-tilepro.h \
-	config/tc-vax.h \
 	config/tc-v850.h \
+	config/tc-vax.h \
+	config/tc-visium.h \
 	config/tc-xstormy16.h \
 	config/tc-xc16x.h \
 	config/tc-xgate.h \
@@ -882,6 +884,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-tilepro.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-v850.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-vax.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-visium.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-xc16x.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-xgate.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-xstormy16.Po@am__quote@
@@ -1767,6 +1770,20 @@ tc-tilepro.obj: config/tc-tilepro.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-tilepro.obj `if test -f 'config/tc-tilepro.c'; then $(CYGPATH_W) 'config/tc-tilepro.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-tilepro.c'; fi`
 
+tc-v850.o: config/tc-v850.c
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-v850.o -MD -MP -MF $(DEPDIR)/tc-v850.Tpo -c -o tc-v850.o `test -f 'config/tc-v850.c' || echo '$(srcdir)/'`config/tc-v850.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/tc-v850.Tpo $(DEPDIR)/tc-v850.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='config/tc-v850.c' object='tc-v850.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-v850.o `test -f 'config/tc-v850.c' || echo '$(srcdir)/'`config/tc-v850.c
+
+tc-v850.obj: config/tc-v850.c
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-v850.obj -MD -MP -MF $(DEPDIR)/tc-v850.Tpo -c -o tc-v850.obj `if test -f 'config/tc-v850.c'; then $(CYGPATH_W) 'config/tc-v850.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-v850.c'; fi`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/tc-v850.Tpo $(DEPDIR)/tc-v850.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='config/tc-v850.c' object='tc-v850.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-v850.obj `if test -f 'config/tc-v850.c'; then $(CYGPATH_W) 'config/tc-v850.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-v850.c'; fi`
+
 tc-vax.o: config/tc-vax.c
 @am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-vax.o -MD -MP -MF $(DEPDIR)/tc-vax.Tpo -c -o tc-vax.o `test -f 'config/tc-vax.c' || echo '$(srcdir)/'`config/tc-vax.c
 @am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/tc-vax.Tpo $(DEPDIR)/tc-vax.Po
@@ -1781,19 +1798,19 @@ tc-vax.obj: config/tc-vax.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-vax.obj `if test -f 'config/tc-vax.c'; then $(CYGPATH_W) 'config/tc-vax.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-vax.c'; fi`
 
-tc-v850.o: config/tc-v850.c
-@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-v850.o -MD -MP -MF $(DEPDIR)/tc-v850.Tpo -c -o tc-v850.o `test -f 'config/tc-v850.c' || echo '$(srcdir)/'`config/tc-v850.c
-@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/tc-v850.Tpo $(DEPDIR)/tc-v850.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='config/tc-v850.c' object='tc-v850.o' libtool=no @AMDEPBACKSLASH@
+tc-visium.o: config/tc-visium.c
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-visium.o -MD -MP -MF $(DEPDIR)/tc-visium.Tpo -c -o tc-visium.o `test -f 'config/tc-visium.c' || echo '$(srcdir)/'`config/tc-visium.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/tc-visium.Tpo $(DEPDIR)/tc-visium.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='config/tc-visium.c' object='tc-visium.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-v850.o `test -f 'config/tc-v850.c' || echo '$(srcdir)/'`config/tc-v850.c
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-visium.o `test -f 'config/tc-visium.c' || echo '$(srcdir)/'`config/tc-visium.c
 
-tc-v850.obj: config/tc-v850.c
-@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-v850.obj -MD -MP -MF $(DEPDIR)/tc-v850.Tpo -c -o tc-v850.obj `if test -f 'config/tc-v850.c'; then $(CYGPATH_W) 'config/tc-v850.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-v850.c'; fi`
-@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/tc-v850.Tpo $(DEPDIR)/tc-v850.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='config/tc-v850.c' object='tc-v850.obj' libtool=no @AMDEPBACKSLASH@
+tc-visium.obj: config/tc-visium.c
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-visium.obj -MD -MP -MF $(DEPDIR)/tc-visium.Tpo -c -o tc-visium.obj `if test -f 'config/tc-visium.c'; then $(CYGPATH_W) 'config/tc-visium.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-visium.c'; fi`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/tc-visium.Tpo $(DEPDIR)/tc-visium.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='config/tc-visium.c' object='tc-visium.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-v850.obj `if test -f 'config/tc-v850.c'; then $(CYGPATH_W) 'config/tc-v850.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-v850.c'; fi`
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-visium.obj `if test -f 'config/tc-visium.c'; then $(CYGPATH_W) 'config/tc-visium.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-visium.c'; fi`
 
 tc-xstormy16.o: config/tc-xstormy16.c
 @am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-xstormy16.o -MD -MP -MF $(DEPDIR)/tc-xstormy16.Tpo -c -o tc-xstormy16.o `test -f 'config/tc-xstormy16.c' || echo '$(srcdir)/'`config/tc-xstormy16.c
diff --git a/gas/config/tc-visium.c b/gas/config/tc-visium.c
new file mode 100644
index 0000000..f3a9816
--- /dev/null
+++ b/gas/config/tc-visium.c
@@ -0,0 +1,2328 @@
+/* This is the machine dependent code of the Visium Assembler.
+
+   Copyright (C) 2005-2014 Free Software Foundation, 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 2, 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, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA. */
+
+#include "as.h"
+#include "safe-ctype.h"
+#include "subsegs.h"
+#include "obstack.h"
+
+#include "opcode/visium.h"
+#include "elf/visium.h"
+#include "dwarf2dbg.h"
+#include "dw2gencfi.h"
+
+/* Relocations and fixups:
+
+   There are two different cases where an instruction or data
+   directive operand requires relocation, or fixup.
+
+   1. Relative branch instructions, take an 16-bit signed word
+   offset. The formula for computing the offset is this:
+
+    offset = (destination - pc) / 4
+
+   Branch instructions never branch to a label not declared
+   locally, so the actual offset can always be computed by the assembler.
+   However, we provide a relocation type to support this.
+
+   2. Load literal instructions, such as MOVIU, which take a 16-bit
+   literal operand. The literal may be the top or bottom half of
+   a 32-bit value computed by the assembler, or by the linker. We provide
+   two relocation types here.
+
+   3. Data items (long, word and byte) preset with a value computed by
+   the linker.  */
+
+
+/* This string holds the chars that always start a comment. If the
+   pre-processor is disabled, these aren't very useful. The macro
+   tc_comment_chars points to this. We use this, rather than the usual
+   comment_chars, so that the --bitwise-or option will work.  */
+const char *visium_comment_chars = "!;";
+
+/* This array holds the chars that only start a comment at the beginning
+   of a line.  If the line seems to have the form '# 123 filename' .line
+   and .file directives will appear in the pre-processed output. Note that
+   input_file.c hand checks for '#' at the beginning of the first line of
+   the input file. This is because the compiler outputs #NO_APP at the
+   beginning of its output. Also note that comments like this one will
+   always work.  */
+const char line_comment_chars[] = "#!;";
+const char line_separator_chars[] = "";
+
+/* Chars that can be used to separate mantissa from exponent in floating point
+   numbers.  */
+const char EXP_CHARS[] = "eE";
+
+/* Chars that mean this number is a floating point constant, as in
+   "0f12.456" or "0d1.2345e12".
+
+   ...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.  */
+const char FLT_CHARS[] = "rRsSfFdDxXeE";
+
+/* The size of a relocation record.  */
+const int md_reloc_size = 8;
+
+/* The architecture for which we are assembling.  */
+enum visium_arch_val
+{
+  VISIUM_ARCH_DEF,
+  VISIUM_ARCH_MCM24,
+  VISIUM_ARCH_MCM,
+  VISIUM_ARCH_GR6
+};
+
+static enum visium_arch_val visium_arch = VISIUM_ARCH_DEF;
+
+/* The opcode architecture for which we are assembling.  In contrast to the
+   previous one, this only determines which instructions are supported.  */
+static enum visium_opcode_arch_val visium_opcode_arch = VISIUM_OPCODE_ARCH_DEF;
+
+/* Flags to set in the ELF header e_flags field.  */
+static flagword visium_flags = 0;
+
+/* More than this number of nops in an alignment op gets a branch instead.  */
+static unsigned int nop_limit = 5;
+
+
+/* Translate internal representation of relocation info to BFD target
+   format.  */
+arelent *
+tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
+{
+  arelent *reloc;
+  bfd_reloc_code_real_type code;
+
+  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;
+
+  switch (fixp->fx_r_type)
+    {
+    case BFD_RELOC_8:
+    case BFD_RELOC_16:
+    case BFD_RELOC_32:
+    case BFD_RELOC_8_PCREL:
+    case BFD_RELOC_16_PCREL:
+    case BFD_RELOC_32_PCREL:
+    case BFD_RELOC_VISIUM_HI16:
+    case BFD_RELOC_VISIUM_LO16:
+    case BFD_RELOC_VISIUM_IM16:
+    case BFD_RELOC_VISIUM_REL16:
+    case BFD_RELOC_VISIUM_HI16_PCREL:
+    case BFD_RELOC_VISIUM_LO16_PCREL:
+    case BFD_RELOC_VISIUM_IM16_PCREL:
+    case BFD_RELOC_VTABLE_INHERIT:
+    case BFD_RELOC_VTABLE_ENTRY:
+      code = fixp->fx_r_type;
+      break;
+    default:
+      as_bad_where (fixp->fx_file, fixp->fx_line,
+		    "internal error: unknown relocation type %d (`%s')",
+		    fixp->fx_r_type,
+		    bfd_get_reloc_code_name (fixp->fx_r_type));
+      return 0;
+    }
+
+  reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
+  if (reloc->howto == 0)
+    {
+      as_bad_where (fixp->fx_file, fixp->fx_line,
+		    "internal error: can't export reloc type %d (`%s')",
+		    fixp->fx_r_type, bfd_get_reloc_code_name (code));
+      return 0;
+    }
+
+  /* Write the addend.  */
+  if (reloc->howto->pc_relative == 0)
+    reloc->addend = fixp->fx_addnumber;
+  else
+    reloc->addend = fixp->fx_offset;
+
+  return reloc;
+}
+
+extern char *input_line_pointer;
+
+
+static void s_bss (int);
+static void visium_rdata (int);
+
+static void visium_update_parity_bit (char *);
+static char *parse_exp (char *, expressionS *);
+
+/* These are the back-ends for the various machine dependent pseudo-ops.  */
+void demand_empty_rest_of_line (void);
+
+
+static void
+s_bss (int ignore ATTRIBUTE_UNUSED)
+{
+  /* We don't support putting frags in the BSS segment, we fake it
+     by marking in_bss, then looking at s_skip for clues.  */
+
+  subseg_set (bss_section, 0);
+  demand_empty_rest_of_line ();
+}
+
+
+/* This table describes all the machine specific pseudo-ops the assembler
+   has to support. The fields are:
+
+   1: Pseudo-op name without dot.
+   2: Function to call to execute this pseudo-op.
+   3: Integer arg to pass to the function.  */
+const pseudo_typeS md_pseudo_table[] =
+{
+  {"bss", s_bss, 0},
+  {"skip", s_space, 0},
+  {"align", s_align_bytes, 0},
+  {"noopt", s_ignore, 0},
+  {"optim", s_ignore, 0},
+  {"rdata", visium_rdata, 0},
+  {"rodata", visium_rdata, 0},
+  {0, 0, 0}
+};
+
+
+static void
+visium_rdata (int xxx)
+{
+  char *save_line = input_line_pointer;
+  static char section[] = ".rodata\n";
+
+  /* Just pretend this is .section .rodata */
+  input_line_pointer = section;
+  obj_elf_section (xxx);
+  input_line_pointer = save_line;
+}
+
+/* Align a section.  */
+valueT
+md_section_align (asection *seg, valueT addr)
+{
+  int align = bfd_get_section_alignment (stdoutput, seg);
+
+  return ((addr + (1 << align) - 1) & (-1 << align));
+}
+
+void
+md_number_to_chars (char *buf, valueT val, int n)
+{
+  number_to_chars_bigendian (buf, val, n);
+}
+
+symbolS *
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+/* The parse options.  */
+const char *md_shortopts = "m:";
+
+struct option md_longopts[] =
+{
+  {NULL, no_argument, NULL, 0}
+};
+
+size_t md_longopts_size = sizeof (md_longopts);
+
+struct visium_option_table
+{
+  char *option;			/* Option name to match.  */
+  char *help;			/* Help information.  */
+  int *var;			/* Variable to change.  */
+  int value;			/* To what to change it.  */
+  char *deprecated;		/* If non-null, print this message. */
+};
+
+static struct visium_option_table visium_opts[] =
+{
+  {NULL, NULL, NULL, 0, NULL}
+};
+
+struct visium_arch_option_table
+{
+  char *name;
+  enum visium_arch_val value;
+};
+
+static struct visium_arch_option_table visium_archs[] =
+{
+  {"mcm24", VISIUM_ARCH_MCM24},
+  {"mcm",   VISIUM_ARCH_MCM},
+  {"gr5",   VISIUM_ARCH_MCM},
+  {"gr6",   VISIUM_ARCH_GR6},
+  {NULL, 0}
+};
+
+struct visium_long_option_table
+{
+  char *option;			/* Substring to match.  */
+  char *help;			/* Help information.  */
+  int (*func) (char *subopt);	/* Function to decode sub-option.  */
+  char *deprecated;		/* If non-null, print this message.  */
+};
+
+static int
+visium_parse_arch (char *str)
+{
+  struct visium_arch_option_table *opt;
+
+  if (strlen (str) == 0)
+    {
+      as_bad ("missing architecture name `%s'", str);
+      return 0;
+    }
+
+
+  for (opt = visium_archs; opt->name != NULL; opt++)
+    if (strcmp (opt->name, str) == 0)
+      {
+	visium_arch = opt->value;
+	return 1;
+      }
+
+  as_bad ("unknown architecture `%s'\n", str);
+  return 0;
+}
+
+static struct visium_long_option_table visium_long_opts[] =
+{
+  {"mtune=", "<arch_name>\t assemble for architecture <arch name>",
+   visium_parse_arch, NULL},
+  {NULL, NULL, NULL, NULL}
+};
+
+int
+md_parse_option (int c, char *arg)
+{
+  struct visium_option_table *opt;
+  struct visium_long_option_table *lopt;
+
+  switch (c)
+    {
+    case 'a':
+      /* Listing option.  Just ignore these, we don't support additional
+         ones.  */
+      return 0;
+
+    default:
+      for (opt = visium_opts; opt->option != NULL; opt++)
+	{
+	  if (c == opt->option[0]
+	      && ((arg == NULL && opt->option[1] == 0)
+		  || strcmp (arg, opt->option + 1) == 0))
+	    {
+	      /* If the option is deprecated, tell the user.  */
+	      if (opt->deprecated != NULL)
+		as_tsktsk ("option `-%c%s' is deprecated: %s", c,
+			   arg ? arg : "", opt->deprecated);
+
+	      if (opt->var != NULL)
+		*opt->var = opt->value;
+
+	      return 1;
+	    }
+	}
+
+      for (lopt = visium_long_opts; lopt->option != NULL; lopt++)
+	{
+	  /* These options are expected to have an argument.  */
+	  if (c == lopt->option[0]
+	      && arg != NULL
+	      && strncmp (arg, lopt->option + 1,
+			  strlen (lopt->option + 1)) == 0)
+	    {
+	      /* If the option is deprecated, tell the user.  */
+	      if (lopt->deprecated != NULL)
+		as_tsktsk ("option `-%c%s' is deprecated: %s", c, arg,
+			   lopt->deprecated);
+
+	      /* Call the sup-option parser.  */
+	      return lopt->func (arg + strlen (lopt->option) - 1);
+	    }
+	}
+
+      return 0;
+    }
+
+  return 1;
+}
+
+void
+md_show_usage (FILE * fp)
+{
+  struct visium_option_table *opt;
+  struct visium_long_option_table *lopt;
+
+  fprintf (fp, " Visium-specific assembler options:\n");
+
+  for (opt = visium_opts; opt->option != NULL; opt++)
+    if (opt->help != NULL)
+      fprintf (fp, "  -%-23s%s\n", opt->option, opt->help);
+
+  for (lopt = visium_long_opts; lopt->option != NULL; lopt++)
+    if (lopt->help != NULL)
+      fprintf (fp, "  -%s%s\n", lopt->option, lopt->help);
+
+}
+
+/* Interface to relax_segment.  */
+
+/* Return the estimate of the size of a machine dependent frag
+   before any relaxing is done.  It may also create any necessary
+   relocations.  */
+int
+md_estimate_size_before_relax (fragS * fragP,
+			       segT segment ATTRIBUTE_UNUSED)
+{
+  fragP->fr_var = 4;
+  return 4;
+}
+
+/* Get the address of a symbol during relaxation.  From tc-arm.c.  */
+static addressT
+relaxed_symbol_addr (fragS *fragp, long stretch)
+{
+  fragS *sym_frag;
+  addressT addr;
+  symbolS *sym;
+
+  sym = fragp->fr_symbol;
+  sym_frag = symbol_get_frag (sym);
+  know (S_GET_SEGMENT (sym) != absolute_section
+	|| sym_frag == &zero_address_frag);
+  addr = S_GET_VALUE (sym) + fragp->fr_offset;
+
+  /* If frag has yet to be reached on this pass, assume it will
+     move by STRETCH just as we did.  If this is not so, it will
+     be because some frag between grows, and that will force
+     another pass.  */
+  if (stretch != 0
+      && sym_frag->relax_marker != fragp->relax_marker)
+    {
+      fragS *f;
+
+      /* Adjust stretch for any alignment frag.  Note that if have
+	 been expanding the earlier code, the symbol may be
+	 defined in what appears to be an earlier frag.  FIXME:
+	 This doesn't handle the fr_subtype field, which specifies
+	 a maximum number of bytes to skip when doing an
+	 alignment.  */
+      for (f = fragp; f != NULL && f != sym_frag; f = f->fr_next)
+	{
+	  if (f->fr_type == rs_align || f->fr_type == rs_align_code)
+	    {
+	      if (stretch < 0)
+		stretch = - ((- stretch)
+			     & ~ ((1 << (int) f->fr_offset) - 1));
+	      else
+		stretch &= ~ ((1 << (int) f->fr_offset) - 1);
+	      if (stretch == 0)
+		break;
+	    }
+	}
+      if (f != NULL)
+	addr += stretch;
+    }
+
+  return addr;
+}
+
+/* Relax a machine dependent frag.  This returns the amount by which
+   the current size of the frag should change.  */
+int
+visium_relax_frag (asection *sec, fragS *fragP, long stretch)
+{
+  int old_size, new_size;
+  addressT addr;
+
+  /* We only handle relaxation for the BRR instruction.  */
+  gas_assert (fragP->fr_subtype == mode_ci);
+
+  if (!S_IS_DEFINED (fragP->fr_symbol)
+      || sec != S_GET_SEGMENT (fragP->fr_symbol)
+      || S_IS_WEAK (fragP->fr_symbol))
+    return 0;
+
+  old_size = fragP->fr_var;
+  addr = relaxed_symbol_addr (fragP, stretch);
+
+  /* If the target is the address of the instruction, we'll insert a NOP.  */
+  if (addr == fragP->fr_address + fragP->fr_fix)
+    new_size = 8;
+  else
+    new_size = 4;
+
+  fragP->fr_var = new_size;
+  return new_size - old_size;
+}
+
+/* Convert a machine dependent frag.  */
+void
+md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, segT sec ATTRIBUTE_UNUSED,
+		 fragS * fragP)
+{
+  char *buf = fragP->fr_literal + fragP->fr_fix;
+  expressionS exp;
+  fixS *fixP;
+
+  /* We only handle relaxation for the BRR instruction.  */
+  gas_assert (fragP->fr_subtype == mode_ci);
+
+  /* Insert the NOP if requested.  */
+  if (fragP->fr_var == 8)
+    {
+      memcpy (buf + 4, buf, 4);
+      memset (buf, 0, 4);
+      fragP->fr_fix += 4;
+    }
+
+  exp.X_op = O_symbol;
+  exp.X_add_symbol = fragP->fr_symbol;
+  exp.X_add_number = fragP->fr_offset;
+
+  /* Now we can create the relocation at the correct offset.  */
+  fixP = fix_new_exp (fragP, fragP->fr_fix, 4, &exp, 1, BFD_RELOC_VISIUM_REL16);
+  fixP->fx_file = fragP->fr_file;
+  fixP->fx_line = fragP->fr_line;
+  fragP->fr_fix += 4;
+  fragP->fr_var = 0;
+}
+
+/* The location from which a PC relative jump should be calculated,
+   given a PC relative jump reloc.  */
+long
+visium_pcrel_from_section (fixS *fixP, segT sec)
+{
+  if (fixP->fx_addsy != (symbolS *) NULL
+      && (!S_IS_DEFINED (fixP->fx_addsy)
+	  || S_GET_SEGMENT (fixP->fx_addsy) != sec))
+    {
+      /* The symbol is undefined (or is defined but not in this section).
+         Let the linker figure it out.  */
+      return 0;
+    }
+
+  /* Return the address of the instruction.  */
+  return fixP->fx_where + fixP->fx_frag->fr_address;
+}
+
+/* Indicate whether a fixup against a locally defined
+   symbol should be adjusted to be against the section
+   symbol.  */
+bfd_boolean
+visium_fix_adjustable (fixS *fix)
+{
+  /* We need the symbol name for the VTABLE entries.  */
+  return (fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT
+	  && fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY);
+}
+
+static void
+visium_update_parity_bit (char *buf)
+{
+  int p1 = (buf[0] & 0x7f) ^ buf[1] ^ buf[2] ^ buf[3];
+  int p2 = 0;
+  int i;
+
+  for (i = 1; i <= 8; i++)
+    {
+      p2 += p1 & 0x01;
+      p1 >>= 1;
+    }
+
+  buf[0] = (buf[0] & 0x7f) | ((p2 << 7) & 0x80);
+}
+
+/* This is called from HANDLE_ALIGN in write.c.  Fill in the contents
+   of an rs_align_code fragment.  */
+void
+visium_handle_align (fragS *fragP)
+{
+  valueT count
+    = fragP->fr_next->fr_address - (fragP->fr_address + fragP->fr_fix);
+  valueT fix = count & 3;
+  char *p = fragP->fr_literal + fragP->fr_fix;
+
+  if (fix)
+    {
+      memset (p, 0, fix);
+      p += fix;
+      count -= fix;
+      fragP->fr_fix += fix;
+    }
+
+  if (count == 0)
+    return;
+
+  fragP->fr_var = 4;
+
+  if (count > 4 * nop_limit && count <= 131068)
+    {
+      struct frag *rest;
+
+      /* Make a branch, then follow with nops.  Insert another
+         frag to handle the nops.  */
+      md_number_to_chars (p, 0x78000000 + (count >> 2), 4);
+      visium_update_parity_bit (p);
+
+      rest = xmalloc (SIZEOF_STRUCT_FRAG + 4);
+      memcpy (rest, fragP, SIZEOF_STRUCT_FRAG);
+      fragP->fr_next = rest;
+      rest->fr_address += rest->fr_fix + 4;
+      rest->fr_fix = 0;
+      /* If we leave the next frag as rs_align_code we'll come here
+	 again, resulting in a bunch of branches rather than a
+	 branch followed by nops.  */
+      rest->fr_type = rs_align;
+      p = rest->fr_literal;
+    }
+
+  memset (p, 0, 4);
+}
+
+/* Apply a fixS to the frags, now that we know the value it ought to
+   hold.  */
+void
+md_apply_fix (fixS * fixP, valueT * value, segT segment)
+{
+  char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+  offsetT val;
+  long insn;
+
+  val = *value;
+
+  gas_assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
+
+  /* Remember value for tc_gen_reloc.  */
+  fixP->fx_addnumber = val;
+
+  /* Since DIFF_EXPR_OK is defined, .-foo gets turned into PC
+     relative relocs. If this has happened, a non-PC relative
+     reloc must be reinstalled with its PC relative version here.  */
+  if (fixP->fx_pcrel)
+    {
+      switch (fixP->fx_r_type)
+	{
+	case BFD_RELOC_8:
+	  fixP->fx_r_type = BFD_RELOC_8_PCREL;
+	  break;
+	case BFD_RELOC_16:
+	  fixP->fx_r_type = BFD_RELOC_16_PCREL;
+	  break;
+	case BFD_RELOC_32:
+	  fixP->fx_r_type = BFD_RELOC_32_PCREL;
+	  break;
+	case BFD_RELOC_VISIUM_HI16:
+	  fixP->fx_r_type = BFD_RELOC_VISIUM_HI16_PCREL;
+	  break;
+	case BFD_RELOC_VISIUM_LO16:
+	  fixP->fx_r_type = BFD_RELOC_VISIUM_LO16_PCREL;
+	  break;
+	case BFD_RELOC_VISIUM_IM16:
+	  fixP->fx_r_type = BFD_RELOC_VISIUM_IM16_PCREL;
+	  break;
+	  /* Pacify gcc -Wall.  */
+	default:
+	  break;
+	}
+    }
+
+  /* If this is a data relocation, just output VAL.  */
+  switch (fixP->fx_r_type)
+    {
+    case BFD_RELOC_8:
+    case BFD_RELOC_8_PCREL:
+      md_number_to_chars (buf, val, 1);
+      break;
+    case BFD_RELOC_16:
+    case BFD_RELOC_16_PCREL:
+      md_number_to_chars (buf, val, 2);
+      break;
+    case BFD_RELOC_32:
+    case BFD_RELOC_32_PCREL:
+      md_number_to_chars (buf, val, 4);
+      break;
+    case BFD_RELOC_VTABLE_INHERIT:
+    case BFD_RELOC_VTABLE_ENTRY:
+      fixP->fx_done = 0;
+      break;
+    default:
+      /* It's a relocation against an instruction.  */
+      insn = bfd_getb32 ((unsigned char *) buf);
+
+      switch (fixP->fx_r_type)
+	{
+	case BFD_RELOC_VISIUM_REL16:
+	  if (!fixP->fx_addsy
+	      || (S_IS_DEFINED (fixP->fx_addsy)
+		  && S_GET_SEGMENT (fixP->fx_addsy) == segment))
+	    {
+	      if (val > 0x1fffc || val < -0x20000)
+		as_bad_where
+		 (fixP->fx_file, fixP->fx_line,
+		  "16-bit word displacement out of range: value = %d",
+		  (int) val);
+	      val = (val >> 2);
+
+	      insn = (insn & 0xffff0000) | (val & 0x0000ffff);
+	    }
+	  break;
+
+	case BFD_RELOC_VISIUM_HI16:
+	case BFD_RELOC_VISIUM_HI16_PCREL:
+	  if (!fixP->fx_addsy)
+	    {
+	      insn = (insn & 0xffff0000) | ((val >> 16) & 0x0000ffff);
+	    }
+	  else
+	    {
+	      /* FIXME: Need comment explaining why we do this.  */
+	      insn = (insn & 0xffff0000);
+	    }
+	  break;
+
+	case BFD_RELOC_VISIUM_LO16:
+	case BFD_RELOC_VISIUM_LO16_PCREL:
+	  if (!fixP->fx_addsy)
+	    {
+	      insn = (insn & 0xffff0000) | (val & 0x0000ffff);
+	    }
+	  else
+	    {
+	      /* FIXME: Need comment explaining why we do this.  */
+	      insn = (insn & 0xffff0000);
+	    }
+	  break;
+
+	case BFD_RELOC_VISIUM_IM16:
+	case BFD_RELOC_VISIUM_IM16_PCREL:
+	  if (!fixP->fx_addsy)
+	    {
+	      if ((val & 0xffff0000) != 0)
+		as_bad_where (fixP->fx_file, fixP->fx_line,
+			      "16-bit immediate out of range: value = %d",
+			      (int) val);
+
+	      insn = (insn & 0xffff0000) | val;
+	    }
+	  else
+	    {
+	      /* FIXME: Need comment explaining why we do this.  */
+	      insn = (insn & 0xffff0000);
+	    }
+	  break;
+
+	case BFD_RELOC_NONE:
+	default:
+	  as_bad_where (fixP->fx_file, fixP->fx_line,
+			"bad or unhandled relocation type: 0x%02x",
+			fixP->fx_r_type);
+	  break;
+	}
+
+      bfd_putb32 (insn, (unsigned char *) buf);
+      visium_update_parity_bit (buf);
+      break;
+    }
+
+  /* Are we finished with this relocation now?  */
+  if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
+    fixP->fx_done = 1;
+}
+
+char *
+parse_exp (char *s, expressionS * op)
+{
+  char *save = input_line_pointer;
+  char *new;
+
+  if (!s)
+    {
+      return s;
+    }
+
+  input_line_pointer = s;
+  expression (op);
+  new = input_line_pointer;
+  input_line_pointer = save;
+  return new;
+}
+
+/* If the given string is a Visium opcode mnemonic return the code
+   otherwise return -1. Use binary chop to find matching entry.  */
+static int
+get_opcode (int *code, enum addressing_mode *mode, char *flags, char *mnem)
+{
+  int l = 0;
+  int r = sizeof (opcode_table) / sizeof (struct opcode_entry) - 1;
+
+  do
+    {
+      int mid = (l + r) / 2;
+      int ans = strcmp (mnem, opcode_table[mid].mnem);
+
+      if (ans < 0)
+	r = mid - 1;
+      else if (ans > 0)
+	l = mid + 1;
+      else
+	{
+	  *code = opcode_table[mid].code;
+	  *mode = opcode_table[mid].mode;
+	  *flags = opcode_table[mid].flags;
+
+	  return 0;
+	}
+    }
+  while (l <= r);
+
+  return -1;
+}
+
+/* This function is called when the assembler starts up. It is called
+   after the options have been parsed and the output file has been
+   opened.  */
+void
+md_begin (void)
+{
+  switch (visium_arch)
+    {
+    case VISIUM_ARCH_DEF:
+      break;
+    case VISIUM_ARCH_MCM24:
+      visium_opcode_arch = VISIUM_OPCODE_ARCH_GR5;
+      visium_flags |= EF_VISIUM_ARCH_MCM24;
+      break;
+    case VISIUM_ARCH_MCM:
+      visium_opcode_arch = VISIUM_OPCODE_ARCH_GR5;
+      visium_flags |= EF_VISIUM_ARCH_MCM;
+      break;
+    case VISIUM_ARCH_GR6:
+      visium_opcode_arch = VISIUM_OPCODE_ARCH_GR6;
+      visium_flags |= EF_VISIUM_ARCH_MCM | EF_VISIUM_ARCH_GR6;
+      nop_limit = 2;
+      break;
+    default:
+      gas_assert (0);
+    }
+
+  bfd_set_private_flags (stdoutput, visium_flags);
+}
+
+/* This is identical to the md_atof in m68k.c.  I think this is right,
+   but I'm not sure.
+
+   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.  */
+
+/* Equal to MAX_PRECISION in atof-ieee.c.  */
+#define MAX_LITTLENUMS 6
+
+char *
+md_atof (int type, char *litP, int *sizeP)
+{
+  int i, prec;
+  LITTLENUM_TYPE words[MAX_LITTLENUMS];
+  char *t;
+
+  switch (type)
+    {
+    case 'f':
+    case 'F':
+    case 's':
+    case 'S':
+      prec = 2;
+      break;
+
+    case 'd':
+    case 'D':
+    case 'r':
+    case 'R':
+      prec = 4;
+      break;
+
+    case 'x':
+    case 'X':
+      prec = 6;
+      break;
+
+    case 'p':
+    case 'P':
+      prec = 6;
+      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 * sizeof (LITTLENUM_TYPE);
+
+  if (target_big_endian)
+    {
+      for (i = 0; i < prec; i++)
+	{
+	  md_number_to_chars (litP, (valueT) words[i],
+			      sizeof (LITTLENUM_TYPE));
+	  litP += sizeof (LITTLENUM_TYPE);
+	}
+    }
+  else
+    {
+      for (i = prec - 1; i >= 0; i--)
+	{
+	  md_number_to_chars (litP, (valueT) words[i],
+			      sizeof (LITTLENUM_TYPE));
+	  litP += sizeof (LITTLENUM_TYPE);
+	}
+    }
+
+  return 0;
+}
+
+static inline char *
+skip_space (char *s)
+{
+  while (*s == ' ' || *s == '\t')
+    ++s;
+
+  return s;
+}
+
+static int
+parse_gen_reg (char **sptr, int *rptr)
+{
+  char *s = skip_space (*sptr);
+  char buf[10];
+  int cnt;
+  int l, r;
+
+  cnt = 0;
+  memset (buf, '\0', 10);
+  while ((ISALNUM (*s)) && cnt < 10)
+    buf[cnt++] = TOLOWER (*s++);
+
+  l = 0;
+  r = sizeof (gen_reg_table) / sizeof (struct reg_entry) - 1;
+
+  do
+    {
+      int mid = (l + r) / 2;
+      int ans = strcmp (buf, gen_reg_table[mid].name);
+
+      if (ans < 0)
+	r = mid - 1;
+      else if (ans > 0)
+	l = mid + 1;
+      else
+	{
+	  *rptr = gen_reg_table[mid].code;
+	  *sptr = s;
+	  return 0;
+	}
+    }
+  while (l <= r);
+
+  return -1;
+}
+
+static int
+parse_fp_reg (char **sptr, int *rptr)
+{
+  char *s = skip_space (*sptr);
+  char buf[10];
+  int cnt;
+  int l, r;
+
+  cnt = 0;
+  memset (buf, '\0', 10);
+  while ((ISALNUM (*s)) && cnt < 10)
+    buf[cnt++] = TOLOWER (*s++);
+
+  l = 0;
+  r = sizeof (fp_reg_table) / sizeof (struct reg_entry) - 1;
+
+  do
+    {
+      int mid = (l + r) / 2;
+      int ans = strcmp (buf, fp_reg_table[mid].name);
+
+      if (ans < 0)
+	r = mid - 1;
+      else if (ans > 0)
+	l = mid + 1;
+      else
+	{
+	  *rptr = fp_reg_table[mid].code;
+	  *sptr = s;
+	  return 0;
+	}
+    }
+  while (l <= r);
+
+  return -1;
+}
+
+static int
+parse_cc (char **sptr, int *rptr)
+{
+  char *s = skip_space (*sptr);
+  char buf[10];
+  int cnt;
+  int l, r;
+
+  cnt = 0;
+  memset (buf, '\0', 10);
+  while ((ISALNUM (*s)) && cnt < 10)
+    buf[cnt++] = TOLOWER (*s++);
+
+  l = 0;
+  r = sizeof (cc_table) / sizeof (struct cc_entry) - 1;
+
+  do
+    {
+      int mid = (l + r) / 2;
+      int ans = strcmp (buf, cc_table[mid].name);
+
+      if (ans < 0)
+	r = mid - 1;
+      else if (ans > 0)
+	l = mid + 1;
+      else
+	{
+	  *rptr = cc_table[mid].code;
+	  *sptr = s;
+	  return 0;
+	}
+    }
+  while (l <= r);
+
+  return -1;
+}
+
+/* Previous dest is the destination register number of the instruction
+   before the current one.  */
+static int previous_dest = 0;
+static int previous_mode = 0;
+static int condition_code = 0;
+static int this_dest = 0;
+static int this_mode = 0;
+
+
+/* This is the main function in this file. It takes a line of assembly language
+   source code and assembles it. Note, labels and pseudo ops have already
+   been removed, so too has leading white space. */
+void
+md_assemble (char *str0)
+{
+  char *str = str0;
+  int cnt;
+  char mnem[10];
+  int opcode;
+  enum addressing_mode amode;
+  char arch_flags;
+  int ans;
+
+  char *output;
+  int reloc = 0;
+  relax_substateT relax = 0;
+  expressionS e1;
+  int r1, r2, r3;
+  int cc;
+  int indx;
+
+  /* Initialize the expression.  */
+  e1.X_op = O_absent;
+
+  /* Initialize destination register.
+     If the instruction we just looked at is in the delay slot of an
+     unconditional branch, then there is no index hazard.  */
+  if ((previous_mode == mode_cad || previous_mode == mode_ci)
+      && condition_code == 15)
+    this_dest = 0;
+
+  previous_dest = this_dest;
+  previous_mode = this_mode;
+  this_dest = 0;
+
+  /* Drop leading whitespace (probably not required).  */
+  while (*str == ' ')
+    str++;
+
+  /* Get opcode mnemonic and make sure it's in lower case.  */
+  cnt = 0;
+  memset (mnem, '\0', 10);
+  while ((ISALNUM (*str) || *str == '.' || *str == '_') && cnt < 10)
+    mnem[cnt++] = TOLOWER (*str++);
+
+  /* Look up mnemonic in opcode table, and get the code,
+     the instruction format, and the flags that indicate
+     which family members support this mnenonic.  */
+  if (get_opcode (&opcode, &amode, &arch_flags, mnem) < 0)
+    {
+      as_bad ("Unknown instruction mnenonic `%s'", mnem);
+      return;
+    }
+
+  if ((VISIUM_OPCODE_ARCH_MASK (visium_opcode_arch) & arch_flags) == 0)
+    {
+      as_bad ("Architecture mismatch on `%s'", mnem);
+      return;
+    }
+
+  this_mode = amode;
+
+  switch (amode)
+    {
+    case mode_d:
+      /* register :=
+         Example:
+         readmda r1  */
+      ans = parse_gen_reg (&str, &r1);
+      if (ans < 0)
+	{
+	  as_bad ("Dest register required");
+	  return;
+	}
+      opcode |= (r1 << 10);
+      this_dest = r1;
+      break;
+
+    case mode_a:
+      /* op= register
+         Example: asld r1  */
+      ans = parse_gen_reg (&str, &r1);
+      if (ans < 0)
+	{
+	  as_bad ("SourceA register required");
+	  return;
+	}
+      opcode |= (r1 << 16);
+      break;
+
+    case mode_ab:
+      /* register * register
+         Example:
+         mults r1,r2  */
+      ans = parse_gen_reg (&str, &r1);
+      if (ans < 0)
+	{
+	  as_bad ("SourceA register required");
+	  return;
+	}
+      str = skip_space (str);
+      if (*str == ',')
+	{
+	  str++;
+	  ans = parse_gen_reg (&str, &r2);
+	  if (ans < 0)
+	    {
+	      as_bad ("SourceB register required");
+	      return;
+	    }
+	  opcode |= (r1 << 16) | (r2 << 4);
+	}
+      else
+	{
+	  as_bad ("SourceB register required");
+	  return;
+	}
+      break;
+
+    case mode_da:
+      /* register := register
+         Example:
+         extb.l  r1,r2  */
+      ans = parse_gen_reg (&str, &r1);
+      if (ans < 0)
+	{
+	  as_bad ("Dest register required");
+	  return;
+	}
+      str = skip_space (str);
+      if (*str == ',')
+	{
+	  str++;
+	  ans = parse_gen_reg (&str, &r2);
+	  if (ans < 0)
+	    {
+	      as_bad ("SourceA register required");
+	      return;
+	    }
+	  opcode |= (r1 << 10) | (r2 << 16);
+	}
+      else
+	{
+	  as_bad ("SourceB register required");
+	  return;
+	}
+      this_dest = r1;
+      break;
+
+    case mode_dab:
+      /* register := register * register
+         Example:
+         add.l r1,r2,r3  */
+      ans = parse_gen_reg (&str, &r1);
+      if (ans < 0)
+	{
+	  as_bad ("Dest register required");
+	  return;
+	}
+      str = skip_space (str);
+      if (*str == ',')
+	{
+	  str++;
+	  ans = parse_gen_reg (&str, &r2);
+	  if (ans < 0)
+	    {
+	      as_bad ("SourceA register required");
+	      return;
+	    }
+	  str = skip_space (str);
+	  if (*str == ',')
+	    {
+	      str++;
+	      ans = parse_gen_reg (&str, &r3);
+	      if (ans < 0)
+		{
+		  as_bad ("SourceB register required");
+		  return;
+		}
+
+	      /* Got three regs, assemble instruction.  */
+	      opcode |= (r1 << 10) | (r2 << 16) | (r3 << 4);
+	    }
+	  else
+	    {
+	      as_bad ("SourceA register required");
+	      return;
+	    }
+	}
+      else
+	{
+	  as_bad ("Dest register required");
+	  return;
+	}
+      this_dest = r1;
+      break;
+
+    case mode_iab:
+      /* 5-bit immediate * register * register
+         Example:
+         eamwrite 3,r1,r2  */
+      str = parse_exp (str, &e1);
+      str = skip_space (str);
+      if (e1.X_op != O_absent && *str == ',')
+	{
+	  int eam_op = e1.X_add_number;
+
+	  str = skip_space (str + 1);
+	  ans = parse_gen_reg (&str, &r2);
+	  if (ans < 0)
+	    {
+	      as_bad ("SourceA register required");
+	      return;
+	    }
+	  str = skip_space (str);
+	  if (*str == ',')
+	    {
+	      str++;
+	      ans = parse_gen_reg (&str, &r3);
+	      if (ans < 0)
+		{
+		  as_bad ("SourceB register required");
+		  return;
+		}
+
+	      /* Got three operands, assemble instruction.  */
+	      if (eam_op < 0 || eam_op > 31)
+		{
+		  as_bad ("eam_op out of range");
+		}
+	      opcode |= ((eam_op & 0x1f) << 10) | (r2 << 16) | (r3 << 4);
+	    }
+	}
+      else
+	{
+	  as_bad ("EAM_OP required");
+	  return;
+	}
+      break;
+
+    case mode_0ab:
+      /* zero * register * register
+         Example:
+         cmp.l  r1,r2 */
+      ans = parse_gen_reg (&str, &r1);
+      if (ans < 0)
+	{
+	  as_bad ("SourceA register required");
+	  return;
+	}
+      str = skip_space (str);
+      if (*str == ',')
+	{
+	  str++;
+	  ans = parse_gen_reg (&str, &r2);
+	  if (ans < 0)
+	    {
+	      as_bad ("SourceB register required");
+	      return;
+	    }
+	  opcode |= (r1 << 16) | (r2 << 4);
+	}
+      else
+	{
+	  as_bad ("SourceB register required");
+	  return;
+	}
+      break;
+
+    case mode_da0:
+      /* register * register * zero
+         Example:
+         move.l  r1,r2  */
+      ans = parse_gen_reg (&str, &r1);
+      if (ans < 0)
+	{
+	  as_bad ("Dest register required");
+	  return;
+	}
+      str = skip_space (str);
+      if (*str == ',')
+	{
+	  str++;
+	  ans = parse_gen_reg (&str, &r2);
+	  if (ans < 0)
+	    {
+	      as_bad ("SourceA register required");
+	      return;
+	    }
+	  opcode |= (r1 << 10) | (r2 << 16);
+	}
+      else
+	{
+	  as_bad ("SourceA register required");
+	  return;
+	}
+      this_dest = r1;
+      break;
+
+    case mode_cad:
+      /* condition * register * register
+         Example:
+         bra  tr,r1,r2  */
+      ans = parse_cc (&str, &cc);
+      if (ans < 0)
+	{
+	  as_bad ("condition code required");
+	  return;
+	}
+
+      str = skip_space (str);
+      if (*str == ',')
+	{
+	  str = skip_space (str + 1);
+	  ans = parse_gen_reg (&str, &r2);
+	  if (ans < 0)
+	    {
+	      as_bad ("SourceA register required");
+	      return;
+	    }
+	  str = skip_space (str);
+	  if (*str == ',')
+	    {
+	      str++;
+	      ans = parse_gen_reg (&str, &r3);
+	      if (ans < 0)
+		{
+		  as_bad ("Dest register required");
+		  return;
+		}
+
+	      /* Got three operands, assemble instruction.  */
+	      opcode |= (cc << 27) | (r2 << 16) | (r3 << 10);
+	    }
+	  else
+	    {
+	      as_bad ("Dest register required");
+	      return;
+	    }
+	}
+      else
+	{
+	  as_bad ("SourceA register required");
+	  return;
+	}
+
+      if (previous_mode == mode_cad || previous_mode == mode_ci)
+	as_bad ("branch instruction in delay slot");
+
+      this_dest = r3;
+      condition_code = cc;
+      break;
+
+    case mode_das:
+      /* register := register * 5-bit imediate/register shift count
+         Example:
+         asl.l  r1,r2,4  */
+      ans = parse_gen_reg (&str, &r1);
+      if (ans < 0)
+	{
+	  as_bad ("Dest register required");
+	  return;
+	}
+      str = skip_space (str);
+      if (*str == ',')
+	{
+	  str++;
+	  ans = parse_gen_reg (&str, &r2);
+	  if (ans < 0)
+	    {
+	      as_bad ("SourceA register required");
+	      return;
+	    }
+	  str = skip_space (str);
+	  if (*str == ',')
+	    {
+	      str++;
+	      ans = parse_gen_reg (&str, &r3);
+	      if (ans == 0)
+		{
+		  opcode |= (r1 << 10) | (r2 << 16) | (r3 << 4);
+		}
+	      else
+		{
+		  str = parse_exp (str, &e1);
+		  if (e1.X_op == O_constant)
+		    {
+		      int imm = e1.X_add_number;
+
+		      if (imm < 0 || imm > 31)
+			as_bad ("immediate value out of range");
+
+		      opcode |=
+			(r1 << 10) | (r2 << 16) | (1 << 9) | ((imm & 0x1f) <<
+							      4);
+		    }
+		  else
+		    {
+		      as_bad ("immediate operand required");
+		      return;
+		    }
+		}
+	    }
+	}
+      else
+	{
+	  as_bad ("SourceA register required");
+	  return;
+	}
+      this_dest = r1;
+      break;
+
+    case mode_di:
+      /* register := 5-bit immediate
+         Example:
+         eamread r1,3  */
+      ans = parse_gen_reg (&str, &r1);
+      if (ans < 0)
+	{
+	  as_bad ("Dest register required");
+	  return;
+	}
+      str = skip_space (str);
+      if (*str == ',')
+	{
+	  str++;
+	  str = parse_exp (str, &e1);
+	  if (e1.X_op == O_constant)
+	    {
+	      int opnd2 = e1.X_add_number;
+
+	      if (opnd2 < 0 || opnd2 > 31)
+		{
+		  as_bad ("immediate operand out of range");
+		  return;
+		}
+	      opcode |= (r1 << 10) | ((opnd2 & 0x1f) << 4);
+	    }
+	  else
+	    {
+	      as_bad ("immediate operand required");
+	      return;
+	    }
+	}
+      else
+	{
+	  as_bad ("immediate operand required");
+	  return;
+	}
+      this_dest = r1;
+      break;
+
+    case mode_ir:
+      /* 5-bit immediate * register, e.g. trace 1,r1  */
+      str = parse_exp (str, &e1);
+      str = skip_space (str);
+      if (e1.X_op == O_constant && *str == ',')
+	{
+	  int opnd1 = e1.X_add_number;
+
+	  str = skip_space (str + 1);
+	  ans = parse_gen_reg (&str, &r2);
+	  if (ans < 0)
+	    {
+	      as_bad ("SourceA register required");
+	      return;
+	    }
+
+	  /* Got two operands, assemble instruction.  */
+	  if (opnd1 < 0 || opnd1 > 31)
+	    {
+	      as_bad ("1st operand out of range");
+	    }
+	  opcode |= ((opnd1 & 0x1f) << 10) | (r2 << 16);
+	}
+      else
+	{
+	  as_bad ("Immediate operand required");
+	  return;
+	}
+      break;
+
+    case mode_ai:
+      /* register *= 16-bit unsigned immediate
+         Example:
+         addi  r1,123  */
+      ans = parse_gen_reg (&str, &r1);
+      if (ans < 0)
+	{
+	  as_bad ("Dest register required");
+	  return;
+	}
+      opcode |= (r1 << 16);
+
+      str = skip_space (str);
+      if (*str != ',')
+	{
+	  as_bad ("immediate value missing");
+	  return;
+	}
+      this_dest = r1;
+
+      /* fall through...  */
+
+    case mode_i:
+      /* MOVIL/WRTL traditionally get an implicit "%l" applied
+	 to their immediate value.  For other opcodes, unless
+	 the immediate value is decorated with "%u" or "%l"
+	 it must be in the range 0 .. 65535.  */
+      if ((opcode & 0x7fe00000) == 0x04800000
+	  || (opcode & 0x7fe00000) == 0x05000000)
+	reloc = BFD_RELOC_VISIUM_LO16;
+      else
+	reloc = BFD_RELOC_VISIUM_IM16;
+
+      str = skip_space (str + 1);
+
+      if (*str == '%')
+	{
+	  if (str[1] == 'u')
+	    reloc = BFD_RELOC_VISIUM_HI16;
+	  else if (str[1] == 'l')
+	    reloc = BFD_RELOC_VISIUM_LO16;
+	  else
+	    {
+	      as_bad ("bad char after %%");
+	      return;
+	    }
+
+	  str += 2;
+	}
+      str = parse_exp (str, &e1);
+      if (e1.X_op != O_absent)
+	{
+	  if (e1.X_op == O_constant)
+	    {
+	      int imm = e1.X_add_number;
+
+	      if (reloc == BFD_RELOC_VISIUM_HI16)
+		opcode |= ((imm >> 16) & 0xffff);
+	      else if (reloc == BFD_RELOC_VISIUM_LO16)
+		opcode |= (imm & 0xffff);
+	      else
+		{
+		  if (imm < 0 || imm > 0xffff)
+		    as_bad ("immediate value out of range");
+
+		  opcode |= (imm & 0xffff);
+		}
+	      /* No relocation is needed.  */
+	      reloc = 0;
+	    }
+	}
+      else
+	{
+	  as_bad ("immediate value missing");
+	  return;
+	}
+      break;
+
+    case mode_bax:
+      /* register * register * 5-bit immediate,
+         SourceB * SourceA * Index
+         Examples
+         write.l (r1),r2
+         write.l 3(r1),r2  */
+      str = skip_space (str);
+
+      indx = 0;
+      if (*str != '(')
+	{
+	  str = parse_exp (str, &e1);
+	  if (e1.X_op == O_constant)
+	    {
+	      indx = e1.X_add_number;
+
+	      if (indx < 0 || indx > 31)
+		{
+		  as_bad ("Index out of range");
+		  return;
+		}
+	    }
+	  else
+	    {
+	      as_bad ("Index(SourceA) required");
+	      return;
+	    }
+	}
+
+      str = skip_space (str);
+
+      if (*str != '(')
+	{
+	  as_bad ("Index(SourceA) required");
+	  return;
+	}
+
+      str = skip_space (str + 1);
+
+      ans = parse_gen_reg (&str, &r1);
+      if (ans < 0)
+	{
+	  as_bad ("SourceA register required");
+	  return;
+	}
+      str = skip_space (str);
+      if (*str != ')')
+	{
+	  as_bad ("(SourceA) required");
+	  return;
+	}
+      str = skip_space (str + 1);
+
+      if (*str == ',')
+	{
+	  str = skip_space (str + 1);
+	  ans = parse_gen_reg (&str, &r2);
+	  if (ans < 0)
+	    {
+	      as_bad ("SourceB register required");
+	      return;
+	    }
+	}
+      else
+	{
+	  as_bad ("SourceB register required");
+	  return;
+	}
+
+      opcode |= (r1 << 16) | (r2 << 4) | ((indx & 0x1f) << 10);
+
+      if (indx != 0 && previous_mode == mode_cad)
+	{
+	  /* We're in a delay slot.
+	     If the base reg is the destination of the branch, then issue
+	     an error message.
+	     Otherwise it is safe to use the base and index.  */
+	  if (previous_dest != 0 && r1 == previous_dest)
+	    {
+	      as_bad ("base register not ready");
+	      return;
+	    }
+	}
+      else if (previous_dest != 0
+	       && r1 == previous_dest
+	       && (visium_arch == VISIUM_ARCH_MCM
+		   || visium_arch == VISIUM_ARCH_MCM24
+		   || (visium_arch == VISIUM_ARCH_DEF && indx != 0)))
+	{
+	  as_warn ("base register not ready, NOP inserted.");
+	  /* Insert a NOP before the write instruction.  */
+	  output = frag_more (4);
+	  memset (output, 0, 4);
+	}
+      break;
+
+    case mode_dax:
+      /*  register := register * 5-bit immediate
+         Examples:
+         read.b  r1,(r2)
+         read.w  r1,3(r2)  */
+      ans = parse_gen_reg (&str, &r1);
+      if (ans < 0)
+	{
+	  as_bad ("Dest register required");
+	  return;
+	}
+      str = skip_space (str);
+      if (*str != ',')
+	{
+	  as_bad ("SourceA required");
+	  return;
+	}
+      str = skip_space (str + 1);
+
+      indx = 0;
+      if (*str != '(')
+	{
+	  str = parse_exp (str, &e1);
+	  if (e1.X_op == O_constant)
+	    {
+	      indx = e1.X_add_number;
+
+	      if (indx < 0 || indx > 31)
+		{
+		  as_bad ("Index out of range");
+		  return;
+		}
+	    }
+	  else
+	    {
+	      as_bad ("Immediate 0 to 31 required");
+	      return;
+	    }
+	}
+      if (*str != '(')
+	{
+	  as_bad ("(SourceA) required");
+	  return;
+	}
+      str++;
+      ans = parse_gen_reg (&str, &r2);
+      if (ans < 0)
+	{
+	  as_bad ("SourceA register required");
+	  return;
+	}
+      str = skip_space (str);
+      if (*str != ')')
+	{
+	  as_bad ("(SourceA) required");
+	  return;
+	}
+      str++;
+      opcode |= (r1 << 10) | (r2 << 16) | ((indx & 0x1f) << 4);
+      this_dest = r1;
+
+      if (indx != 0 && previous_mode == mode_cad)
+	{
+	  /* We're in a delay slot.
+	     If the base reg is the destination of the branch, then issue
+	     an error message.
+	     Otherwise it is safe to use the base and index.  */
+	  if (previous_dest != 0 && r2 == previous_dest)
+	    {
+	      as_bad ("base register not ready");
+	      return;
+	    }
+	}
+      else if (previous_dest != 0
+	       && r2 == previous_dest
+	       && (visium_arch == VISIUM_ARCH_MCM
+		   || visium_arch == VISIUM_ARCH_MCM24
+		   || (visium_arch == VISIUM_ARCH_DEF && indx != 0)))
+	{
+	  as_warn ("base register not ready, NOP inserted.");
+	  /* Insert a NOP before the read instruction.  */
+	  output = frag_more (4);
+	  memset (output, 0, 4);
+	}
+      break;
+
+    case mode_s:
+      /* special mode
+         Example:
+         nop  */
+      str = skip_space (str);
+      break;
+
+    case mode_ci:
+      /* condition * 16-bit signed word displacement
+         Example:
+         brr L1  */
+      ans = parse_cc (&str, &cc);
+      if (ans < 0)
+	{
+	  as_bad ("condition code required");
+	  return;
+	}
+      opcode |= (cc << 27);
+
+      str = skip_space (str);
+      if (*str == ',')
+	{
+	  str = skip_space (str + 1);
+	  str = parse_exp (str, &e1);
+	  if (e1.X_op != O_absent)
+	    {
+	      if (e1.X_op == O_constant)
+		{
+		  int imm = e1.X_add_number;
+
+		  if (imm < -32768 || imm > 32767)
+		    as_bad ("immediate value out of range");
+
+		  /* The GR6 doesn't correctly handle a 0 displacement
+		     so we insert a NOP and change it to -1.  */
+		  if (imm == 0 && cc != 0 && visium_arch == VISIUM_ARCH_GR6)
+		    {
+		      output = frag_more (4);
+		      memset (output, 0, 4);
+		      imm = -1;
+		    }
+
+		  opcode |= (imm & 0xffff);
+		}
+	      else if (e1.X_op == O_symbol)
+		{
+		  /* The GR6 doesn't correctly handle a 0 displacement
+		     so the instruction requires relaxation.  */
+		  if (cc != 0 && visium_arch == VISIUM_ARCH_GR6)
+		    relax = amode;
+		  else
+		    reloc = BFD_RELOC_VISIUM_REL16;
+		}
+	      else
+		{
+		  as_bad ("immediate value missing");
+		  return;
+		}
+	    }
+	  else
+	    {
+	      as_bad ("immediate value missing");
+	      return;
+	    }
+	}
+      else
+	{
+	  as_bad ("immediate value missing");
+	  return;
+	}
+
+      if (previous_mode == mode_cad || previous_mode == mode_ci)
+	as_bad ("branch instruction in delay slot");
+
+      condition_code = cc;
+      break;
+
+    case mode_fdab:
+      /* float := float * float
+         Example
+         fadd    f4,f3,f2  */
+      ans = parse_fp_reg (&str, &r1);
+      if (ans < 0)
+	{
+	  as_bad ("floating point destination register required");
+	  return;
+	}
+      str = skip_space (str);
+      if (*str == ',')
+	{
+	  str++;
+	  ans = parse_fp_reg (&str, &r2);
+	  if (ans < 0)
+	    {
+	      as_bad ("floating point SourceA register required");
+	      return;
+	    }
+	  str = skip_space (str);
+	  if (*str == ',')
+	    {
+	      str++;
+	      ans = parse_fp_reg (&str, &r3);
+	      if (ans < 0)
+		{
+		  as_bad ("floating point SourceB register required");
+		  return;
+		}
+
+	      /* Got 3 floating regs, assemble instruction.  */
+	      opcode |= (r1 << 10) | (r2 << 16) | (r3 << 4);
+	    }
+	  else
+	    {
+	      as_bad ("floating point SourceB register required");
+	      return;
+	    }
+	}
+      else
+	{
+	  as_bad ("floating point SourceA register required");
+	  return;
+	}
+      break;
+
+    case mode_ifdab:
+      /* 4-bit immediate * float * float * float
+         Example
+         fpinst   10,f1,f2,f3  */
+      str = parse_exp (str, &e1);
+      str = skip_space (str);
+      if (e1.X_op != O_absent && *str == ',')
+	{
+	  int finst = e1.X_add_number;
+
+	  str = skip_space (str + 1);
+	  ans = parse_fp_reg (&str, &r1);
+	  if (ans < 0)
+	    {
+	      as_bad ("floating point destination register required");
+	      return;
+	    }
+	  str = skip_space (str);
+	  if (*str == ',')
+	    {
+	      str++;
+	      ans = parse_fp_reg (&str, &r2);
+	      if (ans < 0)
+		{
+		  as_bad ("floating point SourceA register required");
+		  return;
+		}
+	      str = skip_space (str);
+	      if (*str == ',')
+		{
+		  str++;
+		  ans = parse_fp_reg (&str, &r3);
+		  if (ans < 0)
+		    {
+		      as_bad ("floating point SourceB register required");
+		      return;
+		    }
+
+		  /* Got immediate and 3 floating regs,
+		     assemble instruction.  */
+		  if (finst < 0 || finst > 15)
+		    as_bad ("finst out of range");
+
+		  opcode |=
+		    ((finst & 0xf) << 27) | (r1 << 10) | (r2 << 16) | (r3 <<
+								       4);
+		}
+	      else
+		{
+		  as_bad ("floating point SourceB register required");
+		  return;
+		}
+	    }
+	  else
+	    {
+	      as_bad ("floating point SourceA register required");
+	      return;
+	    }
+	}
+      else
+	{
+	  as_bad ("finst missing");
+	  return;
+	}
+      break;
+
+    case mode_idfab:
+      /* 4-bit immediate * register * float * float
+         Example
+         fpuread   4,r25,f2,f3  */
+      str = parse_exp (str, &e1);
+      str = skip_space (str);
+      if (e1.X_op != O_absent && *str == ',')
+	{
+	  int finst = e1.X_add_number;
+
+	  str = skip_space (str + 1);
+	  ans = parse_gen_reg (&str, &r1);
+	  if (ans < 0)
+	    {
+	      as_bad ("destination general register required");
+	      return;
+	    }
+	  str = skip_space (str);
+	  if (*str == ',')
+	    {
+	      str++;
+	      ans = parse_fp_reg (&str, &r2);
+	      if (ans < 0)
+		{
+		  as_bad ("floating point SourceA register required");
+		  return;
+		}
+	      str = skip_space (str);
+	      if (*str == ',')
+		{
+		  str++;
+		  ans = parse_fp_reg (&str, &r3);
+		  if (ans < 0)
+		    {
+		      as_bad ("floating point SourceB register required");
+		      return;
+		    }
+
+		  /* Got immediate and 3 floating regs,
+		     assemble instruction.  */
+		  if (finst < 0 || finst > 15)
+		    as_bad ("finst out of range");
+
+		  opcode |=
+		    ((finst & 0xf) << 27) | (r1 << 10) | (r2 << 16) | (r3 <<
+								       4);
+		}
+	      else
+		{
+		  as_bad ("floating point SourceB register required");
+		  return;
+		}
+	    }
+	  else
+	    {
+	      as_bad ("floating point SourceA register required");
+	      return;
+	    }
+	}
+      else
+	{
+	  as_bad ("finst missing");
+	  return;
+	}
+      break;
+
+    case mode_fda:
+      /* float := float
+         Example
+         fsqrt    f4,f3  */
+      ans = parse_fp_reg (&str, &r1);
+      if (ans < 0)
+	{
+	  as_bad ("floating point destination register required");
+	  return;
+	}
+      str = skip_space (str);
+      if (*str == ',')
+	{
+	  str++;
+	  ans = parse_fp_reg (&str, &r2);
+	  if (ans < 0)
+	    {
+	      as_bad ("floating point source register required");
+	      return;
+	    }
+
+	  /* Got 2 floating regs, assemble instruction.  */
+	  opcode |= (r1 << 10) | (r2 << 16);
+	}
+      else
+	{
+	  as_bad ("floating point source register required");
+	  return;
+	}
+      break;
+
+    case mode_fdra:
+      /* float := register
+         Example
+         fload   f15,r6  */
+      ans = parse_fp_reg (&str, &r1);
+      if (ans < 0)
+	{
+	  as_bad ("floating point destination register required");
+	  return;
+	}
+      str = skip_space (str);
+      if (*str == ',')
+	{
+	  str++;
+	  ans = parse_gen_reg (&str, &r2);
+	  if (ans < 0)
+	    {
+	      as_bad ("SourceA general register required");
+	      return;
+	    }
+
+	  /* Got 2 regs, assemble instruction.  */
+	  opcode |= (r1 << 10) | (r2 << 16);
+	}
+      else
+	{
+	  as_bad ("SourceA general register required");
+	  return;
+	}
+      break;
+
+    case mode_rdfab:
+      /* register := float * float
+         Example
+         fcmp    r0,f4,f8
+         For the GR6, register must be r0 and can be omitted.  */
+      ans = parse_gen_reg (&str, &r1);
+      if (ans < 0)
+	{
+	  if (visium_opcode_arch == VISIUM_OPCODE_ARCH_GR5)
+	    {
+	      as_bad ("Dest general register required");
+	      return;
+	    }
+	  r1 = 0;
+	}
+      else
+	{
+	  if (r1 != 0 && visium_opcode_arch != VISIUM_OPCODE_ARCH_GR5)
+	    {
+	      as_bad ("FCMP/FCMPE can only use r0 as Dest register");
+	      return;
+	     }
+
+	  str = skip_space (str);
+	  if (*str == ',')
+	    str++;
+	  else
+	    {
+	      as_bad ("floating point SourceA register required");
+	      return;
+	    }
+	}
+
+      ans = parse_fp_reg (&str, &r2);
+      if (ans < 0)
+	{
+	  as_bad ("floating point SourceA register required");
+	  return;
+	}
+      str = skip_space (str);
+      if (*str == ',')
+	{
+	  str++;
+	  ans = parse_fp_reg (&str, &r3);
+	  if (ans < 0)
+	    {
+	      as_bad ("floating point SourceB register required");
+	      return;
+	    }
+
+	  /* Got 3 regs, assemble instruction.  */
+	  opcode |= (r1 << 10) | (r2 << 16) | (r3 << 4);
+	}
+
+      this_dest = r1;
+      break;
+
+    case mode_rdfa:
+      /* register := float
+         Example
+         fstore r5,f12  */
+      ans = parse_gen_reg (&str, &r1);
+      if (ans < 0)
+	{
+	  as_bad ("Dest general register required");
+	  return;
+	}
+      str = skip_space (str);
+      if (*str == ',')
+	{
+	  str++;
+	  ans = parse_fp_reg (&str, &r2);
+	  if (ans < 0)
+	    {
+	      as_bad ("floating point source register required");
+	      return;
+	    }
+
+	  /* Got 2 regs, assemble instruction.  */
+	  opcode |= (r1 << 10) | (r2 << 16);
+	}
+      else
+	{
+	  as_bad ("floating point source register required");
+	  return;
+	}
+
+      this_dest = r1;
+      break;
+
+    case mode_rrr:
+      /* register register register, all sources and destinations 
+         Example:
+         bmd   r1,r2,r3  */
+
+      ans = parse_gen_reg (&str, &r1);
+      if (ans < 0)
+	{
+	  as_bad ("destination address register required");
+	  return;
+	}
+      str = skip_space (str);
+      if (*str == ',')
+	{
+	  str++;
+	  ans = parse_gen_reg (&str, &r2);
+	  if (ans < 0)
+	    {
+	      as_bad ("source address register required");
+	      return;
+	    }
+	  str = skip_space (str);
+	  if (*str == ',')
+	    {
+	      str++;
+	      ans = parse_gen_reg (&str, &r3);
+	      if (ans < 0)
+		{
+		  as_bad ("count register required");
+		  return;
+		}
+
+	      /* We insist on three registers but the opcode can only use
+		 r1,r2,r3.  */
+	      if (r1 != 1 || r2 != 2 || r3 != 3)
+		{
+		  as_bad ("BMI/BMD can only use format op r1,r2,r3"); 
+		  return;
+		}
+
+	      /* Opcode is unmodified by what comes out of the table.  */
+	    }
+	  else
+	    {
+	      as_bad ("register required");
+	      return;
+	    }
+	}
+      else
+	{
+	  as_bad ("register required");
+	  return;
+	}
+
+      this_dest = r1;
+      break;
+
+    default:
+      break;
+    }
+
+  if (relax)
+    output = frag_var (rs_machine_dependent, 8, 4, relax, e1.X_add_symbol,
+		       e1.X_add_number, NULL);
+  else
+    output = frag_more (4);
+
+  /* Build the 32-bit instruction in a host-endian-neutral fashion.  */
+  output[0] = (opcode >> 24) & 0xff;
+  output[1] = (opcode >> 16) & 0xff;
+  output[2] = (opcode >> 8) & 0xff;
+  output[3] = (opcode >> 0) & 0xff;
+
+  if (relax)
+    /* The size of the instruction is unknown, so tie the debug info to the
+       start of the instruction.  */
+    dwarf2_emit_insn (0);
+  else
+    {
+      if (reloc)
+	fix_new_exp (frag_now, output - frag_now->fr_literal, 4, &e1,
+		     reloc == BFD_RELOC_VISIUM_REL16, reloc);
+      else
+	visium_update_parity_bit (output);
+
+      dwarf2_emit_insn (4);
+    }
+
+  if (*str != '\0')
+    as_bad ("junk after instruction");
+}
+
+void
+visium_cfi_frame_initial_instructions (void)
+{
+  /* The CFA is in SP on function entry.  */
+  cfi_add_CFA_def_cfa (23, 0);
+}
+
+int
+visium_regname_to_dw2regnum (char *regname)
+{
+  if (!regname[0])
+    return -1;
+
+  if (regname[0] == 'f' && regname[1] == 'p' && !regname[2])
+    return 22;
+
+  if (regname[0] == 's' && regname[1] == 'p' && !regname[2])
+    return 23;
+
+  if (regname[0] == 'm' && regname[1] == 'd' && !regname[3])
+    switch (regname[2])
+      {
+      case 'b': return 32;
+      case 'a': return 33;
+      case 'c': return 34;
+      default : return -1;
+      }
+
+  if (regname[0] == 'f' || regname[0] == 'r')
+    {
+      char *p;
+      unsigned int regnum = strtoul (regname + 1, &p, 10);
+      if (*p)
+	return -1;
+      if (regnum >= (regname[0] == 'f' ? 16 : 32))
+	return -1;
+      if (regname[0] == 'f')
+	regnum += 35;
+      return regnum;
+    }
+
+  return -1;
+}
diff --git a/gas/config/tc-visium.h b/gas/config/tc-visium.h
new file mode 100644
index 0000000..6e1f791
--- /dev/null
+++ b/gas/config/tc-visium.h
@@ -0,0 +1,79 @@
+/* tc-visium.h -- Header file for tc-visium.c.
+
+   Copyright (C) 2005-2014 Free Software Foundation, 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 2, 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, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA. */
+
+#define TC_VISIUM
+
+#define LISTING_HEADER "VISIUM GAS "
+
+/* The target BFD architecture.  */
+#define TARGET_ARCH bfd_arch_visium
+
+#define TARGET_BYTES_BIG_ENDIAN 1
+
+#define TARGET_FORMAT "elf32-visium"
+
+/* Permit temporary numeric labels.  */
+#define LOCAL_LABELS_FB 1
+
+/* .-foo gets turned into PC relative relocs.  */
+#define DIFF_EXPR_OK
+
+/* We don't support external symbols overriding.  */
+#define EXTERN_FORCE_RELOC 0
+
+/* We don't need to handle .word strangely.  */
+#define WORKING_DOT_WORD
+
+#define tc_fix_adjustable(FIXP) visium_fix_adjustable (FIXP)
+extern bfd_boolean visium_fix_adjustable (struct fix *);
+
+#define HANDLE_ALIGN(FRAGP)		 \
+  if ((FRAGP)->fr_type == rs_align_code) \
+    visium_handle_align (FRAGP);
+extern void visium_handle_align (struct frag *);
+
+#define md_relax_frag(segment, fragp, stretch) \
+  visium_relax_frag (segment, fragp, stretch)
+extern int visium_relax_frag (asection *, struct frag *, long);
+
+/* Call md_pcrel_from_section, not md_pcrel_from.  */
+#define MD_PCREL_FROM_SECTION(FIXP, SEC) visium_pcrel_from_section (FIXP, SEC)
+extern long visium_pcrel_from_section (struct fix *, segT);
+
+/* Values passed to md_apply_fix3 don't include the symbol value.  */
+#define MD_APPLY_SYM_VALUE(FIX) 0
+
+#define md_operand(x)
+
+#define tc_comment_chars visium_comment_chars
+extern const char *visium_comment_chars;
+
+#define TARGET_USE_CFIPOP 1
+
+#define tc_cfi_frame_initial_instructions visium_cfi_frame_initial_instructions
+extern void visium_cfi_frame_initial_instructions (void);
+
+#define tc_regname_to_dw2regnum visium_regname_to_dw2regnum
+extern int visium_regname_to_dw2regnum (char *regname);
+
+#define DWARF2_LINE_MIN_INSN_LENGTH     4
+#define DWARF2_DEFAULT_RETURN_COLUMN    21
+#define DWARF2_CIE_DATA_ALIGNMENT       (-4)
diff --git a/gas/configure.tgt b/gas/configure.tgt
index d07d445..853988a 100644
--- a/gas/configure.tgt
+++ b/gas/configure.tgt
@@ -107,6 +107,7 @@ case ${cpu} in
   tilegx*be)		cpu_type=tilegx endian=big ;;
   tilegx*)		cpu_type=tilegx endian=little ;;
   v850*)		cpu_type=v850 ;;
+  visium)		cpu_type=visium endian=big ;;
   x86_64*)		cpu_type=i386 arch=x86_64;;
   xgate)		cpu_type=xgate ;;
   xtensa*)		cpu_type=xtensa arch=xtensa ;;
@@ -453,6 +454,8 @@ case ${generic_target} in
   vax-*-netbsdelf*)			fmt=elf em=nbsd ;;
   vax-*-linux-*)			fmt=elf em=linux ;;
 
+  visium-*-elf)				fmt=elf ;;
+
   xstormy16-*-*)			fmt=elf ;;
   
   xgate-*-*)    			fmt=elf ;;
diff --git a/gas/po/POTFILES.in b/gas/po/POTFILES.in
index d1fd07f..3514075 100644
--- a/gas/po/POTFILES.in
+++ b/gas/po/POTFILES.in
@@ -161,6 +161,8 @@ config/tc-v850.c
 config/tc-v850.h
 config/tc-vax.c
 config/tc-vax.h
+config/tc-visium.c
+config/tc-visium.h
 config/tc-xc16x.c
 config/tc-xc16x.h
 config/tc-xgate.c
diff --git a/gas/testsuite/gas/elf/elf.exp b/gas/testsuite/gas/elf/elf.exp
index af5dbb2..291c2a7 100644
--- a/gas/testsuite/gas/elf/elf.exp
+++ b/gas/testsuite/gas/elf/elf.exp
@@ -172,11 +172,12 @@ if { [is_elf_format] } then {
     run_dump_test "symver"
 
     # No indirect functions on non-GNU targets.
-    # The MSP port sets the ELF header's OSABI field to ELFOSABI_STANDALONE.
+    # The Visium and MSP set the ELF header's OSABI field to ELFOSABI_STANDALONE.
     # The non-eabi ARM ports sets it to ELFOSABI_ARM.
     # So for these targets we cannot include an IFUNC symbol type
     # in the symbol type test.
     if { [istarget "*-*-hpux*"]
+	 || [istarget "visium-*-*"]
 	 || [istarget "msp*-*-*"]
 	 || [istarget "arm*-*-*"]} then {
 	# hppa64 has a non-standard common directive

-- 
1.7.7


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