2002-06-18 Dave Brolley <brolley@redhat.com>
authorDave Brolley <brolley@redhat.com>
Tue, 18 Jun 2002 21:15:21 +0000 (21:15 +0000)
committerDave Brolley <brolley@redhat.com>
Tue, 18 Jun 2002 21:15:21 +0000 (21:15 +0000)
From Catherine Moore, Michael Meissner, Richard Sandiford, Dave Brolley:
* po/POTFILES.in: Add tc-frv.c, tc-frv.h.
* configure.in: Support frv-*-*.
* Makefile.am (CPU_TYPES): Add frv.
(TARGET_CPU_CFILES): Add tc-frv.c.
(TARGET_CPU_HFILES): Add tc-frv.h.
(DEPTC_frv_coff): New variable.
(DEPTC_frv_elf): New variable.
(DEPOBJ_frv_coff): New variable.
(DEPOBJ_frv_elf): New variable.
(DEP_frv_coff): New variable.
(DEP_frv_elf): New variable.
* tc-frv.c: New file.
* tc-frv.h: New file.

gas/ChangeLog
gas/Makefile.am
gas/Makefile.in
gas/NEWS
gas/config/tc-frv.c [new file with mode: 0644]
gas/config/tc-frv.h [new file with mode: 0644]
gas/configure
gas/configure.in
gas/po/POTFILES.in

index a62852e..81c4d96 100644 (file)
@@ -1,3 +1,20 @@
+2002-06-18  Dave Brolley  <brolley@redhat.com>
+
+       From Catherine Moore, Michael Meissner, Richard Sandiford, Dave Brolley:
+       * po/POTFILES.in: Add tc-frv.c, tc-frv.h.
+       * configure.in: Support frv-*-*.
+       * Makefile.am (CPU_TYPES): Add frv.
+       (TARGET_CPU_CFILES): Add tc-frv.c.
+       (TARGET_CPU_HFILES): Add tc-frv.h.
+       (DEPTC_frv_coff): New variable.
+       (DEPTC_frv_elf): New variable.
+       (DEPOBJ_frv_coff): New variable.
+       (DEPOBJ_frv_elf): New variable.
+       (DEP_frv_coff): New variable.
+       (DEP_frv_elf): New variable.
+       * tc-frv.c: New file.
+       * tc-frv.h: New file.
+
 2002-06-17  Catherine Moore <clm@redhat.com>
 
         * config/obj-elf.h (TARGET_SYMBOL_FIELDS): Conditionally define.
 2002-06-17  Catherine Moore <clm@redhat.com>
 
         * config/obj-elf.h (TARGET_SYMBOL_FIELDS): Conditionally define.
index 560b5ed..e458e2e 100644 (file)
@@ -47,6 +47,7 @@ CPU_TYPES = \
        d30v \
        dlx \
        fr30 \
        d30v \
        dlx \
        fr30 \
+       frv \
        h8300 \
        h8500 \
        hppa \
        h8300 \
        h8500 \
        hppa \
@@ -236,6 +237,7 @@ TARGET_CPU_CFILES = \
        config/tc-d30v.c \
        config/tc-dlx.c \
        config/tc-fr30.c \
        config/tc-d30v.c \
        config/tc-dlx.c \
        config/tc-fr30.c \
+       config/tc-frv.c \
        config/tc-h8300.c \
        config/tc-h8500.c \
        config/tc-hppa.c \
        config/tc-h8300.c \
        config/tc-h8500.c \
        config/tc-hppa.c \
@@ -284,6 +286,7 @@ TARGET_CPU_HFILES = \
        config/tc-d30v.h \
        config/tc-dlx.h \
        config/tc-fr30.h \
        config/tc-d30v.h \
        config/tc-dlx.h \
        config/tc-fr30.h \
+       config/tc-frv.h \
        config/tc-h8300.h \
        config/tc-h8500.h \
        config/tc-hppa.h \
        config/tc-h8300.h \
        config/tc-h8500.h \
        config/tc-hppa.h \
@@ -1067,6 +1070,18 @@ DEPTC_fr30_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \
   $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \
   $(srcdir)/../opcodes/fr30-desc.h $(INCDIR)/opcode/cgen.h \
   $(srcdir)/../opcodes/fr30-opc.h cgen.h
   $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \
   $(srcdir)/../opcodes/fr30-desc.h $(INCDIR)/opcode/cgen.h \
   $(srcdir)/../opcodes/fr30-opc.h cgen.h
+DEPTC_frv_coff = $(INCDIR)/symcat.h $(srcdir)/config/obj-coff.h \
+  $(srcdir)/config/tc-frv.h $(INCDIR)/coff/internal.h \
+  $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h $(INCDIR)/safe-ctype.h \
+  subsegs.h $(INCDIR)/obstack.h $(srcdir)/../opcodes/frv-desc.h \
+  $(INCDIR)/opcode/cgen.h $(srcdir)/../opcodes/frv-opc.h \
+  cgen.h
+DEPTC_frv_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \
+  $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \
+  $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-frv.h \
+  $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \
+  $(srcdir)/../opcodes/frv-desc.h $(INCDIR)/opcode/cgen.h \
+  $(srcdir)/../opcodes/frv-opc.h cgen.h
 DEPTC_h8300_coff = $(INCDIR)/symcat.h $(srcdir)/config/obj-coff.h \
   $(srcdir)/config/tc-h8300.h $(INCDIR)/coff/internal.h \
   $(INCDIR)/coff/h8300.h $(INCDIR)/coff/external.h $(BFDDIR)/libcoff.h \
 DEPTC_h8300_coff = $(INCDIR)/symcat.h $(srcdir)/config/obj-coff.h \
   $(srcdir)/config/tc-h8300.h $(INCDIR)/coff/internal.h \
   $(INCDIR)/coff/h8300.h $(INCDIR)/coff/external.h $(BFDDIR)/libcoff.h \
@@ -1577,6 +1592,15 @@ DEPOBJ_fr30_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \
   $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-fr30.h \
   $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \
   struc-symbol.h $(INCDIR)/aout/aout64.h
   $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-fr30.h \
   $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \
   struc-symbol.h $(INCDIR)/aout/aout64.h
+DEPOBJ_frv_coff = $(INCDIR)/symcat.h $(srcdir)/config/obj-coff.h \
+  $(srcdir)/config/tc-frv.h $(INCDIR)/coff/internal.h \
+  $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h \
+  subsegs.h
+DEPOBJ_frv_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \
+  $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \
+  $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-frv.h \
+  $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \
+  struc-symbol.h $(INCDIR)/aout/aout64.h
 DEPOBJ_h8300_coff = $(INCDIR)/symcat.h $(srcdir)/config/obj-coff.h \
   $(srcdir)/config/tc-h8300.h $(INCDIR)/coff/internal.h \
   $(INCDIR)/coff/h8300.h $(INCDIR)/coff/external.h $(BFDDIR)/libcoff.h \
 DEPOBJ_h8300_coff = $(INCDIR)/symcat.h $(srcdir)/config/obj-coff.h \
   $(srcdir)/config/tc-h8300.h $(INCDIR)/coff/internal.h \
   $(INCDIR)/coff/h8300.h $(INCDIR)/coff/external.h $(BFDDIR)/libcoff.h \
@@ -2015,6 +2039,12 @@ DEP_fr30_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-fr30.h \
 DEP_fr30_elf = $(srcdir)/config/obj-elf.h $(INCDIR)/symcat.h \
   $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \
   $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-fr30.h
 DEP_fr30_elf = $(srcdir)/config/obj-elf.h $(INCDIR)/symcat.h \
   $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \
   $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-fr30.h
+DEP_frv_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-frv.h \
+  $(INCDIR)/symcat.h $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h \
+  $(INCDIR)/bfdlink.h
+DEP_frv_elf = $(srcdir)/config/obj-elf.h $(INCDIR)/symcat.h \
+  $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \
+  $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-frv.h
 DEP_h8300_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-h8300.h \
   $(INCDIR)/symcat.h $(INCDIR)/coff/internal.h $(INCDIR)/coff/h8300.h \
   $(INCDIR)/coff/external.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h
 DEP_h8300_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-h8300.h \
   $(INCDIR)/symcat.h $(INCDIR)/coff/internal.h $(INCDIR)/coff/h8300.h \
   $(INCDIR)/coff/external.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h
index 66b5634..fd808ae 100644 (file)
@@ -158,6 +158,7 @@ CPU_TYPES = \
        d30v \
        dlx \
        fr30 \
        d30v \
        dlx \
        fr30 \
+       frv \
        h8300 \
        h8500 \
        hppa \
        h8300 \
        h8500 \
        hppa \
@@ -353,6 +354,7 @@ TARGET_CPU_CFILES = \
        config/tc-d30v.c \
        config/tc-dlx.c \
        config/tc-fr30.c \
        config/tc-d30v.c \
        config/tc-dlx.c \
        config/tc-fr30.c \
+       config/tc-frv.c \
        config/tc-h8300.c \
        config/tc-h8500.c \
        config/tc-hppa.c \
        config/tc-h8300.c \
        config/tc-h8500.c \
        config/tc-hppa.c \
@@ -402,6 +404,7 @@ TARGET_CPU_HFILES = \
        config/tc-d30v.h \
        config/tc-dlx.h \
        config/tc-fr30.h \
        config/tc-d30v.h \
        config/tc-dlx.h \
        config/tc-fr30.h \
+       config/tc-frv.h \
        config/tc-h8300.h \
        config/tc-h8500.h \
        config/tc-hppa.h \
        config/tc-h8300.h \
        config/tc-h8500.h \
        config/tc-hppa.h \
@@ -795,6 +798,20 @@ DEPTC_fr30_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \
   $(srcdir)/../opcodes/fr30-desc.h $(INCDIR)/opcode/cgen.h \
   $(srcdir)/../opcodes/fr30-opc.h cgen.h
 
   $(srcdir)/../opcodes/fr30-desc.h $(INCDIR)/opcode/cgen.h \
   $(srcdir)/../opcodes/fr30-opc.h cgen.h
 
+DEPTC_frv_coff = $(INCDIR)/symcat.h $(srcdir)/config/obj-coff.h \
+  $(srcdir)/config/tc-frv.h $(INCDIR)/coff/internal.h \
+  $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h $(INCDIR)/safe-ctype.h \
+  subsegs.h $(INCDIR)/obstack.h $(srcdir)/../opcodes/frv-desc.h \
+  $(INCDIR)/opcode/cgen.h $(srcdir)/../opcodes/frv-opc.h \
+  cgen.h
+
+DEPTC_frv_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \
+  $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \
+  $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-frv.h \
+  $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \
+  $(srcdir)/../opcodes/frv-desc.h $(INCDIR)/opcode/cgen.h \
+  $(srcdir)/../opcodes/frv-opc.h cgen.h
+
 DEPTC_h8300_coff = $(INCDIR)/symcat.h $(srcdir)/config/obj-coff.h \
   $(srcdir)/config/tc-h8300.h $(INCDIR)/coff/internal.h \
   $(INCDIR)/coff/h8300.h $(INCDIR)/coff/external.h $(BFDDIR)/libcoff.h \
 DEPTC_h8300_coff = $(INCDIR)/symcat.h $(srcdir)/config/obj-coff.h \
   $(srcdir)/config/tc-h8300.h $(INCDIR)/coff/internal.h \
   $(INCDIR)/coff/h8300.h $(INCDIR)/coff/external.h $(BFDDIR)/libcoff.h \
@@ -1414,6 +1431,17 @@ DEPOBJ_fr30_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \
   $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \
   struc-symbol.h $(INCDIR)/aout/aout64.h
 
   $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \
   struc-symbol.h $(INCDIR)/aout/aout64.h
 
+DEPOBJ_frv_coff = $(INCDIR)/symcat.h $(srcdir)/config/obj-coff.h \
+  $(srcdir)/config/tc-frv.h $(INCDIR)/coff/internal.h \
+  $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h $(INCDIR)/obstack.h \
+  subsegs.h
+
+DEPOBJ_frv_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \
+  $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \
+  $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-frv.h \
+  $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \
+  struc-symbol.h $(INCDIR)/aout/aout64.h
+
 DEPOBJ_h8300_coff = $(INCDIR)/symcat.h $(srcdir)/config/obj-coff.h \
   $(srcdir)/config/tc-h8300.h $(INCDIR)/coff/internal.h \
   $(INCDIR)/coff/h8300.h $(INCDIR)/coff/external.h $(BFDDIR)/libcoff.h \
 DEPOBJ_h8300_coff = $(INCDIR)/symcat.h $(srcdir)/config/obj-coff.h \
   $(srcdir)/config/tc-h8300.h $(INCDIR)/coff/internal.h \
   $(INCDIR)/coff/h8300.h $(INCDIR)/coff/external.h $(BFDDIR)/libcoff.h \
@@ -1961,6 +1989,14 @@ DEP_fr30_elf = $(srcdir)/config/obj-elf.h $(INCDIR)/symcat.h \
   $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \
   $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-fr30.h
 
   $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \
   $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-fr30.h
 
+DEP_frv_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-frv.h \
+  $(INCDIR)/symcat.h $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h \
+  $(INCDIR)/bfdlink.h
+
+DEP_frv_elf = $(srcdir)/config/obj-elf.h $(INCDIR)/symcat.h \
+  $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \
+  $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-frv.h
+
 DEP_h8300_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-h8300.h \
   $(INCDIR)/symcat.h $(INCDIR)/coff/internal.h $(INCDIR)/coff/h8300.h \
   $(INCDIR)/coff/external.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h
 DEP_h8300_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-h8300.h \
   $(INCDIR)/symcat.h $(INCDIR)/coff/internal.h $(INCDIR)/coff/h8300.h \
   $(INCDIR)/coff/external.h $(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h
index 087815b..55b7c58 100644 (file)
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -1,4 +1,7 @@
 -*- text -*-
 -*- text -*-
+Support for the Fujitsu FRV architecture added by Red Hat. Models for FR400 and
+FR500 included.
+
 Support for DLX processor added.
 
 GASP has now been deprecated and will be removed in a future release.  Use the
 Support for DLX processor added.
 
 GASP has now been deprecated and will be removed in a future release.  Use the
diff --git a/gas/config/tc-frv.c b/gas/config/tc-frv.c
new file mode 100644 (file)
index 0000000..8b4683f
--- /dev/null
@@ -0,0 +1,1606 @@
+/* tc-frv.c -- Assembler for the Fujitsu FRV.
+   Copyright (C) 2002 Free Software Foundation.
+
+   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 <stdio.h>
+#include "as.h"
+#include "dwarf2dbg.h"
+#include "subsegs.h"     
+#include "symcat.h"
+#include "opcodes/frv-desc.h"
+#include "opcodes/frv-opc.h"
+#include "cgen.h"
+#include "libbfd.h"
+#include "elf/common.h"
+#include "elf/frv.h"
+
+/* Structure to hold all of the different components describing
+   an individual instruction.  */
+typedef struct
+{
+  const CGEN_INSN *    insn;
+  const CGEN_INSN *    orig_insn;
+  CGEN_FIELDS          fields;
+#if CGEN_INT_INSN_P
+  CGEN_INSN_INT         buffer [1];
+#define INSN_VALUE(buf) (*(buf))
+#else
+  unsigned char         buffer [CGEN_MAX_INSN_SIZE];
+#define INSN_VALUE(buf) (buf)
+#endif
+  char *               addr;
+  fragS *              frag;
+  int                   num_fixups;
+  fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
+  int                   indices [MAX_OPERAND_INSTANCES];
+}
+frv_insn;
+
+enum vliw_insn_type
+{
+  VLIW_GENERIC_TYPE,           /* Don't care about this insn.  */
+  VLIW_BRANCH_TYPE,            /* A Branch.  */
+  VLIW_LABEL_TYPE,             /* A Label.  */
+  VLIW_NOP_TYPE,               /* A NOP.  */
+  VLIW_BRANCH_HAS_NOPS         /* A Branch that requires NOPS.  */
+};
+
+/* We're going to use these in the fr_subtype field to mark 
+   whether to keep inserted nops.  */
+
+#define NOP_KEEP 1             /* Keep these NOPS.  */
+#define NOP_DELETE 2           /* Delete these NOPS.  */
+
+#define DO_COUNT    true
+#define DONT_COUNT  false
+
+/* A list of insns within a VLIW insn.  */
+struct vliw_insn_list
+{
+  /*  The type of this insn.  */
+  enum vliw_insn_type  type;
+
+  /*  The corresponding gas insn information.  */
+  const CGEN_INSN      *insn;
+
+  /*  For branches and labels, the symbol that is referenced.  */
+  symbolS              *sym;
+
+  /*  For branches, the frag containing the single nop that was generated.  */
+  fragS                        *snop_frag;
+
+  /*  For branches, the frag containing the double nop that was generated.  */
+  fragS                        *dnop_frag;
+
+  /*  Pointer to raw data for this insn.  */
+  char                 *address;
+
+  /* Next insn in list.  */
+  struct vliw_insn_list *next;
+};
+
+static struct vliw_insn_list single_nop_insn = {
+   VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
+
+static struct vliw_insn_list double_nop_insn = {
+   VLIW_NOP_TYPE, NULL, NULL, NULL, NULL, NULL, NULL };
+
+struct vliw_chain
+{
+  int                  num;
+  int                  insn_count;
+  struct vliw_insn_list *insn_list;
+  struct vliw_chain     *next;
+};
+
+static struct vliw_chain       *vliw_chain_top;
+static struct vliw_chain       *current_vliw_chain;
+static struct vliw_chain       *previous_vliw_chain;
+static struct vliw_insn_list   *current_vliw_insn;
+
+const char comment_chars[]        = ";";
+const char line_comment_chars[]   = "#";
+const char line_separator_chars[] = ""; 
+const char EXP_CHARS[]            = "eE";
+const char FLT_CHARS[]            = "dD";
+
+static FRV_VLIW vliw;
+
+/* Default machine */
+
+#ifdef  DEFAULT_CPU_FRV
+#define DEFAULT_MACHINE bfd_mach_frv
+#define DEFAULT_FLAGS  EF_FRV_CPU_GENERIC
+
+#else
+#ifdef  DEFAULT_CPU_FR300
+#define DEFAULT_MACHINE        bfd_mach_fr300
+#define DEFAULT_FLAGS  EF_FRV_CPU_FR300
+
+#else
+#ifdef DEFAULT_CPU_SIMPLE
+#define        DEFAULT_MACHINE bfd_mach_frvsimple
+#define DEFAULT_FLAGS  EF_FRV_CPU_SIMPLE
+
+#else
+#ifdef DEFAULT_CPU_TOMCAT
+#define        DEFAULT_MACHINE bfd_mach_frvtomcat
+#define DEFAULT_FLAGS  EF_FRV_CPU_TOMCAT
+
+#else
+#ifdef  DEFAULT_CPU_FR400
+#define DEFAULT_MACHINE        bfd_mach_fr400
+#define DEFAULT_FLAGS  EF_FRV_CPU_FR400
+
+#else
+#define DEFAULT_MACHINE        bfd_mach_fr500
+#define DEFAULT_FLAGS  EF_FRV_CPU_FR500
+#endif
+#endif
+#endif
+#endif
+#endif
+
+static unsigned long frv_mach = bfd_mach_frv;
+
+/* Flags to set in the elf header */
+static flagword frv_flags = DEFAULT_FLAGS;
+
+static int frv_user_set_flags_p = 0;
+static int frv_pic_p = 0;
+static const char *frv_pic_flag = (const char *)0;
+
+/* Print tomcat-specific debugging info.  */
+static int tomcat_debug = 0;
+
+/* Tomcat-specific NOP statistics.  */
+static int tomcat_stats = 0;
+static int tomcat_doubles = 0;
+static int tomcat_singles = 0;
+
+/* Forward reference to static functions */
+static void frv_set_flags              PARAMS ((int));
+static void frv_pic_ptr                        PARAMS ((int));
+static void frv_frob_file_section      PARAMS ((bfd *, asection *, PTR));
+
+/* The target specific pseudo-ops which we support.  */
+const pseudo_typeS md_pseudo_table[] =
+{
+  { "eflags",  frv_set_flags,          0 },
+  { "word",    cons,                   4 },
+  { "picptr",  frv_pic_ptr,            4 },
+  { "file",    dwarf2_directive_file,  0 },
+  { "loc",     dwarf2_directive_loc,   0 },
+  { NULL,      NULL,                   0 }
+};
+
+\f
+#define FRV_SHORTOPTS "G:"
+const char * md_shortopts = FRV_SHORTOPTS;
+
+#define OPTION_GPR_32          (OPTION_MD_BASE)
+#define OPTION_GPR_64          (OPTION_MD_BASE + 1)
+#define OPTION_FPR_32          (OPTION_MD_BASE + 2)
+#define OPTION_FPR_64          (OPTION_MD_BASE + 3)
+#define OPTION_SOFT_FLOAT      (OPTION_MD_BASE + 4)
+#define OPTION_DWORD_YES       (OPTION_MD_BASE + 5)
+#define OPTION_DWORD_NO                (OPTION_MD_BASE + 6)
+#define OPTION_DOUBLE          (OPTION_MD_BASE + 7)
+#define OPTION_NO_DOUBLE       (OPTION_MD_BASE + 8)
+#define OPTION_MEDIA           (OPTION_MD_BASE + 9)
+#define OPTION_NO_MEDIA                (OPTION_MD_BASE + 10)
+#define OPTION_CPU             (OPTION_MD_BASE + 11)
+#define OPTION_PIC             (OPTION_MD_BASE + 12)
+#define OPTION_BIGPIC          (OPTION_MD_BASE + 13)
+#define OPTION_LIBPIC          (OPTION_MD_BASE + 14)
+#define OPTION_MULADD          (OPTION_MD_BASE + 15)
+#define OPTION_NO_MULADD       (OPTION_MD_BASE + 16)
+#define OPTION_TOMCAT_DEBUG    (OPTION_MD_BASE + 17)
+#define OPTION_TOMCAT_STATS    (OPTION_MD_BASE + 18)
+#define OPTION_PACK            (OPTION_MD_BASE + 19)
+#define OPTION_NO_PACK         (OPTION_MD_BASE + 20)
+
+struct option md_longopts[] =
+{
+  { "mgpr-32",         no_argument,            NULL, OPTION_GPR_32        },
+  { "mgpr-64",         no_argument,            NULL, OPTION_GPR_64        },
+  { "mfpr-32",         no_argument,            NULL, OPTION_FPR_32        },
+  { "mfpr-64",         no_argument,            NULL, OPTION_FPR_64        },
+  { "mhard-float",     no_argument,            NULL, OPTION_FPR_64        },
+  { "msoft-float",     no_argument,            NULL, OPTION_SOFT_FLOAT    },
+  { "mdword",          no_argument,            NULL, OPTION_DWORD_YES     },
+  { "mno-dword",       no_argument,            NULL, OPTION_DWORD_NO      },
+  { "mdouble",         no_argument,            NULL, OPTION_DOUBLE        },
+  { "mno-double",      no_argument,            NULL, OPTION_NO_DOUBLE     },
+  { "mmedia",          no_argument,            NULL, OPTION_MEDIA         },
+  { "mno-media",       no_argument,            NULL, OPTION_NO_MEDIA      },
+  { "mcpu",            required_argument,      NULL, OPTION_CPU           },
+  { "mpic",            no_argument,            NULL, OPTION_PIC           },
+  { "mPIC",            no_argument,            NULL, OPTION_BIGPIC        },
+  { "mlibrary-pic",    no_argument,            NULL, OPTION_LIBPIC        },
+  { "mmuladd",         no_argument,            NULL, OPTION_MULADD        },
+  { "mno-muladd",      no_argument,            NULL, OPTION_NO_MULADD     },
+  { "mtomcat-debug",    no_argument,            NULL, OPTION_TOMCAT_DEBUG  },
+  { "mtomcat-stats",   no_argument,            NULL, OPTION_TOMCAT_STATS  },
+  { "mpack",           no_argument,            NULL, OPTION_PACK          },
+  { "mno-pack",                no_argument,            NULL, OPTION_NO_PACK       },
+  { NULL,              no_argument,            NULL, 0                 },
+};
+
+size_t md_longopts_size = sizeof (md_longopts);
+
+/* What value to give to bfd_set_gp_size.  */
+static int g_switch_value = 8;
+
+int
+md_parse_option (c, arg)
+     int    c;
+     char * arg;
+{
+  switch (c)
+    {
+    default:
+      return 0;
+
+    case 'G':
+      g_switch_value = atoi (arg);
+      if (! g_switch_value)
+       frv_flags |= EF_FRV_G0;
+      break;
+
+    case OPTION_GPR_32:
+      frv_flags = (frv_flags & ~EF_FRV_GPR_MASK) | EF_FRV_GPR_32;
+      break;
+
+    case OPTION_GPR_64:
+      frv_flags = (frv_flags & ~EF_FRV_GPR_MASK) | EF_FRV_GPR_64;
+      break;
+
+    case OPTION_FPR_32:
+      frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_32;
+      break;
+
+    case OPTION_FPR_64:
+      frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_64;
+      break;
+
+    case OPTION_SOFT_FLOAT:
+      frv_flags = (frv_flags & ~EF_FRV_FPR_MASK) | EF_FRV_FPR_NONE;
+      break;
+
+    case OPTION_DWORD_YES:
+      frv_flags = (frv_flags & ~EF_FRV_DWORD_MASK) | EF_FRV_DWORD_YES;
+      break;
+
+    case OPTION_DWORD_NO:
+      frv_flags = (frv_flags & ~EF_FRV_DWORD_MASK) | EF_FRV_DWORD_NO;
+      break;
+
+    case OPTION_DOUBLE:
+      frv_flags |= EF_FRV_DOUBLE;
+      break;
+
+    case OPTION_NO_DOUBLE:
+      frv_flags &= ~EF_FRV_DOUBLE;
+      break;
+
+    case OPTION_MEDIA:
+      frv_flags |= EF_FRV_MEDIA;
+      break;
+
+    case OPTION_NO_MEDIA:
+      frv_flags &= ~EF_FRV_MEDIA;
+      break;
+
+    case OPTION_MULADD:
+      frv_flags |= EF_FRV_MULADD;
+      break;
+
+    case OPTION_NO_MULADD:
+      frv_flags &= ~EF_FRV_MULADD;
+      break;
+
+    case OPTION_PACK:
+      frv_flags &= ~EF_FRV_NOPACK;
+      break;
+
+    case OPTION_NO_PACK:
+      frv_flags |= EF_FRV_NOPACK;
+      break;
+
+    case OPTION_CPU:
+      {
+       char *p;
+       int cpu_flags = EF_FRV_CPU_GENERIC;
+
+       /* Identify the processor type */
+       p = arg;
+       if (strcmp (p, "frv") == 0)
+         {
+           cpu_flags = EF_FRV_CPU_GENERIC;
+           frv_mach = bfd_mach_frv;
+         }
+
+       else if (strcmp (p, "fr500") == 0)
+         {
+           cpu_flags = EF_FRV_CPU_FR500;
+           frv_mach = bfd_mach_fr500;
+         }
+
+       else if (strcmp (p, "fr400") == 0)
+         {
+           cpu_flags = EF_FRV_CPU_FR400;
+           frv_mach = bfd_mach_fr400;
+         }
+
+       else if (strcmp (p, "fr300") == 0)
+         {
+           cpu_flags = EF_FRV_CPU_FR300;
+           frv_mach = bfd_mach_fr300;
+         }
+
+       else if (strcmp (p, "simple") == 0)
+         {
+           cpu_flags = EF_FRV_CPU_SIMPLE;
+           frv_mach = bfd_mach_frvsimple;
+           frv_flags |= EF_FRV_NOPACK;
+         }
+
+        else if (strcmp (p, "tomcat") == 0)
+          {
+            cpu_flags = EF_FRV_CPU_TOMCAT;
+            frv_mach = bfd_mach_frvtomcat;
+          }
+
+       else
+         {
+           as_fatal ("Unknown cpu -mcpu=%s", arg);
+           return 0;
+         }
+
+       frv_flags = (frv_flags & ~EF_FRV_CPU_MASK) | cpu_flags;
+      }
+      break;
+
+    case OPTION_PIC:
+      frv_flags |= EF_FRV_PIC;
+      frv_pic_p = 1;
+      frv_pic_flag = "-fpic";
+      break;
+
+    case OPTION_BIGPIC:
+      frv_flags |= EF_FRV_BIGPIC;
+      frv_pic_p = 1;
+      frv_pic_flag = "-fPIC";
+      break;
+
+    case OPTION_LIBPIC:
+      frv_flags |= (EF_FRV_LIBPIC | EF_FRV_G0);
+      frv_pic_p = 1;
+      frv_pic_flag = "-mlibrary-pic";
+      g_switch_value = 0;
+      break;
+
+    case OPTION_TOMCAT_DEBUG:
+      tomcat_debug = 1;
+      break;
+
+    case OPTION_TOMCAT_STATS:
+      tomcat_stats = 1;
+      break;
+    }
+
+  return 1;
+}
+
+void
+md_show_usage (stream)
+  FILE * stream;
+{
+  fprintf (stream, _("FRV specific command line options:\n"));
+  fprintf (stream, _("-G n         Data >= n bytes is in small data area\n"));
+  fprintf (stream, _("-mgpr-32     Note 32 gprs are used\n"));
+  fprintf (stream, _("-mgpr-64     Note 64 gprs are used\n"));
+  fprintf (stream, _("-mfpr-32     Note 32 fprs are used\n"));
+  fprintf (stream, _("-mfpr-64     Note 64 fprs are used\n"));
+  fprintf (stream, _("-msoft-float Note software fp is used\n"));
+  fprintf (stream, _("-mdword      Note stack is aligned to a 8 byte boundary\n"));
+  fprintf (stream, _("-mno-dword   Note stack is aligned to a 4 byte boundary\n"));
+  fprintf (stream, _("-mdouble     Note fp double insns are used\n"));
+  fprintf (stream, _("-mmedia      Note media insns are used\n"));
+  fprintf (stream, _("-mmuladd     Note multiply add/subtract insns are used\n"));
+  fprintf (stream, _("-mpack       Note instructions are packed\n"));
+  fprintf (stream, _("-mno-pack    Do not allow instructions to be packed\n"));
+  fprintf (stream, _("-mpic        Note small position independent code\n"));
+  fprintf (stream, _("-mPIC        Note large position independent code\n"));
+  fprintf (stream, _("-mlibrary-pic Compile library for large position indepedent code\n"));
+  fprintf (stream, _("-mcpu={fr500|fr400|fr300|frv|simple|tomcat}\n"));
+  fprintf (stream, _("             Record the cpu type\n"));
+  fprintf (stream, _("-mtomcat-stats Print out stats for tomcat workarounds\n"));
+  fprintf (stream, _("-mtomcat-debug Debug tomcat workarounds\n"));
+} 
+
+\f
+void
+md_begin ()
+{
+  /* Initialize the `cgen' interface.  */
+  
+  /* Set the machine number and endian.  */
+  gas_cgen_cpu_desc = frv_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
+                                        CGEN_CPU_OPEN_ENDIAN,
+                                        CGEN_ENDIAN_BIG,
+                                        CGEN_CPU_OPEN_END);
+  frv_cgen_init_asm (gas_cgen_cpu_desc);
+
+  /* This is a callback from cgen to gas to parse operands.  */
+  cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
+
+  /* Set the ELF flags if desired. */
+  if (frv_flags)
+    bfd_set_private_flags (stdoutput, frv_flags);
+
+  /* Set the machine type */
+  bfd_default_set_arch_mach (stdoutput, bfd_arch_frv, frv_mach);
+
+  /* Set up gp size so we can put local common items in .sbss */
+  bfd_set_gp_size (stdoutput, g_switch_value);
+
+  frv_vliw_reset (& vliw, frv_mach, frv_flags);
+}
+
+int chain_num = 0;
+
+struct vliw_insn_list *
+frv_insert_vliw_insn (count)
+      boolean count;
+{
+  struct vliw_insn_list *vliw_insn_list_entry;
+  struct vliw_chain     *vliw_chain_entry;
+
+  if (current_vliw_chain == NULL)
+    {
+      vliw_chain_entry = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
+      vliw_chain_entry->insn_count = 0;
+      vliw_chain_entry->insn_list  = NULL;
+      vliw_chain_entry->next       = NULL;
+      vliw_chain_entry->num        = chain_num++;
+
+      if (!vliw_chain_top)
+       vliw_chain_top = vliw_chain_entry;
+      current_vliw_chain = vliw_chain_entry;
+      if (previous_vliw_chain)
+       previous_vliw_chain->next = vliw_chain_entry;
+    }
+
+  vliw_insn_list_entry = (struct vliw_insn_list *) xmalloc (sizeof (struct vliw_insn_list));
+  vliw_insn_list_entry->type      = VLIW_GENERIC_TYPE;
+  vliw_insn_list_entry->insn      = NULL;
+  vliw_insn_list_entry->sym       = NULL;
+  vliw_insn_list_entry->snop_frag = NULL;
+  vliw_insn_list_entry->dnop_frag = NULL;
+  vliw_insn_list_entry->next      = NULL;
+
+  if (count)
+    current_vliw_chain->insn_count++;
+
+  if (current_vliw_insn)
+    current_vliw_insn->next = vliw_insn_list_entry;
+  current_vliw_insn = vliw_insn_list_entry;
+
+  if (!current_vliw_chain->insn_list)
+    current_vliw_chain->insn_list = current_vliw_insn;
+
+  return vliw_insn_list_entry;
+}
+
+  /* Identify the following cases:
+     1) A VLIW insn that contains both a branch and the branch destination.
+        This requires the insertion of two vliw instructions before the
+        branch.  The first consists of two nops.  The second consists of
+        a single nop.
+     2) A single instruction VLIW insn which is the destination of a branch
+        that is in the next VLIW insn.  This requires the insertion of a vliw
+        insn containing two nops before the branch.
+     3) A double instruction VLIW insn which contains the destination of a
+        branch that is in the next VLIW insn.  This requires the insertion of
+        a VLIW insn containing a single nop before the branch.
+     4) A single instruction VLIW insn which contains branch destination (x),
+        followed by a single instruction VLIW insn which does not contain
+        the branch to (x), followed by a VLIW insn which does contain the branch
+        to (x).  This requires the insertion of a VLIW insn containing a single
+        nop before the VLIW instruction containing the branch.
+  */
+#define FRV_IS_NOP(insn) (insn.buffer[0] == FRV_NOP_PACK || insn.buffer[0] == FRV_NOP_NOPACK)
+#define FRV_NOP_PACK   0x00880000  /* ori.p  gr0,0,gr0 */
+#define FRV_NOP_NOPACK 0x80880000  /* ori    gr0,0,gr0 */
+
+/* Check a vliw insn for an insn of type containing the sym passed in label_sym.  */
+
+static struct vliw_insn_list *
+frv_find_in_vliw (vliw_insn_type, this_chain, label_sym)
+    enum vliw_insn_type vliw_insn_type;
+    struct vliw_chain *this_chain;
+    symbolS *label_sym;
+{
+
+  struct vliw_insn_list *the_insn;
+
+  if (!this_chain)
+    return NULL;
+
+  for (the_insn = this_chain->insn_list; the_insn; the_insn = the_insn->next)
+    {
+      if (the_insn->type == vliw_insn_type
+         && the_insn->sym == label_sym)
+       return the_insn;
+    }
+
+  return NULL;
+}
+
+enum vliw_nop_type
+{
+  /* A Vliw insn containing a single nop insn.  */
+  VLIW_SINGLE_NOP,
+  
+  /* A Vliw insn containing two nop insns.  */
+  VLIW_DOUBLE_NOP,
+
+  /* Two vliw insns.  The first containing two nop insns.  
+     The second contain a single nop insn.  */
+  VLIW_DOUBLE_THEN_SINGLE_NOP
+};
+
+static void
+frv_debug_tomcat (start_chain)
+   struct vliw_chain *start_chain;
+{
+   struct vliw_chain *this_chain;
+   struct vliw_insn_list *this_insn;
+   int i = 1;
+
+  for (this_chain = start_chain; this_chain; this_chain = this_chain->next, i++)
+    {
+      fprintf (stderr, "\nVliw Insn #%d, #insns: %d\n", i, this_chain->insn_count);
+
+      for (this_insn = this_chain->insn_list; this_insn; this_insn = this_insn->next)
+       {
+         if (this_insn->type == VLIW_LABEL_TYPE)
+           fprintf (stderr, "Label Value: %d\n", (int) this_insn->sym);
+         else if (this_insn->type == VLIW_BRANCH_TYPE)
+           fprintf (stderr, "%s to %d\n", this_insn->insn->base->name, (int) this_insn->sym);
+         else if (this_insn->type == VLIW_BRANCH_HAS_NOPS)
+           fprintf (stderr, "nop'd %s to %d\n", this_insn->insn->base->name, (int) this_insn->sym);
+         else if (this_insn->type == VLIW_NOP_TYPE)
+           fprintf (stderr, "Nop\n");
+         else
+           fprintf (stderr, "  %s\n", this_insn->insn->base->name);
+       }
+   }
+}
+
+
+static void
+frv_adjust_vliw_count (this_chain)
+    struct vliw_chain *this_chain;
+{
+  struct vliw_insn_list *this_insn;
+
+  this_chain->insn_count = 0;
+
+  for (this_insn = this_chain->insn_list;
+       this_insn;
+       this_insn = this_insn->next)
+    {
+      if (this_insn->type != VLIW_LABEL_TYPE)
+       this_chain->insn_count++;
+    }
+
+}
+
+/* Insert the desired nop combination in the vliw chain before insert_before_insn.
+   Rechain the vliw insn.  */
+
+
+static struct vliw_chain *
+frv_tomcat_shuffle (this_nop_type, vliw_to_split, insert_before_insn)
+   enum vliw_nop_type    this_nop_type;
+   struct vliw_chain     *vliw_to_split;
+   struct vliw_insn_list *insert_before_insn;
+{
+
+  boolean pack_prev = false;
+  struct vliw_chain *return_me = NULL;
+  struct vliw_insn_list *prev_insn = NULL;
+  struct vliw_insn_list *curr_insn = vliw_to_split->insn_list;
+
+  struct vliw_chain *double_nop = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
+  struct vliw_chain *single_nop = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
+  struct vliw_chain *second_part = (struct vliw_chain *) xmalloc (sizeof (struct vliw_chain));
+  struct vliw_chain *curr_vliw = vliw_chain_top;
+  struct vliw_chain *prev_vliw = NULL;
+
+  while (curr_insn && curr_insn != insert_before_insn)
+    {
+      /* We can't set the packing bit on a label.  If we have the case
+        label 1:
+        label 2:
+        label 3:
+          branch that needs nops
+       Then don't set pack bit later.  */
+
+      if (curr_insn->type != VLIW_LABEL_TYPE)
+       pack_prev = true;
+      prev_insn = curr_insn;
+      curr_insn = curr_insn->next;
+    } 
+
+  while (curr_vliw && curr_vliw != vliw_to_split)
+    {
+      prev_vliw = curr_vliw;
+      curr_vliw = curr_vliw->next;
+    }
+
+  switch (this_nop_type)
+    {
+    case VLIW_SINGLE_NOP:
+      if (!prev_insn)
+       {
+       /* Branch is first,  Insert the NOP prior to this vliw insn.  */
+       if (prev_vliw)
+         prev_vliw->next = single_nop;
+       else
+         vliw_chain_top = single_nop;
+       single_nop->next = vliw_to_split;
+       vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
+       return_me = vliw_to_split;
+       }
+      else
+       {
+         /* Set the packing bit on the previous insn.  */
+         if (pack_prev)
+           {
+             unsigned char *buffer = prev_insn->address;
+             buffer[0] |= 0x80;
+           }
+         /* The branch is in the middle.  Split this vliw insn into first
+            and second parts.  Insert the NOP inbetween.  */
+
+          second_part->insn_list = insert_before_insn;
+         second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
+          second_part->next      = vliw_to_split->next;
+         frv_adjust_vliw_count (second_part);
+
+          single_nop->next       = second_part;
+          vliw_to_split->next    = single_nop;
+          prev_insn->next        = NULL;
+          return_me = second_part;
+         frv_adjust_vliw_count (vliw_to_split);
+       }
+      break;
+
+    case VLIW_DOUBLE_NOP:
+      if (!prev_insn)
+       {
+       /* Branch is first,  Insert the NOP prior to this vliw insn.  */
+        if (prev_vliw)
+          prev_vliw->next = double_nop;
+        else
+          vliw_chain_top = double_nop;
+
+       double_nop->next = vliw_to_split;
+       return_me = vliw_to_split;
+       vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
+       }
+      else
+       {
+         /* Set the packing bit on the previous insn.  */
+         if (pack_prev)
+           {
+             unsigned char *buffer = prev_insn->address;
+             buffer[0] |= 0x80;
+           }
+
+       /* The branch is in the middle.  Split this vliw insn into first
+          and second parts.  Insert the NOP inbetween.  */
+          second_part->insn_list = insert_before_insn;
+         second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
+          second_part->next      = vliw_to_split->next;
+         frv_adjust_vliw_count (second_part);
+          double_nop->next       = second_part;
+          vliw_to_split->next    = single_nop;
+          prev_insn->next        = NULL;
+         frv_adjust_vliw_count (vliw_to_split);
+          return_me = second_part;
+       }
+      break;
+
+    case VLIW_DOUBLE_THEN_SINGLE_NOP:
+      double_nop->next = single_nop;
+      double_nop->insn_count = 2;
+      double_nop->insn_list = &double_nop_insn;
+      single_nop->insn_count = 1;
+      single_nop->insn_list = &single_nop_insn;
+
+      if (!prev_insn)
+       {
+         /* The branch is the first insn in this vliw.  Don't split the vliw.  Insert
+            the nops prior to this vliw.  */
+          if (prev_vliw)
+            prev_vliw->next = double_nop;
+          else
+            vliw_chain_top = double_nop;
+         single_nop->next = vliw_to_split;
+         return_me = vliw_to_split;
+         vliw_to_split->insn_list->type = VLIW_BRANCH_HAS_NOPS;
+       }
+      else
+       {
+         /* Set the packing bit on the previous insn.  */
+         if (pack_prev)
+           {
+             unsigned char *buffer = prev_insn->address;
+             buffer[0] |= 0x80;
+           }
+
+         /* The branch is in the middle of this vliw insn.  Split into first and
+            second parts.  Insert the nop vliws in between.  */  
+         second_part->insn_list = insert_before_insn;
+         second_part->insn_list->type = VLIW_BRANCH_HAS_NOPS;
+         second_part->next      = vliw_to_split->next;
+         frv_adjust_vliw_count (second_part);
+
+         single_nop->next       = second_part;
+
+         vliw_to_split->next    = double_nop;
+         prev_insn->next        = NULL;
+         frv_adjust_vliw_count (vliw_to_split);
+
+         return_me = second_part;
+       }
+      break;
+    }
+
+  return return_me;
+}
+
+static void
+frv_tomcat_analyze_vliw_chains ()
+{
+  struct vliw_chain *vliw1 = NULL;
+  struct vliw_chain *vliw2 = NULL;
+  struct vliw_chain *vliw3 = NULL;
+
+  struct vliw_insn_list *this_insn = NULL;
+  struct vliw_insn_list *temp_insn = NULL;
+
+  /* We potentially need to look at three VLIW insns to determine if the
+     workaround is required.  Set them up.  Ignore existing nops during analysis. */
+
+#define FRV_SET_VLIW_WINDOW(VLIW1, VLIW2, VLIW3) \
+  if (VLIW1 && VLIW1->next)                     \
+    VLIW2 = VLIW1->next;                        \
+  else                                          \
+    VLIW2 = NULL;                               \
+  if (VLIW2 && VLIW2->next)                     \
+    VLIW3 = VLIW2->next;                        \
+  else                                          \
+    VLIW3 = NULL
+
+  vliw1 = vliw_chain_top;
+
+workaround_top:
+
+  FRV_SET_VLIW_WINDOW (vliw1, vliw2, vliw3);
+
+  if (!vliw1)
+    return;
+
+  if (vliw1->insn_count == 1)
+    {
+      /* check vliw1 for a label. */
+      if (vliw1->insn_list->type == VLIW_LABEL_TYPE)
+       {
+         temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, vliw1->insn_list->sym);
+         if (temp_insn)
+           {
+             vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_NOP, vliw2, vliw1->insn_list);
+             temp_insn->dnop_frag->fr_subtype = NOP_KEEP;
+             vliw1 = vliw1->next;
+             if (tomcat_stats)
+               tomcat_doubles++;
+             goto workaround_top;
+           }
+         else if (vliw2 
+                  && vliw2->insn_count == 1
+                  && (temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw3, vliw1->insn_list->sym)) != NULL)
+           {
+             temp_insn->snop_frag->fr_subtype = NOP_KEEP;
+             vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw3, vliw3->insn_list);
+             if (tomcat_stats)
+               tomcat_singles++;
+             goto workaround_top;
+           }
+       }
+    }
+
+  if (vliw1->insn_count == 2)
+    {
+      struct vliw_insn_list *this_insn;
+      /* check vliw1 for a label. */
+      for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
+       {
+         if (this_insn->type == VLIW_LABEL_TYPE)
+           {
+             if ((temp_insn = frv_find_in_vliw (VLIW_BRANCH_TYPE, vliw2, this_insn->sym, temp_insn)) != NULL)
+               {
+                 temp_insn->snop_frag->fr_subtype = NOP_KEEP;
+                 vliw1 = frv_tomcat_shuffle (VLIW_SINGLE_NOP, vliw2, this_insn);
+                 if (tomcat_stats)
+                   tomcat_singles++;
+               }
+             else
+               vliw1 = vliw1->next;
+              goto workaround_top;
+            }
+       }
+    }
+  /* Examine each insn in this VLIW.  Look for the workaround criteria.  */
+  for (this_insn = vliw1->insn_list; this_insn; this_insn = this_insn->next)
+    {
+      /* Don't look at labels or nops.  */
+      while (this_insn
+            && (this_insn->type == VLIW_LABEL_TYPE
+                 || this_insn->type == VLIW_NOP_TYPE
+                || this_insn->type == VLIW_BRANCH_HAS_NOPS))
+       this_insn = this_insn->next;
+
+      if (!this_insn)
+        {
+         vliw1 = vliw2;
+         goto workaround_top;
+       }
+
+      if (frv_is_branch_insn (this_insn->insn))
+       {
+         if ((temp_insn = frv_find_in_vliw (VLIW_LABEL_TYPE, vliw1, this_insn->sym, temp_insn)) != NULL)
+           {
+             /* Insert [nop/nop] [nop] before branch.  */
+             this_insn->snop_frag->fr_subtype = NOP_KEEP;
+             this_insn->dnop_frag->fr_subtype = NOP_KEEP;
+             vliw1 = frv_tomcat_shuffle (VLIW_DOUBLE_THEN_SINGLE_NOP, vliw1, this_insn);
+             goto workaround_top;
+           }
+       }
+
+
+    }
+  /* This vliw insn checks out okay.  Take a look at the next one.  */
+  vliw1 = vliw1->next;
+  goto workaround_top;
+}
+
+void
+frv_tomcat_workaround ()
+{
+  if (frv_mach != bfd_mach_frvtomcat)
+    return;
+
+  if (tomcat_debug)
+    frv_debug_tomcat (vliw_chain_top);
+
+  frv_tomcat_analyze_vliw_chains ();
+
+  if (tomcat_stats)
+    {
+      fprintf (stderr, "Inserted %d Single Nops\n", tomcat_singles);
+      fprintf (stderr, "Inserted %d Double Nops\n", tomcat_doubles);
+    }
+}
+
+void
+md_assemble (str)
+     char * str;
+{
+  frv_insn insn;
+  char *errmsg;
+  int packing_constraint;
+  finished_insnS  finished_insn;
+  fragS *double_nop_frag = NULL;
+  fragS *single_nop_frag = NULL;
+  struct vliw_insn_list *vliw_insn_list_entry = NULL;
+
+  /* Initialize GAS's cgen interface for a new instruction.  */
+  gas_cgen_init_parse ();
+
+  insn.insn = frv_cgen_assemble_insn
+    (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, &errmsg);
+  
+  if (!insn.insn)
+    {
+      as_bad (errmsg);
+      return;
+    }
+  
+  /* If the cpu is tomcat, then we need to insert nops to workaround
+     hardware limitations.  We need to keep track of each vliw unit
+     and examine the length of the unit and the individual insns
+     within the unit to determine the number and location of the
+     required nops.  */
+  if (frv_mach == bfd_mach_frvtomcat)
+    {
+      /* If we've just finished a VLIW insn OR this is a branch,
+        then start up a new frag.  Fill it with nops.  We will get rid
+        of those that are not required after we've seen all of the 
+        instructions but before we start resolving fixups.  */
+      if ( !FRV_IS_NOP (insn)
+         && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
+       {
+         char *buffer;
+
+         frag_wane (frag_now);
+         frag_new (0);
+         double_nop_frag = frag_now;
+         buffer = frag_var (rs_machine_dependent, 8, 8, NOP_DELETE, NULL, 0, 0);
+         md_number_to_chars (buffer, FRV_NOP_PACK, 4);
+         md_number_to_chars (buffer+4, FRV_NOP_NOPACK, 4);
+
+         frag_wane (frag_now);
+         frag_new (0);
+         single_nop_frag = frag_now;
+         buffer = frag_var (rs_machine_dependent, 4, 4, NOP_DELETE, NULL, 0, 0);
+         md_number_to_chars (buffer, FRV_NOP_NOPACK, 4);
+       }
+
+      vliw_insn_list_entry = frv_insert_vliw_insn (DO_COUNT);
+      vliw_insn_list_entry->insn   = insn.insn;
+      if (frv_is_branch_insn (insn.insn))
+       vliw_insn_list_entry->type = VLIW_BRANCH_TYPE;
+
+      if ( !FRV_IS_NOP (insn)
+         && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
+       {
+         vliw_insn_list_entry->snop_frag = single_nop_frag;
+         vliw_insn_list_entry->dnop_frag = double_nop_frag;
+       }
+    }
+
+  /* Make sure that this insn does not violate the VLIW packing constraints.  */
+  /* -mno-pack disallows any packing whatsoever.  */
+  if (frv_flags & EF_FRV_NOPACK)
+    {
+      if (! insn.fields.f_pack)
+       {
+         as_bad (_("VLIW packing used for -mno-pack"));
+         return;
+       }
+    }
+  /* -mcpu=FRV is an idealized FR-V implementation that supports all of the
+     instructions, don't do vliw checking.  */
+  else if (frv_mach != bfd_mach_frv)
+    {
+      packing_constraint = frv_vliw_add_insn (& vliw, insn.insn);
+      if (insn.fields.f_pack)
+       frv_vliw_reset (& vliw, frv_mach, frv_flags);
+      if (packing_constraint)
+       {
+         as_bad (_("VLIW packing constraint violation"));
+         return;
+       }
+    }
+
+  /* Doesn't really matter what we pass for RELAX_P here.  */
+  gas_cgen_finish_insn (insn.insn, insn.buffer,
+                       CGEN_FIELDS_BITSIZE (& insn.fields), 1, &finished_insn);
+
+
+  /* If the cpu is tomcat, then we need to insert nops to workaround
+     hardware limitations.  We need to keep track of each vliw unit
+     and examine the length of the unit and the individual insns
+     within the unit to determine the number and location of the
+     required nops.  */
+  if (frv_mach == bfd_mach_frvtomcat)
+    {
+      if (vliw_insn_list_entry)
+        vliw_insn_list_entry->address = finished_insn.addr;
+      else
+       abort();
+
+      if (insn.fields.f_pack)
+       {
+         /* We've completed a VLIW insn.  */
+         previous_vliw_chain = current_vliw_chain;
+         current_vliw_chain = NULL;
+         current_vliw_insn  = NULL;
+        } 
+    }
+}
+
+/* The syntax in the manual says constants begin with '#'.
+   We just ignore it.  */
+
+void 
+md_operand (expressionP)
+     expressionS * expressionP;
+{
+  if (* input_line_pointer == '#')
+    {
+      input_line_pointer ++;
+      expression (expressionP);
+    }
+}
+
+valueT
+md_section_align (segment, size)
+     segT   segment;
+     valueT size;
+{
+  int align = bfd_get_section_alignment (stdoutput, segment);
+  return ((size + (1 << align) - 1) & (-1 << align));
+}
+
+symbolS *
+md_undefined_symbol (name)
+  char * name ATTRIBUTE_UNUSED;
+{
+  return 0;
+}
+\f
+/* Interface to relax_segment.  */
+
+/* FIXME: Build table by hand, get it working, then machine generate.  */
+const relax_typeS md_relax_table[] =
+{
+  {1, 1, 0, 0},
+  {511 - 2 - 2, -512 - 2 + 2, 0, 2 },
+  {0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 },
+  {0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }
+};
+
+long
+frv_relax_frag (fragP, stretch)
+     fragS   *fragP ATTRIBUTE_UNUSED;
+     long    stretch ATTRIBUTE_UNUSED;
+{
+  return 0;
+}
+
+/* Return an initial guess of the length by which a fragment must grow to
+   hold a branch to reach its destination.
+   Also updates fr_type/fr_subtype as necessary.
+
+   Called just before doing relaxation.
+   Any symbol that is now undefined will not become defined.
+   The guess for fr_var is ACTUALLY the growth beyond fr_fix.
+   Whatever we do to grow fr_fix or fr_var contributes to our returned value.
+   Although it may not be explicit in the frag, pretend fr_var starts with a
+   0 value.  */
+
+int
+md_estimate_size_before_relax (fragP, segment)
+     fragS * fragP;
+     segT    segment ATTRIBUTE_UNUSED;
+{
+  switch (fragP->fr_subtype)
+    {
+    case NOP_KEEP:
+      return fragP->fr_var;
+
+    default:
+    case NOP_DELETE:
+      return 0;
+    }     
+} 
+
+/* *fragP has been relaxed to its final size, and now needs to have
+   the bytes inside it modified to conform to the new size.
+
+   Called after relaxation is finished.
+   fragP->fr_type == rs_machine_dependent.
+   fragP->fr_subtype is the subtype of what the address relaxed to.  */
+
+void
+md_convert_frag (abfd, sec, fragP)
+  bfd *   abfd ATTRIBUTE_UNUSED;
+  segT    sec ATTRIBUTE_UNUSED;
+  fragS * fragP;
+{
+  switch (fragP->fr_subtype)
+    {
+    default:
+    case NOP_DELETE:
+      return;
+
+    case NOP_KEEP:
+      fragP->fr_fix = fragP->fr_var;
+      fragP->fr_var = 0;
+      return;   
+    }
+}
+\f
+/* Functions concerning relocs.  */
+
+/* The location from which a PC relative jump should be calculated,
+   given a PC relative reloc.  */
+
+long
+md_pcrel_from_section (fixP, sec)
+     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 (fixP->fx_frag->fr_address + fixP->fx_where) & ~1;
+}
+
+/* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
+   Returns BFD_RELOC_NONE if no reloc type can be found.
+   *FIXP may be modified if desired.  */
+
+bfd_reloc_code_real_type
+md_cgen_lookup_reloc (insn, operand, fixP)
+     const CGEN_INSN *    insn ATTRIBUTE_UNUSED;
+     const CGEN_OPERAND * operand;
+     fixS *               fixP;
+{
+  switch (operand->type)
+    {
+    case FRV_OPERAND_LABEL16:
+      fixP->fx_pcrel = true;
+      return BFD_RELOC_FRV_LABEL16;
+
+    case FRV_OPERAND_LABEL24:
+      fixP->fx_pcrel = true;
+      return BFD_RELOC_FRV_LABEL24;
+
+    case FRV_OPERAND_UHI16:
+    case FRV_OPERAND_ULO16:
+    case FRV_OPERAND_SLO16:
+
+      /* The relocation type should be recorded in opinfo */
+      if (fixP->fx_cgen.opinfo != 0)
+        return fixP->fx_cgen.opinfo;
+      break;
+
+    case FRV_OPERAND_D12:
+    case FRV_OPERAND_S12:
+      return BFD_RELOC_FRV_GPREL12;
+
+    case FRV_OPERAND_U12:
+      return BFD_RELOC_FRV_GPRELU12;
+
+    default: 
+      break;
+    }
+  return BFD_RELOC_NONE;
+}
+
+
+/* See whether we need to force a relocation into the output file.
+   This is used to force out switch and PC relative relocations when
+   relaxing.  */
+
+int
+frv_force_relocation (fix)
+     fixS * fix;
+{
+  if (fix->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+      || fix->fx_r_type == BFD_RELOC_VTABLE_ENTRY
+      || fix->fx_r_type == BFD_RELOC_FRV_GPREL12
+      || fix->fx_r_type == BFD_RELOC_FRV_GPRELU12)
+    return 1;
+
+  return 0;
+}
+\f
+/* Write a value out to the object file, using the appropriate endianness.  */
+
+void
+frv_md_number_to_chars (buf, val, n)
+     char * buf;
+     valueT val;
+     int    n;
+{
+  number_to_chars_bigendian (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.
+*/
+
+/* Equal to MAX_PRECISION in atof-ieee.c */
+#define MAX_LITTLENUMS 6
+
+char *
+md_atof (type, litP, sizeP)
+     char   type;
+     char * litP;
+     int *  sizeP;
+{
+  int              i;
+  int              prec;
+  LITTLENUM_TYPE   words [MAX_LITTLENUMS];
+  char *           t;
+  char *           atof_ieee ();
+
+  switch (type)
+    {
+    case 'f':
+    case 'F':
+    case 's':
+    case 'S':
+      prec = 2;
+      break;
+
+    case 'd':
+    case 'D':
+    case 'r':
+    case 'R':
+      prec = 4;
+      break;
+
+   /* FIXME: Some targets allow other format chars for bigger sizes here.  */
+
+    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);
+
+  for (i = 0; i < prec; i++)
+    {
+      md_number_to_chars (litP, (valueT) words[i],
+                         sizeof (LITTLENUM_TYPE));
+      litP += sizeof (LITTLENUM_TYPE);
+    }
+     
+  return 0;
+}
+
+boolean
+frv_fix_adjustable (fixP)
+   fixS * fixP;
+{
+  bfd_reloc_code_real_type reloc_type;
+
+  if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
+    {
+      const CGEN_INSN *insn = NULL;
+      int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
+      const CGEN_OPERAND *operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
+      reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
+    }
+  else
+    reloc_type = fixP->fx_r_type;
+
+  if (fixP->fx_addsy == NULL)
+    return 1;
+  
+  /* Prevent all adjustments to global symbols. */
+  if (S_IS_EXTERN (fixP->fx_addsy))
+    return 0;
+  
+  if (S_IS_WEAK (fixP->fx_addsy))
+    return 0;
+  
+  /* We need the symbol name for the VTABLE entries */
+  if (   reloc_type == BFD_RELOC_VTABLE_INHERIT
+      || reloc_type == BFD_RELOC_VTABLE_ENTRY
+      || reloc_type == BFD_RELOC_FRV_GPREL12
+      || reloc_type == BFD_RELOC_FRV_GPRELU12)
+    return 0;
+
+  return 1;
+}
+
+/* Allow user to set flags bits.  */
+void
+frv_set_flags (arg)
+     int arg ATTRIBUTE_UNUSED;
+{
+  flagword new_flags = get_absolute_expression ();
+  flagword new_mask = ~ (flagword)0;
+
+  frv_user_set_flags_p = 1;
+  if (*input_line_pointer == ',')
+    {
+      ++input_line_pointer;
+      new_mask = get_absolute_expression ();
+    }
+
+  frv_flags = (frv_flags & ~new_mask) | (new_flags & new_mask);
+  bfd_set_private_flags (stdoutput, frv_flags);
+}
+
+/* Frv specific function to handle 4 byte initializations for pointers that are
+   considered 'safe' for use with pic support.  Until frv_frob_file{,_section}
+   is run, we encode it a BFD_RELOC_CTOR, and it is turned back into a normal
+   BFD_RELOC_32 at that time.  */
+
+void
+frv_pic_ptr (nbytes)
+     int nbytes;
+{
+  expressionS exp;
+  char *p;
+
+  if (nbytes != 4)
+    abort ();
+
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
+  if (is_it_end_of_statement ())
+    {
+      demand_empty_rest_of_line ();
+      return;
+    }
+
+#ifdef md_cons_align
+  md_cons_align (nbytes);
+#endif
+
+  do
+    {
+      expression (&exp);
+
+      p = frag_more (4);
+      memset (p, 0, 4);
+      fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &exp, 0,
+                  BFD_RELOC_CTOR);
+    }
+  while (*input_line_pointer++ == ',');
+
+  input_line_pointer--;                        /* Put terminator back into stream. */
+  demand_empty_rest_of_line ();
+}
+
+\f
+
+#ifdef DEBUG
+#define DPRINTF1(A)    fprintf (stderr, A)
+#define DPRINTF2(A,B)  fprintf (stderr, A, B)
+#define DPRINTF3(A,B,C)        fprintf (stderr, A, B, C)
+
+#else
+#define DPRINTF1(A)
+#define DPRINTF2(A,B)
+#define DPRINTF3(A,B,C)
+#endif
+
+/* Go through a the sections looking for relocations that are problematical for
+   pic.  If not pic, just note that this object can't be linked with pic.  If
+   it is pic, see if it needs to be marked so that it will be fixed up, or if
+   not possible, issue an error.  */
+
+static void
+frv_frob_file_section (abfd, sec, ptr)
+     bfd *abfd;
+     asection *sec;
+     PTR ptr ATTRIBUTE_UNUSED;
+{
+  segment_info_type *seginfo = seg_info (sec);
+  fixS *fixp;
+  CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
+  flagword flags = bfd_get_section_flags (abfd, sec);
+
+  /* Skip relocations in known sections (.ctors, .dtors, and .gcc_except_table)
+     since we can fix those up by hand.  */
+  int known_section_p = (sec->name
+                        && sec->name[0] == '.'
+                        && ((sec->name[1] == 'c'
+                             && strcmp (sec->name, ".ctor") == 0)
+                            || (sec->name[1] == 'd'
+                                && strcmp (sec->name, ".dtor") == 0)
+                            || (sec->name[1] == 'g'
+                                && strcmp (sec->name, ".gcc_except_table") == 0)));
+
+  DPRINTF3 ("\nFrv section %s%s\n", sec->name, (known_section_p) ? ", known section" : "");
+  if ((flags & SEC_ALLOC) == 0)
+    {
+      DPRINTF1 ("\tSkipping non-loaded section\n");
+      return;
+    }
+
+  for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
+    {
+      symbolS *s = fixp->fx_addsy;
+      bfd_reloc_code_real_type reloc;
+      int non_pic_p;
+      int opindex;
+      const CGEN_OPERAND *operand;
+      const CGEN_INSN *insn = fixp->fx_cgen.insn;
+
+      if (fixp->fx_done)
+       {
+         DPRINTF1 ("\tSkipping reloc that has already been done\n");
+         continue;
+       }
+
+      if (fixp->fx_pcrel)
+       {
+         DPRINTF1 ("\tSkipping reloc that is PC relative\n");
+         continue;
+       }
+
+      if (! s)
+       {
+         DPRINTF1 ("\tSkipping reloc without symbol\n");
+         continue;
+       }
+
+      if (fixp->fx_r_type < BFD_RELOC_UNUSED)
+       {
+         opindex = -1;
+         reloc = fixp->fx_r_type;
+       }
+      else
+       {
+         opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED;
+         operand = cgen_operand_lookup_by_num (cd, opindex);
+         reloc = md_cgen_lookup_reloc (insn, operand, fixp);
+       }
+
+      DPRINTF3 ("\treloc %s\t%s", bfd_get_reloc_code_name (reloc), S_GET_NAME (s));
+
+      non_pic_p = 0;
+      switch (reloc)
+       {
+       default:
+         break;
+
+       case BFD_RELOC_32:
+         /* Skip relocations in known sections (.ctors, .dtors, and
+            .gcc_except_table) since we can fix those up by hand.  Also
+            skip forward references to constants.  Also skip a difference
+            of two symbols, which still uses the BFD_RELOC_32 at this
+            point.  */
+         if (! known_section_p
+             && S_GET_SEGMENT (s) != absolute_section
+             && !fixp->fx_subsy
+             && (flags & (SEC_READONLY | SEC_CODE)) == 0)
+           {
+             non_pic_p = 1;
+           }
+         break;
+
+         /* FIXME -- should determine if any of the GP relocation really uses
+            gr16 (which is not pic safe) or not.  Right now, assume if we
+            aren't being compiled with -mpic, the usage is non pic safe, but
+            is safe with -mpic.  */
+       case BFD_RELOC_FRV_GPREL12:
+       case BFD_RELOC_FRV_GPRELU12:
+       case BFD_RELOC_FRV_GPREL32:
+       case BFD_RELOC_FRV_GPRELHI:
+       case BFD_RELOC_FRV_GPRELLO:
+         non_pic_p = ! frv_pic_p;
+         break;
+
+       case BFD_RELOC_FRV_LO16:
+       case BFD_RELOC_FRV_HI16:
+         if (S_GET_SEGMENT (s) != absolute_section)
+           non_pic_p = 1;
+         break;
+
+       case BFD_RELOC_VTABLE_INHERIT:
+       case BFD_RELOC_VTABLE_ENTRY:
+         non_pic_p = 1;
+         break;
+
+         /* If this is a blessed BFD_RELOC_32, convert it back to the normal
+             relocation.  */
+       case BFD_RELOC_CTOR:
+         fixp->fx_r_type = BFD_RELOC_32;
+         break;
+       }
+
+      if (non_pic_p)
+       {
+         DPRINTF1 (" (Non-pic relocation)\n");
+         if (frv_pic_p)
+           as_warn_where (fixp->fx_file, fixp->fx_line,
+                          _("Relocation %s is not safe for %s"),
+                          bfd_get_reloc_code_name (reloc), frv_pic_flag);
+
+         else if ((frv_flags & EF_FRV_NON_PIC_RELOCS) == 0)
+           {
+             frv_flags |= EF_FRV_NON_PIC_RELOCS;
+             bfd_set_private_flags (abfd, frv_flags);
+           }
+       }
+#ifdef DEBUG
+      else
+       DPRINTF1 ("\n");
+#endif
+    }
+}
+
+/* After all of the symbols have been adjusted, go over the file looking
+   for any relocations that pic won't support.  */
+
+void
+frv_frob_file ()
+{
+  bfd_map_over_sections (stdoutput, frv_frob_file_section, (PTR)0);
+}
+
+void
+frv_frob_label (this_label)
+    symbolS *this_label;
+{
+  struct vliw_insn_list *vliw_insn_list_entry;
+
+  if (frv_mach != bfd_mach_frvtomcat)
+    return;
+
+  if (now_seg != text_section)
+    return;
+
+  vliw_insn_list_entry = frv_insert_vliw_insn(DONT_COUNT);
+  vliw_insn_list_entry->type = VLIW_LABEL_TYPE;
+  vliw_insn_list_entry->sym  = this_label; 
+}
+
+fixS *
+frv_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
+     fragS *              frag;
+     int                  where;
+     const CGEN_INSN *    insn;
+     int                  length;
+     const CGEN_OPERAND * operand;
+     int                  opinfo;
+     expressionS *        exp;
+{
+  fixS * fixP = gas_cgen_record_fixup_exp (frag, where, insn, length,
+                                           operand, opinfo, exp);
+
+  if (frv_mach == bfd_mach_frvtomcat
+      && current_vliw_insn
+      && current_vliw_insn->type == VLIW_BRANCH_TYPE
+      && exp != NULL)
+    current_vliw_insn->sym = exp->X_add_symbol;
+    
+  return fixP;
+}
diff --git a/gas/config/tc-frv.h b/gas/config/tc-frv.h
new file mode 100644 (file)
index 0000000..b399cd9
--- /dev/null
@@ -0,0 +1,89 @@
+/* tc-frv.h -- Header file for tc-frv.c.
+   Copyright (C) 2002 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_FRV
+
+#ifndef BFD_ASSEMBLER
+/* leading space so will compile with cc */
+ #error FRV support requires BFD_ASSEMBLER
+#endif
+
+#define LISTING_HEADER "FRV GAS "
+
+/* The target BFD architecture.  */
+#define TARGET_ARCH bfd_arch_frv
+
+#define TARGET_FORMAT "elf32-frv"
+
+#define TARGET_BYTES_BIG_ENDIAN 1
+
+/* call md_pcrel_from_section, not md_pcrel_from */
+long md_pcrel_from_section PARAMS ((struct fix *, segT));
+#define MD_PCREL_FROM_SECTION(FIXP, SEC) md_pcrel_from_section (FIXP, SEC)
+
+/* Permit temporary numeric labels.  */
+#define LOCAL_LABELS_FB 1
+
+#define DIFF_EXPR_OK           /* .-foo gets turned into PC relative relocs */
+
+/* We don't need to handle .word strangely.  */
+#define WORKING_DOT_WORD
+
+#define md_apply_fix3 gas_cgen_md_apply_fix3
+
+extern void frv_tomcat_workaround PARAMS ((void));
+#define md_cleanup frv_tomcat_workaround
+
+#define md_number_to_chars frv_md_number_to_chars
+
+extern long frv_relax_frag PARAMS ((fragS *, long));
+#define md_relax_frag(segment, fragP, stretch) frv_relax_frag(fragP, stretch)
+
+#define obj_fix_adjustable(fixP) frv_fix_adjustable (fixP)
+extern boolean frv_fix_adjustable PARAMS ((struct fix *));
+
+#ifdef OBJ_ELF
+/* This arranges for gas/write.c to not apply a relocation if
+   obj_fix_adjustable() says it is not adjustable.  */
+#define TC_FIX_ADJUSTABLE(fixP) obj_fix_adjustable (fixP)
+#endif
+
+/* When relaxing, we need to emit various relocs we otherwise wouldn't.  */
+#define TC_FORCE_RELOCATION(fix) frv_force_relocation (fix)
+extern int frv_force_relocation PARAMS ((struct fix *));
+
+#undef GAS_CGEN_MAX_FIXUPS
+#define GAS_CGEN_MAX_FIXUPS 1
+
+void frv_frob_label PARAMS ((symbolS *));
+#define tc_frob_label(sym) frv_frob_label(sym)
+
+#define tc_gen_reloc gas_cgen_tc_gen_reloc
+
+#define md_cgen_record_fixup_exp frv_cgen_record_fixup_exp
+
+/* Call md_pcrel_from_section(), not md_pcrel_from().  */
+#define MD_PCREL_FROM_SECTION(FIXP, SEC) md_pcrel_from_section (FIXP, SEC)
+extern long md_pcrel_from_section PARAMS ((struct fix *, segT));
+
+/* After all of the symbols have been adjusted, go over the file looking
+   for any relocations that pic won't support.  */
+#define tc_frob_file() frv_frob_file ()
+extern void frv_frob_file      PARAMS ((void));
index ea8f754..619fbfc 100755 (executable)
@@ -2378,6 +2378,7 @@ for this_target in $target $canon_targets ; do
 
 
       fr30-*-*)                    fmt=elf bfd_gas=yes ;;
 
 
       fr30-*-*)                    fmt=elf bfd_gas=yes ;;
+      frv-*-*)             fmt=elf bfd_gas=yes ;;
 
       hppa-*-linux-gnu*)    case ${cpu} in
                                hppa*64*)
 
       hppa-*-linux-gnu*)    case ${cpu} in
                                hppa*64*)
@@ -2742,6 +2743,9 @@ EOF
        using_cgen=yes
        ;;
 
        using_cgen=yes
        ;;
 
+      frv)
+       using_cgen=yes
+       ;;
       m68k)
        case ${extra_objects} in
        *m68k-parse.o*) ;;
       m68k)
        case ${extra_objects} in
        *m68k-parse.o*) ;;
index 53a1dce..09422cd 100644 (file)
@@ -217,6 +217,7 @@ changequote([,])dnl
 
 
       fr30-*-*)                    fmt=elf bfd_gas=yes ;;
 
 
       fr30-*-*)                    fmt=elf bfd_gas=yes ;;
+      frv-*-*)             fmt=elf bfd_gas=yes ;;
 
       hppa-*-linux-gnu*)    case ${cpu} in
                                hppa*64*)
 
       hppa-*-linux-gnu*)    case ${cpu} in
                                hppa*64*)
@@ -574,6 +575,9 @@ changequote([,])dnl
        using_cgen=yes
        ;;
 
        using_cgen=yes
        ;;
 
+      frv)
+       using_cgen=yes
+       ;;
       m68k)
        case ${extra_objects} in
        *m68k-parse.o*) ;;
       m68k)
        case ${extra_objects} in
        *m68k-parse.o*) ;;
index c170361..6f67bf4 100644 (file)
@@ -60,6 +60,8 @@ config/tc-dlx.c
 config/tc-dlx.h
 config/tc-fr30.c
 config/tc-fr30.h
 config/tc-dlx.h
 config/tc-fr30.c
 config/tc-fr30.h
+config/tc-frv.c
+config/tc-frv.h
 config/tc-h8300.c
 config/tc-h8300.h
 config/tc-h8500.c
 config/tc-h8300.c
 config/tc-h8300.h
 config/tc-h8500.c