<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">diff -burN orig.binutils-2.14/bfd/archures.c binutils-2.14/bfd/archures.c
--- orig.binutils-2.14/bfd/archures.c	2003-04-24 09:36:06.000000000 -0300
+++ binutils-2.14/bfd/archures.c	2007-04-29 04:00:33.000000000 -0300
@@ -137,6 +137,7 @@
 .#define bfd_mach_mips5000		5000
 .#define bfd_mach_mips5400		5400
 .#define bfd_mach_mips5500		5500
+.#define bfd_mach_mips5900		5900
 .#define bfd_mach_mips6000		6000
 .#define bfd_mach_mips8000		8000
 .#define bfd_mach_mips10000		10000
@@ -147,6 +148,11 @@
 .#define bfd_mach_mipsisa32             32
 .#define bfd_mach_mipsisa32r2           33
 .#define bfd_mach_mipsisa64             64
+.#define bfd_mach_dvp_dma		42000
+.#define bfd_mach_dvp_vif		42001
+.#define bfd_mach_dvp_vu		42002
+.#define bfd_mach_dvp_gif		42003
+.#define bfd_mach_dvp_p(mach) ((mach) &gt;= 42000 &amp;&amp; (mach) &lt;= 42003)
 .  bfd_arch_i386,      {* Intel 386 *}
 .#define bfd_mach_i386_i386 1
 .#define bfd_mach_i386_i8086 2
diff -burN orig.binutils-2.14/bfd/bfd-in2.h binutils-2.14/bfd/bfd-in2.h
--- orig.binutils-2.14/bfd/bfd-in2.h	2003-05-03 13:06:57.000000000 -0300
+++ binutils-2.14/bfd/bfd-in2.h	2007-04-29 04:00:33.000000000 -0300
@@ -1605,6 +1605,7 @@
 #define bfd_mach_mips5000              5000
 #define bfd_mach_mips5400              5400
 #define bfd_mach_mips5500              5500
+#define bfd_mach_mips5900              5900
 #define bfd_mach_mips6000              6000
 #define bfd_mach_mips8000              8000
 #define bfd_mach_mips10000             10000
@@ -1615,6 +1616,11 @@
 #define bfd_mach_mipsisa32             32
 #define bfd_mach_mipsisa32r2           33
 #define bfd_mach_mipsisa64             64
+#define bfd_mach_dvp_dma               42000
+#define bfd_mach_dvp_vif               42001
+#define bfd_mach_dvp_vu                42002
+#define bfd_mach_dvp_gif               42003
+#define bfd_mach_dvp_p(mach) ((mach) &gt;= 42000 &amp;&amp; (mach) &lt;= 42003)
   bfd_arch_i386,      /* Intel 386 */
 #define bfd_mach_i386_i386 1
 #define bfd_mach_i386_i8086 2
@@ -2374,6 +2380,7 @@
   BFD_RELOC_MIPS_REL16,
   BFD_RELOC_MIPS_RELGOT,
   BFD_RELOC_MIPS_JALR,
+  BFD_RELOC_MIPS15_S3,
 
 /* Fujitsu Frv Relocations.  */
   BFD_RELOC_FRV_LABEL16,
@@ -2386,6 +2393,21 @@
   BFD_RELOC_FRV_GPRELHI,
   BFD_RELOC_FRV_GPRELLO,
 
+/* MIPS DVP Relocations. 
+This is an 11-bit pc relative reloc.  The recorded address is for the 
+lower instruction word, and the value is in 128 bit units.  */
+  BFD_RELOC_MIPS_DVP_11_PCREL,
+
+/* This is a 27 bit address left shifted by 4.  */
+  BFD_RELOC_MIPS_DVP_27_S4,
+
+/* This is the 11 bit offset operand of ilw/stw instructions 
+left shifted by 4.  */
+  BFD_RELOC_MIPS_DVP_11_S4,
+
+/* This is the 15 bit unsigned immediate operand of the iaddiu instruction 
+left shifted by 3.  */
+  BFD_RELOC_MIPS_DVP_U15_S3,
 
 /* i386/elf relocations  */
   BFD_RELOC_386_GOT32,
diff -burN orig.binutils-2.14/bfd/config.bfd binutils-2.14/bfd/config.bfd
--- orig.binutils-2.14/bfd/config.bfd	2003-06-02 17:35:20.000000000 -0300
+++ binutils-2.14/bfd/config.bfd	2007-04-29 04:00:33.000000000 -0300
@@ -63,6 +63,9 @@
 *)	         targ_archs=bfd_${targ_cpu}_arch ;;
 esac
 
+case "${targ}" in 
+  mips64*-scei*-elf*) targ_archs="${targ_archs} bfd_dvp_arch" ;; 
+esac 
 
 # WHEN ADDING ENTRIES TO THIS MATRIX:
 #  Make sure that the left side always has two dashes.  Otherwise you
@@ -323,6 +326,10 @@
     targ_defvec=bfd_elf32_frv_vec
     ;;
 
+  dvp-*-*)
+    targ_defvec=bfd_elf32_littlemips_vec
+    targ_selvecs="bfd_elf64_littlemips_vec"
+    ;;
 
   h8300*-*-elf)
     targ_defvec=bfd_elf32_h8300_vec
@@ -781,6 +788,10 @@
     targ_defvec=bfd_elf32_bigmips_vec
     targ_selvecs="bfd_elf32_littlemips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec"
     ;;
+  mips*-*-irx*)
+    targ_defvec=bfd_elf32_littlemips_vec
+    targ_selvecs="bfd_elf32_bigmips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec"
+    ;;
   mips*-*-none)
     targ_defvec=bfd_elf32_bigmips_vec
     targ_selvecs="bfd_elf32_littlemips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec"
diff -burN orig.binutils-2.14/bfd/configure binutils-2.14/bfd/configure
--- orig.binutils-2.14/bfd/configure	2003-06-12 11:25:46.000000000 -0300
+++ binutils-2.14/bfd/configure	2007-04-29 04:00:33.000000000 -0300
@@ -6046,6 +6046,8 @@
 done
 selvecs="$f"
 
+# dvp is really mips, but we need to distinguish it from mips for opcodes  
+selarchs=`echo $selarchs | sed -e s/dvp/mips/g`  
 
 # uniq the associated vectors in all the configured targets.
 f=""
diff -burN orig.binutils-2.14/bfd/configure.in binutils-2.14/bfd/configure.in
--- orig.binutils-2.14/bfd/configure.in	2003-06-12 11:25:46.000000000 -0300
+++ binutils-2.14/bfd/configure.in	2007-04-29 04:00:33.000000000 -0300
@@ -508,6 +508,8 @@
 done
 selvecs="$f"
 
+# dvp is really mips, but we need to distinguish it from mips for opcodes  
+selarchs=`echo $selarchs | sed -e s/dvp/mips/g`  
 
 # uniq the associated vectors in all the configured targets.
 f=""
diff -burN orig.binutils-2.14/bfd/cpu-mips.c binutils-2.14/bfd/cpu-mips.c
--- orig.binutils-2.14/bfd/cpu-mips.c	2002-12-31 03:29:25.000000000 -0400
+++ binutils-2.14/bfd/cpu-mips.c	2007-04-29 04:00:33.000000000 -0300
@@ -75,6 +75,7 @@
   I_mips5000,
   I_mips5400,
   I_mips5500,
+  I_mips5900,
   I_mips6000,
   I_mips8000,
   I_mips10000,
@@ -84,6 +85,10 @@
   I_mipsisa32,
   I_mipsisa32r2,
   I_mipsisa64,
+  I_dvp_dma,
+  I_dvp_vif,
+  I_dvp_vu,
+  I_dvp_gif,
   I_sb1,
 };
 
@@ -105,6 +110,7 @@
   N (64, 64, bfd_mach_mips5000, "mips:5000",      FALSE, NN(I_mips5000)),
   N (64, 64, bfd_mach_mips5400, "mips:5400",      FALSE, NN(I_mips5400)),
   N (64, 64, bfd_mach_mips5500, "mips:5500",      FALSE, NN(I_mips5500)),
+  N (64, 32, bfd_mach_mips5900, "mips:5900",      FALSE, NN(I_mips5900)),
   N (32, 32, bfd_mach_mips6000, "mips:6000",      FALSE, NN(I_mips6000)),
   N (64, 64, bfd_mach_mips8000, "mips:8000",      FALSE, NN(I_mips8000)),
   N (64, 64, bfd_mach_mips10000,"mips:10000",     FALSE, NN(I_mips10000)),
@@ -114,6 +120,10 @@
   N (32, 32, bfd_mach_mipsisa32,  "mips:isa32",   FALSE, NN(I_mipsisa32)),
   N (32, 32, bfd_mach_mipsisa32r2,"mips:isa32r2", FALSE, NN(I_mipsisa32r2)),
   N (64, 64, bfd_mach_mipsisa64,  "mips:isa64",   FALSE, NN(I_mipsisa64)),
+  N (32, 32, bfd_mach_dvp_dma, "dvp:dma",         FALSE, NN(I_dvp_dma)),
+  N (32, 32, bfd_mach_dvp_vif, "dvp:vif",         FALSE, NN(I_dvp_vif)),
+  N (32, 32, bfd_mach_dvp_vu, "dvp:vu",           FALSE, NN(I_dvp_vu)),
+  N (32, 32, bfd_mach_dvp_gif, "dvp:gif",         FALSE, NN(I_dvp_gif)),
   N (64, 64, bfd_mach_mips_sb1, "mips:sb1",       FALSE, 0),
 };
 
diff -burN orig.binutils-2.14/bfd/elf32-mips.c binutils-2.14/bfd/elf32-mips.c
--- orig.binutils-2.14/bfd/elf32-mips.c	2003-04-08 23:55:40.000000000 -0300
+++ binutils-2.14/bfd/elf32-mips.c	2007-04-29 04:00:33.000000000 -0300
@@ -75,6 +75,8 @@
   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
 static bfd_reloc_status_type mips16_gprel_reloc
   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type dvp_u15_s3_reloc
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
 static bfd_reloc_status_type mips_elf_final_gp
   PARAMS ((bfd *, asymbol *, bfd_boolean, char **, bfd_vma *));
 static bfd_boolean mips_elf_assign_gp
@@ -603,6 +605,81 @@
 	 0x07ff001f,	        /* dst_mask */
 	 FALSE);		/* pcrel_offset */
 
+static reloc_howto_type elf_mips15_s3_howto =
+  HOWTO (R_MIPS15_S3,           /* type */
+         3,                     /* rightshift */
+         2,                     /* size (0 = byte, 1 = short, 2 = long) */
+         15,                    /* bitsize */
+         FALSE,                 /* pc_relative */
+         6,                     /* bitpos */
+         complain_overflow_bitfield, /* complain_on_overflow */
+         bfd_elf_generic_reloc, /* special_function */
+         "R_MIPS15_S3",         /* name */
+         TRUE,                  /* partial_inplace */
+         0x001fffc0,            /* src_mask */
+         0x001fffc0,            /* dst_mask */
+         FALSE);                /* pcrel_offset */
+         
+/* DVP relocations. 
+   Note that partial_inplace and pcrel_offset are backwards from the 
+   mips port.  This is intentional as it seems more reasonable.  */
+static reloc_howto_type elf_mips_dvp_11_pcrel_howto =
+  HOWTO (R_MIPS_DVP_11_PCREL,   /* type */
+         3,                     /* rightshift */
+         2,                     /* size (0 = byte, 1 = short, 2 = long) */
+         11,                    /* bitsize */
+         TRUE,                  /* pc_relative */
+         0,                     /* bitpos */
+         complain_overflow_signed, /* complain_on_overflow */
+         bfd_elf_generic_reloc, /* special_function */
+         "R_MIPS_DVP_11_PCREL", /* name */
+         FALSE,                 /* partial_inplace */
+         0x7ff,                 /* src_mask */
+         0x7ff,                 /* dst_mask */
+         TRUE);                 /* pcrel_offset */
+static reloc_howto_type elf_mips_dvp_27_s4_howto =
+  HOWTO (R_MIPS_DVP_27_S4,      /* type */
+         4,                     /* rightshift */
+         2,                     /* size (0 = byte, 1 = short, 2 = long) */
+         27,                    /* bitsize */
+         FALSE,                 /* pc_relative */
+         4,                     /* bitpos */
+         complain_overflow_unsigned, /* complain_on_overflow */
+         bfd_elf_generic_reloc, /* special_function */
+         "R_MIPS_DVP_27_S4",    /* name */
+         FALSE,                 /* partial_inplace */
+         0x7ffffff0,            /* src_mask */
+         0x7ffffff0,            /* dst_mask */
+         FALSE);                /* pcrel_offset */
+static reloc_howto_type elf_mips_dvp_11_s4_howto =
+  HOWTO (R_MIPS_DVP_11_S4,      /* type */
+         4,                     /* rightshift */
+         2,                     /* size (0 = byte, 1 = short, 2 = long) */
+         11,                    /* bitsize */
+         FALSE,                 /* pc_relative */
+         0,                     /* bitpos */
+         complain_overflow_signed, /* complain_on_overflow */
+         bfd_elf_generic_reloc, /* special_function */
+         "R_MIPS_DVP_11_S4",    /* name */
+         FALSE,                 /* partial_inplace */
+         0x03ff,                /* src_mask */
+         0x03ff,                /* dst_mask */
+         FALSE);                /* pcrel_offset */
+static reloc_howto_type elf_mips_dvp_u15_s3_howto =
+  HOWTO (R_MIPS_DVP_U15_S3,     /* type */
+         3,                     /* rightshift */
+         2,                     /* size (0 = byte, 1 = short, 2 = long) */
+         15,                    /* bitsize */
+         FALSE,                 /* pc_relative */
+         0,                     /* bitpos */
+         complain_overflow_unsigned, /* complain_on_overflow */
+         dvp_u15_s3_reloc,      /* special_function */
+         "R_MIPS_DVP_U15_S3",   /* name */
+         FALSE,                 /* partial_inplace */
+         0xf03ff,               /* src_mask */
+         0xf03ff,               /* dst_mask */
+         FALSE);                /* pcrel_offset */
+
 /* GNU extensions for embedded-pic.  */
 /* High 16 bits of symbol value, pc-relative.  */
 static reloc_howto_type elf_mips_gnu_rel_hi16 =
@@ -1381,6 +1458,58 @@
   return ret;
 }
 
+/* Handle a dvp R_MIPS_DVP_U15_S3 reloc. 
+   This is needed because the bits aren't contiguous.  */
+         
+static bfd_reloc_status_type
+dvp_u15_s3_reloc (abfd, reloc_entry, symbol, data, input_section,
+                  output_bfd, error_message)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data;
+     asection *input_section;
+     bfd *output_bfd;
+     char **error_message ATTRIBUTE_UNUSED;
+{
+  bfd_vma relocation;
+  bfd_vma x;
+
+  /* If we're relocating, and this is an external symbol with no 
+     addend, we don't want to change anything.  We will only have an 
+     addend if this is a newly created reloc, not read from an ELF 
+     file.  See bfd_elf_generic_reloc.  */
+  if (output_bfd != NULL
+      &amp;&amp; (symbol-&gt;flags &amp; BSF_SECTION_SYM) == 0
+      /* partial_inplace is FALSE, so this test always succeeds, 
+         but for clarity and consistency with bfd_elf_generic_reloc 
+         this is left as is.  */
+      &amp;&amp; (! reloc_entry-&gt;howto-&gt;partial_inplace
+          || reloc_entry-&gt;addend == 0))
+    {
+      reloc_entry-&gt;address += input_section-&gt;output_offset;
+      return bfd_reloc_ok;
+    }
+    
+  if (reloc_entry-&gt;address &gt; input_section-&gt;_cooked_size)
+    return bfd_reloc_outofrange;
+
+  relocation = (symbol-&gt;value
+                + symbol-&gt;section-&gt;output_section-&gt;vma
+                + symbol-&gt;section-&gt;output_offset);
+  relocation += reloc_entry-&gt;addend;
+  relocation &gt;&gt;= 3;
+
+  x = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry-&gt;address);
+  x |= (((relocation &amp; 0x7800) &lt;&lt; 10)
+        | (relocation &amp; 0x7ff));
+  bfd_put_32 (abfd, x, (bfd_byte *) data + reloc_entry-&gt;address);
+
+  if (relocation &amp; ~(bfd_vma) 0x7fff)
+    return bfd_reloc_overflow;
+  return bfd_reloc_ok;
+}
+
 /* A mapping from BFD reloc types to MIPS ELF reloc types.  */
 
 struct elf_reloc_map {
@@ -1451,6 +1580,16 @@
       return &amp;elf_mips16_jump_howto;
     case BFD_RELOC_MIPS16_GPREL:
       return &amp;elf_mips16_gprel_howto;
+    case BFD_RELOC_MIPS15_S3:
+      return &amp;elf_mips15_s3_howto;
+    case BFD_RELOC_MIPS_DVP_11_PCREL:
+      return &amp;elf_mips_dvp_11_pcrel_howto;
+    case BFD_RELOC_MIPS_DVP_27_S4:
+      return &amp;elf_mips_dvp_27_s4_howto;
+    case BFD_RELOC_MIPS_DVP_11_S4:
+      return &amp;elf_mips_dvp_11_s4_howto;
+    case BFD_RELOC_MIPS_DVP_U15_S3:
+      return &amp;elf_mips_dvp_u15_s3_howto;
     case BFD_RELOC_VTABLE_INHERIT:
       return &amp;elf_mips_gnu_vtinherit_howto;
     case BFD_RELOC_VTABLE_ENTRY:
@@ -1481,6 +1620,16 @@
       return &amp;elf_mips16_jump_howto;
     case R_MIPS16_GPREL:
       return &amp;elf_mips16_gprel_howto;
+    case R_MIPS15_S3:
+      return &amp;elf_mips15_s3_howto;
+    case R_MIPS_DVP_11_PCREL:
+      return &amp;elf_mips_dvp_11_pcrel_howto;
+    case R_MIPS_DVP_27_S4:
+      return &amp;elf_mips_dvp_27_s4_howto;
+    case R_MIPS_DVP_11_S4:
+      return &amp;elf_mips_dvp_11_s4_howto;
+    case R_MIPS_DVP_U15_S3:
+      return &amp;elf_mips_dvp_u15_s3_howto;
     case R_MIPS_GNU_VTINHERIT:
       return &amp;elf_mips_gnu_vtinherit_howto;
     case R_MIPS_GNU_VTENTRY:
diff -burN orig.binutils-2.14/bfd/elf.c binutils-2.14/bfd/elf.c
--- orig.binutils-2.14/bfd/elf.c	2003-06-02 17:35:20.000000000 -0300
+++ binutils-2.14/bfd/elf.c	2007-04-29 04:00:33.000000000 -0300
@@ -2214,7 +2214,7 @@
   newsect-&gt;_raw_size = hdr-&gt;p_filesz;
   newsect-&gt;filepos = hdr-&gt;p_offset;
   newsect-&gt;flags |= SEC_HAS_CONTENTS;
-  if (hdr-&gt;p_type == PT_LOAD)
+  if (hdr-&gt;p_type == PT_LOAD || hdr-&gt;p_type == PT_MIPS_IRXHDR)
     {
       newsect-&gt;flags |= SEC_ALLOC;
       newsect-&gt;flags |= SEC_LOAD;
@@ -2244,7 +2244,7 @@
       newsect-&gt;vma = hdr-&gt;p_vaddr + hdr-&gt;p_filesz;
       newsect-&gt;lma = hdr-&gt;p_paddr + hdr-&gt;p_filesz;
       newsect-&gt;_raw_size = hdr-&gt;p_memsz - hdr-&gt;p_filesz;
-      if (hdr-&gt;p_type == PT_LOAD)
+      if (hdr-&gt;p_type == PT_LOAD || hdr-&gt;p_type == PT_MIPS_IRXHDR)
 	{
 	  newsect-&gt;flags |= SEC_ALLOC;
 	  if (hdr-&gt;p_flags &amp; PF_X)
@@ -3744,7 +3744,7 @@
       else
 	p-&gt;p_paddr = m-&gt;sections[0]-&gt;lma;
 
-      if (p-&gt;p_type == PT_LOAD
+      if ((p-&gt;p_type == PT_LOAD || p-&gt;p_type == PT_MIPS_IRXHDR)
 	  &amp;&amp; (abfd-&gt;flags &amp; D_PAGED) != 0)
 	p-&gt;p_align = bed-&gt;maxpagesize;
       else if (m-&gt;count == 0)
@@ -3765,7 +3765,7 @@
 	  p-&gt;p_memsz = bed-&gt;s-&gt;sizeof_ehdr;
 	  if (m-&gt;count &gt; 0)
 	    {
-	      BFD_ASSERT (p-&gt;p_type == PT_LOAD);
+	      BFD_ASSERT (p-&gt;p_type == PT_LOAD || p-&gt;p_type == PT_MIPS_IRXHDR);
 
 	      if (p-&gt;p_vaddr &lt; (bfd_vma) off)
 		{
@@ -3780,7 +3780,7 @@
 	      if (! m-&gt;p_paddr_valid)
 		p-&gt;p_paddr -= off;
 	    }
-	  if (p-&gt;p_type == PT_LOAD)
+	  if (p-&gt;p_type == PT_LOAD || p-&gt;p_type == PT_MIPS_IRXHDR)
 	    {
 	      filehdr_vaddr = p-&gt;p_vaddr;
 	      filehdr_paddr = p-&gt;p_paddr;
@@ -3794,7 +3794,7 @@
 
 	  if (m-&gt;includes_filehdr)
 	    {
-	      if (p-&gt;p_type == PT_LOAD)
+	      if (p-&gt;p_type == PT_LOAD || p-&gt;p_type == PT_MIPS_IRXHDR)
 		{
 		  phdrs_vaddr = p-&gt;p_vaddr + bed-&gt;s-&gt;sizeof_ehdr;
 		  phdrs_paddr = p-&gt;p_paddr + bed-&gt;s-&gt;sizeof_ehdr;
@@ -3812,7 +3812,7 @@
 		    p-&gt;p_paddr -= off - p-&gt;p_offset;
 		}
 
-	      if (p-&gt;p_type == PT_LOAD)
+	      if (p-&gt;p_type == PT_LOAD || p-&gt;p_type == PT_MIPS_IRXHDR)
 		{
 		  phdrs_vaddr = p-&gt;p_vaddr;
 		  phdrs_paddr = p-&gt;p_paddr;
@@ -3825,7 +3825,7 @@
 	  p-&gt;p_memsz += alloc * bed-&gt;s-&gt;sizeof_phdr;
 	}
 
-      if (p-&gt;p_type == PT_LOAD
+      if (p-&gt;p_type == PT_LOAD || p-&gt;p_type == PT_MIPS_IRXHDR
 	  || (p-&gt;p_type == PT_NOTE &amp;&amp; bfd_get_format (abfd) == bfd_core))
 	{
 	  if (! m-&gt;includes_filehdr &amp;&amp; ! m-&gt;includes_phdrs)
@@ -3860,7 +3860,7 @@
 	      bfd_vma adjust = sec-&gt;lma - (p-&gt;p_paddr + p-&gt;p_memsz);
 
 	      p-&gt;p_memsz += adjust;
-	      if (p-&gt;p_type == PT_LOAD
+	      if (p-&gt;p_type == PT_LOAD || p-&gt;p_type == PT_MIPS_IRXHDR
 		  || (p-&gt;p_type == PT_NOTE
 		      &amp;&amp; bfd_get_format (abfd) == bfd_core))
 		{
@@ -3872,7 +3872,7 @@
 		p-&gt;p_filesz += adjust;
 	    }
 
-	  if (p-&gt;p_type == PT_LOAD)
+	  if (p-&gt;p_type == PT_LOAD || p-&gt;p_type == PT_MIPS_IRXHDR)
 	    {
 	      bfd_signed_vma adjust;
 
@@ -3977,7 +3977,8 @@
 		}
 
 	      if (align &gt; p-&gt;p_align
-		  &amp;&amp; (p-&gt;p_type != PT_LOAD || (abfd-&gt;flags &amp; D_PAGED) == 0))
+		  &amp;&amp; ((p-&gt;p_type != PT_LOAD &amp;&amp; p-&gt;p_type != PT_MIPS_IRXHDR)
+                  || (abfd-&gt;flags &amp; D_PAGED) == 0))
 		p-&gt;p_align = align;
 	    }
 
@@ -3998,7 +3999,7 @@
        m != NULL;
        m = m-&gt;next, p++)
     {
-      if (p-&gt;p_type != PT_LOAD &amp;&amp; m-&gt;count &gt; 0)
+      if (p-&gt;p_type != PT_LOAD &amp;&amp; p-&gt;p_type != PT_MIPS_IRXHDR &amp;&amp; m-&gt;count &gt; 0)
 	{
 	  BFD_ASSERT (! m-&gt;includes_filehdr &amp;&amp; ! m-&gt;includes_phdrs);
 	  p-&gt;p_offset = m-&gt;sections[0]-&gt;filepos;
diff -burN orig.binutils-2.14/bfd/elflink.h binutils-2.14/bfd/elflink.h
--- orig.binutils-2.14/bfd/elflink.h	2003-06-02 17:35:21.000000000 -0300
+++ binutils-2.14/bfd/elflink.h	2007-04-29 04:00:33.000000000 -0300
@@ -7238,9 +7238,18 @@
 			 elf_link_output_extsym that this symbol is
 			 used by a reloc.  */
 		      BFD_ASSERT (rh-&gt;indx &lt; 0);
+		      if (elf_elfheader (output_bfd)-&gt;e_type != ET_IRX
+			  || finfo-&gt;info-&gt;strip != strip_all)
+			{
 		      rh-&gt;indx = -2;
-
 		      *rel_hash = rh;
+			}
+		      else
+			{
+			  irela-&gt;r_info =
+			    ELF_R_INFO (0, ELF_R_TYPE (irela-&gt;r_info)); 
+			  *rel_hash = NULL;
+			}
 
 		      continue;
 		    }
@@ -7269,7 +7278,8 @@
 		      else
 			{
 			  r_symndx = sec-&gt;output_section-&gt;target_index;
-			  BFD_ASSERT (r_symndx != 0);
+			  /* r_symndx is zero in stripped IRX files.  */
+			  /* BFD_ASSERT (r_symndx != 0); */
 			}
 
 		      /* Adjust the addend according to where the
diff -burN orig.binutils-2.14/bfd/elfxx-mips.c binutils-2.14/bfd/elfxx-mips.c
--- orig.binutils-2.14/bfd/elfxx-mips.c	2003-06-02 17:35:22.000000000 -0300
+++ binutils-2.14/bfd/elfxx-mips.c	2007-04-29 04:00:33.000000000 -0300
@@ -4064,6 +4064,9 @@
     case E_MIPS_MACH_5500:
       return bfd_mach_mips5500;
 
+    case E_MIPS_MACH_5900:
+      return bfd_mach_mips5900;
+
     case E_MIPS_MACH_SB1:
       return bfd_mach_mips_sb1;
 
@@ -4379,6 +4382,10 @@
      probably get away with this.  */
   switch (hdr-&gt;sh_type)
     {
+    case SHT_MIPS_IOPMOD:
+      if (strcmp (name, ".iopmod") != 0)
+	return FALSE;
+      break;
     case SHT_MIPS_LIBLIST:
       if (strcmp (name, ".liblist") != 0)
 	return FALSE;
@@ -4436,6 +4443,15 @@
 		      sizeof ".MIPS.post_rel" - 1) != 0)
 	return FALSE;
       break;
+    case SHT_DVP_OVERLAY_TABLE:
+      if (strcmp (name, SHNAME_DVP_OVERLAY_TABLE) !=0)
+        return FALSE;
+      break;
+    case SHT_DVP_OVERLAY:
+      if (strncmp (name, SHNAME_DVP_OVERLAY_PREFIX,
+                   sizeof (SHNAME_DVP_OVERLAY_PREFIX) - 1) !=0)
+        return FALSE;
+      break;
     default:
       return FALSE;
     }
@@ -4540,7 +4556,25 @@
 
   name = bfd_get_section_name (abfd, sec);
 
-  if (strcmp (name, ".liblist") == 0)
+  if (strcmp (name, ".iopmod") == 0)
+    {
+      /* Verify that this bfd is going to be an IRX, and not an object 
+         file or a rogue elf with an .iopmod section by looking for 
+         the PT_MIPS_IRXHDR program header.  */
+      struct elf_segment_map *m;
+
+      for (m = elf_tdata (abfd)-&gt;segment_map; m != NULL; m = m-&gt;next)
+        if (m-&gt;p_type == PT_MIPS_IRXHDR)
+          {
+            /* Mark the file as an IRX.  */
+            elf_elfheader (abfd)-&gt;e_type = ET_IRX;
+            /* Setup the section type and flags.  */
+            hdr-&gt;sh_type = SHT_MIPS_IOPMOD;
+            hdr-&gt;sh_addr = 0;
+            hdr-&gt;sh_flags &amp;= ~(SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR);
+          }
+    }
+  else if (strcmp (name, ".liblist") == 0)
     {
       hdr-&gt;sh_type = SHT_MIPS_LIBLIST;
       hdr-&gt;sh_info = sec-&gt;_raw_size / sizeof (Elf32_Lib);
@@ -4639,6 +4673,17 @@
       hdr-&gt;sh_flags |= SHF_ALLOC;
       hdr-&gt;sh_entsize = 8;
     }
+  else if (strcmp (name, SHNAME_DVP_OVERLAY_TABLE) == 0)
+    {
+      hdr-&gt;sh_type = SHT_DVP_OVERLAY_TABLE;
+      hdr-&gt;sh_entsize = sizeof (Elf32_Dvp_External_Overlay);
+      /* The sh_link field is set in final_write_processing.  */
+    }
+  else if (strcmp (name, SHNAME_DVP_OVERLAY_STRTAB) == 0)
+    hdr-&gt;sh_type = SHT_STRTAB;
+  else if (strncmp (name, SHNAME_DVP_OVERLAY_PREFIX,
+                    sizeof (SHNAME_DVP_OVERLAY_PREFIX) - 1) == 0)
+    hdr-&gt;sh_type = SHT_DVP_OVERLAY;
 
   /* The generic elf_fake_sections will set up REL_HDR using the
      default kind of relocations.  But, we may actually need both
@@ -7300,6 +7345,10 @@
       val = E_MIPS_ARCH_4 | E_MIPS_MACH_5500;
       break;
 
+    case bfd_mach_mips5900:
+      val = E_MIPS_ARCH_3 | E_MIPS_MACH_5900;
+      break;
+
     case bfd_mach_mips5000:
     case bfd_mach_mips8000:
     case bfd_mach_mips10000:
@@ -7418,6 +7467,13 @@
 	  (*hdrpp)-&gt;sh_link = elf_section_data (sec)-&gt;this_idx;
 	  break;
 
+        case SHT_DVP_OVERLAY_TABLE:
+          /* ??? This may not be technically necessary, just going with  
+             the flow ...  */
+          sec = bfd_get_section_by_name (abfd, SHNAME_DVP_OVERLAY_STRTAB);
+          if (sec != NULL)
+            (*hdrpp)-&gt;sh_link = elf_section_data (sec)-&gt;this_idx;
+          break;
 	}
     }
 }
@@ -9112,6 +9168,7 @@
   { bfd_mach_mips4300, bfd_mach_mips4000 },
   { bfd_mach_mips4100, bfd_mach_mips4000 },
   { bfd_mach_mips4010, bfd_mach_mips4000 },
+  { bfd_mach_mips5900, bfd_mach_mips4000 },
 
   /* MIPS32 extensions.  */
   { bfd_mach_mipsisa32r2, bfd_mach_mipsisa32 },
@@ -9276,7 +9333,7 @@
     {
       (*_bfd_error_handler)
 	(_("%s: linking 32-bit code with 64-bit code"),
-	 bfd_archive_filename (ibfd));
+	 bfd_archive_filename (ibfd), old_flags, new_flags);
       ok = FALSE;
     }
   else if (!mips_mach_extends_p (bfd_get_mach (ibfd), bfd_get_mach (obfd)))
diff -burN orig.binutils-2.14/bfd/libbfd.h binutils-2.14/bfd/libbfd.h
--- orig.binutils-2.14/bfd/libbfd.h	2003-04-01 11:50:27.000000000 -0400
+++ binutils-2.14/bfd/libbfd.h	2007-04-29 04:00:33.000000000 -0300
@@ -872,6 +872,7 @@
   "BFD_RELOC_MIPS_REL16",
   "BFD_RELOC_MIPS_RELGOT",
   "BFD_RELOC_MIPS_JALR",
+  "BFD_RELOC_MIPS15_S3",
   "BFD_RELOC_FRV_LABEL16",
   "BFD_RELOC_FRV_LABEL24",
   "BFD_RELOC_FRV_LO16",
@@ -881,6 +882,10 @@
   "BFD_RELOC_FRV_GPREL32",
   "BFD_RELOC_FRV_GPRELHI",
   "BFD_RELOC_FRV_GPRELLO",
+  "BFD_RELOC_MIPS_DVP_11_PCREL",
+  "BFD_RELOC_MIPS_DVP_27_S4",
+  "BFD_RELOC_MIPS_DVP_11_S4",
+  "BFD_RELOC_MIPS_DVP_U15_S3",
 
   "BFD_RELOC_386_GOT32",
   "BFD_RELOC_386_PLT32",
diff -burN orig.binutils-2.14/bfd/reloc.c binutils-2.14/bfd/reloc.c
--- orig.binutils-2.14/bfd/reloc.c	2003-04-23 18:09:02.000000000 -0300
+++ binutils-2.14/bfd/reloc.c	2007-04-29 04:00:33.000000000 -0300
@@ -2128,6 +2128,8 @@
   BFD_RELOC_MIPS_RELGOT
 ENUMX
   BFD_RELOC_MIPS_JALR
+ENUMX
+  BFD_RELOC_MIPS15_S3
 COMMENT
 ENUM
   BFD_RELOC_FRV_LABEL16
@@ -2155,6 +2157,27 @@
   MIPS ELF relocations.
 
 COMMENT
+ENUM 
+  BFD_RELOC_MIPS_DVP_11_PCREL 
+ENUMDOC 
+  MIPS DVP Relocations. 
+  This is an 11-bit pc relative reloc.  The recorded address is for the 
+  lower instruction word, and the value is in 128 bit units. 
+ENUM 
+  BFD_RELOC_MIPS_DVP_27_S4 
+ENUMDOC 
+  This is a 27 bit address left shifted by 4. 
+ENUM 
+  BFD_RELOC_MIPS_DVP_11_S4 
+ENUMDOC 
+  This is the 11 bit offset operand of ilw/stw instructions 
+  left shifted by 4. 
+ENUM 
+  BFD_RELOC_MIPS_DVP_U15_S3 
+ENUMDOC 
+  This is the 15 bit unsigned immediate operand of the iaddiu instruction 
+  left shifted by 3. 
+COMMENT 
 
 ENUM
   BFD_RELOC_386_GOT32
diff -burN orig.binutils-2.14/config.sub binutils-2.14/config.sub
--- orig.binutils-2.14/config.sub	2003-06-02 17:35:43.000000000 -0300
+++ binutils-2.14/config.sub	2007-04-29 04:00:33.000000000 -0300
@@ -250,6 +250,7 @@
 	| mipsisa64sb1 | mipsisa64sb1el \
 	| mipsisa64sr71k | mipsisa64sr71kel \
 	| mipstx39 | mipstx39el \
+	| mips64r5900 | mips64r5900el \
 	| mn10200 | mn10300 \
 	| msp430 \
 	| ns16k | ns32k \
@@ -261,7 +262,7 @@
 	| sh64 | sh64le \
 	| sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
 	| strongarm \
-	| tahoe | thumb | tic80 | tron \
+	| tahoe | dvp | thumb | tic80 | tron \
 	| v850 | v850e \
 	| we32k \
 	| x86 | xscale | xstormy16 | xtensa \
@@ -322,6 +323,7 @@
 	| mipsisa64sb1-* | mipsisa64sb1el-* \
 	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
 	| mipstx39-* | mipstx39el-* \
+	| mips64r5900-* | mips64r5900el-* \
 	| msp430-* \
 	| none-* | np1-* | nv1-* | ns16k-* | ns32k-* \
 	| orion-* \
@@ -635,6 +637,24 @@
 		basic_machine=m68k-atari
 		os=-mint
 		;;
+	mipsEE* | ee | ps2)
+		basic_machine=mips64r5900el-scei
+		case $os in
+		    -linux*)
+			;;
+		    *)
+			os=-elf
+			;;
+		esac
+		;;
+	iop)
+		basic_machine=mipsel-scei
+		os=-irx
+		;;
+	dvp)
+		basic_machine=dvp-scei
+		os=-elf
+		;;
 	mips3*-*)
 		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
 		;;
@@ -1131,7 +1151,7 @@
 	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
 	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
 	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
-	      | -powermax* | -dnix*)
+	      | -powermax* | -dnix* | -irx*)
 	# Remember, each alternative MUST END IN *, to match a version number.
 		;;
 	-qnx*)
diff -burN orig.binutils-2.14/configure binutils-2.14/configure
--- orig.binutils-2.14/configure	2003-06-02 17:35:43.000000000 -0300
+++ binutils-2.14/configure	2007-04-29 04:00:33.000000000 -0300
@@ -1116,6 +1116,9 @@
   d30v-*-*)
     noconfigdirs="$noconfigdirs ${libgcj}"
     ;;
+  dvp-*-*)
+    noconfigdirs="$noconfigdirs ld"
+    ;;
   fr30-*-elf*)
     noconfigdirs="$noconfigdirs ${libgcj}"
     ;;
diff -burN orig.binutils-2.14/configure.in binutils-2.14/configure.in
--- orig.binutils-2.14/configure.in	2003-06-12 11:33:14.000000000 -0300
+++ binutils-2.14/configure.in	2007-04-29 04:00:33.000000000 -0300
@@ -456,6 +456,9 @@
   d30v-*-*)
     noconfigdirs="$noconfigdirs ${libgcj}"
     ;;
+  dvp-*-*)
+    noconfigdirs="$noconfigdirs ld"
+    ;;
   fr30-*-elf*)
     noconfigdirs="$noconfigdirs ${libgcj}"
     ;;
diff -burN orig.binutils-2.14/gas/config/tc-dvp.c binutils-2.14/gas/config/tc-dvp.c
--- orig.binutils-2.14/gas/config/tc-dvp.c	1969-12-31 20:00:00.000000000 -0400
+++ binutils-2.14/gas/config/tc-dvp.c	2007-04-29 04:00:33.000000000 -0300
@@ -0,0 +1,3436 @@
+/* tc-dvp.c -- Assembler for the DVP
+   Copyright (C) 1997, 1998 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 "as.h"
+#include "config.h" 
+#include "struc-symbol.h"
+#include "subsegs.h"
+#include "safe-ctype.h" 
+/* Needed by opcode/dvp.h.  */
+#include "dis-asm.h"
+#include "opcode/dvp.h"
+#include "elf/mips.h"
+
+#ifdef USE_STDARG
+#include &lt;stdarg.h&gt;
+#else
+#include &lt;varargs.h&gt;
+#endif
+
+/* Value of VIF `nop' instruction.  */
+#define VIFNOP 0
+
+#define MIN(a,b) ((a) &lt; (b) ? (a) : (b))
+
+/* Compute DMA operand index number of OP.  */
+#define DMA_OPERAND_INDEX(op) ((op) - dma_operands)
+
+/* Our local label prefix.  */
+#define LOCAL_LABEL_PREFIX ".L"
+/* Label prefix for end markers used in autocounts.  */
+#define END_LABEL_PREFIX ".L.end."
+/* Label to use for unique labels.  */
+#define UNIQUE_LABEL_PREFIX ".L.dvptmp."
+/* Prefix for mips version of labels defined in vu code.
+   Note that symbols that begin with '$' are local symbols
+   on mips targets, so we can't begin it with '$'.  */
+#define VU_LABEL_PREFIX "_$"
+/* Prefix for symbols at start of vu overlays, in r5900 space.  */
+#define VUOVERLAY_START_PREFIX "__start_"
+
+static long parse_float PARAMS ((char **, const char **));
+static symbolS * create_label PARAMS ((const char *, const char *));
+static symbolS * create_colon_label PARAMS ((int, const char *, const char *));
+static char * unique_name PARAMS ((const char *));
+static int vuoverlay_section_p PARAMS ((segT));
+static char * vuoverlay_section_name PARAMS ((symbolS *));
+static void create_vuoverlay_section PARAMS ((const char *, symbolS *,
+					      symbolS *, symbolS *));
+static symbolS * compute_mpgloc PARAMS ((symbolS *, symbolS *, symbolS *));
+static int compute_nloop PARAMS ((gif_type, int, int));
+static void check_nloop PARAMS ((gif_type, int, int, int,
+				 char *, unsigned int));
+static long eval_expr PARAMS ((dvp_cpu, int, int, const char *, ...));
+static long parse_dma_addr_autocount ();
+static void inline_dma_data PARAMS ((int, DVP_INSN *));
+static void setup_dma_autocount PARAMS ((const char *, DVP_INSN *, int));
+
+static void insert_operand 
+     PARAMS ((dvp_cpu, const dvp_opcode *, const dvp_operand *, int,
+	      DVP_INSN *, offsetT, const char **));
+static void insert_operand_final
+     PARAMS ((dvp_cpu, const dvp_operand *, int,
+	      DVP_INSN *, offsetT, char *, unsigned int));
+
+static void insert_mpg_marker PARAMS ((unsigned long));
+static void insert_unpack_marker PARAMS ((unsigned long));
+static int insert_file PARAMS ((const char *,
+				void (*) PARAMS ((unsigned long)),
+				unsigned long, int));
+
+static int vif_insn_type PARAMS ((char));
+static int vif_length_value PARAMS ((char, int, int, int));
+static void install_vif_length PARAMS ((char *, int));
+
+const char comment_chars[] = ";";
+const char line_comment_chars[] = "#";
+const char line_separator_chars[] = "!";
+const char EXP_CHARS[] = "eE";
+const char FLT_CHARS[] = "dD";
+
+/* Last label seen.
+   When we see a .dmastart, any immediately preceding label is
+   automagically aligned as well.  */
+static symbolS *last_label_seen;
+/* Labels for vu code are duplicated, one in vu space, one in normal space.
+   This records the label in vu space.  */
+static symbolS *last_label_seen2;
+
+/* Current assembler state.
+   Instructions like mpg and direct are followed by a restricted set of
+   instructions.  In the case of a '*' length argument an end marker must
+   be provided.  (e.g. mpg is followed by vu insns until a .EndMpg is
+   seen).
+
+   Allowed state transitions:
+   ASM_INIT &lt;--&gt; ASM_MPG
+                 ASM_DIRECT &lt;--&gt; ASM_GIF
+                 ASM_UNPACK &lt;--&gt; ASM_GIF
+                 ASM_VU
+		 ASM_GIF
+
+   FIXME: Make the ASM_INIT -&gt; ASM_VU a one way transition.
+   ".vu" must be seen at the top of the file,
+   and cannot be switched out of.
+*/
+
+typedef enum {
+  ASM_INIT, ASM_DIRECT, ASM_MPG, ASM_UNPACK, ASM_VU, ASM_GIF, ASM_MAX
+} asm_state;
+
+/* We need to maintain a stack of the current and previous status to handle
+   such things as "direct ...; gifpacked ... ; .endgif ; .enddirect".  */
+#define MAX_STATE_DEPTH 2
+static asm_state asm_state_stack[MAX_STATE_DEPTH];
+/* Current state's index in the stack.  */
+static int cur_state_level;
+/* Macro to fetch the current state.  */
+#define CUR_ASM_STATE (asm_state_stack[cur_state_level])
+
+/* Functions to push/pop the state stack.  */
+static void push_asm_state PARAMS ((asm_state));
+static void pop_asm_state PARAMS ((int));
+static void set_asm_state PARAMS ((asm_state, const char *));
+
+/* Set to non-zero if any non-vu insn seen.
+   Used to control type of relocations emitted.  */
+static int non_vu_insn_seen_p = 0;
+
+/* Current cpu (machine variant) type state.
+   We copy the mips16 way of recording what the current machine type is in
+   the code.  A label is created whenever necessary and has an "other" value
+   the denotes the machine type.  */
+static dvp_cpu cur_cpu;
+/* Record the current mach type.  */
+static void record_mach PARAMS ((dvp_cpu, int));
+/* Force emission of mach type label at next insn.
+   This isn't static as TC_START_LABEL uses it.  */
+int force_mach_label PARAMS ((void));
+/* Given a dvp_cpu value, return the STO_DVP value to use.  */
+static int cpu_sto PARAMS ((dvp_cpu, const char **));
+
+/* Nonzero if inside .DmaData.  */
+static int dma_data_state = 0;
+/* Label of .DmaData (internally generated for inline data).  */
+static const char *dma_data_name;
+
+/* Variable length VIF insn support.  */
+/* Label at start of insn's data.  */
+static symbolS *vif_data_start;
+/* Label at end of insn's data.  */
+static symbolS *vif_data_end;
+
+/* Special symbol $.mpgloc.  The value is in bytes.
+   This value is kept absolute, for simplicity.
+   The st_other field for this must always be set to STO_DVP_VU because
+   symbols computed from this will get their st_other field clobbered
+   with this one (via resolve_symbol_value,copy_symbol_attributes).  */
+static symbolS *mpgloc_sym;
+
+/* Handle of the current vu overlay section.  */
+static segT vuoverlay_section;
+
+/* The overlay table section is a table mapping lma's to vma's.  */
+static segT vuoverlay_table_section;
+/* String table to record section names in the overlay table.  */
+static segT vuoverlay_string_section;
+
+/* Table to map vu space labels to their overlay sections.
+   Labels in vu space are first put in the ABS section to simplify
+   PC relative branch calculations (s1 - s2 isn't supported if they're
+   in different sections).  Before the file is written out the labels
+   are moved to their overlay section.  */
+typedef struct ovlysym {
+  struct ovlysym *next;
+  segT sec;
+  symbolS *sym;
+} ovlysymS;
+static ovlysymS *ovlysym_table;
+
+/* GIF insn support.  */
+/* Type of insn.  */
+static int gif_insn_type;
+/* Name of label of insn's data.  */
+static const char *gif_data_name;
+/* Pointer to frag of insn.  */
+static fragS *gif_insn_frag;
+/* Pointer to current gif insn in gif_insn_frag.  */
+static char *gif_insn_frag_loc;
+/* The length value specified in the insn, or -1 if '*'.  */
+static int gif_user_value;
+
+/* Count of vu insns seen since the last mpg.
+   Set to -1 to disable automatic mpg insertion.  */
+static int vu_count;
+
+/* Non-zero if packing vif instructions in dma tags.  */
+static int dma_pack_vif_p;
+
+/* Non-zero if dma insns are to be included in the output.
+   This is the default, but writing "if (! no_dma)" is klunky.  */
+static int output_dma = 1;
+/* Non-zero if vif insns are to be included in the output.  */
+static int output_vif = 1;
+
+/* Current opcode/operand for use by md_operand.  */
+static const dvp_opcode *cur_opcode;
+static const dvp_operand *cur_operand;
+
+/* Options for the `caller' argument to s_endmpg.  */
+typedef enum { ENDMPG_USER, ENDMPG_INTERNAL, ENDMPG_MIDDLE } endmpg_caller;
+
+/* Relaxation support.  */
+#define RELAX_MPG 1
+#define RELAX_DIRECT 2
+/* vu insns aren't relaxed, but they use machine dependent frags so we
+   must handle them during relaxation */
+#define RELAX_VU 3
+#define RELAX_ENCODE(type, growth) (10 + (growth))
+#define RELAX_GROWTH(state) ((state) - 10)
+/* Return non-zero if STATE represents a relaxed state.  */
+#define RELAX_DONE_P(state) ((state) &gt;= 10)
+
+const char *md_shortopts = "";
+
+struct option md_longopts[] =
+{
+#define OPTION_NO_DMA (OPTION_MD_BASE + 1)
+  { "no-dma", no_argument, NULL, OPTION_NO_DMA },
+#define OPTION_NO_DMA_VIF (OPTION_NO_DMA + 1)
+  { "no-dma-vif", no_argument, NULL, OPTION_NO_DMA_VIF },
+
+  {NULL, no_argument, NULL, 0}
+};
+size_t md_longopts_size = sizeof(md_longopts);
+
+int
+md_parse_option (c, arg)
+     int c;
+     char *arg;
+{
+  switch (c)
+    {
+    case OPTION_NO_DMA :
+      output_dma = 0;
+      break;
+    case OPTION_NO_DMA_VIF :
+      output_dma = 0;
+      output_vif = 0;
+      break;
+    default :
+      return 0;
+    }
+  return 1;
+}
+
+void
+md_show_usage (stream)
+  FILE *stream;
+{
+  fprintf (stream, "\
+DVP options:\n\
+-no-dma			do not include DMA instructions in the output\n\
+-no-dma-vif		do not include DMA or VIF instructions in the output\n\
+");
+} 
+
+static void s_dmadata PARAMS ((int));
+static void s_enddmadata PARAMS ((int));
+static void s_dmapackvif PARAMS ((int));
+static void s_enddirect PARAMS ((int));
+static void s_endmpg PARAMS ((int));
+static void s_endunpack PARAMS ((int));
+static void s_endgif PARAMS ((int));
+static void s_vu PARAMS ((int));
+static void s_dvp_func PARAMS ((int));
+
+/* The target specific pseudo-ops which we support.  */
+const pseudo_typeS md_pseudo_table[] =
+{
+  { "word", cons, 4 },
+  { "quad", cons, 16 },
+  { "dmadata", s_dmadata, 0 },
+  { "dmapackvif", s_dmapackvif, 0 },
+  { "enddirect", s_enddirect, 0 },
+  { "enddmadata", s_enddmadata, 0 },
+  { "endmpg", s_endmpg, ENDMPG_USER },
+  { "endunpack", s_endunpack, 0 },
+  { "endgif", s_endgif, 0 },
+  { "vu", s_vu, 0 },
+  /* We need to intercept .func/.endfunc so that we can prepend _$.
+     ??? Not sure this is right though as _$foo is the lma version.  */
+  { "func", s_dvp_func, 0 },
+  { "endfunc", s_dvp_func, 1 },
+  { NULL, NULL, 0 }
+};
+
+void
+md_begin ()
+{
+  /* Initialize the opcode tables.
+     This involves computing the hash chains.  */
+  dvp_opcode_init_tables (0);
+
+  /* Force a mach type label for the first insn.  */
+  force_mach_label ();
+
+  /* Initialize the parsing state.  */
+  set_asm_state (ASM_INIT, NULL);
+
+  /* Pack vif insns in dma tags by default.  */
+  dma_pack_vif_p = 1;
+
+  /* Disable automatic mpg insertion.  */
+  vu_count = -1;
+
+  /* Initialize $.mpgloc.  */
+  mpgloc_sym = expr_build_uconstant (0);
+  S_SET_OTHER (mpgloc_sym, STO_DVP_VU);
+
+  /* Create the vu overlay table section.  */
+  {
+    /* Must preserve the current seg/subseg.  It is the initial one.  */
+    segT orig_seg = now_seg;
+    subsegT orig_subseg = now_subseg;
+
+    vuoverlay_table_section = subseg_new (SHNAME_DVP_OVERLAY_TABLE, 0);
+    record_alignment (now_seg, 2);
+    vuoverlay_string_section = subseg_new (SHNAME_DVP_OVERLAY_STRTAB, 0);
+    /* Ensure first byte in executable is zero.  So what if we waste
+       a few bytes.  */
+    FRAG_APPEND_1_CHAR (0);
+
+    subseg_set (orig_seg, orig_subseg);
+  }
+
+  /* Set the type of the output file to r5900.  */
+  bfd_set_arch_mach (stdoutput, bfd_arch_mips, 5900);
+}
+
+/* We need to keep a list of fixups.  We can't simply generate them as
+   we go, because that would require us to first create the frag, and
+   that would screw up references to ``.''.  */
+
+struct dvp_fixup
+{
+  /* the cpu this fixup is associated with */
+  dvp_cpu cpu;
+  /* index into `dvp_operands' */
+  int opindex;
+  /* byte offset from beginning of instruction */
+  int offset;
+  /* user specified value [when there is one] */
+  int user_value;
+  /* wl,cl values, only used with unpack insn */
+  short wl,cl;
+  /* the expression */
+  expressionS exp;
+};
+
+#define MAX_FIXUPS 5
+
+static int fixup_count;
+static struct dvp_fixup fixups[MAX_FIXUPS];
+
+/* Given a cpu type and operand number, return a temporary reloc type
+   for use in generating the fixup that encodes the cpu type and operand.  */
+static int encode_fixup_reloc_type PARAMS ((dvp_cpu, int));
+/* Given an encoded fixup reloc type, decode it into cpu and operand.  */
+static void decode_fixup_reloc_type PARAMS ((int, dvp_cpu *,
+					     const dvp_operand **));
+
+static void assemble_dma PARAMS ((char *));
+static void assemble_gif PARAMS ((char *));
+static void assemble_vif PARAMS ((char *));
+static void assemble_vu PARAMS ((char *));
+static const dvp_opcode * assemble_vu_insn PARAMS ((dvp_cpu,
+						    const dvp_opcode *,
+						    const dvp_operand *,
+						    char **, char *));
+static const dvp_opcode * assemble_one_insn PARAMS ((dvp_cpu,
+						     const dvp_opcode *,
+						     const dvp_operand *,
+						     int, int,
+						     char **, DVP_INSN *));
+
+/* Main entry point for assembling an instruction.  */
+
+void
+md_assemble (str)
+     char *str;
+{
+  /* Skip leading white space.  */
+  while (isspace (*str))
+    str++;
+
+  /* After a gif tag, no insns can appear until a .endgif is seen.  */
+  if (CUR_ASM_STATE == ASM_GIF)
+    {
+      as_bad ("missing .endgif");
+      pop_asm_state (1);
+      /* We still parse the instruction.  */
+    }
+
+  if (CUR_ASM_STATE == ASM_INIT)
+    {
+      if (strncasecmp (str, "dma", 3) == 0)
+	assemble_dma (str);
+      else if (strncasecmp (str, "gif", 3) == 0)
+	assemble_gif (str);
+      else
+	assemble_vif (str);
+      non_vu_insn_seen_p = 1;
+    }
+  else if (CUR_ASM_STATE == ASM_DIRECT
+	   || CUR_ASM_STATE == ASM_UNPACK)
+    {
+      assemble_gif (str);
+      non_vu_insn_seen_p = 1;
+    }
+  else if (CUR_ASM_STATE == ASM_VU
+	   || CUR_ASM_STATE == ASM_MPG)
+    assemble_vu (str);
+  else
+    as_fatal ("internal error: unknown parse state");
+}
+
+/* Subroutine of md_assemble to assemble DMA instructions.  */
+
+static void
+assemble_dma (str)
+     char *str;
+{
+  DVP_INSN insn_buf[2];
+  /* Insn's length, in 32 bit words.  */
+  int len;
+  /* Pointer to allocated frag.  */
+  char *f;
+  int i;
+  const dvp_opcode *opcode;
+
+  if (output_dma)
+    {
+      /* Do an implicit alignment to a 16 byte boundary.
+	 Do it now so that inline dma data labels are at the right place.  */
+      /* ??? One can certainly argue all this implicit alignment is
+	 questionable.  The thing is assembler programming is all that will
+	 mostly likely ever be done and not doing so forces an extra [and
+	 arguably unnecessary] burden on the programmer.
+	 ??? On the other hand this automagic alignment requires the supremely
+	 grotesque last_label_seen hack.  Assembler macros may have been a
+	 better way to go.  */
+      frag_align (4, 0, 0);
+      record_alignment (now_seg, 4);
+
+      /* Advance up the immediately preceding label if present.  */
+      if (last_label_seen)
+	{
+	  assert (S_GET_SEGMENT (last_label_seen) == now_seg);
+	  last_label_seen-&gt;sy_frag = frag_now;
+	  S_SET_VALUE (last_label_seen, frag_now_fix ());
+	}
+    }
+
+  /* This is the DMA tag.  */
+  insn_buf[0] = 0;
+  insn_buf[1] = 0;
+
+  opcode = assemble_one_insn (DVP_DMA,
+			      dma_opcode_lookup_asm (str), dma_operands,
+			      0, 0, &amp;str, insn_buf);
+  if (opcode == NULL)
+    return;
+  if (!output_dma)
+    return;
+
+  record_mach (DVP_DMA, 0);
+
+  f = frag_more (8);
+
+  /* Write out the DMA instruction. */
+  for (i = 0; i &lt; 2; ++i)
+    md_number_to_chars (f + i * 4, insn_buf[i], 4);
+
+  /* Create any fixups.  */
+  /* FIXME: It might eventually be possible to combine all the various
+     copies of this bit of code.  */
+  for (i = 0; i &lt; fixup_count; ++i)
+    {
+      int op_type, reloc_type, offset;
+      const dvp_operand *operand;
+
+      /* Create a fixup for this operand.
+	 At this point we do not use a bfd_reloc_code_real_type for
+	 operands residing in the insn, but instead just use the
+	 operand index.  This lets us easily handle fixups for any
+	 operand type, although that is admittedly not a very exciting
+	 feature.  We pick a BFD reloc type in md_apply_fix.  */
+
+      op_type = fixups[i].opindex;
+      offset = fixups[i].offset;
+      reloc_type = encode_fixup_reloc_type (DVP_DMA, op_type);
+      operand = &amp;dma_operands[op_type];
+      fix_new_exp (frag_now, f + offset - frag_now-&gt;fr_literal, 4,
+		   &amp;fixups[i].exp,
+		   (operand-&gt;flags &amp; DVP_OPERAND_RELATIVE_BRANCH) != 0,
+		   (bfd_reloc_code_real_type) reloc_type);
+    }
+
+  /* The upper two words are vif insns.  */
+  record_mach (DVP_VIF, 0);
+
+  /* If not doing dma/vif packing, fill out the insn with vif nops.
+     ??? We take advantage of the fact that the default fill value of zero
+     is the vifnop insn.  This occurs for example when handling mpg
+     alignment.  It also occurs when one dma tag immediately follows the
+     previous one.  */
+  if (! dma_pack_vif_p)
+    {
+      f = frag_more (8);
+      md_number_to_chars (f + 0, VIFNOP, 4);
+      md_number_to_chars (f + 4, VIFNOP, 4);
+    }
+}
+
+/* Subroutine of md_assemble to assemble VIF instructions.  */
+
+static void
+assemble_vif (str)
+     char *str;
+{
+  /* Space for the instruction.
+     The variable length insns can require much more space than this.
+     It is allocated later, when we know we have such an insn.  */
+  DVP_INSN insn_buf[5];
+  /* Insn's length, in 32 bit words.  */
+  int len;
+  /* Pointer to allocated frag.  */
+  char *f;
+  int i,wl,cl;
+  const dvp_opcode *opcode;
+  fragS * insn_frag;
+  /* Name of file to read data from.  */
+  const char *file;
+  /* Length in 32 bit words.  */
+  int data_len;
+  /* Macro expansion, if there is one.  */
+  char * macstr;
+
+  /* First check for macros.  */
+  macstr = dvp_expand_macro (vif_macros, vif_macro_count, str);
+  if (macstr)
+    {
+      /* The macro may expand into several insns (delimited with '\n'),
+	 so loop.  */
+      char * next = macstr;
+      do
+	{
+	  char *p = strchr (next, '\n');
+	  if (p)
+	    *p = 0;
+	  assemble_vif (next);
+	  next = p ? p + 1 : 0;
+	}
+      while (next);
+      free (macstr);
+      return;
+    }
+
+  opcode = assemble_one_insn (DVP_VIF,
+			      vif_opcode_lookup_asm (str), vif_operands,
+			      0, 0, &amp;str, insn_buf);
+  if (opcode == NULL)
+    return;
+
+  if (opcode-&gt;flags &amp; VIF_OPCODE_LENVAR)
+    len = 1; /* actual data follows later */
+  else if (opcode-&gt;flags &amp; VIF_OPCODE_LEN2)
+    len = 2;
+  else if (opcode-&gt;flags &amp; VIF_OPCODE_LEN5)
+    len = 5;
+  else
+    len = 1;
+
+  /* We still have to switch modes (if mpg for example) so we can't exit
+     early if -no-vif.  */
+
+  if (output_vif)
+    {
+      /* Record the mach before doing the alignment so that we properly
+	 disassemble any inserted vifnop's.  For mpg and direct insns
+	 force the recording of the mach type for the next insn.  The data
+	 will switch the mach type and we want to ensure it's switched
+	 back.  */
+
+      if (opcode-&gt;flags &amp; (VIF_OPCODE_MPG | VIF_OPCODE_DIRECT))
+	record_mach (DVP_VIF, 1);
+      else
+	record_mach (DVP_VIF, 0);
+
+      /* For variable length instructions record a fixup that is the symbol
+	 marking the end of the data.  eval_expr will queue the fixup
+	 which will then be emitted later.  */
+      if (opcode-&gt;flags &amp; VIF_OPCODE_LENVAR)
+	{
+	  char *name;
+
+	  asprintf (&amp;name, "%s%s", LOCAL_LABEL_PREFIX,
+		    unique_name ("varlen"));
+	  vif_data_end = symbol_new (name, now_seg, 0, 0);
+	  symbol_table_insert (vif_data_end);
+	  fixups[fixup_count].cpu = DVP_VIF;
+	  fixups[fixup_count].exp.X_op = O_symbol;
+	  fixups[fixup_count].exp.X_add_symbol = vif_data_end;
+	  fixups[fixup_count].exp.X_add_number = 0;
+	  fixups[fixup_count].opindex = vif_operand_datalen_special;
+	  fixups[fixup_count].offset = 0;
+
+	  /* See what the user specified.  */
+	  vif_get_var_data (&amp;file, &amp;data_len);
+	  if (file)
+	    data_len = -1;
+	  fixups[fixup_count].user_value = data_len;
+	  /* Get the wl,cl values.  Only useful for the unpack insn but
+	     it doesn't hurt to always record them.  */
+	  vif_get_wl_cl (&amp;wl, &amp;cl);
+	  fixups[fixup_count].wl = wl;
+	  fixups[fixup_count].cl = cl;
+	  ++fixup_count;
+	}
+
+      /* Obtain space in which to store the instruction.  */
+
+      if (opcode-&gt;flags &amp; VIF_OPCODE_MPG)
+	{
+	  /* The data must be aligned on a 64 bit boundary (so the mpg insn
+	     comes just before that 64 bit boundary).
+	     Do this by putting the mpg insn in a relaxable fragment
+	     with a symbol that marks the beginning of the aligned data.  */
+
+	  /* Ensure relaxable fragments are in their own fragment.
+	     Otherwise md_apply_fix3 mishandles fixups to insns earlier
+	     in the fragment (because we set fr_opcode for the `mpg' insn
+	     because it can move in the fragment).  */
+	  frag_wane (frag_now);
+	  frag_new (0);
+
+	  /* One could combine the previous two lines with the following.
+	     They're not for clarity: keep separate the actions being
+	     performed.  */
+
+	  /* This dance with frag_grow is so we can record frag_now in
+	     insn_frag.  frag_var always changes frag_now.  We must allocate
+	     the maximal amount of space we need so there's room to move
+	     the insn in the frag during relaxation.  */
+	  frag_grow (8);
+	  /* Allocate space for the fixed part.  */
+	  f = frag_more (4);
+	  insn_frag = frag_now;
+
+	  frag_var (rs_machine_dependent,
+		    4, /* max chars */
+		    0, /* variable part is empty at present */
+		    RELAX_MPG, /* subtype */
+		    NULL, /* no symbol */
+		    0, /* offset */
+		    f); /* opcode */
+
+	  frag_align (3, 0, 0);
+	  record_alignment (now_seg, 3);
+
+	  /* Put a symbol at the start of data.  The relaxation code uses
+	     this to figure out how many bytes to insert.  $.mpgloc
+	     calculations use it.  The disassembler uses it.  The overlay
+	     tracking table uses it.
+	     Update $.mpgloc.
+	     Create an overlay section.  */
+	  {
+	    int mpgloc = vif_get_mpgloc ();
+	    const char * section_name;
+
+	    /* Update $.mpgloc if explicitly set.
+	       Otherwise just use the current value.  */
+	    if (mpgloc != -1)
+	      {
+		/* The value is recorded in bytes, mpgloc is in dwords.  */
+		mpgloc_sym = expr_build_uconstant (mpgloc * 8);
+		S_SET_OTHER (mpgloc_sym, STO_DVP_VU);
+	      }
+
+	    section_name = vuoverlay_section_name (mpgloc_sym);
+	    vif_data_start = create_colon_label (STO_DVP_VU,
+#if 0
+						 VUOVERLAY_START_PREFIX,
+#else
+						 LOCAL_LABEL_PREFIX,
+#endif
+						 section_name);
+	    insn_frag-&gt;fr_symbol = vif_data_start;
+
+	    create_vuoverlay_section (section_name, mpgloc_sym,
+				      vif_data_start, vif_data_end);
+	  }
+	}
+      else if (opcode-&gt;flags &amp; VIF_OPCODE_DIRECT)
+	{
+	  /* The data must be aligned on a 128 bit boundary (so the direct insn
+	     comes just before that 128 bit boundary).
+	     Do this by putting the direct insn in a relaxable fragment.
+	     with a symbol that marks the beginning of the aligned data.  */
+
+	  /* Ensure relaxable fragments are in their own fragment.
+	     Otherwise md_apply_fix3 mishandles fixups to insns earlier
+	     in the fragment (because we set fr_opcode for the `direct' insn
+	     because it can move in the fragment).  */
+	  frag_wane (frag_now);
+	  frag_new (0);
+
+	  /* One could combine the previous two lines with the following.
+	     They're not for clarity: keep separate the actions being
+	     performed.  */
+
+	  /* This dance with frag_grow is so we can record frag_now in
+	     insn_frag.  frag_var always changes frag_now.  We must allocate
+	     the maximal amount of space we need so there's room to move
+	     the insn in the frag during relaxation.  */
+	  frag_grow (16);
+	  /* Allocate space for the fixed part.  */
+	  f = frag_more (4);
+	  insn_frag = frag_now;
+
+	  frag_var (rs_machine_dependent,
+		    12, /* max chars */
+		    0, /* variable part is empty at present */
+		    RELAX_DIRECT, /* subtype */
+		    NULL, /* no symbol */
+		    0, /* offset */
+		    f); /* opcode */
+
+	  frag_align (4, 0, 0);
+	  record_alignment (now_seg, 4);
+
+	  /* Put a symbol at the start of data.  The relaxation code uses
+	     this to figure out how many bytes to insert.  */
+	  vif_data_start = create_colon_label (0, LOCAL_LABEL_PREFIX,
+					       unique_name ("direct"));
+	  insn_frag-&gt;fr_symbol = vif_data_start;
+	}
+      else if (opcode-&gt;flags &amp; VIF_OPCODE_UNPACK)
+	{
+	  f = frag_more (len * 4);
+	  insn_frag = frag_now;
+	  /* Put a symbol at the start of data.  $.unpackloc calculations
+	     use it.  */
+	  /* ??? $.unpackloc is gone.  Is this also used for data length
+	     verification?  */
+	  vif_data_start = create_colon_label (STO_DVP_VIF, LOCAL_LABEL_PREFIX,
+					       unique_name ("unpack"));
+	}
+      else
+	{
+	  /* Reminder: it is important to fetch enough space in one call to
+	     `frag_more'.  We use (f - frag_now-&gt;fr_literal) to compute where
+	     we are and we don't want frag_now to change between calls.  */
+	  f = frag_more (len * 4);
+	  insn_frag = frag_now;
+	}
+
+      /* Write out the instruction.  */
+      for (i = 0; i &lt; len; ++i)
+	md_number_to_chars (f + i * 4, insn_buf[i], 4);
+
+      /* Create any fixups.  */
+      /* FIXME: It might eventually be possible to combine all the various
+	 copies of this bit of code.  */
+      for (i = 0; i &lt; fixup_count; ++i)
+	{
+	  int op_type, reloc_type, offset;
+	  const dvp_operand *operand;
+	  fixS *fixP;
+
+	  /* Create a fixup for this operand.
+	     At this point we do not use a bfd_reloc_code_real_type for
+	     operands residing in the insn, but instead just use the
+	     operand index.  This lets us easily handle fixups for any
+	     operand type, although that is admittedly not a very exciting
+	     feature.  We pick a BFD reloc type in md_apply_fix.  */
+
+	  op_type = fixups[i].opindex;
+	  offset = fixups[i].offset;
+	  reloc_type = encode_fixup_reloc_type (DVP_VIF, op_type);
+	  operand = &amp;vif_operands[op_type];
+	  fixP = fix_new_exp (insn_frag, f + offset - insn_frag-&gt;fr_literal, 4,
+			      &amp;fixups[i].exp,
+			      (operand-&gt;flags &amp; DVP_OPERAND_RELATIVE_BRANCH) != 0,
+			      (bfd_reloc_code_real_type) reloc_type);
+	  fixP-&gt;tc_fix_data.user_value = fixups[i].user_value;
+	  fixP-&gt;tc_fix_data.wl = fixups[i].wl;
+	  fixP-&gt;tc_fix_data.cl = fixups[i].cl;
+
+	  /* Set fx_tcbit so other parts of the code know this fixup is for
+	     a vif insn.  */
+	  fixP-&gt;fx_tcbit = 1;
+	}
+    }
+
+  /* Handle variable length insns.  */
+
+  if (opcode-&gt;flags &amp; VIF_OPCODE_LENVAR)
+    {
+      /* See what the user specified.  */
+      vif_get_var_data (&amp;file, &amp;data_len);
+
+      if (file)
+	{
+	  int byte_len;
+
+	  /* The handling for each of mpg,direct,unpack is basically the same:
+	     - emit a label to set the mach type for the data we're inserting
+	     - switch to the new assembler state
+	     - insert the file
+	     - call the `end' handler  */
+
+	  if (opcode-&gt;flags &amp; VIF_OPCODE_MPG)
+	    {
+	      record_mach (DVP_VUUP, 1);
+	      set_asm_state (ASM_MPG, "mpg");
+	      byte_len = insert_file (file, insert_mpg_marker, 0, 256 * 8);
+	      s_endmpg (ENDMPG_INTERNAL);
+	    }
+	  else if (opcode-&gt;flags &amp; VIF_OPCODE_DIRECT)
+	    {
+	      record_mach (DVP_GIF, 1);
+	      set_asm_state (ASM_DIRECT, "direct");
+	      byte_len = insert_file (file, NULL, 0, 0);
+	      s_enddirect (1);
+	    }
+	  else if (opcode-&gt;flags &amp; VIF_OPCODE_UNPACK)
+	    {
+	      int max_len = 0; /*unpack_max_byte_len (insn_buf[0]);*/
+	      set_asm_state (ASM_UNPACK, "unpack");
+	      byte_len = insert_file (file, NULL /*insert_unpack_marker*/,
+				      insn_buf[0], max_len);
+	      s_endunpack (1);
+	    }
+	  else
+	    as_fatal ("internal error: unknown cpu type for variable length vif insn");
+	}
+      else /* file == NULL */
+	{
+	  /* data_len == -1 means the value must be computed from
+	     the data.  */
+	  if (data_len &lt;= -2)
+	    as_bad ("invalid data length");
+
+	  if (output_vif &amp;&amp; data_len != -1)
+	    install_vif_length (f, data_len);
+
+	  if (opcode-&gt;flags &amp; VIF_OPCODE_MPG)
+	    {
+	      set_asm_state (ASM_MPG, "mpg");
+	      /* Enable automatic mpg insertion every 256 insns.  */
+	      vu_count = 0;
+	    }
+	  else if (opcode-&gt;flags &amp; VIF_OPCODE_DIRECT)
+	    set_asm_state (ASM_DIRECT, "direct");
+	  else if (opcode-&gt;flags &amp; VIF_OPCODE_UNPACK)
+	    set_asm_state (ASM_UNPACK, "unpack");
+	}
+    }
+}
+
+/* Subroutine of md_assemble to assemble GIF instructions.
+   We assume CUR_ASM_STATE is one of ASM_{INIT,DIRECT,UNPACK}.  */
+
+static void
+assemble_gif (str)
+     char *str;
+{
+  DVP_INSN insn_buf[4];
+  const dvp_opcode *opcode;
+  char *f;
+  int i;
+
+  insn_buf[0] = insn_buf[1] = insn_buf[2] = insn_buf[3] = 0;
+
+  opcode = assemble_one_insn (DVP_GIF,
+			      gif_opcode_lookup_asm (str), gif_operands,
+			      0, 0, &amp;str, insn_buf);
+  if (opcode == NULL)
+    return;
+
+  /* Do an implicit alignment to a 16 byte boundary.  */
+  frag_align (4, 0, 0);
+  record_alignment (now_seg, 4);
+
+  /* Advance up the immediately preceding label if present.  */
+  if (last_label_seen)
+    {
+      assert (S_GET_SEGMENT (last_label_seen) == now_seg);
+      last_label_seen-&gt;sy_frag = frag_now;
+      S_SET_VALUE (last_label_seen, frag_now_fix ());
+    }
+
+  /* Insert a label so we can compute the number of quadwords when the
+     .endgif is seen.  This is put before the mach type label because gif
+     insns are followed by data and we don't want the disassembler to try
+     to disassemble them as mips insns (since it uses the st_other field)
+     of the closest label to choose the mach type and since we don't have
+     a special st_other value for "data".  */
+  gif_data_name = S_GET_NAME (create_colon_label (0, LOCAL_LABEL_PREFIX,
+						  unique_name ("gifdata")));
+
+  record_mach (DVP_GIF, 1);
+
+  gif_insn_frag_loc = f = frag_more (16);
+  gif_insn_frag = frag_now;
+  for (i = 0; i &lt; 4; ++i)
+    md_number_to_chars (f + i * 4, insn_buf[i], 4);
+
+  /* Record the type of the gif tag so we know how to compute nloop
+     in s_endgif.  */
+  if (strcmp (opcode-&gt;mnemonic, "gifpacked") == 0)
+    gif_insn_type = GIF_PACKED;
+  else if (strcmp (opcode-&gt;mnemonic, "gifreglist") == 0)
+    gif_insn_type = GIF_REGLIST;
+  else if (strcmp (opcode-&gt;mnemonic, "gifimage") == 0)
+    gif_insn_type = GIF_IMAGE;
+  else
+    abort ();
+  push_asm_state (ASM_GIF);
+}
+
+/* Subroutine of md_assemble to assemble VU instructions.  */
+
+static void
+assemble_vu (str)
+     char *str;
+{
+  int i;
+  char *f;
+  const dvp_opcode *opcode;
+  /* The lower instruction has the lower address so insns[0] = lower insn,
+     insns[1] = upper insn.  */
+  DVP_INSN insns[2];
+  fragS * insn_frag;
+
+  /* Handle automatic mpg insertion if enabled.  */
+  if (CUR_ASM_STATE == ASM_MPG
+      &amp;&amp; vu_count == 256)
+    insert_mpg_marker (0);
+
+  /* Do an implicit alignment to a 8 byte boundary.  */
+  frag_align (3, 0, 0);
+  record_alignment (now_seg, 3);
+
+  /* Advance up the immediately preceding label if present.  */
+  if (last_label_seen)
+    {
+      assert (S_GET_SEGMENT (last_label_seen) == now_seg);
+      last_label_seen-&gt;sy_frag = frag_now;
+      S_SET_VALUE (last_label_seen, frag_now_fix ());
+
+      /* Do the same for the copy in vu space.
+	 Note that there won't be one if the file is all vu code.  */
+      if (last_label_seen2)
+	{
+	  symbolS * cur_mpgloc = compute_mpgloc (mpgloc_sym, vif_data_start,
+						 expr_build_dot ());
+	  last_label_seen2-&gt;sy_value = cur_mpgloc-&gt;sy_value;
+	}
+    }
+
+  record_mach (DVP_VUUP, 0);
+
+#ifdef VERTICAL_BAR_SEPARATOR
+  char *p = strchr (str, '|');
+
+  if (p == NULL)
+    {
+      as_bad ("lower instruction missing");
+      return;
+    }
+
+  *p = 0;
+  opcode = assemble_one_insn (DVP_VUUP,
+			      vu_upper_opcode_lookup_asm (str), vu_operands,
+			      0, 4, &amp;str, &amp;insns[1]);
+  *p = '|';
+  str = p + 1;
+#else
+  opcode = assemble_one_insn (DVP_VUUP,
+			     vu_upper_opcode_lookup_asm (str), vu_operands,
+			     0, 4, &amp;str, &amp;insns[1]);
+#endif
+
+  /* Don't assemble next one if we couldn't assemble the first.  */
+  if (opcode == NULL)
+    return;
+
+  if (*str == 0)
+    {
+      as_bad ("lower instruction missing");
+      return;
+    }
+
+  /* Assemble the lower insn.
+     Pass `fixup_count' for `init_fixup_count' so that we don't clobber
+     any fixups the upper insn had.  */
+  opcode = assemble_one_insn (DVP_VULO,
+			      vu_lower_opcode_lookup_asm (str), vu_operands,
+			      fixup_count, 0, &amp;str, &amp;insns[0]);
+  if (opcode == NULL)
+    return;
+
+  /* If there were fixups and we're inside mpg, create a machine dependent
+     fragment so that we can record the current value of $.mpgloc in fr_symbol.
+     Reminder: it is important to fetch enough space in one call to
+     `frag_more'.  We use (f - frag_now-&gt;fr_literal) to compute where
+     we are and we don't want frag_now to change between calls.  */
+  if (fixup_count != 0
+      &amp;&amp; CUR_ASM_STATE == ASM_MPG)
+    {
+      symbolS * cur_mpgloc;
+
+      /* Ensure we get a new frag.  */
+      frag_wane (frag_now);
+      frag_new (0);
+
+      /* Compute the current $.mpgloc.  */
+      cur_mpgloc = compute_mpgloc (mpgloc_sym, vif_data_start,
+				   expr_build_dot ());
+
+      /* We need to use frag_now afterwards, so we can't just call frag_var.
+	 Instead we use frag_more and save the value of frag_now in
+	 insn_frag.  */
+      f = frag_more (8);
+      insn_frag = frag_now;
+      /* Turn the frag into a machine dependent frag.  */
+      frag_variant (rs_machine_dependent,
+		    0, /* max chars */
+		    0, /* no variable part */
+		    RELAX_VU, /* subtype */
+		    cur_mpgloc, /* $.mpgloc */
+		    0, /* offset */
+		    NULL); /* opcode */
+    }
+  else
+    {
+      f = frag_more (8);
+      insn_frag = frag_now;
+    }
+
+  /* Write out the instructions.  */
+  md_number_to_chars (f, insns[0], 4);
+  md_number_to_chars (f + 4, insns[1], 4);
+
+  /* Create any fixups.  */
+  for (i = 0; i &lt; fixup_count; ++i)
+    {
+      int op_type, reloc_type;
+      const dvp_operand *operand;
+      dvp_cpu cpu;
+
+      /* Create a fixup for this operand.
+	 At this point we do not use a bfd_reloc_code_real_type for
+	 operands residing in the insn, but instead just use the
+	 operand index.  This lets us easily handle fixups for any
+	 operand type, although that is admittedly not a very exciting
+	 feature.  We pick a BFD reloc type in md_apply_fix.  */
+
+      cpu = fixups[i].cpu;
+      op_type = fixups[i].opindex;
+      reloc_type = encode_fixup_reloc_type (cpu, op_type);
+      operand = &amp;vu_operands[op_type];
+
+      /* Branch operands inside mpg have to be handled specially.
+	 We want a pc relative relocation in a section different from our own.
+	 See the br-2.s dejagnu testcase for a good example.  */
+      if (CUR_ASM_STATE == ASM_MPG
+	  &amp;&amp; (operand-&gt;flags &amp; DVP_OPERAND_RELATIVE_BRANCH) != 0)
+	{
+	  symbolS *e1,*e2,*diff_expr;
+
+	  /* For "br foo" we want "foo - (. + 8)".  */
+	  e1 = expr_build_binary (O_add, insn_frag-&gt;fr_symbol,
+				  expr_build_uconstant (8));
+	  e2 = make_expr_symbol (&amp;fixups[i].exp);
+	  diff_expr = expr_build_binary (O_subtract, e2, e1);
+	  fixups[i].exp.X_op = O_symbol; 
+	  fixups[i].exp.X_add_symbol = diff_expr;
+	  fixups[i].exp.X_add_number = 0;
+	}
+
+      fix_new_exp (insn_frag, f + fixups[i].offset - insn_frag-&gt;fr_literal, 4,
+		   &amp;fixups[i].exp,
+		   CUR_ASM_STATE == ASM_MPG /* pcrel */
+		   ? 0
+		   : (operand-&gt;flags &amp; DVP_OPERAND_RELATIVE_BRANCH) != 0,
+		   (bfd_reloc_code_real_type) reloc_type);
+    }
+
+  /* If this was the "loi" pseudo-insn, we need to set the `i' bit.  */
+  if (strcmp (opcode-&gt;mnemonic, "loi") == 0)
+    f[7] |= 0x80;
+
+  /* Increment the vu insn counter.
+     If get reach 256 we need to insert an `mpg'.  */
+  ++vu_count;
+}
+
+/* Assemble one instruction at *PSTR.
+   CPU indicates what component we're assembling for.
+   The assembled instruction is stored in INSN_BUF.
+   OPCODE is a pointer to the head of the hash chain.
+   INIT_FIXUP_COUNT is the initial value for `fixup_count'.
+   It exists to allow the fixups for multiple calls to this insn to be
+   queued up before actually emitting them.
+   *PSTR is updated to point passed the parsed instruction.
+
+   If the insn is successfully parsed the result is a pointer to the opcode
+   entry that successfully matched and *PSTR is updated to point passed
+   the parsed insn.  If an error occurs the result is NULL and *PSTR is left
+   at some random point in the string (??? may wish to leave it pointing where
+   the error occured).  */
+
+static const dvp_opcode *
+assemble_one_insn (cpu, opcode, operand_table, init_fixup_count, fixup_offset,
+		   pstr, insn_buf)
+     dvp_cpu cpu;
+     const dvp_opcode *opcode;
+     const dvp_operand *operand_table;
+     int init_fixup_count;
+     int fixup_offset;
+     char **pstr;
+     DVP_INSN *insn_buf;
+{
+  char *start, *str;
+
+  /* Keep looking until we find a match.  */
+
+  start = str = *pstr;
+  for ( ; opcode != NULL; opcode = DVP_OPCODE_NEXT_ASM (opcode))
+    {
+      int past_opcode_p, num_suffixes;
+      const unsigned char *syn;
+
+      /* Ensure the mnemonic part matches.  */
+      for (str = start, syn = opcode-&gt;mnemonic; *syn != '\0'; ++str, ++syn)
+	if (tolower (*str) != tolower (*syn))
+	  break;
+      if (*syn != '\0')
+	continue;
+
+      /* Scan the syntax string.  If it doesn't match, try the next one.  */
+
+      dvp_opcode_init_parse ();
+      insn_buf[opcode-&gt;opcode_word] = opcode-&gt;value;
+      fixup_count = init_fixup_count;
+      past_opcode_p = 0;
+      num_suffixes = 0;
+
+      /* We don't check for (*str != '\0') here because we want to parse
+	 any trailing fake arguments in the syntax string.  */
+      for (/*str = start, */ syn = opcode-&gt;syntax; *syn != '\0'; )
+	{
+	  int mods,index;
+	  const dvp_operand *operand;
+	  const char *errmsg;
+	  long value;
+
+	  /* Non operand chars must match exactly.
+	     Operand chars that are letters are not part of symbols
+	     and are case insensitive.  */
+	  if (*syn &lt; 128)
+	    {
+	      if (tolower (*str) == tolower (*syn))
+		{
+		  if (*syn == ' ')
+		    past_opcode_p = 1;
+		  ++syn;
+		  ++str;
+		}
+	      else
+		break;
+	      continue;
+	    }
+
+	  /* We have a suffix or an operand.  Pick out any modifiers.  */
+	  mods = 0;
+	  index = DVP_OPERAND_INDEX (*syn);
+	  while (DVP_MOD_P (operand_table[index].flags))
+	    {
+	      mods |= operand_table[index].flags &amp; DVP_MOD_BITS;
+	      ++syn;
+	      index = DVP_OPERAND_INDEX (*syn);
+	    }
+	  operand = operand_table + index;
+
+	  if (operand-&gt;flags &amp; DVP_OPERAND_FAKE)
+	    {
+	      long value = 0;
+
+	      if (operand-&gt;flags &amp; DVP_OPERAND_DMA_INLINE)
+		{
+		  inline_dma_data ((mods &amp; DVP_OPERAND_AUTOCOUNT) != 0,
+				  insn_buf);
+		  ++syn;
+		  continue;
+		}
+
+	      if (operand-&gt;parse)
+		{
+		  errmsg = NULL;
+		  value = (*operand-&gt;parse) (opcode, operand, mods,
+					     &amp;str, &amp;errmsg);
+		  if (errmsg)
+		    break;
+		}
+	      if (operand-&gt;insert)
+		{
+		  errmsg = NULL;
+		  (*operand-&gt;insert) (opcode, operand, mods, insn_buf,
+				      (offsetT) value, &amp;errmsg);
+		  /* If we get an error, go on to try the next insn.  */
+		  if (errmsg)
+		    break;
+		}
+	      ++syn;
+	      continue;
+	    }
+
+	  /* Are we finished with suffixes?  */
+	  if (!past_opcode_p)
+	    {
+	      long suf_value;
+
+	      if (!(operand-&gt;flags &amp; DVP_OPERAND_SUFFIX))
+		as_fatal ("internal error: bad opcode table, missing suffix flag");
+
+	      /* Parse the suffix.  If we're at a space in the input string
+		 there are no more suffixes.  Suffix parse routines must be
+		 prepared to deal with this.  */
+	      errmsg = NULL;
+	      suf_value = (*operand-&gt;parse) (opcode, operand, mods, &amp;str,
+					     &amp;errmsg);
+	      if (errmsg)
+		{
+		  /* This can happen, for example, in ARC's in "blle foo" and
+		     we're currently using the template "b%q%.n %j".  The "bl"
+		     insn occurs later in the table so "lle" isn't an illegal
+		     suffix.  */
+		  break;
+		}
+
+	      /* Insert the suffix's value into the insn.  */
+	      insert_operand (cpu, opcode, operand, mods, insn_buf,
+			      (offsetT) suf_value, &amp;errmsg);
+
+	      ++syn;
+	      continue;
+	    }
+
+	  /* This is an operand, either a register or an expression of
+	     some kind.  */
+
+	  value = 0;
+
+	  if (operand-&gt;flags &amp; DVP_OPERAND_SUFFIX)
+	    as_fatal ("internal error: bad opcode table, suffix wrong");
+
+	  /* Is there anything left to parse?
+	     We don't check for this at the top because we want to parse
+	     any trailing fake arguments in the syntax string.  */
+	  /* ??? This doesn't allow operands with a legal value of "".  */
+	  if (*str == '\0')
+	    break;
+
+	  /* Parse the operand.  */
+	  if (operand-&gt;flags &amp; DVP_OPERAND_FLOAT)
+	    {
+	      errmsg = 0;
+	      value = parse_float (&amp;str, &amp;errmsg);
+	      if (errmsg)
+		break;
+	    }
+	  else if ((operand-&gt;flags &amp; DVP_OPERAND_DMA_ADDR)
+		   &amp;&amp; (mods &amp; DVP_OPERAND_AUTOCOUNT))
+	    {
+	      errmsg = 0;
+	      value = parse_dma_addr_autocount (opcode, operand, mods,
+						insn_buf, &amp;str, &amp;errmsg);
+	      if (errmsg)
+		break;
+	    }
+	  else
+	    {
+	      char *origstr,*hold;
+	      expressionS exp;
+
+	      /* First see if there is a special parser.  */
+	      origstr = str;
+	      if (operand-&gt;parse)
+		{
+		  errmsg = NULL;
+		  value = (*operand-&gt;parse) (opcode, operand, mods,
+					     &amp;str, &amp;errmsg);
+		  if (errmsg)
+		    break;
+		}
+
+	      /* If there wasn't a special parser, or there was and it
+		 left the input stream unchanged, use the general
+		 expression parser.  */
+	      if (str == origstr)
+		{
+		  hold = input_line_pointer;
+		  input_line_pointer = str;
+		  /* Set cur_{opcode,operand} for md_operand.  */
+		  cur_opcode = opcode;
+		  cur_operand = operand;
+		  expression (&amp;exp);
+		  cur_opcode = NULL;
+		  str = input_line_pointer;
+		  input_line_pointer = hold;
+
+		  if (exp.X_op == O_illegal
+		      || exp.X_op == O_absent)
+		    break;
+		  else if (exp.X_op == O_constant)
+		    value = exp.X_add_number;
+		  else if (exp.X_op == O_register)
+		    as_fatal ("internal error: got O_register");
+		  else
+		    {
+		      /* We need to generate a fixup for this expression.  */
+		      if (fixup_count &gt;= MAX_FIXUPS)
+			as_fatal ("internal error: too many fixups");
+		      fixups[fixup_count].cpu = cpu;
+		      fixups[fixup_count].exp = exp;
+		      fixups[fixup_count].opindex = index;
+		      /* FIXME: Revisit.  Do we really need operand-&gt;word?
+			 The endianness of a 128 bit DMAtag is rather
+			 twisted.  How about defining word 0 as the word with
+			 the lowest address and basing operand-shift off that.
+			 operand-&gt;word could then be deleted.  */
+		      fixups[fixup_count].offset = fixup_offset;
+		      if (operand-&gt;word != 0)
+			fixups[fixup_count].offset += operand-&gt;word * 4;
+		      else
+			fixups[fixup_count].offset += (operand-&gt;shift / 32) * 4;
+		      ++fixup_count;
+		      value = 0;
+		    }
+		}
+	    }
+
+	  /* Insert the register or expression into the instruction.  */
+	  errmsg = NULL;
+	  insert_operand (cpu, opcode, operand, mods, insn_buf,
+			  (offsetT) value, &amp;errmsg);
+	  if (errmsg != (const char *) NULL)
+	    break;
+
+	  ++syn;
+	}
+
+      /* If we're at the end of the syntax string, we're done.  */
+      if (*syn == '\0')
+	{
+	  int i;
+
+	  /* For the moment we assume a valid `str' can only contain blanks
+	     now.  IE: We needn't try again with a longer version of the
+	     insn and it is assumed that longer versions of insns appear
+	     before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
+
+	  while (isspace (*str))
+	    ++str;
+
+	  if (*str != '\0'
+#ifndef VERTICAL_BAR_SEPARATOR
+	      &amp;&amp; cpu != DVP_VUUP
+#endif
+	      )
+	    as_bad ("junk at end of line: `%s'", str);
+
+	  /* It's now up to the caller to emit the instruction and any
+	     relocations.  */
+	  *pstr = str;
+	  return opcode;
+	}
+
+      /* Try the next entry.  */
+    }
+
+  as_bad ("bad instruction `%s'", start);
+  return 0;
+}
+
+/* Given a dvp cpu type, return it's STO_DVP value.
+   The label prefix to use is stored in *PNAME.  */
+
+static int
+cpu_sto (cpu, pname)
+     dvp_cpu cpu;
+     const char **pname;
+{
+  switch (cpu)
+    {
+    case DVP_DMA : *pname = ".dma."; return STO_DVP_DMA;
+    case DVP_VIF : *pname = ".vif."; return STO_DVP_VIF;
+    case DVP_GIF : *pname = ".gif."; return STO_DVP_GIF;
+    case DVP_VUUP : *pname = ".vu."; return STO_DVP_VU;
+    }
+  abort ();
+}
+
+/* Record the current mach type in the object file.
+   If FORCE_NEXT_P is non-zero, force a label to be emitted the next time
+   we're called.  This is useful for variable length instructions that can
+   have labels embedded within them.  */
+
+static void
+record_mach (cpu, force_next_p)
+     dvp_cpu cpu;
+     int force_next_p;
+{
+  symbolS *label;
+  const char *name;
+  int sto;
+
+  if (cpu == cur_cpu)
+    return;
+
+  sto = cpu_sto (cpu, &amp;name);
+
+  label = create_colon_label (sto, "", unique_name (name));
+
+  if (force_next_p)
+    cur_cpu = DVP_UNKNOWN;
+  else
+    cur_cpu = cpu;
+}
+
+/* Force emission of mach type label at next insn.
+   This isn't static as TC_START_LABEL uses it.
+   The result is the value of TC_START_LABEL.  */
+
+int
+force_mach_label ()
+{
+  cur_cpu = DVP_UNKNOWN;
+  return 1;
+}
+
+/* Push the current parsing state to NEW_STATE.  */
+
+static void
+push_asm_state (new_state)
+     asm_state new_state;
+{
+  asm_state cur_state = CUR_ASM_STATE;
+
+  ++cur_state_level;
+  if (cur_state_level == MAX_STATE_DEPTH)
+    as_fatal ("internal error: unexpected state push");
+  asm_state_stack[cur_state_level] = new_state;
+}
+
+/* TOP_OK_P is non-zero if it's ok that we're at the top of the stack.
+   If so we reset the state to ASM_INIT.  */
+
+static void
+pop_asm_state (top_ok_p)
+     int top_ok_p;
+{
+  if (cur_state_level == 0)
+    {
+      if (! top_ok_p)
+	as_fatal ("internal error: unexpected state pop");
+      CUR_ASM_STATE = ASM_INIT;
+    }
+  else
+    --cur_state_level;
+}
+
+/* Set the top level assembler state.  */
+
+static void
+set_asm_state (state, insn_name)
+     asm_state state;
+     const char *insn_name;
+{
+  if (insn_name)
+    {
+      if (CUR_ASM_STATE != ASM_INIT)
+	as_bad ("illegal place for `%s' instruction", insn_name);
+    }
+  cur_state_level = 0;
+  CUR_ASM_STATE = state;
+}
+
+void 
+md_operand (expressionP)
+     expressionS *expressionP;
+{
+  /* Check if this is a '*' for mpgloc.  */
+  if (cur_opcode
+      &amp;&amp; (cur_opcode-&gt;flags &amp; VIF_OPCODE_MPG) != 0
+      &amp;&amp; (cur_operand-&gt;flags &amp; DVP_OPERAND_VU_ADDRESS) != 0
+      &amp;&amp; *input_line_pointer == '*')
+    {
+      expressionP-&gt;X_op = O_symbol;
+      expressionP-&gt;X_add_symbol = mpgloc_sym;
+      expressionP-&gt;X_add_number = 0;
+
+      /* Advance over the '*'.  */
+      ++input_line_pointer;
+      return;
+    }
+}
+
+valueT
+md_section_align (segment, size)
+     segT segment;
+     valueT size;
+{
+  int align = bfd_get_section_alignment (stdoutput, segment);
+  return ((size + (1 &lt;&lt; align) - 1) &amp; (-1 &lt;&lt; align));
+}
+
+symbolS *
+md_undefined_symbol (name)
+  char *name;
+{
+  return 0;
+}
+
+/* Called before parsing each line via md_start_line_hook.  */
+
+void
+dvp_start_line_hook ()
+{
+  /* If we've advanced since the last label seen, reset it.  */
+  if (last_label_seen
+      &amp;&amp; (now_seg != S_GET_SEGMENT (last_label_seen)
+	  || frag_now != last_label_seen-&gt;sy_frag
+	  || frag_now_fix () != S_GET_VALUE (last_label_seen)))
+    {
+      last_label_seen = NULL;
+      last_label_seen2 = NULL;
+    }
+}
+
+/* Called after parsing the file via md_after_pass_hook.  */
+
+void
+dvp_after_pass_hook ()
+{
+  /* If doing dma packing, ensure the last dma tag is filled out.  */
+  if (dma_pack_vif_p)
+    {
+      /* Nothing to do as vifnops are zero and frag_align at beginning
+	 of dmatag is all we need.  */
+    }
+
+#if 0 /* ??? Doesn't work unless we keep track of the nested include file
+	 level.  */
+  /* Check for missing .EndMpg, and supply one if necessary.  */
+  if (CUR_ASM_STATE == ASM_MPG)
+    s_endmpg (ENDMPG_INTERNAL);
+  else if (CUR_ASM_STATE == ASM_DIRECT)
+    s_enddirect (0);
+  else if (CUR_ASM_STATE == ASM_UNPACK)
+    s_endunpack (0);
+#endif
+}
+
+/* Called after parsing all files via md_end.  */
+
+void
+dvp_end ()
+{
+  /* Check for missing .EndMpg, etc.  */
+  if (CUR_ASM_STATE == ASM_MPG)
+    as_bad ("missing `.endmpg'");
+  else if (CUR_ASM_STATE == ASM_DIRECT)
+    as_bad ("missing `.enddirect'");
+  else if (CUR_ASM_STATE == ASM_UNPACK)
+    as_bad ("missing `.endunpack'");
+}
+
+/* Called via tc_frob_label when a label is defined.  */
+
+void
+dvp_frob_label (sym)
+     symbolS *sym;
+{
+  const char * name = S_GET_NAME (sym);
+  /* Non-zero if SYM is a user specified label.  */
+  int user_label_p =
+    (
+     /* Not sure how we can distinguish them other than by some prefix.  */
+     *name != '.' &amp;&amp; *name != '$'
+     /* -gstabs creates FAKE_LABEL_NAME labels.  */
+     &amp;&amp; ! S_IS_LOCAL (sym)
+     /* Check for recursive invocation creating the _$name.  */
+     &amp;&amp; strncmp (name, VU_LABEL_PREFIX, sizeof (VU_LABEL_PREFIX) - 1) != 0
+     /* Machine generated labels to mark the start of overlays.  */
+     &amp;&amp; strncmp (name, VUOVERLAY_START_PREFIX, sizeof (VUOVERLAY_START_PREFIX) - 1) != 0
+     );
+
+  /* All labels in vu code must be specially marked for the disassembler.
+     The disassembler ignores all previous information at each new label
+     (that has an address higher than the last one).  */
+  if (CUR_ASM_STATE == ASM_MPG
+      || CUR_ASM_STATE == ASM_VU)
+    S_SET_OTHER (sym, STO_DVP_VU);
+
+  if (! user_label_p)
+    return;
+
+  /* If inside an mpg, move vu space labels to their own section and create
+     the corresponding _$ version in normal space.  */
+
+  if (CUR_ASM_STATE == ASM_MPG)
+    {
+      /* Move this symbol to the vu overlay.  */
+      symbolS * cur_mpgloc = compute_mpgloc (mpgloc_sym, vif_data_start,
+					     expr_build_dot ());
+#if 0 /* Don't do this now, leave in ABS and then move to overlay
+	 section before file is written.  */
+      S_SET_SEGMENT (sym, vuoverlay_section);
+#else
+      /* Record the overlay section this symbol is in.  */
+      {
+	ovlysymS *p = (ovlysymS *) xmalloc (sizeof (ovlysymS));
+	p-&gt;next = ovlysym_table;
+	p-&gt;sec = vuoverlay_section;
+	p-&gt;sym = sym;
+	ovlysym_table = p;
+      }
+      S_SET_SEGMENT (sym, expr_section);
+#endif
+      sym-&gt;sy_value = cur_mpgloc-&gt;sy_value;
+      sym-&gt;sy_frag = &amp;zero_address_frag;
+
+      /* Save for later automagic alignment.  */
+      last_label_seen2 = sym;
+
+      /* Create the _$ symbol in normal space.
+	 This is the one we store in last_label_seen (and not last_label_seen2)
+	 because when the need for automagic alignment is queried, we want
+	 now_seg == S_GET_GETMENT (last_label_seen).  */
+      last_label_seen = create_colon_label (STO_DVP_VU, VU_LABEL_PREFIX, name);
+    }
+  else
+    {
+      /* Save for later automagic alignment.  */
+      last_label_seen = sym;
+      last_label_seen2 = NULL;
+    }
+}
+
+/* Move vu space symbols into their overlay sections.
+   Called via tc_frob_file.  */
+
+void
+dvp_frob_file ()
+{
+  ovlysymS *p;
+
+  for (p = ovlysym_table; p; p = p-&gt;next)
+    {
+      /* See the comment near tc_frob_file in write.c.
+	 We are responsible for updating sym-&gt;bsym-&gt;value.  */
+      S_SET_SEGMENT (p-&gt;sym, p-&gt;sec);
+      /* Adjust for the section's vma.  */
+      /* FIXME: bfd doesn't get this right, it adds the section vma
+	 back in (in elf.c:swap_out_syms).  As a workaround the
+	 section vma is assumed to be zero.  Of course, there might
+	 not be a point in setting it to non-zero anyway.  */
+      p-&gt;sym-&gt;bsym-&gt;value -= bfd_get_section_vma (stdoutput, p-&gt;sec);
+    }
+}
+
+/* mpg/direct alignment is handled via relaxation */
+
+/* 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;
+{
+  /* Our initial estimate is always 0.  */
+  return 0;
+} 
+
+/* Perform the relaxation.
+   STRETCH is the amount the start of the frag has already been shifted by.
+   All we have to do is figure out how many bytes we need to insert to
+   get to the recorded symbol (which is at the required alignment).
+   This function is also called for machine dependent vu insn frags.
+   In this case the growth is always 0.  */
+
+long
+dvp_relax_frag (fragP, stretch)
+     fragS * fragP;
+     long stretch;
+{
+  /* Address of variable part.  */
+  long address = fragP-&gt;fr_address + fragP-&gt;fr_fix;
+  /* Symbol marking start of data.  */
+  symbolS * symbolP = fragP-&gt;fr_symbol;
+  /* Address of the symbol.  */
+  long target;
+  long growth;
+
+  /* subtype &gt;= 10 means "done" */
+  if (RELAX_DONE_P (fragP-&gt;fr_subtype))
+    return 0;
+
+  /* vu insn? */
+  if (fragP-&gt;fr_subtype == RELAX_VU)
+    {
+      fragP-&gt;fr_subtype = RELAX_ENCODE (RELAX_VU, 0);
+      return 0;
+    }
+
+  target = S_GET_VALUE (symbolP) + symbolP-&gt;sy_frag-&gt;fr_address;
+
+  if (fragP-&gt;fr_subtype == RELAX_MPG)
+    {
+      /* The frag the symbol is in hasn't been relaxed yet so any .org
+	 adjustments haven't been applied to it.  We know the symbol
+	 is the address of the next frag so adjust target by stretch.  */
+      target += stretch;
+      growth = target - address;
+      if (growth &lt; 0)
+	as_fatal ("internal error: bad mpg alignment handling");
+      fragP-&gt;fr_subtype = RELAX_ENCODE (RELAX_MPG, growth);
+      return growth;
+    }
+
+  if (fragP-&gt;fr_subtype == RELAX_DIRECT)
+    {
+      /* The frag the symbol is in hasn't been relaxed yet so any .org
+	 adjustments haven't been applied to it.  We know the symbol
+	 is the address of the next frag so adjust target by stretch.  */
+      target += stretch;
+      growth = target - address;
+      if (growth &lt; 0)
+	as_fatal ("internal error: bad direct alignment handling");
+      fragP-&gt;fr_subtype = RELAX_ENCODE (RELAX_DIRECT, growth);
+      return growth;
+    }
+
+  as_fatal ("internal error: unknown fr_subtype");
+}
+
+/* *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-&gt;fr_type == rs_machine_dependent.
+   fragP-&gt;fr_subtype is the subtype of what the address relaxed to.  */
+
+void
+md_convert_frag (abfd, sec, fragP)
+  bfd * abfd;
+  segT sec;
+  fragS * fragP;
+{
+  int growth = RELAX_GROWTH (fragP-&gt;fr_subtype);
+
+  fragP-&gt;fr_fix += growth;
+
+  if (growth != 0)
+    {
+      /* We had to grow this fragment.  Shift the mpg/direct insn to the end
+	 (so it abuts the following data).  */
+      DVP_INSN insn = bfd_getl32 (fragP-&gt;fr_opcode);
+      md_number_to_chars (fragP-&gt;fr_opcode, VIFNOP, 4);
+      if (growth &gt; 4)
+	md_number_to_chars (fragP-&gt;fr_opcode + 4, VIFNOP, 4);
+      if (growth &gt; 8)
+	md_number_to_chars (fragP-&gt;fr_opcode + 8, VIFNOP, 4);
+      md_number_to_chars (fragP-&gt;fr_literal + fragP-&gt;fr_fix - 4, insn, 4);
+
+      /* Adjust fr_opcode so md_apply_fix3 works with the right bytes.  */
+      fragP-&gt;fr_opcode += growth;
+    }
+}
+
+/* Functions concerning relocs.  */
+
+/* Spacing between each cpu type's operand numbers.
+   Should be at least as big as any operand table.  */
+#define RELOC_SPACING 256
+
+/* Given a cpu type and operand number, return a temporary reloc type
+   for use in generating the fixup that encodes the cpu type and operand
+   number.  */
+
+static int
+encode_fixup_reloc_type (cpu, opnum)
+     dvp_cpu cpu;
+     int opnum;
+{
+  return (int) BFD_RELOC_UNUSED + ((int) cpu * RELOC_SPACING) + opnum;
+}
+
+/* Given a fixup reloc type, decode it into cpu type and operand.  */
+
+static void
+decode_fixup_reloc_type (fixup_reloc, cpuP, operandP)
+     int fixup_reloc;
+     dvp_cpu *cpuP;
+     const dvp_operand **operandP;
+{
+  dvp_cpu cpu = (fixup_reloc - (int) BFD_RELOC_UNUSED) / RELOC_SPACING;
+  int opnum = (fixup_reloc - (int) BFD_RELOC_UNUSED) % RELOC_SPACING;
+
+  *cpuP = cpu;
+  switch (cpu)
+    {
+    case DVP_VUUP : *operandP = &amp;vu_operands[opnum]; break;
+    case DVP_VULO : *operandP = &amp;vu_operands[opnum]; break;
+    case DVP_DMA : *operandP = &amp;dma_operands[opnum]; break;
+    case DVP_VIF : *operandP = &amp;vif_operands[opnum]; break;
+    case DVP_GIF : *operandP = &amp;gif_operands[opnum]; break;
+    default : as_fatal ("internal error: bad fixup encoding");
+    }
+}
+
+/* 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-&gt;fx_addsy != (symbolS *) NULL
+      &amp;&amp; (! S_IS_DEFINED (fixP-&gt;fx_addsy)
+	  || S_GET_SEGMENT (fixP-&gt;fx_addsy) != sec))
+    {
+      /* If fx_tcbit is set this is for a vif insn and thus should never
+	 happen in correct code.  */
+      /* ??? The error message could be a bit more descriptive.  */
+      if (fixP-&gt;fx_tcbit)
+	as_bad ("unable to compute length of vif insn");
+      /* The symbol is undefined (or is defined but not in this section).
+	 Let the linker figure it out.  +8: branch offsets are relative to the
+	 delay slot.  */
+      return 8;
+    }
+
+  /* If fx_tcbit is set, this is a vif end-of-variable-length-insn marker.
+     In this case the offset is relative to the start of data.
+     Otherwise we assume this is a vu branch.  In this case
+     offsets are calculated based on the address of the next insn.  */
+  if (fixP-&gt;fx_tcbit)
+    {
+      /* As a further refinement, if fr_opcode is NULL this is `unpack'
+	 which doesn't involve any relaxing.  */
+      if (fixP-&gt;fx_frag-&gt;fr_opcode == NULL)
+	return fixP-&gt;fx_frag-&gt;fr_address + fixP-&gt;fx_where + 4;
+      else
+	return fixP-&gt;fx_frag-&gt;fr_address + fixP-&gt;fx_frag-&gt;fr_fix;
+    }
+  else
+    return ((fixP-&gt;fx_frag-&gt;fr_address + fixP-&gt;fx_where) &amp; -8L) + 8;
+}
+
+/* Apply a fixup to the object code.  This is called for all the
+   fixups we generated by calls to fix_new_exp.  At this point all symbol
+   values should be fully resolved, and we attempt to completely resolve the
+   reloc.  If we can not do that, we determine the correct reloc code and put
+   it back in the fixup.  */
+
+void
+md_apply_fix3 (fixP, valueP, seg)
+     fixS *fixP;
+     valueT *valueP;
+     segT seg;
+{
+  char *where = fixP-&gt;fx_frag-&gt;fr_literal + fixP-&gt;fx_where;
+  valueT value;
+
+  /* FIXME FIXME FIXME: The value we are passed in *valueP includes
+     the symbol values.  Since we are using BFD_ASSEMBLER, if we are
+     doing this relocation the code in write.c is going to call
+     bfd_perform_relocation, which is also going to use the symbol
+     value.  That means that if the reloc is fully resolved we want to
+     use *valueP since bfd_perform_relocation is not being used.
+     However, if the reloc is not fully resolved we do not want to use
+     *valueP, and must use fx_offset instead.  However, if the reloc
+     is PC relative, we do want to use *valueP since it includes the
+     result of md_pcrel_from.  This is confusing.  */
+
+  if (fixP-&gt;fx_addsy == (symbolS *) NULL)
+    {
+      value = *valueP;
+      fixP-&gt;fx_done = 1;
+    }
+  else if (fixP-&gt;fx_pcrel)
+    {
+      value = *valueP;
+    }
+  /* If this is for mpgloc and the value is a label in vu space, we
+     know its value.  We don't handle emitting a relocation for this
+     so handle it specially here.
+     The test of fx_tcbit is a quick test to avoid unnecessary cpu.  */
+  else if (fixP-&gt;fx_tcbit
+	   &amp;&amp; fixP-&gt;fx_r_type == encode_fixup_reloc_type (DVP_VIF, vif_operand_mpgloc)
+	   &amp;&amp; vuoverlay_section_p (S_GET_SEGMENT (fixP-&gt;fx_addsy)))
+    {
+      value = *valueP;
+    }
+  else
+    {
+      value = fixP-&gt;fx_offset;
+      if (fixP-&gt;fx_subsy != (symbolS *) NULL)
+	{
+	  if (S_GET_SEGMENT (fixP-&gt;fx_subsy) == absolute_section)
+	    value -= S_GET_VALUE (fixP-&gt;fx_subsy);
+	  else
+	    {
+	      /* We can't actually support subtracting a symbol.  */
+	      as_bad_where (fixP-&gt;fx_file, fixP-&gt;fx_line,
+			    "expression too complex");
+	    }
+	}
+    }
+
+  /* Check for dvp operands.  These are indicated with a reloc value
+     &gt;= BFD_RELOC_UNUSED.  */
+
+  if ((int) fixP-&gt;fx_r_type &gt;= (int) BFD_RELOC_UNUSED)
+    {
+      dvp_cpu cpu;
+      const dvp_operand *operand;
+      DVP_INSN insn;
+      fragS *fragP = fixP-&gt;fx_frag;
+
+      /* If this was a relaxable insn, the opcode may have moved.  Find it.  */
+      if (fragP-&gt;fr_opcode != NULL)
+	where = fragP-&gt;fr_opcode;
+
+      decode_fixup_reloc_type ((int) fixP-&gt;fx_r_type,
+			       &amp; cpu, &amp; operand);
+
+      /* For variable length vif insn data lengths, validate the user specified
+	 value or install the computed value in the instruction.  */
+      if (cpu == DVP_VIF
+	  &amp;&amp; (operand - vif_operands) == vif_operand_datalen_special)
+	{
+	  int insn_type = vif_insn_type (where[3]);
+	  value = vif_length_value (where[3],
+				    fixP-&gt;tc_fix_data.wl, fixP-&gt;tc_fix_data.cl,
+				    value);
+	  if (fixP-&gt;tc_fix_data.user_value != -1)
+	    {
+	      /* We can't do this for unpack insns with wl &gt; cl.  */
+	      if ((insn_type != VIF_OPCODE_UNPACK
+		   || (fixP-&gt;tc_fix_data.wl &lt;= fixP-&gt;tc_fix_data.cl))
+		  &amp;&amp; fixP-&gt;tc_fix_data.user_value != value)
+		as_warn_where (fixP-&gt;fx_file, fixP-&gt;fx_line,
+			       "specified length value doesn't match computed value");
+	      /* Don't override the user specified value.  */
+	    }
+	  else
+	    {
+	      if (output_vif)
+		{
+		  install_vif_length (where, value);
+		}
+	    }
+	  fixP-&gt;fx_done = 1;
+	  return 1;
+	}
+
+      /* For the gif nloop operand, if it was specified by the user ensure
+	 it matches the value we computed.  */
+      if (cpu == DVP_GIF
+	  &amp;&amp; (operand - gif_operands) == gif_operand_nloop)
+	{
+	  value = compute_nloop (fixP-&gt;tc_fix_data.type,
+				 fixP-&gt;tc_fix_data.nregs,
+				 value);
+	  if (fixP-&gt;tc_fix_data.user_value != -1)
+	    {
+	      check_nloop (fixP-&gt;tc_fix_data.type,
+			   fixP-&gt;tc_fix_data.nregs,
+			   fixP-&gt;tc_fix_data.user_value,
+			   value,
+			   fixP-&gt;fx_file, fixP-&gt;fx_line);
+	      /* Don't override the user specified value.  */
+	      fixP-&gt;fx_done = 1;
+	      return 1;
+	    }
+	}
+
+      /* ??? It might be cleaner to not do this at all here (when ! fx_done)
+	 and leave it to bfd_install_relocation.  */
+      if ((operand-&gt;flags &amp; DVP_OPERAND_RELOC_U15_S3) != 0)
+	value &gt;&gt;= 3;
+      else if ((operand-&gt;flags &amp; DVP_OPERAND_RELOC_11_S4) != 0)
+	value &gt;&gt;= 4;
+
+      /* Fetch the instruction, insert the fully resolved operand
+	 value, and stuff the instruction back again.  The fixup is recorded
+	 at the appropriate word so pass DVP_MOD_THIS_WORD so any offset
+	 specified in the tables is ignored.  */
+      insn = bfd_getl32 ((unsigned char *) where);
+      insert_operand_final (cpu, operand, DVP_MOD_THIS_WORD, &amp;insn,
+			    (offsetT) value, fixP-&gt;fx_file, fixP-&gt;fx_line);
+      bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
+
+      /* If this is mpgloc/unpackloc, we're done.  */
+      if (operand-&gt;flags &amp; (DVP_OPERAND_VU_ADDRESS | DVP_OPERAND_UNPACK_ADDRESS))
+	fixP-&gt;fx_done = 1;
+
+      if (fixP-&gt;fx_done)
+	{
+	  /* Nothing else to do here.  */
+	  return 1;
+	}
+
+      /* Determine a BFD reloc value based on the operand information.
+	 We are only prepared to turn a few of the operands into relocs.  */
+      if ((operand-&gt;flags &amp; DVP_OPERAND_RELATIVE_BRANCH) != 0)
+	{
+	  assert (operand-&gt;bits == 11
+		  &amp;&amp; operand-&gt;shift == 0);
+
+	  /* The fixup isn't recorded as a pc relative branch to some label.
+	     Instead a complicated expression is used to compute the desired
+	     value.  Well, that didn't work and we have to emit a reloc.
+	     Things are tricky because the result we want is the difference
+	     of two addresses in a section potentially different from the one
+	     the reloc is in.  Ugh.
+	     The solution is to emit two relocs, one that adds the target
+	     address and one that subtracts the source address + 8 (the
+	     linker will perform the byte-&gt;dword conversion).
+	     This is rather complicated and rather than risk breaking
+	     existing code we fall back on the old way if the file only
+	     contains vu code.  In this case the file is intended to
+	     be fully linked with other vu code and thus we have a normal
+	     situation where the relocation directly corresponds to the
+	     branch insn.  */
+
+	  if (non_vu_insn_seen_p)
+	    {
+	      as_bad_where (fixP-&gt;fx_file, fixP-&gt;fx_line,
+			    "can't handle mpg loaded vu code with branch relocations");
+	      fixP-&gt;fx_done = 1;
+	      return 1;
+	    }
+	  else
+	    {
+	      fixP-&gt;fx_r_type = BFD_RELOC_MIPS_DVP_11_PCREL;
+	    }
+	}
+      else if ((operand-&gt;flags &amp; DVP_OPERAND_DMA_ADDR) != 0
+	       || (operand-&gt;flags &amp; DVP_OPERAND_DMA_NEXT) != 0)
+	{
+	  assert (operand-&gt;bits == 27
+		  &amp;&amp; operand-&gt;shift == 4);
+	  fixP-&gt;fx_r_type = BFD_RELOC_MIPS_DVP_27_S4;
+	}
+      else if ((operand-&gt;flags &amp; DVP_OPERAND_RELOC_11_S4) != 0)
+	{
+	  assert (operand-&gt;bits == 11
+		  &amp;&amp; operand-&gt;shift == 0);
+	  fixP-&gt;fx_r_type = BFD_RELOC_MIPS_DVP_11_S4;
+	  /* ??? bfd_install_relocation will duplicate what we've done to
+	     install the addend, so tell it not to.  This is an instance
+	     where setting partial_inplace to true has some use.  */
+	  value = 0;
+	}
+      else if ((operand-&gt;flags &amp; DVP_OPERAND_RELOC_U15_S3) != 0)
+	{
+	  assert (operand-&gt;bits == 15
+		  &amp;&amp; operand-&gt;shift == 0);
+	  fixP-&gt;fx_r_type = BFD_RELOC_MIPS_DVP_U15_S3;
+	  /* ??? bfd_install_relocation will duplicate what we've done to
+	     install the addend, so tell it not to.  This is an instance
+	     where setting partial_inplace to true has some use.  */
+	  value = 0;
+	}
+      else
+	{
+	  as_bad_where (fixP-&gt;fx_file, fixP-&gt;fx_line,
+			"unresolved expression that must be resolved");
+	  fixP-&gt;fx_done = 1;
+	  return 1;
+	}
+    }
+  else if (fixP-&gt;fx_done)
+    {
+      /* We're finished with this fixup.  Install it because
+	 bfd_install_relocation won't be called to do it.  */
+      switch (fixP-&gt;fx_r_type)
+	{
+	case BFD_RELOC_8:
+	  md_number_to_chars (where, value, 1);
+	  break;
+	case BFD_RELOC_16:
+	  md_number_to_chars (where, value, 2);
+	  break;
+	case BFD_RELOC_32:
+	  md_number_to_chars (where, value, 4);
+	  break;
+	case BFD_RELOC_64:
+	  md_number_to_chars (where, value, 8);
+	  break;
+	default:
+	  as_fatal ("internal error: unexpected fixup");
+	}
+    }
+  else
+    {
+      /* bfd_install_relocation will be called to finish things up.  */
+    }
+
+  /* Tuck `value' away for use by tc_gen_reloc.
+     See the comment describing fx_addnumber in write.h.  */
+  fixP-&gt;fx_addnumber = value;
+
+  return 1;
+}
+
+/* Translate internal representation of relocation info to BFD target
+   format.  */
+
+arelent *
+tc_gen_reloc (section, fixP)
+     asection *section;
+     fixS *fixP;
+{
+  arelent *reloc;
+
+  reloc = (arelent *) xmalloc (sizeof (arelent));
+
+  reloc-&gt;sym_ptr_ptr = &amp;fixP-&gt;fx_addsy-&gt;bsym;
+  reloc-&gt;address = fixP-&gt;fx_frag-&gt;fr_address + fixP-&gt;fx_where;
+  reloc-&gt;howto = bfd_reloc_type_lookup (stdoutput, fixP-&gt;fx_r_type);
+  if (reloc-&gt;howto == (reloc_howto_type *) NULL)
+    {
+      as_bad_where (fixP-&gt;fx_file, fixP-&gt;fx_line,
+		    "internal error: can't export reloc type %d (`%s')",
+		    fixP-&gt;fx_r_type, bfd_get_reloc_code_name (fixP-&gt;fx_r_type));
+      return NULL;
+    }
+
+  if (!fixP-&gt;fx_pcrel != !reloc-&gt;howto-&gt;pc_relative)
+    {
+      as_bad_where (fixP-&gt;fx_file, fixP-&gt;fx_line,
+		    fixP-&gt;fx_pcrel
+		    ? "PC-relative reloc not supported here"
+		    : "PC-relative reloc required here");
+      return NULL;
+    }
+
+  reloc-&gt;addend = fixP-&gt;fx_addnumber;
+
+  return reloc;
+}
+
+/* Write a value out to the object file, using the appropriate endianness.  */
+
+void
+md_number_to_chars (buf, val, n)
+     char *buf;
+     valueT val;
+     int n;
+{
+  if (target_big_endian)
+    number_to_chars_bigendian (buf, val, n);
+  else
+    number_to_chars_littleendian (buf, val, n);
+}
+
+/* Turn a string in input_line_pointer into a floating point constant of type
+   type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
+   emitted is stored in *sizeP .  An error message is returned, or NULL on OK.
+*/
+
+/* 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,prec;
+  LITTLENUM_TYPE words[MAX_LITTLENUMS];
+  LITTLENUM_TYPE *wordP;
+  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);
+
+  if (target_big_endian)
+    {
+      for (i = 0; i &lt; prec; i++)
+	{
+	  md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE));
+	  litP += sizeof (LITTLENUM_TYPE);
+	}
+    }
+  else
+    {
+      for (i = prec - 1; i &gt;= 0; i--)
+	{
+	  md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE));
+	  litP += sizeof (LITTLENUM_TYPE);
+	}
+    }
+     
+  return 0;
+}
+
+/* Miscellaneous utilities.  */
+
+/* Parse a 32 bit floating point number.
+   The result is those 32 bits as an integer.  */
+
+static long
+parse_float (pstr, errmsg)
+     char **pstr;
+     const char **errmsg;
+{
+  if ((*pstr)[0] == '0'
+      &amp;&amp; ((*pstr)[1] == 'x' || (*pstr)[1] == 'X'))
+    {
+      long value;
+      (*pstr) += 2;
+      value = strtoul (*pstr, pstr, 16);
+      return value;
+    }
+  else
+    {
+      LITTLENUM_TYPE words[MAX_LITTLENUMS];
+      if ((*pstr)[0] == '0'
+	  &amp;&amp; isalpha ((*pstr)[1]))
+	(*pstr) += 2;
+      *pstr = atof_ieee (*pstr, 'f', words);
+      return (words[0] &lt;&lt; 16) | words[1];
+    }
+}
+
+/* Scan a symbol and return a pointer to one past the end.  */
+
+#define issymchar(ch) (isalnum(ch) || ch == '_')
+static char *
+scan_symbol (sym)
+    char *sym;
+{
+  while (*sym &amp;&amp; issymchar (*sym))
+    ++sym;
+  return sym;
+}
+
+/* Evaluate an expression for an operand.
+   The result is the value of the expression if it can be evaluated,
+   or 0 if it cannot (say because some symbols haven't been defined yet)
+   in which case a fixup is queued.
+
+   If OPINDEX is 0, don't queue any fixups, just return 0.  */
+
+static long
+#ifdef USE_STDARG
+eval_expr (dvp_cpu cpu, int opindex, int offset, const char *fmt, ...)
+#else
+eval_expr (cpu, opindex, offset, fmt, va_alist)
+     dvp_cpu cpu;
+     int opindex,offset;
+     const char *fmt;
+     va_dcl
+#endif
+{
+  long value;
+  va_list ap;
+  char *str,*save_input;
+  expressionS exp;
+
+#ifdef USE_STDARG
+  va_start (ap, fmt);
+#else
+  va_start (ap);
+#endif
+  vasprintf (&amp;str, fmt, ap);
+  va_end (ap);
+
+  save_input = input_line_pointer;
+  input_line_pointer = str;
+  expression (&amp;exp);
+  input_line_pointer = save_input;
+  free (str);
+  if (exp.X_op == O_constant)
+    value = exp.X_add_number;
+  else
+    {
+      if (opindex != 0)
+	{
+	  fixups[fixup_count].cpu = cpu;
+	  fixups[fixup_count].exp = exp;
+	  fixups[fixup_count].opindex = opindex;
+	  fixups[fixup_count].offset = offset;
+	  fixups[fixup_count].user_value = -1;
+	  fixups[fixup_count].wl = -1;
+	  fixups[fixup_count].cl = -1;
+	  ++fixup_count;
+	}
+      value = 0;
+    }
+  return value;
+}
+
+/* Create a label named by concatenating PREFIX to NAME.  */
+
+static symbolS *
+create_label (prefix, name)
+     const char *prefix, *name;
+{
+  int namelen = strlen (name);
+  int prefixlen = strlen (prefix);
+  char *fullname;
+  symbolS *result;
+
+  fullname = xmalloc (prefixlen + namelen + 1);
+  strcpy (fullname, prefix);
+  strcat (fullname, name);
+  result = symbol_find_or_make (fullname);
+  free (fullname);
+  return result;
+}
+
+/* Create a label named by concatenating PREFIX to NAME,
+   and define it as `.'.
+   STO, if non-zero, is the st_other value to assign to this label.
+   If STO is zero `cur_cpu', call force_mach_label to force record_mach to
+   emit a cpu label.  Otherwise the disassembler gets confused.  */
+
+static symbolS *
+create_colon_label (sto, prefix, name)
+     int sto;
+     const char *prefix, *name;
+{
+  int namelen = strlen (name);
+  int prefixlen = strlen (prefix);
+  char *fullname;
+  symbolS *result;
+
+  fullname = xmalloc (prefixlen + namelen + 1);
+  strcpy (fullname, prefix);
+  strcat (fullname, name);
+  result = colon (fullname);
+  if (sto)
+    S_SET_OTHER (result, sto);
+  else
+    force_mach_label ();
+  free (fullname);
+  return result;
+}
+
+/* Return a malloc'd string useful in creating unique labels.
+   PREFIX is the prefix to use or NULL if we're to pick one.  */
+
+static char *
+unique_name (prefix)
+     const char *prefix;
+{
+  static int counter;
+  char *result;
+
+  if (prefix == NULL)
+    prefix = UNIQUE_LABEL_PREFIX;
+  asprintf (&amp;result, "%s%d", prefix, counter);
+  ++counter;
+  return result;
+}
+
+/* VU support.  */
+
+/* Return a boolean indicating if SEG is a vu overlay section.  */
+
+static int
+vuoverlay_section_p (seg)
+     segT seg;
+{
+  return (strncmp (segment_name (seg), SHNAME_DVP_OVERLAY_PREFIX,
+		   sizeof (SHNAME_DVP_OVERLAY_PREFIX) - 1)
+	  == 0);
+}
+
+/* Return the name of the overlay section.
+   It must be unique among all overlays in the executable.  */
+
+static char *
+vuoverlay_section_name (addr)
+     symbolS *addr;
+{
+  char *section_name;
+  char *file;
+  unsigned int lineno;
+  unsigned int fileno;
+  /* One mpg may actually result in several, counter keeps track of this.  */
+  static int counter;
+
+  as_where (&amp;file, &amp;lineno);
+  for (fileno = 0; *file; ++file)
+    fileno = (fileno &lt;&lt; 1) + *file;
+  if (addr-&gt;sy_value.X_op == O_constant)
+    asprintf (&amp;section_name, "%s.0x%x.%u.%u.%d", SHNAME_DVP_OVERLAY_PREFIX,
+	      (int) S_GET_VALUE (addr), fileno, lineno, counter);
+  else
+    asprintf (&amp;section_name, "%s.unknvma.%u.%u.%d", SHNAME_DVP_OVERLAY_PREFIX,
+	      fileno, lineno, counter);
+  ++counter;
+  return section_name;
+}
+
+/* Create a shadow section for VU code that starts at ADDR in vu space.
+   START_LABEL and END_LABEL, if non-NULL, are symbols marking the start and
+   end of the section.  If NULL, no overlay tracking information is output.  */
+
+static void
+create_vuoverlay_section (section_name, addr, start_label, end_label)
+     const char *section_name;
+     /* Remember, expressions are recorded as symbols.  */
+     symbolS *addr;
+     symbolS *start_label, *end_label;
+{
+  /* Must preserve the current seg/subseg.  */
+  segT orig_seg = now_seg;
+  subsegT orig_subseg = now_subseg;
+
+  /* Create and get handle of a vu overlay section.  All vu symbols go here.
+     The section name must be unique in the entire executable.
+     We achieve this by encoding the source file name and file number.  Ick.
+     ??? A cleaner way would be if mpg took a new argument that named the
+     overlay.  */
+  vuoverlay_section = subseg_new (section_name, 0);
+  bfd_set_section_flags (stdoutput, vuoverlay_section, SEC_CODE);
+  /* There's no point in setting the section vma as we can't get the linker
+     to preserve it.  But what the heck ...  It might be useful to the
+     objdump user.  */
+#if 0  /* FIXME: bfd's elf.c:swap_out_syms always emits symbol values with
+	  the section vma added in so we can't do this.  */
+  if (addr-&gt;sy_value.X_op == O_constant)
+    bfd_set_section_vma (stdoutput, vuoverlay_section, S_GET_VALUE (addr));
+#endif
+
+#if 1
+  /* Create a symbol marking the start of the section.
+     This is different than START_LABEL as this one is for gdb.
+     It needs a symbol to start a section so we give it one.
+     This one could be combined with START_LABEL, but I haven't since
+     they serve different purposes.  */
+  {
+    symbolS * gdb_start_sym;
+    gdb_start_sym = create_colon_label (STO_DVP_VU, VUOVERLAY_START_PREFIX,
+					section_name);
+    gdb_start_sym-&gt;sy_value = addr-&gt;sy_value;
+  }
+#endif
+
+  /* The size of the section won't be known until we see the .endmpg,
+     but we can compute it from the start and end labels.  */
+  /* FIXME: This causes the section to occupy space in the file.  */
+  if (start_label)
+    frag_var (rs_space, 1, 1, (relax_substateT) 0,
+	      expr_build_binary (O_subtract, end_label, start_label),
+	      (offsetT) 0, (char *) 0);
+
+#if 0 /* already done */
+  /* Initialize $.mpgloc.  */
+  mpgloc_sym = expr_build_uconstant (addr);
+  S_SET_OTHER (mpgloc_sym, STO_DVP_VU);
+#endif
+
+#if 0 /* $.mpgloc is kept in the ABS section.  */
+  S_SET_SEGMENT (mpgloc_sym, vuoverlay_section);
+#endif
+
+  /* Add an entry to the vu overlay table.  */
+  if (start_label)
+    {
+      expressionS exp;
+      const char *p;
+      symbolS * name_label;
+
+      /* Put the section name in the overlay string table.  */
+
+      subseg_set (vuoverlay_string_section, 0);
+      name_label = create_colon_label (0, LOCAL_LABEL_PREFIX,
+				       unique_name ("secstr"));
+      /* FIXME: should be a utility to do this.  */
+      for (p = section_name; *p; ++p)
+	FRAG_APPEND_1_CHAR (*p);
+      FRAG_APPEND_1_CHAR (0);
+
+      subseg_set (vuoverlay_table_section, 0);
+
+      /* FIXME: should be a utility to do these.  */
+      /* Offset into string table.  */
+      exp.X_op = O_symbol;
+      exp.X_add_symbol = name_label;
+      exp.X_add_number = 0;
+      emit_expr (&amp;exp, 4);
+
+      /* The section's lma.  */
+      exp.X_op = O_symbol;
+      exp.X_add_symbol = start_label;
+      exp.X_add_number = 0;
+      emit_expr (&amp;exp, 4);
+
+      /* The section's vma.  */
+      exp.X_op = O_symbol;
+      exp.X_add_symbol = addr;
+      exp.X_add_number = 0;
+      emit_expr (&amp;exp, 4);
+    }
+
+  /* Restore the original seg/subseg.  */
+  subseg_set (orig_seg, orig_subseg);
+}
+
+/* Compute a value for $.mpgloc given a symbol at the start of a chunk
+   of code, the $.mpgloc value for the start, and a symbol at the end
+   of the chunk of code.  */
+
+static symbolS *
+compute_mpgloc (startloc, startsym, endsym)
+     symbolS * startloc;
+     symbolS * startsym;
+     symbolS * endsym;
+{
+  symbolS *s;
+
+  s = expr_build_binary (O_subtract, endsym, startsym);
+  s = expr_build_binary (O_add, startloc, s);
+  return s;
+}
+
+/* Compute a value for nloop.  */
+
+static int
+compute_nloop (type, nregs, bytes)
+     gif_type type;
+     int nregs, bytes;
+{
+  int computed_nloop;
+
+  switch (type)
+    {
+    case GIF_PACKED :
+      /* We can't compute a value if no regs were specified and there is a
+	 non-zero amount of data.  Just set to something useful, a warning
+	 will be issued later.  */
+      if (nregs == 0)
+	nregs = 1;
+      computed_nloop = (bytes &gt;&gt; 4) / nregs;
+      break;
+    case GIF_REGLIST :
+      if (nregs == 0)
+	nregs = 1;
+      computed_nloop = (bytes &gt;&gt; 3) / nregs;
+      break;
+    case GIF_IMAGE :
+      computed_nloop = bytes &gt;&gt; 4;
+      break;
+    }
+
+  return computed_nloop;
+}
+
+/* Issue a warning if the user specified nloop value doesn't match the
+   computed value.  */
+
+static void
+check_nloop (type, nregs, user_nloop, computed_nloop, file, line)
+     gif_type type;
+     int nregs,user_nloop,computed_nloop;
+     char *file;
+     unsigned int line;
+{
+  if (user_nloop != computed_nloop)
+    as_warn_where (file, line, "nloop value does not match amount of data");
+}
+
+/* Compute the auto-count value for a DMA tag.
+   INLINE_P is non-zero if the dma data is inline.  */
+
+static void
+setup_dma_autocount (name, insn_buf, inline_p)
+     const char *name;
+     DVP_INSN *insn_buf;
+     int inline_p;
+{
+  long count;
+
+  if (inline_p)
+    {
+      /* -1: The count is the number of following quadwords, so skip the one
+	 containing the dma tag.  */
+      count = eval_expr (DVP_DMA, dma_operand_count, 0,
+			 "((%s%s - %s) &gt;&gt; 4) - 1", END_LABEL_PREFIX, name, name);
+    }
+  else
+    {
+      /* We don't want to subtract 1 here as the begin and end labels
+	 properly surround the data we want to compute the length of.  */
+      count = eval_expr (DVP_DMA, dma_operand_count, 0,
+			 "(%s%s - %s) &gt;&gt; 4", END_LABEL_PREFIX, name, name);
+    }
+
+  /* Store the count field. */
+  insn_buf[0] &amp;= 0xffff0000;
+  insn_buf[0] |= count &amp; 0x0000ffff;
+}
+
+/* Record that inline data follows.  */
+
+static void
+inline_dma_data (autocount_p, insn_buf)
+    int autocount_p;
+    DVP_INSN *insn_buf;
+{
+  if (dma_data_state != 0 )
+    {
+      as_bad ("DmaData blocks cannot be nested.");
+      return;
+    }
+
+  dma_data_state = 1;
+
+  if (autocount_p)
+    {
+      dma_data_name = S_GET_NAME (create_colon_label (0, "", unique_name (NULL)));
+      setup_dma_autocount (dma_data_name, insn_buf, 1);
+    }
+  else
+    dma_data_name = 0;
+}
+
+/* Compute the auto-count value for a DMA tag with out-of-line data.  */
+
+static long
+parse_dma_addr_autocount (opcode, operand, mods, insn_buf, pstr, errmsg)
+    const dvp_opcode *opcode;
+    const dvp_operand *operand;
+    int mods;
+    DVP_INSN *insn_buf;
+    char **pstr;
+    const char **errmsg;
+{
+  char *start = *pstr;
+  char *end = start;
+  long retval;
+  /* Data reference must be a .DmaData label.  */
+  symbolS *label, *label2, *endlabel;
+  const char *name;
+  char c;
+
+  label = label2 = 0;
+  if (! is_name_beginner (*start))
+    {
+      *errmsg = "invalid .DmaData label";
+      return 0;
+    }
+
+  name = start;
+  end = scan_symbol (name);
+  c = *end;
+  *end = 0;
+  label = symbol_find_or_make (name);
+  *end = c;
+
+  /* Use the same prefix as vu labels here.  */
+  label2 = create_label (VU_LABEL_PREFIX, name);
+  endlabel = create_label (END_LABEL_PREFIX, name);
+
+  retval = eval_expr (DVP_DMA, dma_operand_addr, 4, name);
+
+  setup_dma_autocount (name, insn_buf, 0);
+
+  *pstr = end;
+  return retval;
+}
+
+/* Compute the type of vif insn of IBYTE.
+   IBYTE is the msb of the insn.
+   This is only used for mpg,direct,unpack insns.
+   The result is one of VIF_OPCODE_{DIRECT,DIRECTHL,MPG,UNPACK}.  */
+
+static int
+vif_insn_type (ibyte)
+     char ibyte;
+{
+  switch (ibyte &amp; 0x70)
+    {
+    case 0x50 :
+      return (ibyte &amp; 1) ? VIF_OPCODE_DIRECTHL : VIF_OPCODE_DIRECT;
+    case 0x40 :
+      return VIF_OPCODE_MPG;
+    case 0x60 :
+    case 0x70 :
+      return VIF_OPCODE_UNPACK;
+    default :
+      as_fatal ("internal error: bad call to vif_insn_type");
+    }
+}
+
+/* Return the length value to insert in a VIF instruction whose upper
+   byte is IBYTE and whose data length is BYTES.
+   WL,CL are used for unpack insns and are the stcycl values in effect.
+   This does not do the max -&gt; 0 conversion.  */
+
+static int
+vif_length_value (ibyte, wl, cl, bytes)
+     char ibyte;
+     int wl,cl;
+     int bytes;
+{
+  switch (ibyte &amp; 0x70)
+    {
+    case 0x50 : /* direct */
+      /* ??? Worry about data /= 16 cuts off?  */
+      return bytes / 16;
+    case 0x40 : /* mpg */
+      /* ??? Worry about data /= 8 cuts off?  */
+      return bytes / 8;
+    case 0x60 : /* unpack */
+    case 0x70 :
+      return vif_unpack_len_value (ibyte &amp; 15, wl, cl, bytes);
+    default :
+      as_fatal ("internal error: bad call to vif_length_value");
+    }
+}
+
+/* Install length LEN in the vif insn at BUF.
+   LEN is the actual value to store, except that the max-&gt;0 conversion
+   hasn't been done (we do it).
+   The bytes in BUF are in target order.  */
+
+static void
+install_vif_length (buf, len)
+     char *buf;
+     int len;
+{
+  unsigned char ibyte = buf[3];
+
+  if ((ibyte &amp; 0x70) == 0x40)
+    {
+      /* mpg */
+      if (len &gt; 256)
+	as_bad ("`mpg' data length must be between 1 and 256");
+      buf[2] = len == 256 ? 0 : len;
+    }
+  else if ((ibyte &amp; 0x70) == 0x50)
+    {
+      /* direct/directhl */
+      if (len &gt; 65536)
+	as_bad ("`direct' data length must be between 1 and 65536");
+      len = len == 65536 ? 0 : len;
+      buf[0] = len;
+      buf[1] = len &gt;&gt; 8;
+    }
+  else if ((ibyte &amp; 0x60) == 0x60)
+    {
+      /* unpack */
+      /* len == -1 means wl,cl are unknown and thus we can't compute
+	 a useful value */
+      if (len == -1)
+	{
+	  as_bad ("missing `stcycle', can't compute length of `unpack' insn");
+	  len = 1;
+	}
+      if (len &lt; 0 || len &gt; 256)
+	as_bad ("`unpack' data length must be between 0 and 256");
+      /* 256 is recorded as 0 in the insn */
+      len = len == 256 ? 0 : len;
+      buf[2] = len;
+    }
+  else
+    as_fatal ("internal error: bad call to install_vif_length");
+}
+
+/* Finish off the current set of mpg insns, and start a new set.
+   The IGNORE arg exists because insert_unpack_marker uses it and both
+   of these functions are passed to insert_file.  */
+
+static void
+insert_mpg_marker (ignore)
+     unsigned long ignore;
+{
+  s_endmpg (ENDMPG_MIDDLE);
+  /* mpgloc is updated by s_endmpg.  */
+  md_assemble ("mpg *,*");
+  /* Record the cpu type in case we're in the middle of reading binary
+     data.  */
+  record_mach (DVP_VUUP, 0);
+  /* We need a stabs line number entry at the start of the vu code.
+     This has already been called, but too early and we can't stop that.
+     So just emit another.  */
+  generate_lineno_debug ();
+}
+
+/* Finish off the current unpack insn and start a new one.
+   INSN0 is the first word of the insn and is used to figure out what
+   kind of unpack insn it is.  */
+
+static void
+insert_unpack_marker (insn0)
+     unsigned long insn0;
+{
+}
+
+/* Insert a file into the output.
+   The -I arg passed to GAS is used to specify where to find the file.
+   INSERT_MARKER if non-NULL is called every SIZE bytes with an argument of
+   INSERT_MARKER_ARG.  This is used by the mpg insn to insert mpg's every 256
+   insns and by the unpack insn.
+   The result is the number of bytes inserted.
+   If an error occurs an error message is printed and zero is returned.  */
+
+static int
+insert_file (file, insert_marker, insert_marker_arg, size)
+     const char *file;
+     void (*insert_marker) PARAMS ((unsigned long));
+     unsigned long insert_marker_arg;
+     int size;
+{
+  FILE *f;
+  char buf[256];
+  int i, n, total, left_before_marker;
+  char *path;
+
+  path = xmalloc (strlen (file) + include_dir_maxlen + 5 /*slop*/);
+  f = NULL;
+  for (i = 0; i &lt; include_dir_count; i++)
+    {
+      strcpy (path, include_dirs[i]);
+      strcat (path, "/");
+      strcat (path, file);
+      if ((f = fopen (path, FOPEN_RB)) != NULL)
+	break;
+    }
+  free (path);
+  if (f == NULL)
+    f = fopen (file, FOPEN_RB);
+  if (f == NULL)
+    {
+      as_bad ("unable to read file `%s'", file);
+      return 0;
+    }
+
+  total = 0;
+  left_before_marker = 0;
+  do {
+    int bytes;
+    if (insert_marker)
+      bytes = MIN (size - left_before_marker, sizeof (buf));
+    else
+      bytes = sizeof (buf);
+    n = fread (buf, 1, bytes, f);
+    if (n &gt; 0)
+      {
+	char *fr = frag_more (n);
+	memcpy (fr, buf, n);
+	total += n;
+	if (insert_marker)
+	  {
+	    left_before_marker += n;
+	    if (left_before_marker &gt; size)
+	      as_fatal ("internal error: file insertion sanity checky failed");
+	    if (left_before_marker == size)
+	      {
+		(*insert_marker) (insert_marker_arg);
+		left_before_marker = 0;
+	      }
+	  }
+      }
+  } while (n &gt; 0);
+
+  fclose (f);
+  /* We assume the file is smaller than 2^31 bytes.
+     Ok, we shouldn't make any assumptions.  */
+  return total;
+}
+
+/* Insert an operand value into an instruction.  */
+
+static void
+insert_operand (cpu, opcode, operand, mods, insn_buf, val, errmsg)
+     dvp_cpu cpu;
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn_buf;
+     offsetT val;
+     const char **errmsg;
+{
+  if (operand-&gt;insert)
+    {
+      (*operand-&gt;insert) (opcode, operand, mods, insn_buf, (long) val, errmsg);
+    }
+  else
+    {
+      /* We currently assume a field does not cross a word boundary.  */
+      int shift = ((mods &amp; DVP_MOD_THIS_WORD)
+		   ? (operand-&gt;shift &amp; 31)
+		   : operand-&gt;shift);
+      /* FIXME: revisit */
+      if (operand-&gt;word == 0)
+	{
+	  int word = (mods &amp; DVP_MOD_THIS_WORD) ? 0 : (shift / 32);
+	  if (operand-&gt;bits == 32)
+	    insn_buf[word] = val;
+	  else
+	    {
+	      shift = shift % 32;
+	      insn_buf[word] |= ((long) val &amp; ((1 &lt;&lt; operand-&gt;bits) - 1)) &lt;&lt; shift;
+	    }
+	}
+      else
+	{
+	  int word = (mods &amp; DVP_MOD_THIS_WORD) ? 0 : operand-&gt;word;
+	  if (operand-&gt;bits == 32)
+	    insn_buf[word] = val;
+	  else
+	    {
+	      long temp = (long) val &amp; ((1 &lt;&lt; operand-&gt;bits) - 1);
+	      insn_buf[word] |= temp &lt;&lt; operand-&gt;shift;
+	    }
+	}
+    }
+}
+
+/* Insert an operand's final value into an instruction.
+   Here we can give warning messages about operand values if we want to.  */
+
+static void
+insert_operand_final (cpu, operand, mods, insn_buf, val, file, line)
+     dvp_cpu cpu;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn_buf;
+     offsetT val;
+     char *file;
+     unsigned int line;
+{
+  if (operand-&gt;bits != 32)
+    {
+      offsetT min, max, test;
+
+      /* ??? This test belongs more properly in the insert handler.  */
+      if ((operand-&gt;flags &amp; DVP_OPERAND_RELATIVE_BRANCH) != 0)
+	{
+	  if ((val &amp; 7) != 0)
+	    {
+	      if (file == (char *) NULL)
+		as_warn ("branch to misaligned address");
+	      else
+		as_warn_where (file, line, "branch to misaligned address");
+	    }
+	  val &gt;&gt;= 3;
+	}
+      /* ??? This test belongs more properly in the insert handler.  */
+      else if ((operand-&gt;flags &amp; DVP_OPERAND_VU_ADDRESS) != 0)
+	{
+	  if ((val &amp; 7) != 0)
+	    {
+	      if (file == (char *) NULL)
+		as_warn ("misaligned vu address");
+	      else
+		as_warn_where (file, line, "misaligned vu address");
+	    }
+	  val &gt;&gt;= 3;
+	}
+
+      if ((operand-&gt;flags &amp; DVP_OPERAND_SIGNED) != 0)
+	{
+	  if ((operand-&gt;flags &amp; DVP_OPERAND_SIGNOPT) != 0)
+	    max = (1 &lt;&lt; operand-&gt;bits) - 1;
+	  else
+	    max = (1 &lt;&lt; (operand-&gt;bits - 1)) - 1;
+	  min = - (1 &lt;&lt; (operand-&gt;bits - 1));
+	}
+      else
+	{
+	  max = (1 &lt;&lt; operand-&gt;bits) - 1;
+	  min = 0;
+	}
+
+      if ((operand-&gt;flags &amp; DVP_OPERAND_NEGATIVE) != 0)
+	test = - val;
+      else
+	test = val;
+
+      if (test &lt; (offsetT) min || test &gt; (offsetT) max)
+	{
+	  const char *err =
+	    "operand out of range (%s not between %ld and %ld)";
+	  char buf[100];
+
+	  sprint_value (buf, test);
+	  if (file == (char *) NULL)
+	    as_warn (err, buf, min, max);
+	  else
+	    as_warn_where (file, line, err, buf, min, max);
+	}
+    }
+
+  {
+    const char *errmsg = NULL;
+    insert_operand (cpu, NULL, operand, mods, insn_buf, val, &amp;errmsg);
+    if (errmsg != NULL)
+      as_warn_where (file, line, errmsg);
+  }
+}
+
+/* DVP pseudo ops.  */
+
+static void
+s_dmadata (ignore)
+    int ignore;
+{
+  char *name, c;
+
+  dma_data_name = 0;
+
+  if (dma_data_state != 0)
+    {
+      as_bad ("DmaData blocks cannot be nested.");
+      ignore_rest_of_line ();
+      return;
+    }
+  dma_data_state = 1;
+
+  SKIP_WHITESPACE ();		/* Leading whitespace is part of operand. */
+  name = input_line_pointer;
+
+  if (!is_name_beginner (*name))
+    {
+      as_bad ("invalid identifier for \".DmaData\"");
+      ignore_rest_of_line ();
+      return;
+    }
+
+  /* Do an implicit alignment to a 16 byte boundary. */
+  frag_align (4, 0, 0);
+  record_alignment (now_seg, 4);
+
+  c = get_symbol_end ();
+  line_label = colon (name);	/* user-defined label */
+  dma_data_name = S_GET_NAME (line_label);
+  *input_line_pointer = c;
+
+  /* Force emission of a machine type label for the next insn.  */
+  force_mach_label ();
+
+  demand_empty_rest_of_line ();
+}
+
+static void
+s_enddmadata (ignore)
+    int ignore;
+{
+  if (dma_data_state != 1)
+    {
+      as_warn (".EndDmaData encountered outside a DmaData block -- ignored.");
+      ignore_rest_of_line ();
+      dma_data_name = 0;
+    }
+  dma_data_state = 0;
+  demand_empty_rest_of_line ();
+
+  /* If count provided, verify it is correct.  */
+  /* ... */
+
+  /* Fill the data out to a multiple of 16 bytes.  */
+  /* FIXME: Are the fill contents right?  */
+  frag_align (4, 0, 0);
+
+  /* "label" points to beginning of block.
+     Create a name for the final label like _$&lt;name&gt;.  */
+  if (dma_data_name)
+    create_colon_label (0, END_LABEL_PREFIX, dma_data_name);
+}
+
+static void
+s_dmapackvif (ignore)
+    int ignore;
+{
+  /* Syntax: .dmapackvif 0|1 */
+
+  /* Leading whitespace is part of operand. */
+  SKIP_WHITESPACE ();
+  switch (*input_line_pointer++)
+    {
+    case '0':
+      dma_pack_vif_p = 0;
+      break;
+    case '1':
+      dma_pack_vif_p = 1;
+      break;
+    default:
+      as_bad ("illegal argument to `.dmapackvif'");
+    }
+  demand_empty_rest_of_line ();
+}
+
+/* INTERNAL_P is non-zero if invoked internally by this file rather than
+   by the user.  In this case we don't touch the input stream.  */
+
+static void
+s_enddirect (internal_p)
+     int internal_p;
+{
+  if (CUR_ASM_STATE != ASM_DIRECT)
+    {
+      as_bad ("`.enddirect' has no matching `direct' instruction");
+      return;
+    }
+
+    if (!output_vif)
+    {
+        pop_asm_state (1);
+        demand_empty_rest_of_line ();
+      return;
+    }
+  /* Record in the end data symbol the current location.  */
+  if (now_seg != S_GET_SEGMENT (vif_data_end))
+    as_bad (".enddirect in different section");
+  vif_data_end-&gt;sy_frag = frag_now;
+  S_SET_VALUE (vif_data_end, (valueT) frag_now_fix ());
+
+  pop_asm_state (1);
+
+  /* Needn't be reset, but to catch bugs it is.  */
+  vif_data_end = NULL;
+
+  if (! internal_p)
+    demand_empty_rest_of_line ();
+}
+
+/* CALLER denotes who's calling us.
+   If ENDMPG_USER then .endmpg was found in the input stream.
+   If ENDMPG_INTERNAL then we've been invoked to finish off file insertion.
+   If ENDMPG_MIDDLE then we've been invoked in the middle of a long stretch
+   of vu code.  */
+
+static void
+s_endmpg (caller)
+     int caller;
+{
+  if (CUR_ASM_STATE != ASM_MPG)
+    {
+      as_bad ("`.endmpg' has no matching `mpg' instruction");
+      return;
+    }
+
+  if (!output_vif)
+    {
+      pop_asm_state (1);
+      /* Reset the vu insn counter.  */
+      if (caller != ENDMPG_MIDDLE)
+        vu_count = -1;
+      if (caller == ENDMPG_USER)
+        demand_empty_rest_of_line ();
+      return;
+    }
+  /* Record in the end data symbol the current location.  */
+  if (now_seg != S_GET_SEGMENT (vif_data_end))
+    as_bad (".endmpg in different section");
+  vif_data_end-&gt;sy_frag = frag_now;
+  S_SET_VALUE (vif_data_end, (valueT) frag_now_fix ());
+
+  /* Update $.mpgloc.
+     We have to leave the old value alone as it may be used in fixups
+     already recorded.  Since compute_mpgloc allocates a new symbol for the
+     result we're ok.  The new value is the old value plus the number of
+     double words in this chunk.  */
+  mpgloc_sym = compute_mpgloc (mpgloc_sym, vif_data_start, vif_data_end);
+  S_SET_OTHER (mpgloc_sym, STO_DVP_VU);
+
+  pop_asm_state (1);
+
+  /* Needn't be reset, but to catch bugs it is.  */
+  vif_data_end = NULL;
+
+  /* Reset the vu insn counter.  */
+  if (caller != ENDMPG_MIDDLE)
+    vu_count = -1;
+
+  if (caller == ENDMPG_USER)
+    demand_empty_rest_of_line ();
+}
+
+/* INTERNAL_P is non-zero if invoked internally by this file rather than
+   by the user.  In this case we don't touch the input stream.  */
+
+static void
+s_endunpack (internal_p)
+     int internal_p;
+{
+  if (CUR_ASM_STATE != ASM_UNPACK)
+    {
+      as_bad ("`.endunpack' has no matching `unpack' instruction");
+      return;
+    }
+
+    if (!output_vif)
+    {
+        pop_asm_state (1);
+        demand_empty_rest_of_line ();
+      return;
+    }
+
+
+  /* Record in the end data symbol the current location.  */
+  /* ??? $.unpackloc is gone.  Is this also used for data length
+     verification?  */
+  if (now_seg != S_GET_SEGMENT (vif_data_end))
+    as_bad (".endunpack in different section");
+  vif_data_end-&gt;sy_frag = frag_now;
+  S_SET_VALUE (vif_data_end, (valueT) frag_now_fix ());
+
+  /* Round up to next word boundary.  */
+  frag_align (2, 0, 0);
+
+  pop_asm_state (1);
+
+  /* Needn't be reset, but to catch bugs it is.  */
+  vif_data_end = NULL;
+
+  if (! internal_p)
+    demand_empty_rest_of_line ();
+}
+
+static void
+s_endgif (ignore)
+     int ignore;
+{
+  int bytes;
+  int specified_nloop = gif_nloop ();
+  int computed_nloop;
+  int nregs = gif_nregs ();
+  char *file;
+  unsigned int line;
+
+  as_where (&amp;file, &amp;line);
+
+  if (CUR_ASM_STATE != ASM_GIF)
+    {
+      as_bad (".endgif doesn't follow a gif tag");
+      return;
+    }
+  pop_asm_state (1);
+
+  /* Fill out to proper boundary.
+     ??? This may cause eval_expr to always queue a fixup.  So be it.  */
+  switch (gif_insn_type)
+    {
+    case GIF_PACKED :  frag_align (4, 0, 0); break;
+    case GIF_REGLIST : frag_align (3, 0, 0); break;
+    case GIF_IMAGE :   frag_align (4, 0, 0); break;
+    }
+
+  /* The -16 is because the `gif_data_name' label is emitted at the
+     start of the gif tag.  If we're in a different frag from the one we
+     started with, this can't be computed until much later.  To cope we queue
+     a fixup and deal with it then.
+     ??? The other way to handle this is by having expr() compute "syma - symb"
+     when they're in different fragments but the difference is constant.
+     Not sure how much of a slowdown that will introduce though.  */
+  fixup_count = 0;
+  bytes = eval_expr (DVP_GIF, gif_operand_nloop, 0, ". - %s - 16", gif_data_name);
+
+  /* Compute a value for nloop if we can.  */
+
+  if (fixup_count == 0)
+    {
+      computed_nloop = compute_nloop (gif_insn_type, nregs, bytes);
+
+      /* If the user specified nloop, verify it.  */
+      if (specified_nloop != -1)
+	check_nloop (gif_insn_type, nregs,
+		     specified_nloop, computed_nloop,
+		     file, line);
+    }
+
+  /* If computation of nloop can't be done yet, queue a fixup and do it later.
+     Otherwise validate nloop if specified or write the computed value into
+     the insn.  */
+
+  if (fixup_count != 0)
+    {
+      /* FIXME: It might eventually be possible to combine all the various
+	 copies of this bit of code.  */
+      int op_type, reloc_type, offset;
+      const dvp_operand *operand;
+      fixS *fix;
+
+      op_type = fixups[0].opindex;
+      offset = fixups[0].offset;
+      reloc_type = encode_fixup_reloc_type (DVP_GIF, op_type);
+      operand = &amp;gif_operands[op_type];
+      fix = fix_new_exp (gif_insn_frag,
+			 (gif_insn_frag_loc + offset
+			  - gif_insn_frag-&gt;fr_literal),
+			 4, &amp;fixups[0].exp, 0,
+			 (bfd_reloc_code_real_type) reloc_type);
+      /* Record user specified value so we can test it when we compute the
+	 actual value.  */
+      fix-&gt;tc_fix_data.type = gif_insn_type;
+      fix-&gt;tc_fix_data.nregs = nregs;
+      fix-&gt;tc_fix_data.user_value = specified_nloop;
+    }
+  else if (specified_nloop != -1)
+    ; /* nothing to do */
+  else
+    {
+      DVP_INSN insn = bfd_getl32 (gif_insn_frag_loc);
+      insert_operand_final (DVP_GIF, &amp;gif_operands[gif_operand_nloop],
+			    DVP_MOD_THIS_WORD, &amp;insn,
+			    (offsetT) computed_nloop, file, line);
+      bfd_putl32 ((bfd_vma) insn, gif_insn_frag_loc);
+    }
+
+  /* These needn't be reset, but to catch bugs they are.  */
+  gif_data_name = NULL;
+  gif_insn_frag = NULL;
+  gif_insn_frag_loc = NULL;
+
+  demand_empty_rest_of_line ();
+}
+
+static void
+s_vu (ignore)
+     int ignore;
+{
+  /* If in MPG state and the user requests to change to VU state,
+     leave the state as MPG.  This happens when we see an mpg followed
+     by a .include that has .vu.  Note that no attempt is made to support
+     an include depth &gt; 1 for this case.  */
+  if (CUR_ASM_STATE == ASM_MPG)
+    return;
+
+  /* We need to set up things for $.mpgloc calculations.  */
+  /* FIXME: May need to check that we're not clobbering currently
+     in use versions of these.  Also need to worry about which section
+     the .vu is issued in.  On the other hand, ".vu" isn't intended
+     to be supported everywhere.  */
+  vif_data_start = expr_build_dot ();
+  mpgloc_sym = expr_build_uconstant (0);
+  S_SET_OTHER (mpgloc_sym, STO_DVP_VU);
+#if 0 /* ??? wip */
+  create_vuoverlay_section (vuoverlay_section_name (NULL), mpgloc_sym,
+			    NULL, NULL);
+#endif
+
+  set_asm_state (ASM_VU, ".vu");
+
+  demand_empty_rest_of_line ();
+}
+
+/* Same as read.c:s_func except prepend VU_LABEL_PREFIX by default.  */
+
+static void
+s_dvp_func (end_p)
+     int end_p;
+{
+  do_s_func (end_p, VU_LABEL_PREFIX);
+}
diff -burN orig.binutils-2.14/gas/config/tc-dvp.h binutils-2.14/gas/config/tc-dvp.h
--- orig.binutils-2.14/gas/config/tc-dvp.h	1969-12-31 20:00:00.000000000 -0400
+++ binutils-2.14/gas/config/tc-dvp.h	2007-04-29 04:00:33.000000000 -0300
@@ -0,0 +1,105 @@
+/* tc-dvp.h -- Header file for tc-dvp.c.
+   Copyright (C) 1997, 1998 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_DVP
+
+#ifndef BFD_ASSEMBLER
+/* leading space so will compile with cc */
+ #error DVP support requires BFD_ASSEMBLER
+#endif
+
+#define LISTING_HEADER "DVP GAS "
+
+/* The target BFD architecture.  */
+#define TARGET_ARCH bfd_arch_mips
+
+#define TARGET_FORMAT "elf32-littlemips"
+
+#define TARGET_BYTES_BIG_ENDIAN 0
+
+/* Handle +- specially so the scrubber doesn't remove the space after loi
+  in "nop loi +1.0" and "nop loi -1.0".  */
+#define tc_symbol_chars "+-"
+
+/* call md_pcrel_from_section, not md_pcrel_from */
+#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
+
+/* Handle mpg/direct alignment requirements with relaxation.  */
+extern long dvp_relax_frag PARAMS ((fragS *, long));
+#define md_relax_frag(segment, fragP,stretch) dvp_relax_frag ((fragP), (stretch))
+
+#define MD_APPLY_FIX3
+
+/* Ensure insns at labels have their mach type properly recorded.  */
+int force_mach_label PARAMS ((void));
+#define TC_START_LABEL(ch, ptr)	(ch == ':' &amp;&amp; force_mach_label ())
+
+#define TC_HANDLES_FX_DONE
+
+/* Record user specified val, for cases where we can't compute the actual
+   value until the end of assembly.  */
+#define TC_FIX_TYPE \
+struct { \
+  int type; /* gif_type, or vif type */ \
+  int nregs; /* for gif insns only */ \
+  short wl; short cl; /* for unpack only */ \
+  int user_value; \
+}
+/* Code to initialize it.  */
+#define TC_INIT_FIX_DATA(fixP) \
+do { memset (&amp;fixP-&gt;tc_fix_data, 0, sizeof (fixP-&gt;tc_fix_data)); } while (0)
+
+/* Called before parsing each line.  */
+extern void dvp_start_line_hook PARAMS ((void));
+#define md_start_line_hook() dvp_start_line_hook ()
+
+/* Called after parsing a file.  */
+extern void dvp_after_pass_hook PARAMS ((void));
+#define md_after_pass_hook() dvp_after_pass_hook ()
+
+/* Called after parsing all files.  */
+extern void dvp_end PARAMS ((void));
+#define md_end() dvp_end ()
+
+/* Called for each label.  */
+extern void dvp_frob_label PARAMS ((struct symbol *));
+#define tc_frob_label(sym) dvp_frob_label (sym)
+
+/* Called just before writing the file out.  */
+extern void dvp_frob_file PARAMS ((void));
+#define tc_frob_file() dvp_frob_file ()
+
+/* Default section names. */
+#define TEXT_SECTION_NAME	".vutext"
+#define DATA_SECTION_NAME	".vudata"
+#define BSS_SECTION_NAME	".vubss"
+
+#define ELF_TC_SPECIAL_SECTIONS \
+  { ".vubss",	SHT_NOBITS,	SHF_ALLOC + SHF_WRITE		}, \
+  { ".vudata",	SHT_PROGBITS,	SHF_ALLOC + SHF_WRITE		}, \
+  { ".vutext",	SHT_PROGBITS,	SHF_ALLOC + SHF_EXECINSTR	},
diff -burN orig.binutils-2.14/gas/config/tc-mips.c binutils-2.14/gas/config/tc-mips.c
--- orig.binutils-2.14/gas/config/tc-mips.c	2003-06-02 17:35:25.000000000 -0300
+++ binutils-2.14/gas/config/tc-mips.c	2007-04-29 04:00:33.000000000 -0300
@@ -177,6 +177,10 @@
      is passed but can changed if the assembler code uses .set mipsN.  */
   int gp32;
   int fp32;
+  /* r5900 support with mips1/mips2. */
+  /* save mips_arch value on .set push */
+  int march;
+
 };
 
 /* True if -mgp32 was passed.  */
@@ -191,7 +195,7 @@
 
 static struct mips_set_options mips_opts =
 {
-  ISA_UNKNOWN, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0
+  ISA_UNKNOWN, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, CPU_UNKNOWN
 };
 
 /* These variables are filled in with the masks of registers used.
@@ -323,6 +327,7 @@
 #define hilo_interlocks (mips_arch == CPU_R4010                       \
                          || mips_arch == CPU_VR5500                   \
                          || mips_arch == CPU_SB1                      \
+			 || mips_arch == CPU_R5900		      \
                          )
 
 /* Whether the processor uses hardware interlocks to protect reads
@@ -331,6 +336,7 @@
   (mips_opts.isa != ISA_MIPS1  \
    || mips_arch == CPU_VR5400  \
    || mips_arch == CPU_VR5500  \
+   || mips_arch == CPU_R5900   \
    || mips_arch == CPU_R3900)
 
 /* As with other "interlocks" this is used by hardware that has FP
@@ -377,6 +383,12 @@
    an mfhi/mflo instruction is read in the next two instructions.  */
 static int mips_7000_hilo_fix;
 
+/* Whether or not we should warn on short loops (for the r5900 bug) */
+static int mips_warn_short_loop = -1;
+
+/* Whether or not we should warn when using odd FP registers */
+static int mips_single_float = 0;
+
 /* The size of the small data section.  */
 static unsigned int g_switch_value = 8;
 /* Whether the -G option was used.  */
@@ -952,6 +964,10 @@
   PARAMS ((const struct mips_opcode *));
 static void show
   PARAMS ((FILE *, const char *, int *, int *));
+static int is_jump
+  PARAMS ((unsigned long));
+static int check_short_loop
+  PARAMS ((int, fixS *));
 #ifdef OBJ_ELF
 static int mips_need_elf_addend_fixup
   PARAMS ((fixS *));
@@ -1184,6 +1200,10 @@
   int i = 0;
   int broken = 0;
 
+  /* set default value, if not specified */
+  if (mips_warn_short_loop == -1)
+    mips_warn_short_loop = (mips_arch == CPU_R5900);
+
   if (! bfd_set_arch_mach (stdoutput, bfd_arch_mips, mips_arch))
     as_warn (_("Could not set architecture and machine"));
 
@@ -2142,6 +2162,10 @@
 		 | ((address_expr-&gt;X_add_number &amp; 0x3fffc) &gt;&gt; 2));
 	      break;
 
+	    case BFD_RELOC_MIPS15_S3:
+	      ip-&gt;insn_opcode |= ((imm_expr.X_add_number &amp; 0x7fff) &gt;&gt; 3) &lt;&lt; 6;
+	      break;
+
 	    case BFD_RELOC_16_PCREL_S2:
 	      goto need_reloc;
 
@@ -3005,6 +3029,7 @@
   			       (mips_opts.isa
 	      		        | (file_ase_mips16 ? INSN_MIPS16 : 0)),
 			       mips_arch)
+          &amp;&amp; (mips_arch != CPU_R5900 || (insn.insn_mo-&gt;pinfo &amp; FP_D) == 0)
 	  &amp;&amp; (mips_arch != CPU_R4650 || (insn.insn_mo-&gt;pinfo &amp; FP_D) == 0))
 	break;
 
@@ -3544,6 +3569,24 @@
            ? 1                          \
            : 0)
 
+#define UPGRADE_R5900_ISA                               \
+  {                                                     \
+    if ((mips_arch == CPU_R5900) &amp;&amp; (mips_opts.isa != ISA_MIPS3))       \
+      {                                                 \
+        save_isa = mips_opts.isa;                       \
+        mips_opts.isa = ISA_MIPS3;                      \
+      }                                                 \
+  }
+
+#define RESTORE_R5900_ISA               \
+  {                                     \
+    if (save_isa)                       \
+      {                                 \
+        mips_opts.isa = save_isa;       \
+        save_isa = 0;                   \
+      }                                 \
+  }
+
 /*			load_register()
  *  This routine generates the least number of instructions neccessary to load
  *  an absolute expression value into a register.
@@ -3557,6 +3600,7 @@
 {
   int freg;
   expressionS hi32, lo32;
+  int save_isa = 0;
 
   if (ep-&gt;X_op != O_big)
     {
@@ -3609,12 +3653,21 @@
 
   if (HAVE_32BIT_GPRS)
     {
+      if (mips_arch == CPU_R5900)
+        {
+          as_warn (_("Number larger than 32 bits (r5900, but isa:%d)"),
+                   mips_opts.isa);
+        }
+      else
+        {
       as_bad (_("Number (0x%lx) larger than 32 bits"),
 	      (unsigned long) ep-&gt;X_add_number);
       macro_build ((char *) NULL, counter, ep, "addiu", "t,r,j", reg, 0,
 		   (int) BFD_RELOC_LO16);
       return;
     }
+    }
+  UPGRADE_R5900_ISA;
 
   if (ep-&gt;X_op != O_big)
     {
@@ -3651,6 +3704,7 @@
 	    {
 	      macro_build ((char *) NULL, counter, &amp;lo32, "addiu", "t,r,j",
 			   reg, 0, (int) BFD_RELOC_LO16);
+	      RESTORE_R5900_ISA;
 	      return;
 	    }
 	  if (lo32.X_add_number &amp; 0x80000000)
@@ -3660,6 +3714,7 @@
 	      if (lo32.X_add_number &amp; 0xffff)
 		macro_build ((char *) NULL, counter, &amp;lo32, "ori", "t,r,i",
 			     reg, reg, (int) BFD_RELOC_LO16);
+	      RESTORE_R5900_ISA;
 	      return;
 	    }
 	}
@@ -3700,6 +3755,7 @@
 			   (shift &gt;= 32) ? "dsll32" : "dsll",
 			   "d,w,&lt;", reg, reg,
 			   (shift &gt;= 32) ? shift - 32 : shift);
+	      RESTORE_R5900_ISA;
 	      return;
 	    }
 	  ++shift;
@@ -3760,6 +3816,7 @@
 			   (shift &gt;= 32) ? "dsrl32" : "dsrl",
 			   "d,w,&lt;", reg, reg,
 			   (shift &gt;= 32) ? shift - 32 : shift);
+	      RESTORE_R5900_ISA;
 	      return;
 	    }
 	}
@@ -3790,11 +3847,13 @@
 		       (int) BFD_RELOC_HI16);
 	  macro_build ((char *) NULL, counter, (expressionS *) NULL,
 		       "dsrl32", "d,w,&lt;", reg, reg, 0);
+          RESTORE_R5900_ISA;
 	  return;
 	}
 
       if (freg != 0)
 	{
+	  UPGRADE_R5900_ISA;
 	  macro_build ((char *) NULL, counter, (expressionS *) NULL, "dsll",
 		       "d,w,&lt;", reg, freg, 16);
 	  freg = reg;
@@ -3810,6 +3869,7 @@
   if ((lo32.X_add_number &amp; 0xffff) != 0)
     macro_build ((char *) NULL, counter, &amp;lo32, "ori", "t,r,i", reg, freg,
 		 (int) BFD_RELOC_LO16);
+  RESTORE_R5900_ISA;
 }
 
 /* Load an address into a register.  */
@@ -4683,6 +4743,9 @@
 	  if (mips_trap)
 	    macro_build ((char *) NULL, &amp;icnt, (expressionS *) NULL, "teq",
 			 "s,t,q", 0, 0, 7);
+	  else if (mips_arch == CPU_R5900)
+	    macro_build ((char *) NULL, &amp;icnt, (expressionS *) NULL, "break",
+			 "B", 7);
 	  else
 	    macro_build ((char *) NULL, &amp;icnt, (expressionS *) NULL, "break",
 			 "c", 7);
@@ -4705,6 +4768,10 @@
 	  macro_build ((char *) NULL, &amp;icnt, &amp;expr1, "bne", "s,t,p", treg, 0);
 	  macro_build ((char *) NULL, &amp;icnt, (expressionS *) NULL,
 		       dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
+          if (mips_arch == CPU_R5900)
+	    macro_build ((char *) NULL, &amp;icnt, (expressionS *) NULL, "break",
+		         "B", 7);
+	  else
 	  macro_build ((char *) NULL, &amp;icnt, (expressionS *) NULL, "break",
 		       "c", 7);
 	}
@@ -4747,6 +4814,10 @@
 	     that later insns are available for delay slot filling.  */
 	  --mips_opts.noreorder;
 
+	  if (mips_arch == CPU_R5900)
+	    macro_build ((char *) NULL, &amp;icnt, (expressionS *) NULL, "break",
+		         "B", 6);
+	  else
 	  macro_build ((char *) NULL, &amp;icnt, (expressionS *) NULL, "break",
 		       "c", 6);
 	}
@@ -4795,6 +4866,9 @@
 	  if (mips_trap)
 	    macro_build ((char *) NULL, &amp;icnt, (expressionS *) NULL, "teq",
 			 "s,t,q", 0, 0, 7);
+	  else if (mips_arch == CPU_R5900)
+	    macro_build ((char *) NULL, &amp;icnt, (expressionS *) NULL, "break",
+			 "B", 7);
 	  else
 	    macro_build ((char *) NULL, &amp;icnt, (expressionS *) NULL, "break",
 			 "c", 7);
@@ -4867,6 +4941,10 @@
 	  /* We want to close the noreorder block as soon as possible, so
 	     that later insns are available for delay slot filling.  */
 	  --mips_opts.noreorder;
+	  if (mips_arch == CPU_R5900)
+	    macro_build ((char *) NULL, &amp;icnt, (expressionS *) NULL, "break",
+		         "B", 7);
+	  else
 	  macro_build ((char *) NULL, &amp;icnt, (expressionS *) NULL, "break",
 		       "c", 7);
 	}
@@ -6732,7 +6810,7 @@
       s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
       if (strcmp (s, ".lit8") == 0)
 	{
-	  if (mips_opts.isa != ISA_MIPS1)
+	  if (mips_opts.isa != ISA_MIPS1 &amp;&amp; mips_arch != CPU_R5900)
 	    {
 	      macro_build ((char *) NULL, &amp;icnt, &amp;offset_expr, "ldc1",
 			   "T,o(b)", treg, (int) BFD_RELOC_MIPS_LITERAL,
@@ -6757,7 +6835,7 @@
 	      macro_build_lui (NULL, &amp;icnt, &amp;offset_expr, AT);
 	    }
 
-	  if (mips_opts.isa != ISA_MIPS1)
+	  if (mips_opts.isa != ISA_MIPS1 &amp;&amp; mips_arch != CPU_R5900)
 	    {
 	      macro_build ((char *) NULL, &amp;icnt, &amp;offset_expr, "ldc1",
 			   "T,o(b)", treg, (int) BFD_RELOC_LO16, AT);
@@ -6784,7 +6862,7 @@
 	 to adjust when loading from memory.  */
       r = BFD_RELOC_LO16;
     dob:
-      assert (mips_opts.isa == ISA_MIPS1);
+      assert (mips_opts.isa == ISA_MIPS1 || mips_arch == CPU_R5900);
       macro_build ((char *) NULL, &amp;icnt, &amp;offset_expr, "lwc1", "T,o(b)",
 		   target_big_endian ? treg + 1 : treg,
 		   (int) r, breg);
@@ -6823,7 +6901,7 @@
 	}
       /* Itbl support may require additional care here.  */
       coproc = 1;
-      if (mips_opts.isa != ISA_MIPS1)
+      if (mips_opts.isa != ISA_MIPS1 &amp;&amp; mips_arch != CPU_R5900)
 	{
 	  s = "ldc1";
 	  goto ld;
@@ -6840,7 +6918,7 @@
 	  return;
 	}
 
-      if (mips_opts.isa != ISA_MIPS1)
+      if (mips_opts.isa != ISA_MIPS1 &amp;&amp; mips_arch != CPU_R5900)
 	{
 	  s = "sdc1";
 	  goto st;
@@ -7386,6 +7464,10 @@
 		       AT);
 	  macro_build ((char *) NULL, &amp;icnt, (expressionS *) NULL, "nop", "",
 		       0);
+	  if (mips_arch == CPU_R5900)
+	    macro_build ((char *) NULL, &amp;icnt, (expressionS *) NULL, "break",
+		         "B", 6);
+	  else
 	  macro_build ((char *) NULL, &amp;icnt, (expressionS *) NULL, "break",
 		       "c", 6);
 	}
@@ -7424,6 +7506,10 @@
 	  macro_build ((char *) NULL, &amp;icnt, &amp;expr1, "beq", "s,t,p", AT, 0);
 	  macro_build ((char *) NULL, &amp;icnt, (expressionS *) NULL, "nop", "",
 		       0);
+	  if (mips_arch == CPU_R5900)
+	    macro_build ((char *) NULL, &amp;icnt, (expressionS *) NULL, "break",
+		         "B", 6);
+	  else
 	  macro_build ((char *) NULL, &amp;icnt, (expressionS *) NULL, "break",
 		       "c", 6);
 	}
@@ -7661,7 +7747,7 @@
 	  as_bad (_("opcode not supported on this processor"));
 	  return;
 	}
-      assert (mips_opts.isa == ISA_MIPS1);
+      assert (mips_opts.isa == ISA_MIPS1 || mips_arch == CPU_R5900);
       /* Even on a big endian machine $fn comes before $fn+1.  We have
 	 to adjust when storing to memory.  */
       macro_build ((char *) NULL, &amp;icnt, &amp;offset_expr, "swc1", "T,o(b)",
@@ -7970,7 +8056,7 @@
 
     case M_TRUNCWS:
     case M_TRUNCWD:
-      assert (mips_opts.isa == ISA_MIPS1);
+      assert (mips_opts.isa == ISA_MIPS1 || mips_arch == CPU_R5900);
       sreg = (ip-&gt;insn_opcode &gt;&gt; 11) &amp; 0x1f;	/* floating reg */
       dreg = (ip-&gt;insn_opcode &gt;&gt; 06) &amp; 0x1f;	/* floating reg */
 
@@ -8509,7 +8595,7 @@
       case ',': break;
       case '(': break;
       case ')': break;
-      case '+':
+      case '*':
     	switch (c = *p++)
 	  {
 	  case 'A': USE_BITS (OP_MASK_SHAMT,	OP_SH_SHAMT);	break;
@@ -8574,6 +8660,35 @@
       case 'P': USE_BITS (OP_MASK_PERFREG,	OP_SH_PERFREG);	break;
       case 'U': USE_BITS (OP_MASK_RD,           OP_SH_RD);
 	        USE_BITS (OP_MASK_RT,           OP_SH_RT);	break;
+      case '0': USE_BITS (OP_MASK_VADDI,        OP_SH_VADDI);   break;
+      case '1': USE_BITS (OP_MASK_VUTREG,       OP_SH_VUTREG);  break;
+      case '2': USE_BITS (OP_MASK_VUSREG,       OP_SH_VUSREG);  break;
+      case '3': USE_BITS (OP_MASK_VUDREG,       OP_SH_VUDREG);  break;
+      case '4': USE_BITS (OP_MASK_VUTREG,       OP_SH_VUTREG);  break;
+      case '5': USE_BITS (OP_MASK_VUSREG,       OP_SH_VUSREG);  break;
+      case '6': USE_BITS (OP_MASK_VUDREG,       OP_SH_VUDREG);  break;
+      case '7':
+        USE_BITS (OP_MASK_VUTREG,               OP_SH_VUTREG);
+        USE_BITS (OP_MASK_VUFTF,                OP_SH_VUFTF);
+        break;
+      case '8':
+        USE_BITS (OP_MASK_VUSREG,               OP_SH_VUSREG);
+        USE_BITS (OP_MASK_VUFSF,                OP_SH_VUFSF);
+        break;
+      case '9': break;
+      case '=': break;
+      case '_': break;
+      case '@': break;
+      case '^': break;
+      case '!': break;
+      case 'g': USE_BITS (OP_MASK_VUCALLMS,     OP_SH_VUCALLMS);break;
+      case '&amp;': USE_BITS (OP_MASK_VUDEST,       OP_SH_VUDEST);  break;
+      case ';': break;
+      case '#':
+        p++;
+         break;
+      case '-': break;
+      case '+': break;
       case 'e': USE_BITS (OP_MASK_VECBYTE,	OP_SH_VECBYTE);	break;
       case '%': USE_BITS (OP_MASK_VECALIGN,	OP_SH_VECALIGN); break;
       case '[': break;
@@ -8614,6 +8729,7 @@
   unsigned int limlo, limhi;
   char *s_reset;
   char save_c = 0;
+  int full_opcode_match = 1;
 
   insn_error = NULL;
 
@@ -8663,6 +8779,7 @@
 	  insn_error = "unrecognized opcode";
 	  return;
 	}
+      full_opcode_match = 0;
     }
 
   argsStart = s;
@@ -8684,7 +8801,8 @@
 
       if (insn-&gt;pinfo != INSN_MACRO)
 	{
-	  if (mips_arch == CPU_R4650 &amp;&amp; (insn-&gt;pinfo &amp; FP_D) != 0)
+	  if ((mips_arch == CPU_R4650 || mips_arch == CPU_R5900) &amp;&amp;
+              (insn-&gt;pinfo &amp; FP_D) != 0)
 	    ok = FALSE;
 	}
 
@@ -8773,11 +8891,13 @@
 	    case ')':		/* these must match exactly */
 	    case '[':
 	    case ']':
+	    case '-':
+	    case '+':
 	      if (*s++ == *args)
 		continue;
 	      break;
 
-	    case '+':		/* Opcode extension character.  */
+	    case '*':		/* Opcode extension character.  */
 	      switch (*++args)
 		{
 		case 'A':		/* ins/ext position, becomes LSB.  */
@@ -8894,6 +9014,173 @@
 	      s = expr_end;
 	      continue;
 
+            case '0':           /* 5 bit signed immediate at 6 */
+              my_getExpression (&amp;imm_expr, s);
+              check_absolute_expr (ip, &amp;imm_expr);
+              if ((c == '\0' &amp;&amp; imm_expr.X_op != O_constant)
+                  || ((imm_expr.X_add_number &lt; -16
+                       || imm_expr.X_add_number &gt;= 16)
+                      &amp;&amp; imm_expr.X_op == O_constant))
+                {
+                  if (imm_expr.X_op != O_constant
+                      &amp;&amp; imm_expr.X_op != O_big)
+                    insn_error = "absolute expression required";
+                  else
+                    as_bad (_("5 bit expression not in range -16..15"));
+                }
+
+              if (imm_expr.X_add_number &lt; 0)
+                imm_expr.X_add_number = 32 + imm_expr.X_add_number;
+
+              ip-&gt;insn_opcode |= (imm_expr.X_add_number) &lt;&lt; OP_SH_VADDI;
+              imm_expr.X_op = O_absent;
+              s = expr_end;
+              continue;
+
+            case '9':           /* vi27 for vcallmsr */
+              if (strncmp (s, "$vi27", 5) == 0)
+                s += 5;
+              else if (strncmp (s, "vi27", 4) == 0)
+                s += 4;
+              else
+                as_bad (_("expected vi27"));
+              continue;
+
+            case '#':           /* escape character */
+              /* '#' specifies that we've got an optional suffix to this 
+                 operand that must match exactly (if it exists).  */
+              if (*s != '\0' &amp;&amp; *s != ','
+                  &amp;&amp; *s != ' ' &amp;&amp; *s != '\t' &amp;&amp; *s != '\n')
+                {
+                  if (*s == *(args + 1))
+                    {
+                      s++;
+                      args++;
+                      continue;
+                    }
+                  break;
+                }
+              args++;
+              continue;
+
+            case '=':           /* DEST operand completer (optional), must 
+                                   match previous dest if specified.  */
+            case '&amp;':           /* DEST instruction completer */
+            case ';':           /* DEST instruction completer, must be xyz */
+              {
+                int w,x,y,z;
+                static int last_h;
+
+                w = x = y = z = 0;
+
+                /* Parse the completer.  */
+                s_reset = s;
+                while ((!full_opcode_match || *args == '=')
+                       &amp;&amp; *s != '\0' &amp;&amp; *s != ' ' &amp;&amp; *s != ',')
+                  {
+                    if (*s == 'w')
+                      w++;
+                    else if (*s == 'x')
+                      x++;
+                    else if (*s == 'y')
+                      y++;
+                    else if (*s == 'z')
+                      z++;
+                    else
+                      {
+                        insn_error = "Invalid dest specification";
+                        break;
+                      }
+                    s++;
+                  }
+
+                if (insn_error)
+                  continue;
+
+                /* Each completer can only appear once.  */
+                if (w &gt; 1 || x &gt; 1 || y &gt; 1 || z &gt; 1)
+                  {
+                    insn_error = "Invalid dest specification";
+                    continue;
+                  }
+
+                /* If this is the opcode completer, then we must insert 
+                   the appropriate value into the insn.  */
+                if (*args == '&amp;')
+                  {
+                    /* Not strictly in the specs, but requested by users.  */
+                    if (w == 0 &amp;&amp; x == 0 &amp;&amp; y == 0 &amp;&amp; z == 0)
+                      w = x = y = z = 1;
+
+                    ip-&gt;insn_opcode |= ((w &lt;&lt; 21) | (x &lt;&lt; 24)
+                                        | (y &lt;&lt; 23) | (z &lt;&lt; 22));
+                    last_h = (w &lt;&lt; 3) | (x &lt;&lt; 0) | (y &lt;&lt; 1) | (z &lt;&lt; 2);
+                  }
+                else if (*args == ';')
+                  {
+                    /* This implicitly has the .xyz completer.  */
+                    if (w == 0 &amp;&amp; x == 0 &amp;&amp; y == 0 &amp;&amp; z == 0)
+                      x = y = z = 1;
+
+                    if (w != 0 || x != 1 || y != 1 || z != 1)
+                      {
+                        insn_error = "Invalid dest specification";
+                        continue;
+                      }
+
+                    last_h = (w &lt;&lt; 3) | (x &lt;&lt; 0) | (y &lt;&lt; 1) | (z &lt;&lt; 2);
+                  }
+                else
+                  {
+                    int temp;
+
+                    /* This is the operand completer, make sure it matches 
+                       the previous opcode completer.  */
+                    temp = (w &lt;&lt; 3) | (x &lt;&lt; 0) | (y &lt;&lt; 1) | (z &lt;&lt; 2);
+                    if (temp &amp;&amp; temp != last_h)
+                      {
+                        insn_error = "DEST field in operand does not match DEST field in instruction";
+                        continue;
+                      }
+
+                  }
+                continue;
+              }
+
+            case '!':           /* vu0 I register */
+              if (s[0] == 'I')
+                s += 1;
+              else
+                insn_error = "operand `I' expected";
+              continue;
+
+            case '^':           /* vu0 Q register */
+              if (s[0] == 'Q')
+                s += 1;
+              else
+                insn_error = "operand `Q' expected";
+              continue;
+
+            case '_':           /* vu0 R register */
+              if (s[0] == 'R')
+                s += 1;
+              else
+                insn_error = "operand `R' expected";
+              continue;
+
+            case '@':           /* vu0 ACC register */
+              if (s[0] == 'A' &amp;&amp; s[1] == 'C' &amp;&amp; s[2] == 'C')
+                s += 3;
+              else
+                insn_error = "operand `ACC' expected";
+              continue;
+
+            case 'g':
+              my_getSmallExpression (&amp;imm_expr, imm_reloc, s);
+              *imm_reloc = BFD_RELOC_MIPS15_S3;
+              s = expr_end;
+              continue;
+
 	    case 'k':		/* cache code */
 	    case 'h':		/* prefx code */
 	      my_getExpression (&amp;imm_expr, s);
@@ -9007,6 +9294,14 @@
 	      s_reset = s;
 	      if (s[0] == '$')
 		{
+                  /* Allow "$viNN" as coprocessor register name */
+                  if (mips_arch == CPU_R5900
+                      &amp;&amp; *args == 'G'
+                      &amp;&amp; s[1] == 'v'
+                      &amp;&amp; s[2] == 'i')
+                    {
+                      s += 2;
+                    }
 
 		  if (ISDIGIT (s[1]))
 		    {
@@ -9026,47 +9321,56 @@
 		    goto notreg;
 		  else
 		    {
-		      if (s[1] == 'r' &amp;&amp; s[2] == 'a')
-			{
-			  s += 3;
-			  regno = RA;
-			}
-		      else if (s[1] == 'f' &amp;&amp; s[2] == 'p')
-			{
-			  s += 3;
-			  regno = FP;
-			}
-		      else if (s[1] == 's' &amp;&amp; s[2] == 'p')
-			{
-			  s += 3;
-			  regno = SP;
-			}
-		      else if (s[1] == 'g' &amp;&amp; s[2] == 'p')
-			{
-			  s += 3;
-			  regno = GP;
-			}
-		      else if (s[1] == 'a' &amp;&amp; s[2] == 't')
-			{
-			  s += 3;
-			  regno = AT;
-			}
-		      else if (s[1] == 'k' &amp;&amp; s[2] == 't' &amp;&amp; s[3] == '0')
-			{
-			  s += 4;
-			  regno = KT0;
-			}
-		      else if (s[1] == 'k' &amp;&amp; s[2] == 't' &amp;&amp; s[3] == '1')
-			{
-			  s += 4;
-			  regno = KT1;
-			}
-		      else if (s[1] == 'z' &amp;&amp; s[2] == 'e' &amp;&amp; s[3] == 'r' &amp;&amp; s[4] == 'o')
-			{
-			  s += 5;
-			  regno = ZERO;
-			}
-		      else if (itbl_have_entries)
+                      int __is_alias = 0;
+                      #define CHECK_ALIAS(x, n) \
+                      if (!__is_alias) \
+                        { \
+                          const char __alias[] = #x, * __p; \
+                          int __i; \
+                          for (__p = __alias, __i = 1; *__p &amp;&amp; (s[__i] == *__p); __p++, __i++); \
+                          if (!*__p) \
+                            { \
+                              s += __i; \
+                              regno = n; \
+                              __is_alias = 1; \
+                            } \
+                        }
+                      CHECK_ALIAS(zr,   ZERO);
+		      CHECK_ALIAS(zero, ZERO);
+		      CHECK_ALIAS(at,   AT);
+                      CHECK_ALIAS(v0,   2);
+                      CHECK_ALIAS(v1,   3);
+                      CHECK_ALIAS(a0,   4);
+                      CHECK_ALIAS(a1,   5);
+                      CHECK_ALIAS(a2,   6);
+                      CHECK_ALIAS(a3,   7);
+                      CHECK_ALIAS(t0,   8);
+                      CHECK_ALIAS(t1,   9);
+                      CHECK_ALIAS(t2,  10);
+                      CHECK_ALIAS(t3,  11);
+                      CHECK_ALIAS(t4,  12);
+                      CHECK_ALIAS(t5,  13);
+                      CHECK_ALIAS(t6,  14);
+                      CHECK_ALIAS(t7,  15);
+                      CHECK_ALIAS(s0,  16);
+                      CHECK_ALIAS(s1,  17);
+                      CHECK_ALIAS(s2,  18);
+                      CHECK_ALIAS(s3,  19);
+                      CHECK_ALIAS(s4,  20);
+                      CHECK_ALIAS(s5,  21);
+                      CHECK_ALIAS(s6,  22);
+                      CHECK_ALIAS(s7,  23);
+                      CHECK_ALIAS(t8,  24);
+                      CHECK_ALIAS(t9,  25);
+                      CHECK_ALIAS(k0,  KT0);
+		      CHECK_ALIAS(kt0, KT0);
+                      CHECK_ALIAS(k1,  KT1);
+		      CHECK_ALIAS(kt1, KT1);
+		      CHECK_ALIAS(gp,  GP);
+		      CHECK_ALIAS(sp,  SP);
+		      CHECK_ALIAS(fp,  FP);
+		      CHECK_ALIAS(ra,  RA);
+                      if (!__is_alias &amp;&amp; itbl_have_entries)
 			{
 			  char *p, *n;
 			  unsigned long r;
@@ -9090,7 +9394,7 @@
 			  else
 			    goto notreg;
 			}
-		      else
+		      else if (!__is_alias)
 			goto notreg;
 		    }
 		  if (regno == AT
@@ -9223,6 +9527,14 @@
 	    case 'R':		/* floating point source register */
 	    case 'V':
 	    case 'W':
+            case '1':           /* vu0 fp reg position 1 */
+            case '2':           /* vu0 fp reg position 2 */
+            case '3':           /* vu0 fp reg position 3 */
+            case '4':           /* vu0 int reg position 1 */
+            case '5':           /* vu0 int reg position 2 */
+            case '6':           /* vu0 int reg position 3 */
+            case '7':           /* vu0 fp reg with ftf modifier */
+            case '8':           /* vu0 fp reg with fsf modifier */
 	      s_reset = s;
 	      /* Accept $fN for FP and MDMX register numbers, and in
                  addition accept $vN for MDMX register numbers.  */
@@ -9245,6 +9557,7 @@
 
 		  if ((regno &amp; 1) != 0
 		      &amp;&amp; HAVE_32BIT_FPRS
+		      &amp;&amp; mips_single_float == 0
 		      &amp;&amp; ! (strcmp (str, "mtc1") == 0
 			    || strcmp (str, "mfc1") == 0
 			    || strcmp (str, "lwc1") == 0
@@ -9323,6 +9636,94 @@
 		  lastregno = regno;
 		  continue;
 		}
+              if ((s[0] == 'v'
+                   &amp;&amp; (s[1] == 'f' || s[1] == 'i')
+                   &amp;&amp; ISDIGIT ((unsigned char) s[2]))
+                  ||
+                  (s[0] == '$'
+                   &amp;&amp; s[1] == 'v'
+                   &amp;&amp; (s[2] == 'f' || s[2] == 'i')
+                   &amp;&amp; ISDIGIT ((unsigned char) s[3])))
+                {
+                  if(s[0] == '$')
+                    ++s;
+                  s += 2;
+                  regno = 0;
+                  do
+                    {
+                      regno *= 10;
+                      regno += *s - '0';
+                      ++s;
+                    }
+                  while (ISDIGIT ((unsigned char) *s));
+
+                  if (regno &gt; 31)
+                    as_bad (_("Invalid vu0 register number (%d)"), regno);
+
+                  c = *args;
+
+                  if (c == '7' || c == '8')
+                    {
+                      int value;
+
+                      switch (*s)
+                        {
+                        case 'w':
+                          value = 3;
+                          s++;
+                          ip-&gt;insn_opcode |= value &lt;&lt; (c == '7' ? OP_SH_VUFTF : OP_SH_VUFSF);
+                          break;
+                        case 'x':
+                          value = 0;
+                          s++;
+                          ip-&gt;insn_opcode |= value &lt;&lt; (c == '7' ? OP_SH_VUFTF : OP_SH_VUFSF);
+                          break;
+                        case 'y':
+                          value = 1;
+                          s++;
+                          ip-&gt;insn_opcode |= value &lt;&lt; (c == '7' ? OP_SH_VUFTF : OP_SH_VUFSF);
+                          break;
+                        case 'z':
+                          value = 2;
+                          s++;
+                          ip-&gt;insn_opcode |= value &lt;&lt; (c == '7' ? OP_SH_VUFTF : OP_SH_VUFSF);
+                          break;
+                        default:
+                          as_bad (_("Invalid FSF/FTF specification"));
+                        }
+                    }
+
+                  if (*s == ' ')
+                    s++;
+                  if (args[1] != *s)
+                    {
+                      if (c == 'V' || c == 'W')
+                        {
+                          regno = lastregno;
+                          s = s_reset;
+                          args++;
+                        }
+                    }
+                  switch (c)
+                    {
+                    case '1':
+                    case '4':
+                    case '7':
+                      ip-&gt;insn_opcode |= regno &lt;&lt; OP_SH_VUTREG;
+                      break;
+                    case '2':
+                    case '5':
+                    case '8':
+                      ip-&gt;insn_opcode |= regno &lt;&lt; OP_SH_VUSREG;
+                      break;
+                    case '3':
+                    case '6':
+                      ip-&gt;insn_opcode |= regno &lt;&lt; OP_SH_VUDREG;
+                      break;
+                    }
+                  lastregno = regno;
+                  continue;
+                }
 
 	      switch (*args++)
 		{
@@ -10805,8 +11206,20 @@
   {"no-relax-branch", no_argument, NULL, OPTION_NO_RELAX_BRANCH},
 #define OPTION_MIPS32R2 (OPTION_MD_BASE + 41)
   {"mips32r2", no_argument, NULL, OPTION_MIPS32R2},
+#define OPTION_M5900 (OPTION_MD_BASE + 42)
+  {"m5900", no_argument, NULL, OPTION_M5900},
+#define OPTION_NO_M5900 (OPTION_MD_BASE + 43)
+  {"no-m5900", no_argument, NULL, OPTION_NO_M5900},
+#define OPTION_WARN_SHORT_LOOP (OPTION_MD_BASE + 44)
+  {"mwarn-short-loop", no_argument, NULL, OPTION_WARN_SHORT_LOOP},
+#define OPTION_NO_WARN_SHORT_LOOP (OPTION_MD_BASE + 45)
+  {"mno-warn-short-loop", no_argument, NULL, OPTION_NO_WARN_SHORT_LOOP},
+#define OPTION_SINGLE_FLOAT (OPTION_MD_BASE + 46)
+  {"msingle-float", no_argument, NULL,  OPTION_SINGLE_FLOAT},
+#define OPTION_NO_SINGLE_FLOAT (OPTION_MD_BASE + 47)
+  {"no-msingle-float", no_argument, NULL, OPTION_NO_SINGLE_FLOAT},
 #ifdef OBJ_ELF
-#define OPTION_ELF_BASE    (OPTION_MD_BASE + 42)
+#define OPTION_ELF_BASE    (OPTION_MD_BASE + 48)
 #define OPTION_CALL_SHARED (OPTION_ELF_BASE + 0)
   {"KPIC",        no_argument, NULL, OPTION_CALL_SHARED},
   {"call_shared", no_argument, NULL, OPTION_CALL_SHARED},
@@ -10898,8 +11311,9 @@
 	mips_debug = atoi (arg);
       /* When the MIPS assembler sees -g or -g2, it does not do
          optimizations which limit full symbolic debugging.  We take
-         that to be equivalent to -O0.  */
-      if (mips_debug == 2)
+         that to be equivalent to -O0. Careful that we do not increase
+         the opts from 0 to 1 though! */
+      if ((mips_debug == 2) &amp;&amp; (mips_optimize &gt; 1))
 	mips_optimize = 1;
       break;
 
@@ -10975,6 +11389,14 @@
     case OPTION_NO_M3900:
       break;
 
+    case OPTION_M5900:
+      mips_set_option_string (&amp;mips_arch_string, "5900");
+      mips_set_option_string (&amp;mips_tune_string, "5900");
+      break;
+
+    case OPTION_NO_M5900:
+      break;
+
     case OPTION_MDMX:
       mips_opts.ase_mdmx = 1;
       break;
@@ -11027,6 +11449,22 @@
       mips_relax_branch = 0;
       break;
 
+    case OPTION_NO_WARN_SHORT_LOOP:
+      mips_warn_short_loop = 0;
+      break;
+
+    case OPTION_WARN_SHORT_LOOP:
+      mips_warn_short_loop = 1;
+      break;
+
+    case OPTION_NO_SINGLE_FLOAT:
+      mips_single_float = 0;
+      break;
+
+    case OPTION_SINGLE_FLOAT:
+      mips_single_float = 1;
+      break;
+
 #ifdef OBJ_ELF
       /* When generating ELF code, we permit -KPIC and -call_shared to
 	 select SVR4_PIC, and -non_shared to select no PIC.  This is
@@ -11216,6 +11654,7 @@
 void
 mips_after_parse_args ()
 {
+
   /* GP relative stuff not working for PE */
   if (strncmp (TARGET_OS, "pe", 2) == 0
       &amp;&amp; g_switch_value != 0)
@@ -11333,6 +11772,10 @@
 	mips_flag_mdebug = 1;
       else
 #endif /* OBJ_MAYBE_ECOFF */
+      /* We default to .mdebug (ECOFF-style debugging) for R5900 and IRX.  */
+      if (mips_arch == CPU_R5900 || strcmp (TARGET_OS, "irx") == 0)
+        mips_flag_mdebug = 1;
+      else
 	mips_flag_mdebug = 0;
     }
 }
@@ -11580,6 +12023,129 @@
   return 1;
 }
 
+static int is_jump(insn)
+        unsigned long insn;
+{
+        unsigned long op, subop;
+        int jump =0;
+        op = insn &gt;&gt; 26;
+
+        switch (op) {
+          case  16: /* cop0 */
+          case  17: /* cop1 */
+          case  18: /* cop2 */
+                subop = insn &gt;&gt; 21; subop &amp;= 0x1f;
+                if ( subop != 8 ) { 
+                        break;
+                };
+                /* bc?f, bc?t, bc?fl, bc?tl */
+                /* fall through */
+          case   1 : /* branch or trap */
+          case   2 : /* j xx */
+          case   3 : /* jal xx */
+          case   4 : /* beq s,t, xx */
+          case   5 : /* bne s,t, xx */
+          case   6 : /* blez s,t, xx */
+          case   7 : /* bgtz s,t, xx */
+          case  20 : /* beql s,t, xx */
+          case  21 : /* bnezl/bnel */
+          case  22 : /* blezl s, xx */
+          case  23 : /* bgtzl s, xx */
+                jump ++;
+                break;
+          case 0:
+                subop = insn &amp; 0x3f;
+                if ( subop != 8  /* jr */
+                  &amp;&amp; subop != 9  /* jalr */
+                  &amp;&amp; subop != 15 /* sync */ ) 
+                        break;
+                jump ++;
+                break;
+
+        }
+        return jump;
+}
+
+
+/* On the R5900, we must warn loops that satisfy all of the following  
+   conditions: 
+   
+   * a loop consists of less than equal to six instructions(includes 
+     branch delay slot). 
+ 
+   * a loop contains only one conditional branch instruction at the 
+     end of the loop. 
+ 
+   * a loop does not contain any other branch or jump instructions. 
+ 
+   * a branch delay slot of the loop is not nop. ( EE#2.9 or later ) 
+ 
+   We need to do this because of a bug in the chip. 
+ 
+   */
+/* turn ACCEPT_NOP_IN_BDSLOT on for EE#2.9 or later */
+#define ACCEPT_NOP_IN_BDSLOT 
+
+/* return 1, if we must warn */
+static int check_short_loop(loop_target,fixP)
+        int loop_target;  /* loop_length minus BDslot and self; 
+                                0 means jump to itself */
+        fixS *fixP;
+{
+        const int hazardous_distance = 6;
+        unsigned char *buf;
+        unsigned long insn;
+        int place = fixP-&gt;fx_where;  /* place of this jump in bytes */
+        int i;
+        int frag_size;
+
+        /* check loop length */
+        if ( loop_target &lt; 0 
+            || loop_target  &gt; (hazardous_distance - 2 ) ) 
+                return 0;
+
+        /* check jump beyond the boundary */
+        if ( loop_target &gt; (place/4)) {
+                /* XXX: something to be done ?? */
+                return 0;
+        }
+
+#ifdef ACCEPT_NOP_IN_BDSLOT 
+        /* examin if insn in BD slot is nop */
+        frag_size= fixP-&gt;fx_frag-&gt;fr_fix + 
+                fixP-&gt;fx_frag-&gt;fr_offset * fixP-&gt;fx_frag-&gt;fr_var;
+        if ( (place + 4) &lt;= frag_size ) {
+                buf = (unsigned char *) (place + fixP-&gt;fx_frag-&gt;fr_literal);
+                buf += 4;
+                if (target_big_endian)
+                        insn = (buf[0] &lt;&lt; 24) | (buf[1] &lt;&lt; 16) | 
+                                        (buf[2] &lt;&lt; 8) | buf[3];
+                else
+                        insn = (buf[3] &lt;&lt; 24) | (buf[2] &lt;&lt; 16) | 
+                                        (buf[1] &lt;&lt; 8) | buf[0];
+                if (insn == 0) /* nop */
+                        return 0;
+        }
+#endif 
+
+        buf = (unsigned char *) (place + fixP-&gt;fx_frag-&gt;fr_literal);
+        for (i = 0; i &lt; loop_target ; i++) {
+
+                buf -= 4;
+                if (target_big_endian)
+                        insn = (buf[0] &lt;&lt; 24) | (buf[1] &lt;&lt; 16) | 
+                                        (buf[2] &lt;&lt; 8) | buf[3];
+                else
+                        insn = (buf[3] &lt;&lt; 24) | (buf[2] &lt;&lt; 16) | 
+                                        (buf[1] &lt;&lt; 8) | buf[0];
+                if (is_jump(insn)) { 
+                        /* jump insn is found */
+                        return 0; 
+                }       
+        }
+        return 1;
+}
+
 #ifdef OBJ_ELF
 static int
 mips_need_elf_addend_fixup (fixP)
@@ -11785,6 +12351,7 @@
     case BFD_RELOC_MIPS_CALL_HI16:
     case BFD_RELOC_MIPS_CALL_LO16:
     case BFD_RELOC_MIPS16_GPREL:
+    case BFD_RELOC_MIPS15_S3:
       if (fixP-&gt;fx_pcrel)
 	as_bad_where (fixP-&gt;fx_file, fixP-&gt;fx_line,
 		      _("Invalid PC relative reloc"));
@@ -11933,6 +12500,17 @@
       else
 	insn = (buf[3] &lt;&lt; 24) | (buf[2] &lt;&lt; 16) | (buf[1] &lt;&lt; 8) | buf[0];
 
+      /* check short loop */
+      if (mips_warn_short_loop
+         &amp;&amp; ( ( insn &amp; 0xffff0000) != 0x10000000        /* beq $0,$0 */
+            &amp;&amp; (insn &amp; 0xffff0000) != 0x04010000        /* bgez $0 */
+            &amp;&amp; (insn &amp; 0xffff0000) != 0x04110000 )      /* bgezal $0 */
+         ) {
+          if ( check_short_loop( -(value+1),fixP) )
+            as_warn_where (fixP-&gt;fx_file, fixP-&gt;fx_line,
+                      _("Loop length is too short for r5900."));
+      }
+
       if (value + 0x8000 &lt;= 0xffff)
 	insn |= value &amp; 0xffff;
       else
@@ -12539,6 +13117,12 @@
     mips_opts.ase_mdmx = 1;
   else if (strcmp (name, "nomdmx") == 0)
     mips_opts.ase_mdmx = 0;
+  /* r5900 support with mips1/mips2 */
+  else if (strcmp (name, "r5900") == 0)
+    {
+            mips_arch = CPU_R5900;
+            mips_opts.isa = ISA_MIPS3;
+    }
   else if (strncmp (name, "mips", 4) == 0)
     {
       int reset = 0;
@@ -12607,6 +13191,8 @@
 
       s = (struct mips_option_stack *) xmalloc (sizeof *s);
       s-&gt;next = mips_opts_stack;
+      /* r5900 support with mips1/mips2 */
+      mips_opts.march = mips_arch;
       s-&gt;options = mips_opts;
       mips_opts_stack = s;
     }
@@ -12635,6 +13221,8 @@
 
 	  mips_opts = s-&gt;options;
 	  mips_opts_stack = s-&gt;next;
+         /* r5900 support with mips1/mips2 */
+          mips_arch = mips_opts.march;
 	  free (s);
 	}
     }
@@ -14909,6 +15497,7 @@
   { "r4600",          0,      ISA_MIPS3,      CPU_R4600 },
   { "orion",          0,      ISA_MIPS3,      CPU_R4600 },
   { "r4650",          0,      ISA_MIPS3,      CPU_R4650 },
+  { "r5900",          0,      ISA_MIPS3,      CPU_R5900 },
 
   /* MIPS IV */
   { "r8000",          0,      ISA_MIPS4,      CPU_R8000 },
@@ -15134,6 +15723,7 @@
   show (stream, "4010", &amp;column, &amp;first);
   show (stream, "4100", &amp;column, &amp;first);
   show (stream, "4650", &amp;column, &amp;first);
+  show (stream, "5900", &amp;column, &amp;first);
   fputc ('\n', stream);
 
   fprintf (stream, _("\
diff -burN orig.binutils-2.14/gas/configure binutils-2.14/gas/configure
--- orig.binutils-2.14/gas/configure	2003-06-02 17:35:23.000000000 -0300
+++ binutils-2.14/gas/configure	2007-04-29 04:00:33.000000000 -0300
@@ -2338,6 +2338,7 @@
       m5200)		cpu_type=m68k ;;
       m8*)		cpu_type=m88k ;;
       mips*el)		cpu_type=mips endian=little ;;
+      mips*5900*)	cpu_type=mips endian=little ;;
       mips*)		cpu_type=mips endian=big ;;
       or32*)		cpu_type=or32 endian=big ;;
       pjl*)		cpu_type=pj endian=little ;;
@@ -2423,6 +2424,8 @@
       fr30-*-*)				fmt=elf ;;
       frv-*-*)				fmt=elf ;;
 
+      dvp-*-*)				fmt=elf bfd_gas=yes install_tooldir= ;;
+
       hppa-*-linux*)	case ${cpu} in
 			    hppa*64*)	fmt=elf em=hppalinux64;;
 			    hppa*)	fmt=elf em=linux;;
@@ -2577,6 +2580,7 @@
       mips-*-irix6*)			fmt=elf em=irix ;;
       mips-*-irix5*)			fmt=elf em=irix ;;
       mips-*-irix*)			fmt=ecoff em=irix ;;
+      mips-*-irx*)			fmt=elf endian=little ;;
       mips-*-lnews*)			fmt=ecoff em=lnews ;;
       mips-*-riscos*)			fmt=ecoff ;;
       mips*-*-linux*)			fmt=elf em=tmips ;;
@@ -2586,6 +2590,7 @@
       mips-*-netbsd*)			fmt=elf ;;
       mips-*-openbsd*)			fmt=elf ;;
       mips-*-vxworks*)			fmt=elf ;;
+      mips*-*-irx*)			fmt=elf endian=little em=mipsirx ;;
 
       mmix-*-*)				fmt=elf ;;
       mn10200-*-*)			fmt=elf ;;
diff -burN orig.binutils-2.14/gas/configure.in binutils-2.14/gas/configure.in
--- orig.binutils-2.14/gas/configure.in	2003-06-02 17:35:23.000000000 -0300
+++ binutils-2.14/gas/configure.in	2007-04-29 04:00:33.000000000 -0300
@@ -132,6 +132,7 @@
       m5200)		cpu_type=m68k ;;
       m8*)		cpu_type=m88k ;;
       mips*el)		cpu_type=mips endian=little ;;
+      mips*5900*)	cpu_type=mips endian=little ;;
       mips*)		cpu_type=mips endian=big ;;
       or32*)		cpu_type=or32 endian=big ;;
       pjl*)		cpu_type=pj endian=little ;;
@@ -217,6 +218,8 @@
       fr30-*-*)				fmt=elf ;;
       frv-*-*)				fmt=elf ;;
 
+      dvp-*-*)				fmt=elf bfd_gas=yes install_tooldir= ;;
+
       hppa-*-linux*)	case ${cpu} in
 			    hppa*64*)	fmt=elf em=hppalinux64;;
 			    hppa*)	fmt=elf em=linux;;
@@ -376,6 +379,7 @@
       mips-*-netbsd*)			fmt=elf ;;
       mips-*-openbsd*)			fmt=elf ;;
       mips-*-vxworks*)			fmt=elf ;;
+      mips-*-irx*)			fmt=elf endian=little em=mipsirx ;;
 
       mmix-*-*)				fmt=elf ;;
       mn10200-*-*)			fmt=elf ;;
diff -burN orig.binutils-2.14/include/dis-asm.h binutils-2.14/include/dis-asm.h
--- orig.binutils-2.14/include/dis-asm.h	2003-04-01 11:50:30.000000000 -0400
+++ binutils-2.14/include/dis-asm.h	2007-04-29 04:00:33.000000000 -0300
@@ -242,6 +242,8 @@
 extern int print_insn_sh64x_media	PARAMS ((bfd_vma, disassemble_info *));
 extern int print_insn_frv		PARAMS ((bfd_vma, disassemble_info *));
 extern int print_insn_iq2000            PARAMS ((bfd_vma, disassemble_info *));
+extern int print_insn_dvp		PARAMS ((bfd_vma, disassemble_info*));
+extern int dvp_insn_p			PARAMS ((disassemble_info*));
 
 extern disassembler_ftype arc_get_disassembler PARAMS ((void *));
 extern disassembler_ftype cris_get_disassembler PARAMS ((bfd *));
diff -burN orig.binutils-2.14/include/elf/common.h binutils-2.14/include/elf/common.h
--- orig.binutils-2.14/include/elf/common.h	2003-04-23 18:09:04.000000000 -0300
+++ binutils-2.14/include/elf/common.h	2007-04-29 04:00:33.000000000 -0300
@@ -92,6 +92,7 @@
 #define ET_LOOS		0xFE00	/* Operating system-specific */
 #define ET_HIOS		0xFEFF	/* Operating system-specific */
 #define ET_LOPROC	0xFF00	/* Processor-specific */
+#define ET_IRX		0xFF80  /* IRX file for PS2's IOP */
 #define ET_HIPROC	0xFFFF	/* Processor-specific */
 
 /* Values for e_machine, which identifies the architecture.  These numbers
@@ -286,6 +287,7 @@
 #define PT_HIOS		0x6fffffff	/* OS-specific */
 #define PT_LOPROC	0x70000000	/* Processor-specific */
 #define PT_HIPROC	0x7FFFFFFF	/* Processor-specific */
+#define PT_MIPS_IRXHDR	0x70000080	/* Sony's ugly IRX-ELF extension */
 
 #define PT_GNU_EH_FRAME	(PT_LOOS + 0x474e550)
 
diff -burN orig.binutils-2.14/include/elf/mips.h binutils-2.14/include/elf/mips.h
--- orig.binutils-2.14/include/elf/mips.h	2003-01-27 20:01:08.000000000 -0400
+++ binutils-2.14/include/elf/mips.h	2007-04-29 04:00:33.000000000 -0300
@@ -76,6 +76,13 @@
   /* These relocs are used for the mips16.  */
   RELOC_NUMBER (R_MIPS16_26, 100)
   RELOC_NUMBER (R_MIPS16_GPREL, 101)
+  /* This is used by a mips co-processor instruction.  */
+  RELOC_NUMBER (R_MIPS15_S3, 119)
+  /* These relocs are for the dvp.  */
+  RELOC_NUMBER (R_MIPS_DVP_11_PCREL, 120)
+  RELOC_NUMBER (R_MIPS_DVP_27_S4, 121)
+  RELOC_NUMBER (R_MIPS_DVP_11_S4, 122)
+  RELOC_NUMBER (R_MIPS_DVP_U15_S3, 123)
   /* These are GNU extensions to handle embedded-pic.  */
   RELOC_NUMBER (R_MIPS_PC32, 248)
   RELOC_NUMBER (R_MIPS_PC64, 249)
@@ -186,6 +193,7 @@
 #define E_MIPS_MACH_SB1         0x008a0000
 #define E_MIPS_MACH_5400	0x00910000
 #define E_MIPS_MACH_5500	0x00980000
+#define E_MIPS_MACH_5900        0x00920000
 
 /* Processor specific section indices.  These sections do not actually
    exist.  Symbols with a st_shndx field corresponding to one of these
@@ -333,6 +341,17 @@
 /* Runtime procedure descriptor table exception information (ucode) ??? */
 #define SHT_MIPS_PDR_EXCEPTION	0x70000029
 
+/* .iopmod section for IRXs */
+#define SHT_MIPS_IOPMOD		0x70000080
+
+/* The VU overlay table.  */
+#define SHT_DVP_OVERLAY_TABLE           0x7ffff420
+#define SHNAME_DVP_OVERLAY_TABLE        ".DVP.ovlytab"
+#define SHNAME_DVP_OVERLAY_STRTAB       ".DVP.ovlystrtab"
+/* A VU overlay.  */
+#define SHT_DVP_OVERLAY                 0x7ffff421
+/* Prefix of VU overlay sections.  */
+#define SHNAME_DVP_OVERLAY_PREFIX       ".DVP.overlay."
 
 /* A section of type SHT_MIPS_LIBLIST contains an array of the
    following structure.  The sh_link field is the section index of the
@@ -499,6 +518,10 @@
 /* .MIPS.options section.  */
 #define PT_MIPS_OPTIONS		0x70000002
 
+/* IRX header */
+/* #define PT_MIPS_IRXHDR		0x70000080 let's define it in common.h...*/
+
+
 /* Processor specific dynamic array tags.  */
 
 /* 32 bit version number for runtime linker interface.  */
@@ -690,6 +713,16 @@
 #define STO_HIDDEN		STV_HIDDEN
 #define STO_PROTECTED		STV_PROTECTED
 
+/* These values are used for the dvp.  */
+#define STO_DVP_DMA             0xe8  
+#define STO_DVP_VIF             0xe9  
+#define STO_DVP_GIF             0xea  
+#define STO_DVP_VU              0xeb  
+/* Reserve a couple in case we need them.  */
+#define STO_DVP_RES1            0xec  
+#define STO_DVP_RES2            0xed  
+#define STO_DVP_P(sto) ((sto) &gt;= STO_DVP_DMA &amp;&amp; (sto) &lt;= STO_DVP_RES2)  
+
 /* This value is used for a mips16 .text symbol.  */
 #define STO_MIPS16		0xf0
 
@@ -930,6 +963,31 @@
 extern void bfd_mips_elf64_swap_reginfo_out
   PARAMS ((bfd *, const Elf64_Internal_RegInfo *, Elf64_External_RegInfo *));
 
+/* The vu overlay table is an array of this.  */
+
+typedef struct
+{
+  /* `name' is offset into overlay string table section.  */
+  char name[4];
+  char lma[4];
+  char vma[4];
+} Elf32_Dvp_External_Overlay;
+
+typedef struct
+{
+  bfd_vma name;
+  bfd_vma lma;
+  bfd_vma vma;
+} Elf32_Dvp_Internal_Overlay;
+
+/* overlay swapping routines. */
+extern void bfd_dvp_elf32_swap_overlay_in
+  PARAMS ((bfd *, const Elf32_Dvp_External_Overlay *,
+           Elf32_Dvp_Internal_Overlay *));
+extern void bfd_dvp_elf32_swap_overlay_out
+  PARAMS ((bfd *, const Elf32_Dvp_Internal_Overlay *,
+           Elf32_Dvp_External_Overlay *));
+
 /* Masks for the info work of an ODK_EXCEPTIONS descriptor.  */
 #define OEX_FPU_MIN	0x1f	/* FPEs which must be enabled.  */
 #define OEX_FPU_MAX	0x1f00	/* FPEs which may be enabled.  */
diff -burN orig.binutils-2.14/include/opcode/dvp.h binutils-2.14/include/opcode/dvp.h
--- orig.binutils-2.14/include/opcode/dvp.h	1969-12-31 20:00:00.000000000 -0400
+++ binutils-2.14/include/opcode/dvp.h	2007-04-29 04:00:33.000000000 -0300
@@ -0,0 +1,454 @@
+/* Opcode table for the DVP.
+   Copyright 1998 Free Software Foundation, Inc.
+
+This file is part of GAS, the GNU Assembler, GDB, the GNU debugger, and
+the GNU Binutils.
+
+GAS/GDB 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/GDB 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 or GDB; see the file COPYING.	If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* Enum describing each processing component.
+   In the case where one wants to specify DVP_VU, use DVP_VUUP.  */
+typedef enum {
+  DVP_UNKNOWN, DVP_DMA, DVP_VIF, DVP_GIF, DVP_VUUP, DVP_VULO
+} dvp_cpu;
+
+/* Type to denote a DVP instruction (at least a 32 bit unsigned int).  */
+typedef unsigned int DVP_INSN;
+
+/* Maximum number of operands and syntax chars an instruction can have.  */
+#define DVP_MAX_OPERANDS 16
+
+typedef struct dvp_opcode {
+  char *mnemonic;
+  /* The value stored is 128 + operand number.
+     This allows ASCII chars to go here as well.  */
+  unsigned char syntax[DVP_MAX_OPERANDS];
+  DVP_INSN mask, value;	/* recognize insn if (op&amp;mask)==value */
+  unsigned opcode_word;	/* opcode word to contain contain "value"; usually 0 */
+		      	/* (definition of a word is target specific) */
+  int flags;		/* various flag bits */
+
+/* Values for `flags'.  */
+
+/* This insn is a conditional branch.  */
+#define DVP_OPCODE_COND_BRANCH 1
+/* Ignore this insn during disassembly.  */
+#define DVP_OPCODE_IGNORE_DIS 2
+/* CPU specific values begin at 0x10.  */
+
+  /* These values are used to optimize assembly and disassembly.  Each insn is
+     on a list of related insns (same first letter for assembly, same insn code
+     for disassembly).  */
+  /* FIXME: May wish to move this to separate table.  */
+  struct dvp_opcode *next_asm;	/* Next instruction to try during assembly.  */
+  struct dvp_opcode *next_dis;	/* Next instruction to try during disassembly.  */
+
+  /* Macros to create the hash values for the lists.  */
+#define DVP_HASH_UPPER_OPCODE(string) \
+  (tolower ((string)[0]) &gt;= 'a' &amp;&amp; tolower ((string)[0]) &lt;= 'z' \
+   ? tolower ((string)[0]) - 'a' : 26)
+#define DVP_HASH_LOWER_OPCODE(string) \
+  (tolower ((string)[0]) &gt;= 'a' &amp;&amp; tolower ((string)[0]) &lt;= 'z' \
+   ? tolower ((string)[0]) - 'a' : 26)
+/* ??? The icode hashing is very simplistic.
+   upper: bits 0x3c, can't use lower two bits because of bc field
+   lower: upper 6 bits  */
+#define DVP_ICODE_HASH_SIZE 6 /* bits */
+#define DVP_HASH_UPPER_ICODE(insn) \
+  ((insn) &amp; 0x3c)
+#define DVP_HASH_LOWER_ICODE(insn) \
+  ((((insn) &amp; 0xfc) &gt;&gt; 26) &amp; 0x3f)
+
+  /* Macros to access `next_asm', `next_dis' so users needn't care about the
+     underlying mechanism.  */
+#define DVP_OPCODE_NEXT_ASM(op) ((op)-&gt;next_asm)
+#define DVP_OPCODE_NEXT_DIS(op) ((op)-&gt;next_dis)
+} dvp_opcode;
+
+/* The operand table.  */
+
+typedef struct dvp_operand {
+  /* The number of bits in the operand (may be unused for a modifier).  */
+  unsigned char bits;
+
+  /* How far the operand is left shifted in the instruction, or
+     the modifier's flag bit (may be unused for a modifier).  */
+  unsigned char shift;
+
+  /* An index to the instruction word which will contain the operand value.
+     Usually 0.  */
+  unsigned char word;
+
+  /* Various flag bits.  */
+  int flags;
+
+/* Values for `flags'.  */
+
+/* This operand is a suffix to the opcode.  */
+#define DVP_OPERAND_SUFFIX 1
+
+/* This operand is a relative branch displacement.  The disassembler
+   prints these symbolically if possible.  */
+#define DVP_OPERAND_RELATIVE_BRANCH 2
+
+/* This operand is an absolute branch address.  The disassembler
+   prints these symbolically if possible.  */
+#define DVP_OPERAND_ABSOLUTE_BRANCH 4
+
+/* This operand is a mips address.  The disassembler
+   prints these symbolically if possible.  */
+#define DVP_OPERAND_MIPS_ADDRESS 8
+
+/* This operand is a vu address.  The disassembler
+   prints these symbolically if possible.  */
+#define DVP_OPERAND_VU_ADDRESS 0x10
+
+/* This operand takes signed values (default is unsigned).
+   The default was chosen to be unsigned as most fields are unsigned
+   (e.g. registers).  */
+#define DVP_OPERAND_SIGNED 0x20
+
+/* This operand takes signed values, but also accepts a full positive
+   range of values.  That is, if bits is 16, it takes any value from
+   -0x8000 to 0xffff.  */
+#define DVP_OPERAND_SIGNOPT 0x40
+
+/* This operand should be regarded as a negative number for the
+   purposes of overflow checking (i.e., the normal most negative
+   number is disallowed and one more than the normal most positive
+   number is allowed).  This flag will only be set for a signed
+   operand.  */
+#define DVP_OPERAND_NEGATIVE 0x80
+
+/* This operand doesn't really exist.  The program uses these operands
+   in special ways by creating insertion or extraction functions to have
+   arbitrary processing performed during assembly/disassemble.
+   Parse and print routines are ignored for FAKE operands.  */
+#define DVP_OPERAND_FAKE 0x100
+
+/* This operand is the address of the `unpack' insn.  */
+#define DVP_OPERAND_UNPACK_ADDRESS 0x200
+
+/* Inline data.  */
+#define DVP_OPERAND_DMA_INLINE 0x10000
+
+/* Pointer to the data.  */
+#define DVP_OPERAND_DMA_ADDR 0x20000
+
+/* Pointer to the data.  */
+#define DVP_OPERAND_DMA_NEXT 0x40000
+
+/* The actual count operand.  */
+#define DVP_OPERAND_DMA_COUNT 0x80000
+
+/* A 32 bit floating point immediate.  */
+#define DVP_OPERAND_FLOAT 0x100000
+
+/* An 11-bit immediate operand.  May be a label.  */
+#define DVP_OPERAND_RELOC_11_S4 0x200000
+
+/* An 15-bit unsigned immediate operand.  May be a label.  */
+#define DVP_OPERAND_RELOC_U15_S3 0x400000
+
+/* Modifier values.  */
+
+/* A dot is required before a suffix.  e.g. .le  */
+/* ??? Not currently used.  */
+#define DVP_MOD_DOT 0x1000000
+
+/* The count operand was an asterisk.  */
+#define DVP_OPERAND_AUTOCOUNT 0x2000000
+
+/* Ignore the word part of any shift and operate on the "first" word
+   of the instruction.  */
+#define DVP_MOD_THIS_WORD 0x4000000
+
+/* Sum of all DVP_MOD_XXX bits.  */
+#define DVP_MOD_BITS 0xff000000
+
+/* Non-zero if the operand type is really a modifier.  */
+#define DVP_MOD_P(X) ((X) &amp; DVP_MOD_BITS)
+
+  /* Parse function.  This is used by the assembler.
+     MODS is a list of modifiers preceding the operand in the syntax string.
+     If the operand cannot be parsed an error message is stored in ERRMSG,
+     otherwise ERRMSG is unchanged.  */
+  long (*parse) PARAMS ((const struct dvp_opcode *opcode,
+			 const struct dvp_operand *operand,
+			 int mods, char **str, const char **errmsg));
+
+  /* Insertion function.  This is used by the assembler.  To insert an
+     operand value into an instruction, check this field.
+
+     If it is NULL, execute
+         i |= (p &amp; ((1 &lt;&lt; o-&gt;bits) - 1)) &lt;&lt; o-&gt;shift;
+     (I is the instruction which we are filling in, O is a pointer to
+     this structure, and OP is the opcode value; this assumes twos
+     complement arithmetic).
+
+     If this field is not NULL, then simply call it with the
+     instruction and the operand value.  It will overwrite the appropriate
+     bits of the instruction with the operand's value.
+     MODS is a list of modifiers preceding the operand in the syntax string.
+     If the ERRMSG argument is not NULL, then if the operand value is illegal,
+     *ERRMSG will be set to a warning string (the operand will be inserted in
+     any case).  If the operand value is legal, *ERRMSG will be unchanged.
+     OPCODE may be NULL, in which case the value isn't known.  This happens
+     when applying fixups.  */
+
+  void (*insert) PARAMS ((const struct dvp_opcode *opcode,
+			  const struct dvp_operand *operand,
+			  int mods, DVP_INSN *insn,
+			  long value, const char **errmsg));
+
+  /* Extraction function.  This is used by the disassembler.  To
+     extract this operand type from an instruction, check this field.
+
+     If it is NULL, compute
+         op = ((i) &gt;&gt; o-&gt;shift) &amp; ((1 &lt;&lt; o-&gt;bits) - 1);
+	 if ((o-&gt;flags &amp; DVP_OPERAND_SIGNED) != 0
+	     &amp;&amp; (op &amp; (1 &lt;&lt; (o-&gt;bits - 1))) != 0)
+	   op -= 1 &lt;&lt; o-&gt;bits;
+     (I is the instruction, O is a pointer to this structure, and OP
+     is the result; this assumes twos complement arithmetic).
+
+     If this field is not NULL, then simply call it with the
+     instruction value.  It will return the value of the operand.  If
+     the INVALID argument is not NULL, *INVALID will be set to
+     non-zero if this operand type can not actually be extracted from
+     this operand (i.e., the instruction does not match).  If the
+     operand is valid, *INVALID will not be changed.
+     MODS is a list of modifiers preceding the operand in the syntax string.
+
+     INSN is a pointer to one or two `DVP_INSN's.  The first element is
+     the insn, the second is an immediate constant if present.
+     FIXME: just thrown in here for now.
+     */
+
+  long (*extract) PARAMS ((const struct dvp_opcode *opcode,
+			   const struct dvp_operand *operand,
+			   int mods, DVP_INSN *insn, int *pinvalid));
+
+  /* Print function.  This is used by the disassembler.  */
+  void (*print) PARAMS ((const struct dvp_opcode *opcode,
+			 const struct dvp_operand *operand,
+			 int mods, DVP_INSN *insn,
+			 disassemble_info *info, long value));
+} dvp_operand;
+
+/* Given an operand entry, return the table index.  */
+#define DVP_OPERAND_INDEX(op) ((op) - 128)
+
+/* Macro support.  */
+
+typedef struct dvp_macro {
+  const char *template;
+  const char *result;
+} dvp_macro;
+
+/* Expand an instruction if it is a macro, else NULL.  */
+extern char * dvp_expand_macro PARAMS ((const dvp_macro *, int, char *));
+
+/* VU support.  */
+
+/* Flag values.
+   The actual value stored in the insn is left shifted by 27.  */
+#define VU_FLAG_I 16
+#define VU_FLAG_E 8
+#define VU_FLAG_M 4
+#define VU_FLAG_D 2
+#define VU_FLAG_T 1
+
+/* Positions, masks, and values of various fields used in multiple places
+   (the opcode table, the disassembler, GAS).  */
+#define VU_SHIFT_DEST 21
+#define VU_SHIFT_TREG 16
+#define VU_SHIFT_SREG 11
+#define VU_SHIFT_DREG 6
+#define VU_MASK_REG 31
+/* Bits for multiple dest choices.  */
+#define VU_DEST_X 8
+#define VU_DEST_Y 4
+#define VU_DEST_Z 2
+#define VU_DEST_W 1
+/* Values for a single dest choice.  */
+#define VU_SDEST_X 0
+#define VU_SDEST_Y 1
+#define VU_SDEST_Z 2
+#define VU_SDEST_W 3
+
+extern const dvp_operand vu_operands[];
+extern /*const*/ dvp_opcode vu_upper_opcodes[];
+extern /*const*/ dvp_opcode vu_lower_opcodes[];
+extern const int vu_upper_opcodes_count;
+extern const int vu_lower_opcodes_count;
+
+const dvp_opcode *vu_upper_opcode_lookup_asm PARAMS ((const char *));
+const dvp_opcode *vu_lower_opcode_lookup_asm PARAMS ((const char *));
+const dvp_opcode *vu_upper_opcode_lookup_dis PARAMS ((unsigned int));
+const dvp_opcode *vu_lower_opcode_lookup_dis PARAMS ((unsigned int));
+
+/* VIF support.  */
+
+/* VIF opcode flags.
+   The usage here is a bit wasteful of bits, but there's enough bits
+   and we can always make better usage later.
+   We begin at 0x10 because the lower 4 bits are reserved for
+   general opcode flags.  */
+
+/* 2 word instruction */
+#define VIF_OPCODE_LEN2 0x10
+/* 5 word instruction */
+#define VIF_OPCODE_LEN5 0x20
+/* variable length instruction */
+#define VIF_OPCODE_LENVAR 0x40
+/* the mpg instruction */
+#define VIF_OPCODE_MPG 0x80
+/* the direct instruction */
+#define VIF_OPCODE_DIRECT 0x100
+/* the directhl instruction */
+#define VIF_OPCODE_DIRECTHL 0x200
+/* the unpack instruction */
+#define VIF_OPCODE_UNPACK 0x400
+
+/* Instruction flag bits.  M,R,U are only applicable to `unpack'.
+   These aren't the actual bit numbers.  They're for internal use.
+   The insert/extract handlers do the appropriate conversions.  */
+#define VIF_FLAG_I 1
+#define VIF_FLAG_M 2
+#define VIF_FLAG_R 4
+#define VIF_FLAG_U 8
+
+/* The "mode" operand of the "stmod" insn.  */
+#define VIF_MODE_DIRECT 0
+#define VIF_MODE_ADD 1
+#define VIF_MODE_ADDROW 2
+
+/* Unpack types.  */
+typedef enum {
+  VIF_UNPACK_S_32 = 0,
+  VIF_UNPACK_S_16 = 1,
+  VIF_UNPACK_S_8 = 2,
+  VIF_UNPACK_UNUSED3 = 3,
+  VIF_UNPACK_V2_32 = 4,
+  VIF_UNPACK_V2_16 = 5,
+  VIF_UNPACK_V2_8 = 6,
+  VIF_UNPACK_UNUSED7 = 7,
+  VIF_UNPACK_V3_32 = 8,
+  VIF_UNPACK_V3_16 = 9,
+  VIF_UNPACK_V3_8 = 10,
+  VIF_UNPACK_UNUSED11 = 11,
+  VIF_UNPACK_V4_32 = 12,
+  VIF_UNPACK_V4_16 = 13,
+  VIF_UNPACK_V4_8 = 14,
+  VIF_UNPACK_V4_5 = 15
+} unpack_type;
+
+extern const dvp_operand vif_operands[];
+extern /*const*/ dvp_opcode vif_opcodes[];
+extern const int vif_opcodes_count;
+extern const dvp_macro vif_macros[];
+extern const int vif_macro_count;
+const dvp_opcode *vif_opcode_lookup_asm PARAMS ((const char *));
+const dvp_opcode *vif_opcode_lookup_dis PARAMS ((unsigned int));
+
+/* Return length, in 32 bit words, of just parsed vif insn,
+   or 0 if unknown.  */
+int vif_len PARAMS ((void));
+
+/* Given the first word of a VIF insn, return its length.  */
+int vif_insn_len PARAMS ((DVP_INSN, dvp_cpu *));
+
+/* Return the length value to use for an unpack instruction.  */
+int vif_unpack_len_value PARAMS ((unpack_type, int, int, int));
+
+/* Return the length, in words, of an unpack insn.  */
+int vif_unpack_len PARAMS ((unpack_type, int));
+
+/* Fetch user data for variable length insns.  */
+void vif_get_var_data PARAMS ((const char **, int *));
+
+/* Fetch the current values of wl,cl.  */
+void vif_get_wl_cl PARAMS ((int *, int *));
+
+/* Various operand numbers.  */
+extern const int vif_operand_mpgloc;
+extern const int vif_operand_datalen_special;
+
+/* DMA support.  */
+
+/* DMA instruction flags.  */
+#define DMA_FLAG_PCE0 1
+#define DMA_FLAG_PCE1 2
+#define DMA_FLAG_INT 4
+#define DMA_FLAG_SPR 8
+
+extern const dvp_operand dma_operands[];
+extern /*const*/ dvp_opcode dma_opcodes[];
+extern const int dma_opcodes_count;
+const dvp_opcode *dma_opcode_lookup_asm PARAMS ((const char *));
+const dvp_opcode *dma_opcode_lookup_dis PARAMS ((unsigned int));
+int dvp_dma_operand_autocount PARAMS ((int));
+
+/* Various operand numbers.  */
+extern const int dma_operand_count;
+extern const int dma_operand_addr;
+
+/* GIF support.  */
+
+/* Maximum value for nloop.  */
+#define GIF_MAX_NLOOP 32767
+
+/* The PRE bit in the appropriate word in a tag.  */
+#define GIF_PRE (1 &lt;&lt; 14)
+
+/* The values here correspond to the values in the instruction.  */
+typedef enum { GIF_PACKED = 0, GIF_REGLIST = 1, GIF_IMAGE = 2 } gif_type;
+
+typedef enum {
+  GIF_REG_PRIM = 0,
+  GIF_REG_RGBAQ = 1,
+  GIF_REG_ST = 2,
+  GIF_REG_UV = 3,
+  GIF_REG_XYZF2 = 4,
+  GIF_REG_XYZ2 = 5,
+  GIF_REG_TEX0_1 = 6,
+  GIF_REG_TEX0_2 = 7,
+  GIF_REG_CLAMP_1 = 8,
+  GIF_REG_CLAMP_2 = 9,
+  GIF_REG_XYZF = 10,
+  GIF_REG_UNUSED11 = 11, /* 11 is unused */
+  GIF_REG_XYZF3 = 12,
+  GIF_REG_XYZ3 = 13,
+  GIF_REG_A_D = 14,
+  GIF_REG_NOP = 15
+} gif_reg;
+
+extern const dvp_operand gif_operands[];
+extern /*const*/ dvp_opcode gif_opcodes[];
+extern const int gif_opcodes_count;
+const dvp_opcode *gif_opcode_lookup_asm PARAMS ((const char *));
+const dvp_opcode *gif_opcode_lookup_dis PARAMS ((unsigned int));
+extern int gif_nloop PARAMS ((void));
+extern int gif_nregs PARAMS ((void));
+
+/* Various operand numbers.  */
+extern const int gif_operand_nloop;
+
+/* Utility fns in dvp-opc.c.  */
+void dvp_opcode_init_tables PARAMS ((int));
+void dvp_opcode_init_parse PARAMS ((void));
+void dvp_opcode_init_print PARAMS ((void));
diff -burN orig.binutils-2.14/include/opcode/mips.h binutils-2.14/include/opcode/mips.h
--- orig.binutils-2.14/include/opcode/mips.h	2003-04-08 21:12:24.000000000 -0300
+++ binutils-2.14/include/opcode/mips.h	2007-04-29 04:00:33.000000000 -0300
@@ -164,6 +164,24 @@
 #define	OP_OP_SDC2		0x3e
 #define	OP_OP_SDC3		0x3f	/* a.k.a. sd */
 
+/* r5900's VU additional features */
+#define OP_SH_VADDI             6 
+#define OP_MASK_VADDI           0x1f 
+#define OP_SH_VUTREG            16 
+#define OP_MASK_VUTREG          0x1f 
+#define OP_SH_VUSREG            11 
+#define OP_MASK_VUSREG          0x1f 
+#define OP_SH_VUDREG            6 
+#define OP_MASK_VUDREG          0x1f 
+#define OP_SH_VUFSF             21 
+#define OP_MASK_VUFSF           0x3 
+#define OP_SH_VUFTF             23 
+#define OP_MASK_VUFTF           0x3 
+#define OP_SH_VUDEST            21 
+#define OP_MASK_VUDEST          0xf 
+#define OP_SH_VUCALLMS          6 
+#define OP_MASK_VUCALLMS        0x7fff 
+
 /* Values in the 'VSEL' field.  */
 #define MDMX_FMTSEL_IMM_QH	0x1d
 #define MDMX_FMTSEL_IMM_OB	0x1e
@@ -233,13 +251,13 @@
    "x" accept and ignore register name
    "z" must be zero register
    "K" 5 bit Hardware Register (rdhwr instruction) (OP_*_RD)
-   "+A" 5 bit ins/ext position, which becomes LSB (OP_*_SHAMT).
+   "*A" 5 bit ins/ext position, which becomes LSB (OP_*_SHAMT).
 	Enforces: 0 &lt;= pos &lt; 32.
-   "+B" 5 bit ins size, which becomes MSB (OP_*_INSMSB).
-	Requires that "+A" occur first to set position.
+   "*B" 5 bit ins size, which becomes MSB (OP_*_INSMSB).
+	Requires that "*A" occur first to set position.
 	Enforces: 0 &lt; (pos+size) &lt;= 32.
-   "+C" 5 bit ext size, which becomes MSBD (OP_*_EXTMSBD).
-	Requires that "+A" occur first to set position.
+   "*C" 5 bit ext size, which becomes MSBD (OP_*_EXTMSBD).
+	Requires that "*A" occur first to set position.
 	Enforces: 0 &lt; (pos+size) &lt;= 32.
 
    Floating point instructions:
@@ -260,8 +278,27 @@
    "e" 5 bit vector register byte specifier (OP_*_VECBYTE)
    "%" 3 bit immediate vr5400 vector alignment operand (OP_*_VECALIGN)
    see also "k" above
-   "+D" Combined destination register ("G") and sel ("H") for CP0 ops,
+   "*D" Combined destination register ("G") and sel ("H") for CP0 ops,
 	for pretty-printing in disassembly only.
+   "0" vu0 immediate for viaddi (OP_*_VADDI) 
+   "1" vu0 fp reg position 1 (OP_*_VUTREG) 
+   "2" vu0 fp reg position 2 (OP_*_VUSREG) 
+   "3" vu0 fp reg position 3 (OP_*_VUDREG) 
+   "4" vu0 int reg position 1 (OP_*_VUTREG) 
+   "5" vu0 int reg position 2 (OP_*_VUSREG) 
+   "6" vu0 int reg position 3 (OP_*_VURREG) 
+   "7" vu0 fp reg with ftf modifier (OP_*_VUTREG and OP_*_VUFTF) 
+   "8" vu0 fp reg with fsf modifier (OP_*_VUSREG and OP_*_VUFSF) 
+   "9" vi27 for vcallmsr 
+   "#" optional suffix that must match if present 
+   "=" dest operant completer, must match previous dest if present 
+   "&amp;" dest instruction completer (OP_*_VUDEST) 
+   ";" dest instruction completer, must by xyz 
+   "!" vu0 I register 
+   "^" vu0 Q register 
+   "_" vu0 R register 
+   "@" vu0 ACC register 
+   "g" Immediate operand for vcallms instruction. (OP_*_VUCALLMS) 
 
    Macro instructions:
    "A" General 32 bit expression
@@ -283,14 +320,15 @@
    "()" parens surrounding optional value
    ","  separates operands
    "[]" brackets around index for vector-op scalar operand specifier (vr5400)
-   "+"  Start of extension sequence.
+   "+-" auto inc/dec decorators
+   "*"  Start of extension sequence.
 
    Characters used so far, for quick reference when adding more:
-   "%[]&lt;&gt;(),+"
+   "%[]&lt;&gt;(),*!#&amp;+-0123456789;^_="
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-   "abcdefhijklopqrstuvwxz"
+   "abcdefghijkl  opqrstuvwx z"
 
-   Extension character sequences used so far ("+" followed by the
+   Extension character sequences used so far ("*" followed by the
    following), for quick reference when adding more:
    "ABCD"
 */
@@ -418,6 +456,8 @@
 #define INSN_5400		  0x01000000
 /* NEC VR5500 instruction.  */
 #define INSN_5500		  0x02000000
+/* Toshiba R5900 (PlayStation2) instruction.  */
+#define INSN_5900                 0x04000000
 
 /* MIPS ISA defines, use instead of hardcoding ISA level.  */
 
@@ -450,6 +490,7 @@
 #define CPU_R5000	5000
 #define CPU_VR5400	5400
 #define CPU_VR5500	5500
+#define CPU_R5900       5900
 #define CPU_R6000	6000
 #define CPU_R8000	8000
 #define CPU_R10000	10000
@@ -479,6 +520,7 @@
      || (cpu == CPU_VR4120 &amp;&amp; ((insn)-&gt;membership &amp; INSN_4120) != 0)	\
      || (cpu == CPU_VR5400 &amp;&amp; ((insn)-&gt;membership &amp; INSN_5400) != 0)	\
      || (cpu == CPU_VR5500 &amp;&amp; ((insn)-&gt;membership &amp; INSN_5500) != 0)	\
+     || (cpu == CPU_R5900 &amp;&amp; ((insn)-&gt;membership &amp; INSN_5900) != 0)     \
      || 0)	/* Please keep this term for easier source merging.  */
 
 /* This is a list of macro expanded instructions.
diff -burN orig.binutils-2.14/ld/configure.tgt binutils-2.14/ld/configure.tgt
--- orig.binutils-2.14/ld/configure.tgt	2003-06-12 11:25:52.000000000 -0300
+++ binutils-2.14/ld/configure.tgt	2007-04-29 04:00:33.000000000 -0300
@@ -404,8 +404,15 @@
 mips*vr4100-*-elf*)	targ_emul=elf32b4300 ;;
 mips*vr5000el-*-elf*)	targ_emul=elf32l4300 ;;
 mips*vr5000-*-elf*)	targ_emul=elf32b4300 ;;
+mips*r5900*-*-elf*)	targ_emul=elf32l5900
+			targ_extra_emuls=mipsirx
+			;;
+dvp-*-*)                targ_emul=elf32l5900 ;;
 mips*el-*-elf*)		targ_emul=elf32elmip ;;
 mips*-*-elf*)		targ_emul=elf32ebmip ;;
+mips*el-*-irx*)		targ_emul=mipsirx
+			targ_extra_emuls=elf32elmip
+			;;
 mips*el-*-rtems*)	targ_emul=elf32elmip ;;
 mips*-*-rtems*)		targ_emul=elf32ebmip ;;
 mips*el-*-vxworks*)	targ_emul=elf32elmip ;;
diff -burN orig.binutils-2.14/ld/emulparams/elf32l5900.sh binutils-2.14/ld/emulparams/elf32l5900.sh
--- orig.binutils-2.14/ld/emulparams/elf32l5900.sh	1969-12-31 20:00:00.000000000 -0400
+++ binutils-2.14/ld/emulparams/elf32l5900.sh	2007-04-29 04:00:33.000000000 -0300
@@ -0,0 +1,29 @@
+SCRIPT_NAME=elf
+OUTPUT_FORMAT="elf32-littlemips"
+BIG_OUTPUT_FORMAT="elf32-bigmips"
+LITTLE_OUTPUT_FORMAT="elf32-littlemips"
+TEXT_START_ADDR=0x100000
+MAXPAGESIZE=128
+INITIAL_READONLY_SECTIONS='.reginfo : { *(.reginfo) }'
+OTHER_TEXT_SECTIONS='*(.mips16.fn.*) *(.mips16.call.*)'
+OTHER_GOT_SYMBOLS='
+  _gp = ALIGN(16) + 0x7ff0;
+'
+OTHER_GOT_SECTIONS='
+  .lit8 : { *(.lit8) }
+  .lit4 : { *(.lit4) }
+'
+TEXT_START_SYMBOLS='_ftext = . ;'
+DATA_START_SYMBOLS='_fdata = . ;'
+OTHER_BSS_SYMBOLS='_fbss = .;'
+EXECUTABLE_SYMBOLS='_DYNAMIC_LINK = 0;'
+OTHER_SECTIONS='
+  .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
+  .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
+'
+ARCH="mips:5900"
+MACHINE=
+TEMPLATE_NAME=elf32
+GENERATE_SHLIB_SCRIPT=yes
+DYNAMIC_LINK=FALSE
+EMBEDDED=yes
diff -burN orig.binutils-2.14/ld/emulparams/mipsirx.sh binutils-2.14/ld/emulparams/mipsirx.sh
--- orig.binutils-2.14/ld/emulparams/mipsirx.sh	1969-12-31 20:00:00.000000000 -0400
+++ binutils-2.14/ld/emulparams/mipsirx.sh	2007-04-29 04:00:33.000000000 -0300
@@ -0,0 +1,8 @@
+SCRIPT_NAME=irx
+OUTPUT_FORMAT="elf32-littlemips"
+ARCH=mips
+ENTRY=_start
+TEXT_START_ADDR=0x0
+DATA_ADDR=.
+TEMPLATE_NAME=irx
+
diff -burN orig.binutils-2.14/ld/emultempl/irx.em binutils-2.14/ld/emultempl/irx.em
--- orig.binutils-2.14/ld/emultempl/irx.em	1969-12-31 20:00:00.000000000 -0400
+++ binutils-2.14/ld/emultempl/irx.em	2007-04-29 04:00:33.000000000 -0300
@@ -0,0 +1,560 @@
+# This shell script emits a C file. -*- C -*-
+# It does some substitutions.
+test -z "${ELFSIZE}" &amp;&amp; ELFSIZE=32
+if [ -z "$MACHINE" ]; then
+  OUTPUT_ARCH=${ARCH}
+else
+  OUTPUT_ARCH=${ARCH}:${MACHINE}
+fi
+cat &gt;e${EMULATION_NAME}.c &lt;&lt;EOF
+/* This file is is generated by a shell script.  DO NOT EDIT! */
+
+/* IRX emulation code for ${EMULATION_NAME}
+   Copyright (C) 1991, 1993 Free Software Foundation, Inc.
+   Written by Steve Chamberlain steve@cygnus.com
+   IRX support by Douglas C. Knight fsdck@uaf.edu
+
+This file is part of GLD, the Gnu Linker.
+
+This program 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 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#define TARGET_IS_${EMULATION_NAME}
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libiberty.h"
+#include "safe-ctype.h"
+#include "getopt.h"
+
+#include "bfdlink.h"
+
+#include "ld.h"
+#include "ldmain.h"
+#include "ldmisc.h"
+#include "ldexp.h"
+#include "ldlang.h"
+#include "ldfile.h"
+#include "ldemul.h"
+#include &lt;ldgram.h&gt;
+#include "elf/common.h"
+
+static void gld${EMULATION_NAME}_before_parse PARAMS ((void));
+static void gld${EMULATION_NAME}_after_parse PARAMS ((void));
+static void gld${EMULATION_NAME}_after_open PARAMS ((void));
+static void gld${EMULATION_NAME}_before_allocation PARAMS ((void));
+static void gld${EMULATION_NAME}_after_allocation PARAMS ((void));
+static char *gld${EMULATION_NAME}_get_script PARAMS ((int *isfile));
+
+static bfd_boolean building_irx;
+static lang_output_section_statement_type *iopmod_section_statement;
+
+static struct lang_output_section_phdr_list default_phdr = {
+  name: " DEFAULT",
+  next: NULL,
+  used: FALSE
+};
+static struct lang_output_section_phdr_list irxhdr_phdr = {
+  name: " IRXHDR",
+  next: NULL,
+  used: FALSE
+};
+static struct lang_output_section_phdr_list none_phdr = {
+  name: "NONE",
+  next: NULL,
+  used: FALSE
+};
+
+
+/* This is called just before parsing the linker script.  It does some
+   bfd configuration for irx filex, creates the irx program header,
+   and adds an .iopmod output section to the statement list.  */
+
+static void
+gld${EMULATION_NAME}_before_parse (void)
+{
+  ldfile_set_output_arch ("`echo ${ARCH}`");
+
+  /* Only setup IRX headers for executable files.  */
+  if (link_info.relocateable)
+    {
+      building_irx = FALSE;
+      return;
+    }
+  
+  building_irx = TRUE;
+  /* IRX files are dynamic.  They need their relocations.  */
+  link_info.emitrelocations = TRUE;
+  /* This isn't really needed, but I've never seen an IRX that's
+     properly paged.  */
+  config.magic_demand_paged = FALSE;
+  
+  /* The IRXHDR program header must be the first in the list of
+     program headers.  By creating it here, before processing the
+     linker script, it is always at the beginning of the list.  */
+  lang_new_phdr (irxhdr_phdr.name, exp_intop (PT_MIPS_IRXHDR), FALSE,
+		 FALSE, NULL, exp_intop (PF_R));
+
+  /* An .iopmod output section will be needed.  By creating the
+     .iopmod section before parsing the linker script, the iopmod
+     section statement will be placed at the top of the statement list
+     after the *ABS* section, but before any other sections from the
+     linker script.  The statements from the linker script can then be
+     accessed through iopmod_section_statement-&gt;next.  */
+  iopmod_section_statement = lang_output_section_statement_lookup (".iopmod");
+}
+
+
+/* gldmipsirx_after_parse () is executed after the linker script has
+   been parsed.  It puts the .iopmod output section into the IRXHDR
+   segment.  If the linker script did not create any program headers
+   of its own, this function also creates a PT_LOAD segment and puts
+   all of the remaining sections in it.  */
+
+static void
+gld${EMULATION_NAME}_after_parse (void)
+{
+  bfd_boolean linkscript_uses_phdrs;
+  lang_statement_union_type *stat;
+
+  /* Only setup IRX headers for executable files.  */
+  if (building_irx == FALSE)
+    return;
+
+  /* Determine whether the link script assigned any sections to phdrs.  */
+
+  /* FIXME: If none of the sections have been explicitly assigned to a
+     segment, this function assumes that the linker script did not
+     create any program headers.  This function should not put the
+     sections in a new PT_LOAD segment if the linker script, for some
+     odd reason, created program headers but did not assign any of the
+     sections to any segments.  There is currently no way to tell
+     whether the linker script created any program headers because the
+     program header list is a static variable.  If there ever is any
+     reason to create program headers, but have all of the sections
+     remain segmentless, explicitly assign the first section in the
+     linker script to the section "NONE". */
+
+  linkscript_uses_phdrs = FALSE;
+  for (stat = iopmod_section_statement-&gt;next; stat != NULL;
+       stat = stat-&gt;header.next)
+    if (stat-&gt;header.type == lang_output_section_statement_enum)
+      if (stat-&gt;output_section_statement.phdrs != NULL)
+	{
+	  linkscript_uses_phdrs = TRUE;
+	  break;
+	}
+
+  if (! linkscript_uses_phdrs)
+    {
+      /* The linker script didn't use program headers, so build the
+         default segment and put all of the sections in it.  */
+      lang_new_phdr (default_phdr.name, exp_intop (PT_LOAD), FALSE,
+		     FALSE, NULL, exp_intop (PF_R | PF_W | PF_X));
+      for (stat = iopmod_section_statement-&gt;next; stat != NULL;
+	   stat = stat-&gt;header.next)
+	if (stat-&gt;header.type == lang_output_section_statement_enum)
+	    stat-&gt;output_section_statement.phdrs = &amp;default_phdr;
+    }
+
+  /* Add iopmod to the IRXHDR segment.  */
+  irxhdr_phdr.next = iopmod_section_statement-&gt;phdrs;
+  iopmod_section_statement-&gt;phdrs = &amp;irxhdr_phdr;
+
+  /* Keep IRXHDR from following through to following sections.  */
+  for (stat = iopmod_section_statement-&gt;next; stat != NULL;
+       stat = stat-&gt;header.next)
+    if (stat-&gt;header.type == lang_output_section_statement_enum)
+      {
+	if (! stat-&gt;output_section_statement.phdrs)
+	  {
+	    if (irxhdr_phdr.next)
+	      stat-&gt;output_section_statement.phdrs = irxhdr_phdr.next;
+	    else
+	      stat-&gt;output_section_statement.phdrs = &amp;none_phdr;
+	  }
+	break;
+      }
+}
+
+/* This is a macro to add a data statement of data type T and the data
+   expression E to the end of the statement list LP.  */
+
+#define new_data_stat(t,e,lp) {                         \
+  lang_statement_union_type *d;                         \
+  d = stat_alloc (sizeof (lang_data_statement_type));   \
+  d-&gt;header.type = lang_data_statement_enum;            \
+  d-&gt;header.next = NULL;                                \
+  ((lang_data_statement_type *) d)-&gt;exp = e;            \
+  ((lang_data_statement_type *) d)-&gt;type = t;           \
+  lang_statement_append (lp, d, &amp;d-&gt;header.next);       \
+}
+
+/* Called after input files have been opened, and their symbols
+   parsed.  If the .iopmod section is empty, construct a valid .iopmod
+   structure.  If _irx_id is defined, it is used as the id structure to
+   for this irx.  */
+
+static void
+gld${EMULATION_NAME}_after_open (void)
+{
+  lang_statement_list_type *stat_ptr;
+  union lang_statement_union *stat_list_remainder;
+  union lang_statement_union **stat_list_old_tail;
+  struct bfd_link_hash_entry *h;  
+  bfd_vma irxname_pos;
+  asection *irxname_sec;
+  bfd_vma irxid_pos;
+  asection *irxid_sec;
+  int irx_version;
+  char buf[64];
+  bfd_boolean result;
+  unsigned uit;
+  asymbol **syms;
+  arelent **rels;
+  long size;
+  long count;
+
+  /* Only setup IRX headers for executable files.  */
+  if (building_irx == FALSE)
+    return;
+  
+  /* If the linker script didn't already start the .iopmod section,
+     build the basics now.  */
+  stat_ptr = &amp;iopmod_section_statement-&gt;children;
+  if (stat_ptr-&gt;head == NULL)
+    {
+      new_data_stat (LONG, exp_intop (0xffffffff), stat_ptr);
+      new_data_stat (LONG, exp_unop (ABSOLUTE, exp_nameop (NAME, "_start")),
+		 stat_ptr);
+      new_data_stat (LONG, exp_nameop (NAME, "_gp"), stat_ptr);
+      new_data_stat (LONG, exp_nameop (NAME, "_text_size"), stat_ptr);
+      new_data_stat (LONG, exp_nameop (NAME, "_data_size"), stat_ptr);
+      new_data_stat (LONG, exp_nameop (NAME, "_bss_size"), stat_ptr);
+      stat_list_old_tail = NULL;
+    }
+  else
+    {
+      /* If the linker script built an .iopmod section, make sure the
+         first six data statments are LONGS, and that the first LONG
+         is set to the int 0xffffffff.  If not, assume the linker
+         script knows what it's doing, and leave everything alone.  */
+      union lang_statement_union *stat_iter;
+      stat_iter = stat_ptr-&gt;head;
+      /* Make sure the first satement is a LONG data statement with
+         the value 0xffffffff.  */
+      if (stat_iter-&gt;header.type != lang_data_statement_enum
+	  || stat_iter-&gt;data_statement.type != LONG
+	  || stat_iter-&gt;data_statement.exp-&gt;type.node_class != etree_value
+	  || stat_iter-&gt;data_statement.exp-&gt;type.node_code != INT
+	  || stat_iter-&gt;data_statement.exp-&gt;value.value != 0xffffffff)
+	return;
+
+      /* Make sure the next five statements are LONG data statements.  */
+      stat_iter = stat_iter-&gt;header.next;
+      if (stat_iter-&gt;header.type != lang_data_statement_enum
+	  || stat_iter-&gt;data_statement.type != LONG)
+	return;
+      stat_iter = stat_iter-&gt;header.next;
+      if (stat_iter-&gt;header.type != lang_data_statement_enum
+	  || stat_iter-&gt;data_statement.type != LONG)
+	return;
+      stat_iter = stat_iter-&gt;header.next;
+      if (stat_iter-&gt;header.type != lang_data_statement_enum
+	  || stat_iter-&gt;data_statement.type != LONG)
+	return;
+      stat_iter = stat_iter-&gt;header.next;
+      if (stat_iter-&gt;header.type != lang_data_statement_enum
+	  || stat_iter-&gt;data_statement.type != LONG)
+	return;
+      stat_iter = stat_iter-&gt;header.next;
+      if (stat_iter-&gt;header.type != lang_data_statement_enum
+	  || stat_iter-&gt;data_statement.type != LONG)
+	return;
+      
+      /* Cut the statement list off after the six LONGs, so that new
+         data can be inserted.  */
+      stat_list_old_tail = stat_ptr-&gt;tail;
+      stat_ptr-&gt;tail = &amp;stat_iter-&gt;header.next;
+      stat_list_remainder = stat_iter-&gt;header.next;
+    }
+
+  /* Look for an _irx_id symbol.  */
+  h = bfd_link_hash_lookup (link_info.hash, "_irx_id", FALSE, FALSE, TRUE);
+  if (h != NULL)
+    if (h-&gt;type != bfd_link_hash_defined &amp;&amp; h-&gt;type != bfd_link_hash_defweak)
+      h = NULL;
+
+  /* If _irx_id is undefined.  Set the IRX version to 0.0 and name to
+     an empty string.  */
+  if (h == NULL)
+    {
+      new_data_stat (SHORT, exp_intop (0x0), stat_ptr);
+      new_data_stat (BYTE, exp_intop (0x0), stat_ptr);
+      goto eout;
+    }
+
+  /* Retrieve the contents of _irx_id.  */
+  irxid_pos = h-&gt;u.def.value;
+  irxid_sec = h-&gt;u.def.section;
+  result = bfd_get_section_contents (irxid_sec-&gt;owner,
+				     irxid_sec, buf,
+				     irxid_pos, 8);
+  if (! result)
+    {
+      einfo ("%F%P: could not read the contents of _irx_id from %E\n",
+	     irxid_sec-&gt;owner);
+      goto eout;
+    }
+
+  /* Extract the version number, and a pointer to the irx name.  */
+  irxname_pos = bfd_get_32 (irxid_sec-&gt;owner, &amp;buf[0]);
+  irx_version = bfd_get_16 (irxid_sec-&gt;owner, &amp;buf[4]);
+
+  /* Things get really ugly here.  The contents of the symbol table
+     and relocations are already in memory in the bfd's elf backend,
+     after calling the canonicalize functions there are two copies in
+     memory, one in the backends own format, and one in bfd's standard
+     format.  This could be a waste of memory, but we need to follow
+     the relocations, and digging through the backend's data would be
+     even uglier.  */
+
+  /* Canonicalize the symbol table for the bfd contaning _irx_id.  */
+  size = bfd_get_symtab_upper_bound (irxid_sec-&gt;owner);
+  if (size &lt; 0)
+    {
+      einfo ("%F%P: could not read symbols from %E\n", irxid_sec-&gt;owner);
+      goto eout;
+    }
+  syms = xmalloc (size);
+  count = bfd_canonicalize_symtab (irxid_sec-&gt;owner, syms);
+  if (count &lt; 0)
+    {
+      einfo ("%F%P: could not read symbols from %E\n",
+	     irxid_sec-&gt;owner);
+      goto eout;
+    }
+  
+  /* Canonicalize the relocations for the section containing _irx_id.  */
+  size = bfd_get_reloc_upper_bound (irxid_sec-&gt;owner, irxid_sec);
+  if (size &lt; 0)
+    {
+      einfo ("%F%P: could not read relocations from %E\n", irxid_sec-&gt;owner);
+      free (syms);
+      goto eout;
+    }
+  rels = xmalloc (size);
+  count = bfd_canonicalize_reloc (irxid_sec-&gt;owner, irxid_sec, rels, syms);
+  if (count &lt; 0)
+    {
+      einfo ("%F%P: could not read relocations from %E\n", irxid_sec-&gt;owner);
+      free (syms);
+      goto eout;
+    }
+
+  /* Find the relocation for the irx name pointer in _irx_id, and
+     extract the section that the irx name is stored in from it.  */
+  irxname_sec = NULL;
+  for (uit = 0; uit &lt; count; ++uit)
+    {
+      arelent *r;
+      r = rels[uit];
+      if (r-&gt;address == irxid_pos)
+	{
+	  if ((*r-&gt;sym_ptr_ptr)-&gt;flags &amp; (BSF_OBJECT | BSF_FUNCTION
+					  | BSF_SECTION_SYM))
+	    irxname_sec = (*r-&gt;sym_ptr_ptr)-&gt;section;
+	  else
+	    {
+	      /* The irx name is not in the same bfd, but we know what
+		 the symbol is called now, so we can look for it in
+		 the other bfds.  */
+	      h = bfd_link_hash_lookup (link_info.hash,
+					(*r-&gt;sym_ptr_ptr)-&gt;name, FALSE,
+					FALSE, TRUE);
+	      if (h != NULL)
+		{
+		  irxname_pos = h-&gt;u.def.value;
+		  irxname_sec = h-&gt;u.def.section;
+		}
+	    }
+	}
+    }
+
+  /* Release what little memory we can.  */
+  free (rels);
+  free (syms);
+  
+  if (irxname_sec == NULL)
+    {
+      einfo ("%F%P: failed to resolve the irx name\n");
+      goto eout;
+    }
+
+  /* Retrieve up to 63 bytes of the the contents of the irx name.  */
+  count = irxname_sec-&gt;_raw_size;
+  count -= irxname_pos;
+  if (count &gt; 63)
+    count = 63;
+  buf[count] = 0;
+  result = bfd_get_section_contents (irxname_sec-&gt;owner,
+				     irxname_sec, buf,
+				     irxname_pos, count);
+  if (! result)
+    {
+      einfo ("%F%P: failed to resolve the irx name\n");
+      goto eout;
+    }
+
+  /* Set the first LONG in the .iopmod section to the address of the
+     _irx_id structure.  */
+  stat_ptr-&gt;head-&gt;data_statement.exp =
+    exp_unop (ABSOLUTE, exp_nameop (NAME, "_irx_id"));
+  /* Add the version number to the header.  */
+  new_data_stat (SHORT, exp_intop (irx_version), stat_ptr);
+  /* Add each byte of the IRX name to the header.  FIXME: If the name
+     is long and the linker script already has a lot of statements in
+     it, the linker could run out of space in the parse tree.  This
+     data could be added to the linker script as LONGs, and a SHORT,
+     and/or a BYTE to save tree nodes.  */
+  for (uit = 0; (uit &lt; 64) &amp;&amp; (buf[uit] != 0); ++uit)
+    new_data_stat (BYTE, exp_intop ((unsigned int) buf[uit]), stat_ptr);
+  /* Tack a null on to the end of the string.  */
+  new_data_stat (BYTE, exp_intop (0x0), stat_ptr);
+
+ eout:
+  /* Put anything that was cut off the end of the .iopmod section back
+     on.  */
+  if (stat_list_old_tail != NULL)
+    {
+      *stat_ptr-&gt;tail = stat_list_remainder;
+      stat_ptr-&gt;tail = stat_list_old_tail;
+    }
+  return;
+}
+
+/* Called before creating the output sections in the output bfd.
+   Since the .iopmod section's data is completely generated, it
+   doesn't have any alignment attributes associated with it.  Force
+   the iopmod section to be word aligned.  */
+
+static void
+gld${EMULATION_NAME}_before_allocation (void)
+{
+  /* Only setup IRX headers for executable files.  */
+  if (building_irx == FALSE)
+    return;
+
+  if (iopmod_section_statement-&gt;bfd_section-&gt;alignment_power &lt; 2)
+    iopmod_section_statement-&gt;bfd_section-&gt;alignment_power = 2;
+}
+
+/* Called after the output sections have been created.  Makes the
+   .iopmod section exist in the file image, but not in the memory
+   image by marking it as a loaded section, but not allocated.  */
+
+static void
+gld${EMULATION_NAME}_after_allocation (void)
+{
+  /* Only setup IRX headers for executable files.  */
+  if (building_irx == FALSE)
+    return;
+
+  iopmod_section_statement-&gt;bfd_section-&gt;flags |= SEC_LOAD;
+  iopmod_section_statement-&gt;bfd_section-&gt;flags &amp;= ~SEC_ALLOC;
+}
+
+static char *
+gld${EMULATION_NAME}_get_script(isfile)
+     int *isfile;
+EOF
+
+if test -n "$COMPILE_IN"
+then
+# Scripts compiled in.
+
+# sed commands to quote an ld script as a C string.
+sc="-f stringify.sed"
+
+cat &gt;&gt;e${EMULATION_NAME}.c &lt;&lt;EOF
+{			     
+  *isfile = 0;
+
+  if (link_info.relocateable &amp;&amp; config.build_constructors)
+    return
+EOF
+sed $sc ldscripts/${EMULATION_NAME}.xu                 &gt;&gt; e${EMULATION_NAME}.c
+echo '  ; else if (link_info.relocateable) return'     &gt;&gt; e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xr                 &gt;&gt; e${EMULATION_NAME}.c
+echo '  ; else if (!config.text_read_only) return'     &gt;&gt; e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xbn                &gt;&gt; e${EMULATION_NAME}.c
+echo '  ; else if (!config.magic_demand_paged) return' &gt;&gt; e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xn                 &gt;&gt; e${EMULATION_NAME}.c
+echo '  ; else return'                                 &gt;&gt; e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.x                  &gt;&gt; e${EMULATION_NAME}.c
+echo '; }'                                             &gt;&gt; e${EMULATION_NAME}.c
+
+else
+# Scripts read from the filesystem.
+
+cat &gt;&gt;e${EMULATION_NAME}.c &lt;&lt;EOF
+{			     
+  *isfile = 1;
+
+  if (link_info.relocateable &amp;&amp; config.build_constructors)
+    return "ldscripts/${EMULATION_NAME}.xu";
+  else if (link_info.relocateable)
+    return "ldscripts/${EMULATION_NAME}.xr";
+  else if (!config.text_read_only)
+    return "ldscripts/${EMULATION_NAME}.xbn";
+  else if (!config.magic_demand_paged)
+    return "ldscripts/${EMULATION_NAME}.xn";
+  else
+    return "ldscripts/${EMULATION_NAME}.x";
+}
+EOF
+
+fi
+
+cat &gt;&gt;e${EMULATION_NAME}.c &lt;&lt;EOF
+
+struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = 
+{
+  gld${EMULATION_NAME}_before_parse,
+  syslib_default,
+  hll_default,
+  gld${EMULATION_NAME}_after_parse,
+  gld${EMULATION_NAME}_after_open,
+  gld${EMULATION_NAME}_after_allocation,
+  set_output_arch_default,
+  ldemul_default_target,
+  gld${EMULATION_NAME}_before_allocation,
+  gld${EMULATION_NAME}_get_script,
+  "${EMULATION_NAME}",
+  "${OUTPUT_FORMAT}",
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL
+};
+EOF
diff -burN orig.binutils-2.14/ld/Makefile.am binutils-2.14/ld/Makefile.am
--- orig.binutils-2.14/ld/Makefile.am	2003-04-24 09:36:07.000000000 -0300
+++ binutils-2.14/ld/Makefile.am	2007-04-29 04:00:33.000000000 -0300
@@ -154,6 +154,7 @@
 	eelf32_i860.o \
 	eelf32_sparc.o \
 	eelf32b4300.o \
+	eelf32l5900.o \
 	eelf32bmip.o \
 	eelf32bmipn32.o \
 	eelf32btsmip.o \
@@ -249,6 +250,7 @@
 	emipsbsd.o \
 	emipsidt.o \
 	emipsidtl.o \
+	emipsirx.o \
 	emipslit.o \
 	emipslnews.o \
 	emipspe.o \
@@ -662,6 +664,9 @@
   $(srcdir)/emulparams/elf32b4300.sh $(srcdir)/emulparams/elf32bmip.sh \
   $(srcdir)/emultempl/elf32.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} elf32l4300 "$(tdir_elf32l4300)"
+eelf32l5900.c: $(srcdir)/emulparams/elf32l5900.sh
+  $(srcdir)/emultempl/elf32.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+	${GENSCRIPTS} elf32l5900 "$(tdir_elf32l5900)"
 eelf32lmip.c: $(srcdir)/emulparams/elf32lmip.sh \
   $(srcdir)/emulparams/elf32bmip.sh \
   $(srcdir)/emultempl/elf32.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
@@ -1002,6 +1007,9 @@
 emipsidtl.c: $(srcdir)/emulparams/mipsidtl.sh \
   $(srcdir)/emultempl/mipsecoff.em $(srcdir)/scripttempl/mips.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} mipsidtl "$(tdir_mipsidtl)"
+emipsirx.c:  $(srcdir)/emulparams/mipsirx.sh \
+  $(srcdir)/emultempl/irx.em $(srcdir)/scripttempl/irx.sc ${GEN_DEPENDS}
+	${GENSCRIPTS} mipsirx "$(tdir_mipsirx)"
 emipslit.c:  $(srcdir)/emulparams/mipslit.sh \
   $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/mips.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} mipslit "$(tdir_mipslit)"
diff -burN orig.binutils-2.14/ld/Makefile.in binutils-2.14/ld/Makefile.in
--- orig.binutils-2.14/ld/Makefile.in	2003-04-24 09:36:07.000000000 -0300
+++ binutils-2.14/ld/Makefile.in	2007-04-29 04:00:33.000000000 -0300
@@ -283,6 +283,7 @@
 	eelf32iq2000.o \
 	eelf32iq10.o \
 	eelf32l4300.o \
+	eelf32l5900.o \
 	eelf32lmip.o \
 	eelf32lppc.o \
 	eelf32lppcnto.o \
@@ -363,6 +364,7 @@
 	emipsbsd.o \
 	emipsidt.o \
 	emipsidtl.o \
+	emipsirx.o \
 	emipslit.o \
 	emipslnews.o \
 	emipspe.o \
@@ -1388,6 +1390,9 @@
   $(srcdir)/emulparams/elf32b4300.sh $(srcdir)/emulparams/elf32bmip.sh \
   $(srcdir)/emultempl/elf32.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} elf32l4300 "$(tdir_elf32l4300)"
+eelf32l5900.c: $(srcdir)/emulparams/elf32l5900.sh \
+  $(srcdir)/emultempl/elf32.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+	${GENSCRIPTS} elf32l5900 "$(tdir_elf32l5900)"
 eelf32lmip.c: $(srcdir)/emulparams/elf32lmip.sh \
   $(srcdir)/emulparams/elf32bmip.sh \
   $(srcdir)/emultempl/elf32.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
@@ -1728,6 +1733,9 @@
 emipsidtl.c: $(srcdir)/emulparams/mipsidtl.sh \
   $(srcdir)/emultempl/mipsecoff.em $(srcdir)/scripttempl/mips.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} mipsidtl "$(tdir_mipsidtl)"
+emipsirx.c:  $(srcdir)/emulparams/mipsirx.sh \
+  $(srcdir)/emultempl/irx.em $(srcdir)/scripttempl/irx.sc ${GEN_DEPENDS}
+	${GENSCRIPTS} mipsirx "$(tdir_mipsirx)"
 emipslit.c:  $(srcdir)/emulparams/mipslit.sh \
   $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/mips.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} mipslit "$(tdir_mipslit)"
diff -burN orig.binutils-2.14/ld/scripttempl/irx.sc binutils-2.14/ld/scripttempl/irx.sc
--- orig.binutils-2.14/ld/scripttempl/irx.sc	1969-12-31 20:00:00.000000000 -0400
+++ binutils-2.14/ld/scripttempl/irx.sc	2007-04-29 04:00:33.000000000 -0300
@@ -0,0 +1,121 @@
+# Link scripts for PlayStation 2 IRXs.
+
+# NOTE: Limit parameter expansions to a single line.  Cygwin's /bin/sh has
+# been freaking out when it reaches the end of a line, even when the text is
+# being quoted.
+
+test -z "$ENTRY" &amp;&amp; ENTRY=_start
+
+test -z "$TEXT_START_ADDR" &amp;&amp; TEXT_START_ADDR="0x0000"
+
+if test "x$LD_FLAG" = "xn" -o "x$LD_FLAG" = "xN"; then
+  DATA_ADDR=.
+else
+  test -z "$DATA_ADDR" &amp;&amp; DATA_ADDR=0x10000000
+fi
+
+# These variables are used to put braces in parameter expansions so that
+# they expand properly.
+LBRACE="{"
+RBRACE="}"
+
+cat &lt;&lt;EOF
+/* Link script for PlayStation 2 IRXs
+ * Written by Douglas C. Knight &lt;fsdck@uaf.edu&gt;
+ */
+
+OUTPUT_FORMAT("${OUTPUT_FORMAT}")
+
+${RELOCATING+${LIB_SEARCH_DIRS}}
+
+ENTRY(${ENTRY})
+SECTIONS
+{
+  ${RELOCATING+/* This is the .iopmod section for the IRX, it contains}
+  ${RELOCATING+   information that the IOP uses when loading the IRX.}
+  ${RELOCATING+   This section is placed in its own segment.  */}
+  ${RELOCATING+.iopmod : ${LBRACE}}
+  ${RELOCATING+  /* The linker will replace this first LONG with a pointer}
+  ${RELOCATING+     to _irx_id if the symbol has been defined.  */}
+  ${RELOCATING+  LONG (0xffffffff) ;}
+ 
+  ${RELOCATING+  LONG (_start) ;}
+  ${RELOCATING+  LONG (_gp) ;}
+  ${RELOCATING+  LONG (_text_size) ;}
+  ${RELOCATING+  LONG (_data_size) ;}
+  ${RELOCATING+  LONG (_bss_size) ;}
+  ${RELOCATING+  /* The linker will put a SHORT here with the version of}
+  ${RELOCATING+     the IRX (or zero if there is no version).  */}
+  ${RELOCATING+  /* The linker will put a null terminated string here}
+  ${RELOCATING+     containing the name of the IRX (or an empty string if}
+  ${RELOCATING+     the name is not known).  */}
+  ${RELOCATING+${RBRACE}}
+
+  ${RELOCATING+. = ${TEXT_START_ADDR} ;}
+  ${RELOCATING+_ftext = . ;}
+  .text : {
+    CREATE_OBJECT_SYMBOLS
+    * ( .text )
+    * ( .text.* )
+    * ( .init )
+    * ( .fini )
+  } = 0
+  ${RELOCATING+_etext  =  . ;}
+
+  ${RELOCATING+. = ${DATA_ADDR} ;}
+  ${RELOCATING+_fdata = . ;}
+  .rodata : {
+    * ( .rdata )
+    * ( .rodata )
+    * ( .rodata1 )
+    * ( .rodata.* )
+  } = 0
+
+  .data : {
+    * ( .data )
+    * ( .data1 )
+    * ( .data.* )
+    ${CONSTRUCTING+CONSTRUCTORS}
+  }
+
+  ${RELOCATING+. = ALIGN(16) ;}
+  ${RELOCATING+_gp = . + 0x8000 ;}
+
+  .sdata : {
+    * ( .lit8 )
+    * ( .lit4 )
+    * ( .sdata )
+    * ( .sdata.* )
+  }
+  ${RELOCATING+_edata = . ;}
+
+  ${RELOCATING+. = ALIGN(4) ;}
+  ${RELOCATING+_fbss = . ;}
+  .sbss : {
+    * ( .sbss )
+    * ( .scommon )
+  }
+
+  ${RELOCATING+_bss_start = . ;}
+  .bss : {
+    * ( .bss )
+    * ( COMMON )
+    ${RELOCATING+. = ALIGN(4) ;}
+  }
+  ${RELOCATING+_end = . ;}
+
+  ${RELOCATING+_text_size = _etext - _ftext ;}
+  ${RELOCATING+_data_size = _edata - _fdata ;}
+  ${RELOCATING+_bss_size = _end - _fbss ;}
+
+  /* This is the stuff that we don't want to be put in an IRX.  */
+  /DISCARD/ : {
+	* ( .reginfo )
+	* ( .mdebug.* )
+	/* Until I can figure out if there's a better way to rid ourselves of .rel.dyn
+	   this will have to do.  - MRB  */
+	* ( .rel.dyn )
+  }
+}
+
+EOF
diff -burN orig.binutils-2.14/opcodes/configure binutils-2.14/opcodes/configure
--- orig.binutils-2.14/opcodes/configure	2003-06-02 17:35:17.000000000 -0300
+++ binutils-2.14/opcodes/configure	2007-04-29 04:00:33.000000000 -0300
@@ -4671,6 +4671,7 @@
         bfd_tic4x_arch)         ta="$ta tic4x-dis.lo" ;;
 	bfd_tic54x_arch)	ta="$ta tic54x-dis.lo tic54x-opc.lo" ;;
 	bfd_tic80_arch)		ta="$ta tic80-dis.lo tic80-opc.lo" ;;
+	bfd_dvp_arch)		ta="$ta mips-dis.lo mips-opc.lo mips16-opc.lo dvp-dis.lo dvp-opc.lo" ;;
 	bfd_v850_arch)		ta="$ta v850-opc.lo v850-dis.lo" ;;
 	bfd_v850e_arch)		ta="$ta v850-opc.lo v850-dis.lo" ;;
 	bfd_v850ea_arch)	ta="$ta v850-opc.lo v850-dis.lo" ;;
diff -burN orig.binutils-2.14/opcodes/configure.in binutils-2.14/opcodes/configure.in
--- orig.binutils-2.14/opcodes/configure.in	2003-06-02 17:35:17.000000000 -0300
+++ binutils-2.14/opcodes/configure.in	2007-04-29 04:00:33.000000000 -0300
@@ -234,6 +234,7 @@
         bfd_tic4x_arch)         ta="$ta tic4x-dis.lo" ;;
 	bfd_tic54x_arch)	ta="$ta tic54x-dis.lo tic54x-opc.lo" ;;
 	bfd_tic80_arch)		ta="$ta tic80-dis.lo tic80-opc.lo" ;;
+	bfd_dvp_arch)		ta="$ta mips-dis.lo mips-opc.lo mips16-opc.lo dvp-dis.lo dvp-opc.lo" ;;
 	bfd_v850_arch)		ta="$ta v850-opc.lo v850-dis.lo" ;;
 	bfd_v850e_arch)		ta="$ta v850-opc.lo v850-dis.lo" ;;
 	bfd_v850ea_arch)	ta="$ta v850-opc.lo v850-dis.lo" ;;
diff -burN orig.binutils-2.14/opcodes/disassemble.c binutils-2.14/opcodes/disassemble.c
--- orig.binutils-2.14/opcodes/disassemble.c	2003-04-01 11:50:30.000000000 -0400
+++ binutils-2.14/opcodes/disassemble.c	2007-04-29 04:00:33.000000000 -0300
@@ -75,7 +75,6 @@
 #define INCLUDE_SHMEDIA
 #endif
 
-
 disassembler_ftype
 disassembler (abfd)
      bfd *abfd;
@@ -232,12 +231,16 @@
       disassemble = print_insn_mcore;
       break;
 #endif
-#ifdef ARCH_mips
+#if defined(ARCH_mips) || defined(ARCH_dvp)
     case bfd_arch_mips:
+#ifdef ARCH_mips
       if (bfd_big_endian (abfd))
 	disassemble = print_insn_big_mips;
       else
 	disassemble = print_insn_little_mips;
+#else
+	disassemble = print_insn_dvp;
+#endif
       break;
 #endif
 #ifdef ARCH_mmix
diff -burN orig.binutils-2.14/opcodes/dvp-dis.c binutils-2.14/opcodes/dvp-dis.c
--- orig.binutils-2.14/opcodes/dvp-dis.c	1969-12-31 20:00:00.000000000 -0400
+++ binutils-2.14/opcodes/dvp-dis.c	2007-04-29 04:00:33.000000000 -0300
@@ -0,0 +1,439 @@
+/* Instruction printing code for the DVP
+   Copyright (C) 1998 Free Software Foundation, Inc. 
+
+   This program 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 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "dis-asm.h"
+#include "opcode/dvp.h"
+#include "elf-bfd.h"
+#include "elf/mips.h"
+#include "opintl.h"
+
+static int print_dma PARAMS ((bfd_vma, disassemble_info *));
+static int print_vif PARAMS ((bfd_vma, disassemble_info *));
+static int print_gif PARAMS ((bfd_vma, disassemble_info *));
+static int print_vu PARAMS ((bfd_vma, disassemble_info *));
+static void print_insn PARAMS ((dvp_cpu, const dvp_opcode *, const dvp_operand *,
+				bfd_vma, disassemble_info *, DVP_INSN *));
+
+static int read_word PARAMS ((bfd_vma, disassemble_info *, DVP_INSN *));
+
+/* Return the dvp mach number to use or 0 if not at a dvp insn.
+   The different machs are distinguished by marking the start of a group
+   of related insns by a specially marked label.  */
+
+int
+dvp_info_mach_type (info)
+     struct disassemble_info *info;
+{
+  if (info-&gt;flavour == bfd_target_elf_flavour
+      &amp;&amp; info-&gt;symbols != NULL)
+    {
+      asymbol **sym,**symend;
+
+      for (sym = info-&gt;symbols, symend = sym + info-&gt;num_symbols;
+	   sym &lt; symend; ++sym)
+	{
+	  int sto = (*(elf_symbol_type **) sym)-&gt;internal_elf_sym.st_other;
+	  switch (sto)
+	    {
+	    case STO_DVP_DMA : return bfd_mach_dvp_dma;
+	    case STO_DVP_VIF : return bfd_mach_dvp_vif;
+	    case STO_DVP_GIF : return bfd_mach_dvp_gif;
+	    case STO_DVP_VU : return bfd_mach_dvp_vu;
+	    default : break;
+	    }
+	}
+    }
+
+  return 0;
+}
+
+/* Print one instruction from PC on INFO-&gt;STREAM.
+   Return the size of the instruction.  */
+
+int
+print_insn_dvp (memaddr, info)
+     bfd_vma memaddr;
+     disassemble_info *info;
+{
+  int mach;
+  static int initialized = 0;
+
+  if (!initialized)
+    {
+      initialized = 1;
+      dvp_opcode_init_tables (0);
+    }
+
+  mach = dvp_info_mach_type (info);
+  if (mach == bfd_mach_dvp_dma
+      || info-&gt;mach == bfd_mach_dvp_dma)
+    return print_dma (memaddr, info);
+  if (mach == bfd_mach_dvp_vif
+      || info-&gt;mach == bfd_mach_dvp_vif)
+    return print_vif (memaddr, info);
+  if (mach == bfd_mach_dvp_gif
+      || info-&gt;mach == bfd_mach_dvp_gif)
+    return print_gif (memaddr, info);
+  if (mach == bfd_mach_dvp_vu
+      || info-&gt;mach == bfd_mach_dvp_vu)
+    return print_vu (memaddr, info);
+
+  (*info-&gt;fprintf_func) (info-&gt;stream, _("*unknown*"));
+  return 4;
+}
+
+/* Print one DMA instruction from PC on INFO-&gt;STREAM.
+   Return the size of the instruction.  */
+
+static int
+print_dma (memaddr, info)
+     bfd_vma memaddr;
+     disassemble_info *info;
+{
+  bfd_byte buffer[8];
+  int i, status, len;
+  DVP_INSN insn_buf[2];
+
+  /* The length of a dma tag is 16, however the upper two words are
+     vif insns.  */
+
+  len = 8;
+  status = (*info-&gt;read_memory_func) (memaddr, buffer, len, info);
+  if (status != 0)
+    {
+      (*info-&gt;memory_error_func) (status, memaddr, info);
+      return -1;
+    }
+
+  for (i = 0; i &lt; 2; ++i)
+    insn_buf[i] = bfd_getl32 (buffer + i * 4);
+
+  print_insn (DVP_DMA,
+	      dma_opcode_lookup_dis (insn_buf[1]), dma_operands,
+	      memaddr, info, insn_buf);
+  return len;
+}
+
+/* Print one VIF instruction from PC on INFO-&gt;STREAM.
+   Return the size of the instruction.  */
+
+static int
+print_vif (memaddr, info)
+     bfd_vma memaddr;
+     disassemble_info *info;
+{
+  int len;
+  /* Non-zero if vu code follows (i.e. this is mpg).  */
+  dvp_cpu cpu;
+  DVP_INSN insn_buf[5];
+
+  if (read_word (memaddr, info, insn_buf) != 0)
+    return -1;
+
+  len = vif_insn_len (insn_buf[0], &amp;cpu);
+  switch (len)
+    {
+    case 5 :
+      if (read_word (memaddr + 16, info, insn_buf + 4) != 0)
+	return -1;
+      if (read_word (memaddr + 12, info, insn_buf + 3) != 0)
+	return -1;
+      if (read_word (memaddr + 8, info, insn_buf + 2) != 0)
+	return -1;
+      /* fall through */
+    case 2 :
+      if (read_word (memaddr + 4, info, insn_buf + 1) != 0)
+	return -1;
+      /* fall through */
+    case 1 :
+    case 0 :
+      break;
+    }
+
+  print_insn (DVP_VIF,
+	      vif_opcode_lookup_dis (insn_buf[0]), vif_operands,
+	      memaddr, info, insn_buf);
+
+  /* If symbols are present and this is an mpg or direct insn, assume there
+     are symbols to distinguish the mach type so that we can properly
+     disassemble the vu code and gif tags.  */
+  if (info-&gt;symbols
+      &amp;&amp; (cpu == DVP_VUUP || cpu == DVP_GIF))
+    return 4;
+  return len * 4;
+}
+
+/* Print one GIF instruction from PC on INFO-&gt;STREAM.
+   Return the size of the instruction.  */
+
+static int
+print_gif (memaddr, info)
+     bfd_vma memaddr;
+     disassemble_info *info;
+{
+  bfd_byte buffer[16];
+  int i, status, len, type, nloop, nregs;
+  DVP_INSN insn_buf[4];
+
+  status = (*info-&gt;read_memory_func) (memaddr, buffer, 16, info);
+  if (status != 0)
+    {
+      (*info-&gt;memory_error_func) (status, memaddr, info);
+      return -1;
+    }
+  len = 16;
+
+  for (i = 0; i &lt; 4; ++i)
+    insn_buf[i] = bfd_getl32 (buffer + i * 4);
+
+  print_insn (DVP_GIF,
+	      gif_opcode_lookup_dis (insn_buf[1]), gif_operands,
+	      memaddr, info, insn_buf);
+
+  type = (insn_buf[1] &gt;&gt; 26) &amp; 3;
+  nloop = insn_buf[0] &amp; 0x7fff;
+  nregs = (insn_buf[1] &gt;&gt; 28) &amp; 15;
+  switch (type)
+    {
+    case GIF_PACKED :
+      return len + nloop * nregs * 16;
+    case GIF_REGLIST :
+      return len + ((nloop * nregs + 1) &amp; ~1) * 8;
+    case GIF_IMAGE :
+      return len + nloop * 16;
+    }
+
+  return len;
+}
+
+/* Print one VU instruction from PC on INFO-&gt;STREAM.
+   Return the size of the instruction.  */
+
+static int
+print_vu (memaddr, info)
+     bfd_vma memaddr;
+     disassemble_info *info;
+{
+  bfd_byte buffer[8];
+  void *stream = info-&gt;stream;
+  fprintf_ftype func = info-&gt;fprintf_func;
+  int status;
+  /* First element is upper, second is lower.  */
+  DVP_INSN upper,lower;
+
+  status = (*info-&gt;read_memory_func) (memaddr, buffer, 8, info);
+  if (status != 0)
+    {
+      (*info-&gt;memory_error_func) (status, memaddr, info);
+      return -1;
+    }
+  /* The lower instruction has the lower address.  */
+  upper = bfd_getl32 (buffer + 4);
+  lower = bfd_getl32 (buffer);
+
+  /* FIXME: This will need revisiting.  */
+  print_insn (DVP_VUUP,
+	      vu_upper_opcode_lookup_dis (upper), vu_operands,
+	      memaddr, info, &amp;upper);
+#ifdef VERTICAL_BAR_SEPARATOR
+  (*func) (stream, " | ");
+#else
+  /* Not sure how much whitespace to print here.
+     At least two spaces, not more than 9, and having columns line up somewhat
+     seems reasonable.  */
+  (*func) (stream, " \t");
+#endif
+  /* If the 'i' bit is set then the lower word is not an insn but a 32 bit
+     floating point immediate value.  */
+  if (upper &amp; 0x80000000)
+    {
+      /* FIXME: assumes float/int are same size/endian.  */
+      union { float f; int i; } x;
+      x.i = lower;
+      (*func) (stream, "loi %g", x.f);
+    }
+  else
+    print_insn (DVP_VULO,
+		vu_lower_opcode_lookup_dis (lower), vu_operands,
+		memaddr, info, &amp;lower);
+
+  return 8;
+}
+
+/* Print one instruction.
+   OPCODE is a pointer to the head of the hash list.  */
+
+static void
+print_insn (cpu, opcode, operand_table, memaddr, info, insn)
+     dvp_cpu cpu;
+     const dvp_opcode *opcode;
+     const dvp_operand *operand_table;
+     bfd_vma memaddr;
+     disassemble_info *info;
+     DVP_INSN *insn;
+{
+  void *stream = info-&gt;stream;
+  fprintf_ftype func = info-&gt;fprintf_func;
+
+  for ( ; opcode != NULL; opcode = DVP_OPCODE_NEXT_DIS (opcode))
+    {
+      const unsigned char *syn;
+      int mods,invalid,num_operands;
+      long value;
+      const dvp_operand *operand;
+
+      /* Ignore insns that have a mask value of 0.
+	 Such insns are not intended to be disassembled by us.  */
+      if (opcode-&gt;mask == 0)
+	continue;
+      if (opcode-&gt;flags &amp; DVP_OPCODE_IGNORE_DIS)
+	continue;
+      /* Basic bit mask must be correct.  */
+      if ((insn[opcode-&gt;opcode_word] &amp; opcode-&gt;mask) != opcode-&gt;value)
+	continue;
+
+      /* Make two passes over the operands.  First see if any of them
+	 have extraction functions, and, if they do, make sure the
+	 instruction is valid.  */
+
+      dvp_opcode_init_print ();
+      invalid = 0;
+
+      for (syn = opcode-&gt;syntax; *syn; ++syn)
+	{
+	  int index;
+
+	  if (*syn &lt; 128)
+	    continue;
+
+	  mods = 0;
+	  index = DVP_OPERAND_INDEX (*syn);
+	  while (DVP_MOD_P (operand_table[index].flags))
+	    {
+	      mods |= operand_table[index].flags &amp; DVP_MOD_BITS;
+	      ++syn;
+	      index = DVP_OPERAND_INDEX (*syn);
+	    }
+	  operand = operand_table + index;
+	  if (operand-&gt;extract)
+	    (*operand-&gt;extract) (opcode, operand, mods, insn, &amp;invalid);
+	}
+      if (invalid)
+	continue;
+
+      /* The instruction is valid.  */
+
+      (*func) (stream, "%s", opcode-&gt;mnemonic);
+      num_operands = 0;
+      for (syn = opcode-&gt;syntax; *syn; ++syn)
+	{
+	  int index;
+
+	  if (*syn &lt; 128)
+	    {
+	      (*func) (stream, "%c", *syn);
+	      continue;
+	    }
+
+	  /* We have an operand.  Fetch any special modifiers.  */
+	  mods = 0;
+	  index = DVP_OPERAND_INDEX (*syn);
+	  while (DVP_MOD_P (operand_table[index].flags))
+	    {
+	      mods |= operand_table[index].flags &amp; DVP_MOD_BITS;
+	      ++syn;
+	      index = DVP_OPERAND_INDEX (*syn);
+	    }
+	  operand = operand_table + index;
+
+	  /* Extract the value from the instruction.  */
+	  if (operand-&gt;extract)
+	    {
+	      value = (*operand-&gt;extract) (opcode, operand, mods,
+					   insn, (int *) NULL);
+	    }
+	  else
+	    {
+	      /* We currently assume a field does not cross a word boundary.  */
+	      int shift = ((mods &amp; DVP_MOD_THIS_WORD)
+			   ? (operand-&gt;shift &amp; 31)
+			   : operand-&gt;shift);
+	      /* FIXME: There are currently two ways to specify which word:
+		 the `word' member and shift / 32.  */
+	      int word = operand-&gt;word ? operand-&gt;word : shift / 32;
+	      DVP_INSN mask = (operand-&gt;bits == 32
+			       ? 0xffffffff : ((1 &lt;&lt; operand-&gt;bits) - 1));
+	      shift = shift % 32;
+	      value = (insn[word] &gt;&gt; shift) &amp; mask;
+	      if ((operand-&gt;flags &amp; DVP_OPERAND_SIGNED) != 0
+		  &amp;&amp; (value &amp; (1 &lt;&lt; (operand-&gt;bits - 1)))
+		  &amp;&amp; operand-&gt;bits &lt; 8 * sizeof (long))
+		value -= 1L &lt;&lt; operand-&gt;bits;
+	    }
+
+	  /* Print the operand as directed by the flags.  */
+	  if (operand-&gt;print)
+	    (*operand-&gt;print) (opcode, operand, mods, insn, info, value);
+	  else if (operand-&gt;flags &amp; DVP_OPERAND_FAKE)
+	    ; /* nothing to do (??? at least not yet) */
+	  else if (operand-&gt;flags &amp; DVP_OPERAND_RELATIVE_BRANCH)
+	    (*info-&gt;print_address_func) (memaddr + 8 + (value &lt;&lt; 3), info);
+	  /* ??? Not all cases of this are currently caught.  */
+	  else if (operand-&gt;flags &amp; DVP_OPERAND_ABSOLUTE_BRANCH)
+	    (*info-&gt;print_address_func) ((bfd_vma) value &amp; 0xffffffff, info);
+	  else if (operand-&gt;flags &amp; DVP_OPERAND_MIPS_ADDRESS)
+	    (*info-&gt;print_address_func) ((bfd_vma) value &amp; 0xffffffff, info);
+	  else if (operand-&gt;flags &amp; (DVP_OPERAND_VU_ADDRESS | DVP_OPERAND_UNPACK_ADDRESS))
+	    (*func) (stream, "0x%lx", value &amp; 0xffffffff);
+          else if ((operand-&gt;flags &amp; (DVP_OPERAND_SIGNED | DVP_OPERAND_RELOC_11_S4)) != 0
+		   || (value &gt;= -1 &amp;&amp; value &lt; 16))
+	    (*func) (stream, "%ld", value);
+	  else
+	    (*func) (stream, "0x%lx", value);
+
+	  if (! (operand-&gt;flags &amp; DVP_OPERAND_SUFFIX))
+	    ++num_operands;
+	}
+
+      /* We have found and printed an instruction; return.  */
+      return;
+    }
+
+  (*func) (stream, _("*unknown*"));
+}
+
+/* Utility to read one word.
+   The result is 0 for success, -1 for failure.  */
+
+static int
+read_word (memaddr, info, insn_buf)
+     bfd_vma memaddr;
+     disassemble_info *info;
+     DVP_INSN *insn_buf;
+{
+  int status;
+  bfd_byte buffer[4];
+
+  status = (*info-&gt;read_memory_func) (memaddr, buffer, 4, info);
+  if (status != 0)
+    {
+      (*info-&gt;memory_error_func) (status, memaddr, info);
+      return -1;
+    }
+  *insn_buf = bfd_getl32 (buffer);
+  return 0;
+}
diff -burN orig.binutils-2.14/opcodes/dvp-opc.c binutils-2.14/opcodes/dvp-opc.c
--- orig.binutils-2.14/opcodes/dvp-opc.c	1969-12-31 20:00:00.000000000 -0400
+++ binutils-2.14/opcodes/dvp-opc.c	2007-04-29 04:00:33.000000000 -0300
@@ -0,0 +1,3458 @@
+/* Opcode table for the DVP
+   Copyright (c) 1998 Free Software Foundation, Inc.
+   
+   This program 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.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "ansidecl.h"
+#include "libiberty.h"
+#include "sysdep.h"
+#include "dis-asm.h"
+#include "opcode/dvp.h"
+#include "opintl.h"
+
+#include &lt;ctype.h&gt;
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define MIN(a,b) ((a) &lt; (b) ? (a) : (b))
+
+#if defined (__STDC__) || defined (ALMOST_STDC)
+#define XCONCAT2(a,b)	a##b
+#else
+#define XCONCAT2(a,b)	a/**/b
+#endif
+#define CONCAT2(a,b)	XCONCAT2(a,b)
+
+typedef struct {
+  int value;
+  const char *name;
+} keyword;
+
+static int lookup_keyword_value PARAMS ((const keyword *, const char *, int));
+static const char *lookup_keyword_name PARAMS ((const keyword *table, int));
+
+static char *scan_symbol PARAMS ((char *));
+
+/* Return non-zero if CH is a character that may appear in a symbol.  */
+/* FIXME: This will need revisiting.  */
+#define issymchar(ch) (isalnum ((unsigned char) ch) || ch == '_')
+
+#define SKIP_BLANKS(var) while (isspace ((unsigned char) *(var))) ++(var)
+
+/* ??? One can argue it's preferable to have the PARSE_FN support in tc-dvp.c
+   and the PRINT_FN support in dvp-dis.c.  For this project I like having
+   them all in one place.  */
+
+#define PARSE_FN(fn) \
+static long CONCAT2 (parse_,fn) \
+     PARAMS ((const dvp_opcode *, const dvp_operand *, int, char **, \
+	      const char **));
+#define INSERT_FN(fn) \
+static void CONCAT2 (insert_,fn) \
+     PARAMS ((const dvp_opcode *, const dvp_operand *, int, DVP_INSN *, \
+	      long, const char **))
+#define EXTRACT_FN(fn) \
+static long CONCAT2 (extract_,fn) \
+     PARAMS ((const dvp_opcode *, const dvp_operand *, int, DVP_INSN *, \
+	      int *));
+#define PRINT_FN(fn) \
+static void CONCAT2 (print_,fn) \
+     PARAMS ((const dvp_opcode *, const dvp_operand *, int, DVP_INSN *, \
+	      disassemble_info *, long));
+
+PARSE_FN (dotdest);
+INSERT_FN (dotdest);
+EXTRACT_FN (dotdest);
+PRINT_FN (dotdest);
+
+PARSE_FN (dotdest1);
+PARSE_FN (dest1);
+PRINT_FN (dest1);
+
+PARSE_FN (uflags);
+PRINT_FN (uflags);
+
+PARSE_FN (bc);
+EXTRACT_FN (bc);
+PRINT_FN (sdest);
+
+PARSE_FN (vfreg);
+PRINT_FN (vfreg);
+
+PARSE_FN (bcftreg);
+PRINT_FN (bcftreg);
+
+PARSE_FN (accdest);
+PRINT_FN (accdest);
+
+INSERT_FN (xyz);
+INSERT_FN (w);
+
+PARSE_FN (ireg);
+PRINT_FN (ireg);
+
+PARSE_FN (freg);
+PRINT_FN (freg);
+
+PARSE_FN (ffstreg);
+INSERT_FN (ffstreg);
+EXTRACT_FN (ffstreg);
+PRINT_FN (ffstreg);
+
+PARSE_FN (vi01);
+PRINT_FN (vi01);
+
+INSERT_FN (luimm12);
+EXTRACT_FN (luimm12);
+
+INSERT_FN (luimm12up6);
+
+INSERT_FN (luimm15);
+EXTRACT_FN (luimm15);
+
+/* Various types of DVP operands, including insn suffixes.
+
+   Fields are:
+
+   BITS SHIFT FLAGS PARSE_FN INSERT_FN EXTRACT_FN PRINT_FN
+
+   Operand values are 128 + table index.  This allows ASCII chars to be
+   included in the syntax spec.  */
+
+const dvp_operand vu_operands[] =
+{
+  /* place holder (??? not sure if needed) */
+#define UNUSED 128
+  { 0 },
+
+  /* Operands that exist in the same place for essentially the same purpose
+     in both upper and lower instructions.  These don't have a U or L prefix.
+     Operands specific to the upper or lower instruction are so prefixed.  */
+
+  /* Destination indicator attached to mnemonic, with leading '.' or '/'.
+     After parsing this, the value is stored in global `state_vu_mnemonic_dest'
+     so that the register parser can verify the same choice of xyzw is
+     used.  */
+#define DOTDEST (UNUSED + 1)
+  { 4, VU_SHIFT_DEST, 0, DVP_OPERAND_SUFFIX,
+      parse_dotdest, insert_dotdest, extract_dotdest, print_dotdest },
+
+  /* ft reg, with vector specification same as DOTDEST */
+#define VFTREG (DOTDEST + 1)
+  { 5, VU_SHIFT_TREG, 0, 0, parse_vfreg, 0, 0, print_vfreg },
+
+  /* fs reg, with vector specification same as DOTDEST */
+#define VFSREG (VFTREG + 1)
+  { 5, VU_SHIFT_SREG, 0, 0, parse_vfreg, 0, 0, print_vfreg },
+
+  /* fd reg, with vector specification same as DOTDEST */
+#define VFDREG (VFSREG + 1)
+  { 5, VU_SHIFT_DREG, 0, 0, parse_vfreg, 0, 0, print_vfreg },
+
+  /* Upper word operands.  */
+
+  /* flag bits */
+#define UFLAGS (VFDREG + 1)
+  { 5, 27, 0, DVP_OPERAND_SUFFIX, parse_uflags, 0, 0, print_uflags },
+
+  /* broadcast */
+#define UBC (UFLAGS + 1)
+  { 2, 0, 0, DVP_OPERAND_SUFFIX, parse_bc, 0, extract_bc, print_sdest },
+
+  /* ftreg in broadcast case */
+#define UBCFTREG (UBC + 1)
+  { 5, VU_SHIFT_TREG, 0, 0, parse_bcftreg, 0, 0, print_bcftreg },
+
+  /* accumulator dest */
+#define UACCDEST (UBCFTREG + 1)
+  { 0, 0, 0, 0, parse_accdest, 0, 0, print_accdest },
+
+  /* The XYZ operand is a fake one that is used to ensure only "xyz" is
+     specified.  It simplifies the opmula and opmsub entries.  */
+#define UXYZ (UACCDEST + 1)
+  { 0, 0, 0, DVP_OPERAND_FAKE, 0, insert_xyz, 0, 0 },
+
+  /* The W operand is a fake one that is used to ensure only "w" is
+     specified.  It simplifies the clipw entry.  */
+#define UW (UXYZ + 1)
+  { 0, 0, 0, DVP_OPERAND_FAKE, 0, insert_w, 0, 0 },
+
+  /* Lower word operands.  */
+
+  /* 5 bit signed immediate.  */
+#define LIMM5 (UW + 1)
+  { 5, 6, 0, DVP_OPERAND_SIGNED, 0, 0, 0, 0 },
+
+  /* 11 bit signed immediate.  */
+#define LIMM11 (LIMM5 + 1)
+  { 11, 0, 0, DVP_OPERAND_SIGNED, 0, 0, 0, 0 },
+  /* WAS: { 11, 0, 0, DVP_OPERAND_RELOC_11_S4, 0, 0, 0, 0 },*/
+
+  /* 15 bit unsigned immediate.  */
+#define LUIMM15 (LIMM11 + 1)
+  { 15, 0, 0, DVP_OPERAND_RELOC_U15_S3, 0, insert_luimm15, extract_luimm15, 0 },
+
+  /* ID register.  */
+#define LIDREG (LUIMM15 + 1)
+  { 5, 6, 0, 0, parse_ireg, 0, 0, print_ireg },
+
+  /* IS register.  */
+#define LISREG (LIDREG + 1)
+  { 5, 11, 0, 0, parse_ireg, 0, 0, print_ireg },
+
+  /* IT register.  */
+#define LITREG (LISREG + 1)
+  { 5, 16, 0, 0, parse_ireg, 0, 0, print_ireg },
+
+  /* FS reg, with FSF field selector.  */
+#define LFSFFSREG (LITREG + 1)
+  { 5, 11, 0, 0, parse_ffstreg, insert_ffstreg, extract_ffstreg, print_ffstreg },
+
+  /* FS reg, no selector (choice of x,y,z,w is provided by opcode).  */
+#define LFSREG (LFSFFSREG + 1)
+  { 5, 11, 0, 0, parse_freg, 0, 0, print_freg },
+
+  /* FT reg, with FTF field selector.  */
+#define LFTFFTREG (LFSREG + 1)
+  { 5, 16, 0, 0, parse_ffstreg, insert_ffstreg, extract_ffstreg, print_ffstreg },
+
+  /* VI01 register.  */
+#define LVI01 (LFTFFTREG + 1)
+  { 0, 0, 0, 0, parse_vi01, 0, 0, print_vi01 },
+
+  /* 24 bit unsigned immediate.  */
+#define LUIMM24 (LVI01 + 1)
+  { 24, 0, 0, 0, 0, 0, 0, 0 },
+
+  /* 12 bit unsigned immediate, split into 1 and 11 bit pieces.  */
+#define LUIMM12 (LUIMM24 + 1)
+  { 12, 0, 0, 0, 0, insert_luimm12, extract_luimm12, 0 },
+
+  /* upper 6 bits of 12 bit unsigned immediate */
+#define LUIMM12UP6 (LUIMM12 + 1)
+  { 12, 0, 0, 0, 0, insert_luimm12up6, extract_luimm12, 0 },
+
+  /* 11 bit pc-relative signed immediate.  */
+#define LPCREL11 (LUIMM12UP6 + 1)
+  { 11, 0, 0, DVP_OPERAND_SIGNED + DVP_OPERAND_RELATIVE_BRANCH, 0, 0, 0, 0 },
+
+  /* Destination indicator, single letter only, with leading '.' or '/'.  */
+#define LDOTDEST1 (LPCREL11 + 1)
+  { 4, VU_SHIFT_DEST, 0, DVP_OPERAND_SUFFIX,
+      /* Note that we borrow the insert/extract/print functions from the
+	 vector case.  */
+      parse_dotdest1, insert_dotdest, extract_dotdest, print_dotdest },
+
+  /* Destination indicator, single letter only, no leading '.'.  */
+  /* ??? Making this FAKE is a workaround to a limitation in the parser.
+     It can't handle operands with a legitimate value of "".  */
+#define LDEST1 (LDOTDEST1 + 1)
+  { 0, 0, 0, DVP_OPERAND_FAKE, parse_dest1, 0, 0, print_dest1 },
+
+  /* 32 bit floating point immediate.  */
+#define LFIMM32 (LDEST1 + 1)
+  { 32, 0, 0, DVP_OPERAND_FLOAT, 0, 0, 0, 0 },
+/* end of list place holder */
+  { 0 }
+};
+
+/* Macros to put a field's value into the right place.  */
+/* ??? If assembler needs these, move to opcode/dvp.h.  */
+
+/* value X, B bits, shift S */
+#define V(x,b,s) (((x) &amp; ((1 &lt;&lt; (b)) - 1)) &lt;&lt; (s))
+
+/* Field value macros for both upper and lower instructions.
+   These shift a value into the right place in the instruction.  */
+
+/* [FI] T reg field (remember it's V for value, not vector, here).  */
+#define VT(x) V ((x), 5, VU_SHIFT_TREG)
+/* [FI] S reg field.  */
+#define VS(x) V ((x), 5, VU_SHIFT_SREG)
+/* [FI] D reg field.  */
+#define VD(x) V ((x), 5, VU_SHIFT_DREG)
+/* DEST field.  */
+#define VDEST(x) V ((x), 4, 21)
+
+/* Masks for fields in both upper and lower instructions.
+   These mask out all bits but the ones for the field in the instruction.  */
+
+#define MT VT (~0)
+#define MS VS (~0)
+#define MD VD (~0)
+#define MDEST VDEST (~0)
+
+/* Upper instruction Value macros.  */
+
+/* Upper Flag bits.  */
+#define VUF(x) V ((x), 5, 27)
+/* Upper REServed two bits next to flag bits.  */
+#define VURES(x) V ((x), 2, 25)
+/* 4 bit opcode field.  */
+#define VUOP4(x) V ((x), 4, 2)
+/* 6 bit opcode field.  */
+#define VUOP6(x) V ((x), 6, 0)
+/* 9 bit opcode field.  */
+#define VUOP9(x) V ((x), 9, 2)
+/* 11 bit opcode field.  */
+#define VUOP11(x) V ((x), 11, 0)
+/* BroadCast field.  */
+#define VUBC(x) V ((x), 2, 0)
+
+/* Upper instruction field masks.  */
+#define MURES VURES (~0)
+#define MUOP4 VUOP4 (~0)
+#define MUOP6 VUOP6 (~0)
+#define MUOP9 VUOP9 (~0)
+#define MUOP11 VUOP11 (~0)
+
+/* A space, separates instruction name (mnemonic + mnemonic operands) from
+   operands.  */
+#define SP ' '
+/* Commas separate operands.  */
+#define C ','
+/* Special I,P,Q,R operands.  */
+#define I 'i'
+#define P 'p'
+#define Q 'q'
+#define R 'r'
+
+/* VU instructions.
+   [??? some of these comments are left over from the ARC port from which
+   this code is borrowed, delete in time]
+
+   Longer versions of insns must appear before shorter ones (if gas sees
+   "lsr r2,r3,1" when it's parsing "lsr %a,%b" it will think the ",1" is
+   junk).  This isn't necessary for `ld' because of the trailing ']'.
+
+   Instructions that are really macros based on other insns must appear
+   before the real insn so they're chosen when disassembling.  Eg: The `mov'
+   insn is really the `and' insn.
+
+   This table is best viewed on a wide screen (161 columns).  I'd prefer to
+   keep it this way.  The rest of the file, however, should be viewable on an
+   80 column terminal.  */
+
+/* ??? This table also includes macros: asl, lsl, and mov.  The ppc port has
+   a more general facility for dealing with macros which could be used if
+   we need to.  */
+
+/* These tables can't be `const' because members `next_asm' and `next_dis' are
+   computed at run-time.  We could split this into two, as that would put the
+   constant stuff into a readonly section.  */
+
+struct dvp_opcode vu_upper_opcodes[] =
+{
+  /* Macros appear first, so the disassembler will try them first.  */
+  /* ??? Any aliases?  */
+
+  /* The rest of these needn't be sorted, but it helps to find them if they are.  */
+  { "abs",    { UFLAGS, DOTDEST, SP, VFTREG, C, VFSREG },                   MURES + MUOP11,      VUOP11 (0x1fd) },
+  { "add",    { UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG },        MURES + MUOP6,       VUOP6 (0x28) },
+  { "addi",   { UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, I },             MURES + MT + MUOP6,  VUOP6 (0x22) },
+  { "addq",   { UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, Q },             MURES + MT + MUOP6,  VUOP6 (0x20) },
+  { "add",    { UBC, UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + VUOP4 (~0),  VUOP4 (0) },
+  { "adda",   { UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG },      MURES + MUOP11,      VUOP11 (0x2bc) },
+  { "addai",  { UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, I },           MURES + MT + MUOP11, VUOP11 (0x23e) },
+  { "addaq",  { UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, Q },           MURES + MT + MUOP11, VUOP11 (0x23c) },
+  { "adda",   { UBC, UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9,     VUOP9 (0xf) },
+  { "clip",   { UBC, UFLAGS, DOTDEST, SP, VFSREG, C, UBCFTREG, UW },        MURES + MDEST + MUOP11, VDEST (0xe) + VUOP11 (0x1ff) },
+  { "ftoi0",  { UFLAGS, DOTDEST, SP, VFTREG, C, VFSREG },                   MURES + MUOP11,      VUOP11 (0x17c) },
+  { "ftoi4",  { UFLAGS, DOTDEST, SP, VFTREG, C, VFSREG },                   MURES + MUOP11,      VUOP11 (0x17d) },
+  { "ftoi12", { UFLAGS, DOTDEST, SP, VFTREG, C, VFSREG },                   MURES + MUOP11,      VUOP11 (0x17e) },
+  { "ftoi15", { UFLAGS, DOTDEST, SP, VFTREG, C, VFSREG },                   MURES + MUOP11,      VUOP11 (0x17f) },
+  { "itof0",  { UFLAGS, DOTDEST, SP, VFTREG, C, VFSREG },                   MURES + MUOP11,      VUOP11 (0x13c) },
+  { "itof4",  { UFLAGS, DOTDEST, SP, VFTREG, C, VFSREG },                   MURES + MUOP11,      VUOP11 (0x13d) },
+  { "itof12", { UFLAGS, DOTDEST, SP, VFTREG, C, VFSREG },                   MURES + MUOP11,      VUOP11 (0x13e) },
+  { "itof15", { UFLAGS, DOTDEST, SP, VFTREG, C, VFSREG },                   MURES + MUOP11,      VUOP11 (0x13f) },
+  { "madd",   { UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG },        MURES + MUOP6,       VUOP6 (0x29) },
+  { "maddi",  { UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, I },             MURES + MT + MUOP6,  VUOP6 (0x23) },
+  { "maddq",  { UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, Q },             MURES + MT + MUOP6,  VUOP6 (0x21) },
+  { "madd",   { UBC, UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + MUOP4,       VUOP4 (0x2) },
+  { "madda",  { UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG },      MURES + MUOP11,      VUOP11 (0x2bd) },
+  { "maddai", { UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, I },           MURES + MT + MUOP11, VUOP11 (0x23f) },
+  { "maddaq", { UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, Q },           MURES + MT + MUOP11, VUOP11 (0x23d) },
+  { "madda",  { UBC, UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9,     VUOP9 (0x2f) },
+  { "max",    { UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG },        MURES + MUOP6,       VUOP6 (0x2b) },
+  { "maxi",   { UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, I },             MURES + MT + MUOP6,  VUOP6 (0x1d) },
+  { "max",    { UBC, UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + MUOP4,       VUOP4 (0x4) },
+  { "mini",   { UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG },        MURES + MUOP6,       VUOP6 (0x2f) },
+  { "minii",  { UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, I },             MURES + MT + MUOP6,  VUOP6 (0x1f) },
+  { "mini",   { UBC, UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + MUOP4,       VUOP4 (0x5) },
+  { "msub",   { UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG },        MURES + MUOP6,       VUOP6 (0x2d) },
+  { "msubi",  { UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, I },             MURES + MT + MUOP6,  VUOP6 (0x27) },
+  { "msubq",  { UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, Q },             MURES + MT + MUOP6,  VUOP6 (0x25) },
+  { "msub",   { UBC, UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + MUOP4,       VUOP4 (0x3) },
+  { "msuba",  { UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG },      MURES + MUOP11,      VUOP11 (0x2fd) },
+  { "msubai", { UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, I },           MURES + MT + MUOP11, VUOP11 (0x27f) },
+  { "msubaq", { UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, Q },           MURES + MT + MUOP11, VUOP11 (0x27d) },
+  { "msuba",  { UBC, UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9,     VUOP9 (0x3f) },
+  { "mul",    { UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG },        MURES + MUOP6,       VUOP6 (0x2a) },
+  { "muli",   { UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, I },             MURES + MT + MUOP6,  VUOP6 (0x1e) },
+  { "mulq",   { UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, Q },             MURES + MT + MUOP6,  VUOP6 (0x1c) },
+  { "mul",    { UBC, UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + VUOP4 (~0),  VUOP4 (6) },
+  { "mula",   { UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG },      MURES + MUOP11,      VUOP11 (0x2be) },
+  { "mulai",  { UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, I },           MURES + MT + MUOP11, VUOP11 (0x1fe) },
+  { "mulaq",  { UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, Q },           MURES + MT + MUOP11, VUOP11 (0x1fc) },
+  { "mula",   { UBC, UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9,     VUOP9 (0x6f) },
+  { "nop",    { UFLAGS },                                                   MURES + MDEST + MT + MS + MUOP11, VUOP11 (0x2ff) },
+  { "opmula", { UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG, UXYZ }, MURES + MUOP11,     VUOP11 (0x2fe) },
+  { "opmsub", { UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG, UXYZ },  MURES + MUOP6,       VUOP6 (0x2e) },
+  { "sub",    { UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, VFTREG },        MURES + MUOP6,       VUOP6 (0x2c) },
+  { "subi",   { UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, I },             MURES + MT + MUOP6,  VUOP6 (0x26) },
+  { "subq",   { UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, Q },             MURES + MT + MUOP6,  VUOP6 (0x24) },
+  { "sub",    { UBC, UFLAGS, DOTDEST, SP, VFDREG, C, VFSREG, C, UBCFTREG }, MURES + VUOP4 (~0),  VUOP4 (1) },
+  { "suba",   { UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, VFTREG },      MURES + MUOP11,      VUOP11 (0x2fc) },
+  { "subai",  { UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, I },           MURES + MT + MUOP11, VUOP11 (0x27e) },
+  { "subaq",  { UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, Q },           MURES + MT + MUOP11, VUOP11 (0x27c) },
+  { "suba",   { UBC, UFLAGS, DOTDEST, SP, UACCDEST, C, VFSREG, C, UBCFTREG }, MURES + MUOP9,     VUOP9 (0x1f) }
+};
+const int vu_upper_opcodes_count = sizeof (vu_upper_opcodes) / sizeof (vu_upper_opcodes[0]);
+
+/* Lower instruction Value macros.  */
+
+/* 6 bit opcode.  */
+#define VLOP6(x) V ((x), 6, 0)
+/* 7 bit opcode.  */
+#define VLOP7(x) V ((x), 7, 25)
+/* 11 bit opcode.  */
+#define VLOP11(x) V ((x), 11, 0)
+/* 11 bit immediate.  */
+#define VLIMM11(x) V ((x), 11, 0)
+/* FTF field.  */
+#define VLFTF(x) V ((x), 2, 23)
+/* FSF field.  */
+#define VLFSF(x) V ((x), 2, 21)
+/* Upper bit of 12 bit unsigned immediate.  */
+#define VLUIMM12TOP(x) V ((x), 1, 21)
+/* Upper 4 bits of 15 bit unsigned immediate.  */
+#define VLUIMM15TOP(x) VDEST (x)
+
+/* Lower instruction field masks.  */
+#define MLOP6 VLOP6 (~0)
+#define MLOP7 VLOP7 (~0)
+#define MLOP11 VLOP11 (~0)
+#define MLIMM11 VLIMM11 (~0)
+#define MLB24 V (1, 1, 24)
+#define MLUIMM12TOP VLUIMM12TOP (~0)
+/* 12 bit unsigned immediates are split into two parts, 1 bit and 11 bits.
+   The upper 1 bit is part of the `dest' field.  This mask is for the
+   other 3 bits of the dest field.  */
+#define MLUIMM12UNUSED V (7, 3, 22)
+#define MLUIMM15TOP MDEST
+
+struct dvp_opcode vu_lower_opcodes[] =
+{
+  /* Macros appear first, so the disassembler will try them first.  */
+
+  /* There isn't an explicit nop.  Apparently it's "move vf0,vf0".  */
+  { "nop", { 0 }, 0xffffffff, VLOP7 (0x40) + VLIMM11 (0x33c) },
+
+  /* The rest of these needn't be sorted, but it helps to find them if they are.  */
+  { "b",       { SP, LPCREL11 },                      MLOP7 + MDEST + MT + MS,          VLOP7 (0x20) },
+  { "bal",     { SP, LITREG, C, LPCREL11 },           MLOP7 + MDEST + MS,               VLOP7 (0x21) },
+  { "div",     { SP, Q, C, LFSFFSREG, C, LFTFFTREG }, MLOP7 + MLOP11,                   VLOP7 (0x40) + VLOP11 (0x3bc) },
+  { "eatan",   { SP, P, C, LFSFFSREG },               MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7fd) },
+  { "eatanxy", { SP, P, C, LFSREG },                  MLOP7 + MDEST + MT + MLOP11,      VLOP7 (0x40) + VDEST (0xc) + VLOP11 (0x77c) },
+  { "eatanxz", { SP, P, C, LFSREG },                  MLOP7 + MDEST + MT + MLOP11,      VLOP7 (0x40) + VDEST (0xa) + VLOP11 (0x77d) },
+  { "eexp",    { SP, P, C, LFSFFSREG },               MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7fe) },
+  { "eleng",   { SP, P, C, LFSREG },                  MLOP7 + MDEST + MT + MLOP11,      VLOP7 (0x40) + VDEST (0xe) + VLOP11 (0x73e) },
+  { "ercpr",   { SP, P, C, LFSFFSREG },               MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7be) },
+  { "erleng",  { SP, P, C, LFSREG },                  MLOP7 + MDEST + MT + MLOP11,      VLOP7 (0x40) + VDEST (0xe) + VLOP11 (0x73f) },
+  { "ersadd",  { SP, P, C, LFSREG },                  MLOP7 + MDEST + MT + MLOP11,      VLOP7 (0x40) + VDEST (0xe) + VLOP11 (0x73d) },
+  { "ersqrt",  { SP, P, C, LFSFFSREG },               MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7bd) },
+  { "esadd",   { SP, P, C, LFSREG },                  MLOP7 + MDEST + MT + MLOP11,      VLOP7 (0x40) + VDEST (0xe) + VLOP11 (0x73c) },
+  { "esin",    { SP, P, C, LFSFFSREG },               MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7fc) },
+  { "esqrt",   { SP, P, C, LFSFFSREG },               MLOP7 + VLFTF (~0) + MT + MLOP11, VLOP7 (0x40) + VLOP11 (0x7bc) },
+  { "esum",    { SP, P, C, LFSREG },                  MLOP7 + MDEST + MT + MLOP11,      VLOP7 (0x40) + VDEST (0xf) + VLOP11 (0x77e) },
+  { "fcand",   { SP, LVI01, C, LUIMM24 },             MLOP7 + MLB24,                    VLOP7 (0x12) },
+  { "fceq",    { SP, LVI01, C, LUIMM24 },             MLOP7 + MLB24,                    VLOP7 (0x10) },
+  { "fcget",   { SP, LITREG },                        MLOP7 + MDEST + MS + MLIMM11,     VLOP7 (0x1c) },
+  { "fcor",    { SP, LVI01, C, LUIMM24 },             MLOP7 + MLB24,                    VLOP7 (0x13) },
+  { "fcset",   { SP, LUIMM24 },                       MLOP7 + MLB24,                    VLOP7 (0x11) },
+  { "fmand",   { SP, LITREG, C, LISREG },             MLOP7 + MDEST + MLIMM11,          VLOP7 (0x1a) },
+  { "fmeq",    { SP, LITREG, C, LISREG },             MLOP7 + MDEST + MLIMM11,          VLOP7 (0x18) },
+  { "fmor",    { SP, LITREG, C, LISREG },             MLOP7 + MDEST + MLIMM11,          VLOP7 (0x1b) },
+  { "fsand",   { SP, LITREG, C, LUIMM12 },            MLOP7 + MLUIMM12UNUSED + MS,      VLOP7 (0x16) },
+  { "fseq",    { SP, LITREG, C, LUIMM12 },            MLOP7 + MLUIMM12UNUSED + MS,      VLOP7 (0x14) },
+  { "fsor",    { SP, LITREG, C, LUIMM12 },            MLOP7 + MLUIMM12UNUSED + MS,      VLOP7 (0x17) },
+  { "fsset",   { SP, LUIMM12UP6 },                    MLOP7 + MLUIMM12UNUSED + V (~0, 6, 0) + MS + MT, VLOP7 (0x15) },
+  { "iadd",    { SP, LIDREG, C, LISREG, C, LITREG },  MLOP7 + MDEST + MLOP6,            VLOP7 (0x40) + VLOP6 (0x30) },
+  { "iaddi",   { SP, LITREG, C, LISREG, C, LIMM5 },   MLOP7 + MDEST + MLOP6,            VLOP7 (0x40) + VLOP6 (0x32) },
+  { "iaddiu",  { SP, LITREG, C, LISREG, C, LUIMM15 }, MLOP7,                            VLOP7 (0x08) },
+  { "iand",    { SP, LIDREG, C, LISREG, C, LITREG },  MLOP7 + MDEST + MLOP6,            VLOP7 (0x40) + VLOP6 (0x34) },
+  { "ibeq",    { SP, LITREG, C, LISREG, C, LPCREL11 }, MLOP7 + MDEST,                   VLOP7 (0x28) },
+  { "ibgez",   { SP, LISREG, C, LPCREL11 },           MLOP7 + MDEST + MT,               VLOP7 (0x2f) },
+  { "ibgtz",   { SP, LISREG, C, LPCREL11 },           MLOP7 + MDEST + MT,               VLOP7 (0x2d) },
+  { "iblez",   { SP, LISREG, C, LPCREL11 },           MLOP7 + MDEST + MT,               VLOP7 (0x2e) },
+  { "ibltz",   { SP, LISREG, C, LPCREL11 },           MLOP7 + MDEST + MT,               VLOP7 (0x2c) },
+  { "ibne",    { SP, LITREG, C, LISREG, C, LPCREL11 }, MLOP7 + MDEST,                   VLOP7 (0x29) },
+  { "ilw",     { LDOTDEST1, SP, LITREG, C, LIMM11, '(', LISREG, ')', LDEST1 }, MLOP7,   VLOP7 (0x04) },
+  { "ilwr",    { LDOTDEST1, SP, LITREG, C, '(', LISREG, ')', LDEST1 }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3fe) },
+  { "ior",     { SP, LIDREG, C, LISREG, C, LITREG },  MLOP7 + MDEST + MLOP6,            VLOP7 (0x40) + VLOP6 (0x35) },
+  { "isub",    { SP, LIDREG, C, LISREG, C, LITREG },  MLOP7 + MDEST + MLOP6,            VLOP7 (0x40) + VLOP6 (0x31) },
+  { "isubiu",  { SP, LITREG, C, LISREG, C, LUIMM15 }, MLOP7,                            VLOP7 (0x09) },
+  { "isw",     { DOTDEST, SP, LITREG, C, LIMM11, '(', LISREG, ')', LDEST1 }, MLOP7,     VLOP7 (0x05) },
+  { "iswr",    { DOTDEST, SP, LITREG, C, '(', LISREG, ')', LDEST1 }, MLOP7 + MLIMM11,   VLOP7 (0x40) + VLIMM11 (0x3ff) },
+  { "jalr",    { SP, LITREG, C, LISREG },             MLOP7 + MDEST + MLIMM11,          VLOP7 (0x25) },
+  { "jr",      { SP, LISREG },                        MLOP7 + MDEST + MT + MLIMM11,     VLOP7 (0x24) },
+  { "loi",     { SP, LFIMM32 },                       0,                                0 },
+  { "lq",      { DOTDEST, SP, VFTREG, C, LIMM11, '(', LISREG, ')' }, MLOP7,             VLOP7 (0x00) },
+  { "lqd",     { DOTDEST, SP, VFTREG, C, '(', '-', '-', LISREG, ')' }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x37e) },
+  { "lqi",     { DOTDEST, SP, VFTREG, C, '(', LISREG, '+', '+', ')' }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x37c) },
+  /* Only a single VF reg is allowed here.  We can use VFTREG because LDOTDEST1
+     handles verifying only a single choice of xyzw is present.  */
+  { "mfir",    { DOTDEST, SP, VFTREG, C, LISREG },    MLOP7 + MLIMM11,                  VLOP7 (0x40) + VLIMM11 (0x3fd) },
+  { "mfp",     { DOTDEST, SP, VFTREG, C, P },         MLOP7 + MS + MLIMM11,             VLOP7 (0x40) + VLIMM11 (0x67c) },
+  { "move",    { DOTDEST, SP, VFTREG, C, VFSREG },    MLOP7 + MLIMM11,                  VLOP7 (0x40) + VLIMM11 (0x33c) },
+  { "mr32",    { DOTDEST, SP, VFTREG, C, VFSREG },    MLOP7 + MLIMM11,                  VLOP7 (0x40) + VLIMM11 (0x33d) },
+  { "mtir",    { SP, LITREG, C, LFSFFSREG },          MLOP7 + VLFTF (~0) + MLOP11,      VLOP7 (0x40) + VLOP11 (0x3fc) },
+  { "rget",    { DOTDEST, SP, VFTREG, C, R },         MLOP7 + MS + MLIMM11,             VLOP7 (0x40) + VLIMM11 (0x43d) },
+  { "rinit",   { SP, R, C, LFSFFSREG },               MLOP7 + VLFTF (~0) + MT + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43e) },
+  { "rnext",   { DOTDEST, SP, VFTREG, C, R },         MLOP7 + MS + MLIMM11,             VLOP7 (0x40) + VLIMM11 (0x43c) },
+  { "rsqrt",   { SP, Q, C, LFSFFSREG, C, LFTFFTREG }, MLOP7 + MLIMM11,                  VLOP7 (0x40) + VLIMM11 (0x3be) },
+  { "rxor",    { SP, R, C, LFSFFSREG },               MLOP7 + VLFTF (~0) + MT + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x43f) },
+  { "sq",      { DOTDEST, SP, VFSREG, C, LIMM11, '(', LITREG, ')' }, MLOP7,             VLOP7 (0x01) },
+  { "sqd",     { DOTDEST, SP, VFSREG, C, '(', '-', '-', LITREG, ')' }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x37f) },
+  { "sqi",     { DOTDEST, SP, VFSREG, C, '(', LITREG, '+', '+', ')' }, MLOP7 + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x37d) },
+  { "sqrt",    { SP, Q, C, LFTFFTREG },               MLOP7 + VLFSF (~0) + MS + MLIMM11, VLOP7 (0x40) + VLIMM11 (0x3bd) },
+  { "waitp",   { 0 },                                 0xffffffff,                       VLOP7 (0x40) + VLIMM11 (0x7bf) },
+  { "waitq",   { 0 },                                 0xffffffff,                       VLOP7 (0x40) + VLIMM11 (0x3bf) },
+  { "xgkick",  { SP, LISREG },                        MLOP7 + MDEST + MT + MLIMM11,     VLOP7 (0x40) + VLIMM11 (0x6fc) },
+  { "xitop",   { SP, LITREG },                        MLOP7 + MDEST + MS + MLIMM11,     VLOP7 (0x40) + VLIMM11 (0x6bd) },
+  { "xtop",    { SP, LITREG },                        MLOP7 + MDEST + MS + MLIMM11,     VLOP7 (0x40) + VLIMM11 (0x6bc) }
+};
+const int vu_lower_opcodes_count = sizeof (vu_lower_opcodes) / sizeof (vu_lower_opcodes[0]);
+
+/* Value of DEST in use.
+   Each of the registers must specify the same value as the opcode.  */
+static int state_vu_mnemonic_dest;
+
+/* Value of BC to use.
+   The register specified for the ftreg must match the broadcast register
+   specified in the opcode.  */
+static int state_vu_mnemonic_bc;
+
+#define INVALID_DEST 		_("invalid `dest'")
+#define MISSING_DEST 		_("missing `dest'")
+#define MISSING_DOT  		_("missing `.'")
+#define UNKNOWN_REGISTER 	_("unknown register")
+#define INVALID_REGISTER_NUMBER _("invalid register number")
+
+/* Multiple destination choice support.
+   The "dest" string selects any combination of x,y,z,w.
+   [The letters are ordered that way to follow the manual's style.]  */
+
+/* Utility to parse a `dest' spec.
+   Return the found value or zero if not present.
+   *PSTR is set to the character that terminated the parsing.
+   It is up to the caller to do any error checking.  */
+
+static long
+u_parse_dest (pstr)
+     char **pstr;
+{
+  long dest = 0;
+
+  while (**pstr)
+    {
+      switch (**pstr)
+	{
+	case 'x' : case 'X' : dest |= VU_DEST_X; break;
+	case 'y' : case 'Y' : dest |= VU_DEST_Y; break;
+	case 'z' : case 'Z' : dest |= VU_DEST_Z; break;
+	case 'w' : case 'W' : dest |= VU_DEST_W; break;
+	default : return dest;
+	}
+      ++*pstr;
+    }
+
+  return dest;
+}
+
+static long
+parse_dotdest (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  long dest;
+
+  /* If we're at a space, the dest isn't present so use the default: xyzw.  */
+  if (**pstr == ' ')
+    return VU_DEST_X | VU_DEST_Y | VU_DEST_Z | VU_DEST_W;
+
+  if (**pstr != '.' &amp;&amp; **pstr != '/')
+    {
+      *errmsg = MISSING_DOT;
+      return 0;
+    }
+
+  ++*pstr;
+  dest = u_parse_dest (pstr);
+  if (dest == 0 || isalnum ((unsigned char) **pstr))
+    {
+      *errmsg = INVALID_DEST;
+      return 0;
+    }
+
+  return dest;
+}
+
+/* Parse a `dest' spec where only a single letter is allowed,
+   but the encoding handles all four.  */
+
+static long
+parse_dotdest1 (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  char c;
+  long dest;
+
+  if (**pstr != '.' &amp;&amp; **pstr != '/')
+    {
+      *errmsg = MISSING_DOT;
+      return 0;
+    }
+
+  ++*pstr;
+  switch (**pstr)
+    {
+    case 'x' : case 'X' : dest = VU_DEST_X; break;
+    case 'y' : case 'Y' : dest = VU_DEST_Y; break;
+    case 'z' : case 'Z' : dest = VU_DEST_Z; break;
+    case 'w' : case 'W' : dest = VU_DEST_W; break;
+    default : *errmsg = INVALID_DEST; return 0;
+    }
+  ++*pstr;
+  c = tolower (**pstr);
+  if (c == 'x' || c == 'y' || c == 'z' || c == 'w')
+    {
+      *errmsg = _("only one of x,y,z,w can be specified");
+      return 0;
+    }
+  if (isalnum ((unsigned char) **pstr))
+    {
+      *errmsg = INVALID_DEST;
+      return 0;
+    }
+
+  return dest;
+}
+
+/* Parse a `dest' spec with no leading '.', where only a single letter is
+   allowed, but the encoding handles all four.  The value, if specified,
+   must match that recorded in `dest'.  */
+
+static long
+parse_dest1 (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  long dest;
+
+  dest = u_parse_dest (pstr);
+  if (dest == 0)
+    ; /* not specified, nothing to do */
+  else if (dest != VU_DEST_X
+      &amp;&amp; dest != VU_DEST_Y
+      &amp;&amp; dest != VU_DEST_Z
+      &amp;&amp; dest != VU_DEST_W)
+    {
+      *errmsg = _("expecting one of x,y,z,w");
+      return 0;
+    }
+  else if (dest != state_vu_mnemonic_dest)
+    {
+      *errmsg = _("`dest' suffix does not match instruction `dest'");
+      return 0;
+    }
+
+  return dest;
+}
+
+static void
+insert_dotdest (opcode, operand, mods, insn, value, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     long value;
+     const char **errmsg;
+{
+  /* Record the DEST value in use so the register parser can use it.  */
+  state_vu_mnemonic_dest = value;
+  *insn |= value &lt;&lt; operand-&gt;shift;
+}
+
+static long
+extract_dotdest (opcode, operand, mods, insn, pinvalid)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     int *pinvalid;
+{
+  /* Record the DEST value in use so the register printer can use it.  */
+  state_vu_mnemonic_dest = (*insn &gt;&gt; operand-&gt;shift) &amp; ((1 &lt;&lt; operand-&gt;bits) - 1);
+  return state_vu_mnemonic_dest;
+}
+
+/* Utility to print a multiple dest spec.  */
+
+static void
+u_print_dest (info, insn, value)
+     disassemble_info *info;
+     DVP_INSN *insn;
+     long value;
+{
+  if (value &amp; VU_DEST_X)
+    (*info-&gt;fprintf_func) (info-&gt;stream, "x");
+  if (value &amp; VU_DEST_Y)
+    (*info-&gt;fprintf_func) (info-&gt;stream, "y");
+  if (value &amp; VU_DEST_Z)
+    (*info-&gt;fprintf_func) (info-&gt;stream, "z");
+  if (value &amp; VU_DEST_W)
+    (*info-&gt;fprintf_func) (info-&gt;stream, "w");
+}
+
+static void
+print_dotdest (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     disassemble_info *info;
+     long value;
+{
+  (*info-&gt;fprintf_func) (info-&gt;stream, ".");
+  u_print_dest (info, insn, value);
+}
+
+static void
+print_dest1 (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     disassemble_info *info;
+     long value;
+{
+  u_print_dest (info, insn, state_vu_mnemonic_dest);
+}
+
+/* Utilities for single destination choice handling.  */
+
+/* Parse a single dest spec.
+   Return one of VU_SDEST_[XYZW] or -1 if not present.  */
+
+static long
+u_parse_sdest (pstr, errmsg)
+     char **pstr;
+     const char **errmsg;
+{
+  char c;
+  long dest = 0;
+
+  switch (**pstr)
+    {
+    case 'x' : case 'X' : dest = VU_SDEST_X; break;
+    case 'y' : case 'Y' : dest = VU_SDEST_Y; break;
+    case 'z' : case 'Z' : dest = VU_SDEST_Z; break;
+    case 'w' : case 'W' : dest = VU_SDEST_W; break;
+    default : return -1;
+    }
+  ++*pstr;
+  c = tolower (**pstr);
+  if (c == 'x' || c == 'y' || c == 'z' || c == 'w')
+    {
+      *errmsg = _("only one of x,y,z,w can be specified");
+      return 0;
+    }
+  if (isalnum ((unsigned char) **pstr))
+    {
+      *errmsg = INVALID_DEST;
+      return 0;
+    }
+
+  return dest;
+}
+
+static void
+print_sdest (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     disassemble_info *info;
+     long value;
+{
+  char c;
+
+  switch (value)
+    {
+    case VU_SDEST_X : c = 'x'; break;
+    case VU_SDEST_Y : c = 'y'; break;
+    case VU_SDEST_Z : c = 'z'; break;
+    case VU_SDEST_W : c = 'w'; break;
+    default: abort (); return;
+    }
+
+  (*info-&gt;fprintf_func) (info-&gt;stream, "%c", c);
+}
+
+/* The upper word flags bits.  */
+
+static long
+parse_uflags (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  long value = 0;
+  char *str = *pstr;
+
+  if (*str != '[')
+    return 0;
+  ++str;
+  while (*str &amp;&amp; *str != ']')
+    {
+      switch (tolower (*str))
+	{
+	case 'i' : value |= VU_FLAG_I; break;
+	case 'e' : value |= VU_FLAG_E; break;
+	case 'm' : value |= VU_FLAG_M; break;
+	case 'd' : value |= VU_FLAG_D; break;
+	case 't' : value |= VU_FLAG_T; break;
+	default : *errmsg = _("invalid flag character present"); return 0;
+	}
+      ++str;
+    }
+  if (*str != ']')
+    {
+      *errmsg = _("syntax error in flag spec");
+      return 0;
+    }
+  *pstr = str + 1;
+  return value;
+}
+
+static void
+print_uflags (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     disassemble_info *info;
+     long value;
+{
+  if (value)
+    {
+      (*info-&gt;fprintf_func) (info-&gt;stream, "[");
+      if (value &amp; VU_FLAG_I)
+	(*info-&gt;fprintf_func) (info-&gt;stream, "i");
+      if (value &amp; VU_FLAG_E)
+	(*info-&gt;fprintf_func) (info-&gt;stream, "e");
+      if (value &amp; VU_FLAG_M)
+	(*info-&gt;fprintf_func) (info-&gt;stream, "m");
+      if (value &amp; VU_FLAG_D)
+	(*info-&gt;fprintf_func) (info-&gt;stream, "d");
+      if (value &amp; VU_FLAG_T)
+	(*info-&gt;fprintf_func) (info-&gt;stream, "t");
+      (*info-&gt;fprintf_func) (info-&gt;stream, "]");
+    }
+}
+
+/* Broadcase field.  */
+
+static long
+parse_bc (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  long value = u_parse_sdest (pstr, errmsg);
+
+  if (*errmsg)
+    return 0;
+  if (value == -1)
+    {
+      *errmsg = MISSING_DEST;
+      return 0;
+    }
+  if (isalnum ((unsigned char) **pstr))
+    {
+      *errmsg = INVALID_DEST;
+      return 0;
+    }
+  /* Save value for later verification in register parsing.  */
+  state_vu_mnemonic_bc = value;
+  return value;
+}
+
+/* During the extraction process, save the bc field for use in
+   printing the bc register.  */
+
+static long
+extract_bc (opcode, operand, mods, insn, pinvalid)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     int *pinvalid;
+{
+  state_vu_mnemonic_bc = *insn &amp; 3;
+  return state_vu_mnemonic_bc;
+}
+
+static long
+parse_vfreg (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  char *str = *pstr;
+  char *start;
+  long reg;
+  int reg_dest;
+
+  if (tolower (str[0]) != 'v'
+      || tolower (str[1]) != 'f')
+    {
+      *errmsg = UNKNOWN_REGISTER;
+      return 0;
+    }
+
+  start = str = str + 2;
+  reg = strtol (start, &amp;str, 10);
+  if (reg &lt; 0 || reg &gt; 31)
+    {
+      *errmsg = INVALID_REGISTER_NUMBER;
+      return 0;
+    }
+  reg_dest = u_parse_dest (&amp;str);
+  if (isalnum ((unsigned char) *str))
+    {
+      *errmsg = INVALID_DEST;
+      return 0;
+    }
+  if (reg_dest == 0)
+    ; /* not specified, nothing to do */
+  else if (reg_dest != state_vu_mnemonic_dest)
+    {
+      *errmsg = _("register `dest' does not match instruction `dest'");
+      return 0;
+    }
+  *pstr = str;
+  return reg;
+}
+
+static void
+print_vfreg (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     disassemble_info *info;
+     DVP_INSN *insn;
+     long value;
+{
+  (*info-&gt;fprintf_func) (info-&gt;stream, "vf%02ld", value);
+  u_print_dest (info, insn, state_vu_mnemonic_dest);
+}
+
+/* FT register in broadcast case.  */
+
+static long
+parse_bcftreg (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  char *str = *pstr;
+  char *start;
+  long reg;
+  int reg_bc;
+
+  if (tolower (str[0]) != 'v'
+      || tolower (str[1]) != 'f')
+    {
+      *errmsg = UNKNOWN_REGISTER;
+      return 0;
+    }
+
+  start = str = str + 2;
+  reg = strtol (start, &amp;str, 10);
+  if (reg &lt; 0 || reg &gt; 31)
+    {
+      *errmsg = _("invalid register number");
+      return 0;
+    }
+  reg_bc = u_parse_sdest (&amp;str, errmsg);
+  if (*errmsg)
+    return 0;
+  if (reg_bc == -1)
+    ; /* not specified, nothing to do */
+  else if (reg_bc != state_vu_mnemonic_bc)
+    {
+      *errmsg = _("register `bc' does not match instruction `bc'");
+      return 0;
+    }
+  *pstr = str;
+  return reg;
+}
+
+static void
+print_bcftreg (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     disassemble_info *info;
+     long value;
+{
+  (*info-&gt;fprintf_func) (info-&gt;stream, "vf%02ld", value);
+  /* The assembler syntax has been modified to not require the dest spec
+     on the register.  Unlike the normal dest spec, for bc we print the
+     letter because it makes the output more readable without having to
+     remember which register is the bc one.  */
+  print_sdest (opcode, operand, mods, insn, info, state_vu_mnemonic_bc);
+}
+
+/* ACC handling.  */
+
+static long
+parse_accdest (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  char *str = *pstr;
+  long acc_dest = 0;
+
+  if (strncasecmp (str, "acc", 3) != 0)
+    {
+      *errmsg = _("expecting `acc'");
+      return 0;
+    }
+  str += 3;
+  acc_dest = u_parse_dest (&amp;str);
+  if (isalnum ((unsigned char) *str))
+    {
+      *errmsg = INVALID_DEST;
+      return 0;
+    }
+  if (acc_dest == 0)
+    ; /* not specified, nothing to do */
+  else if (acc_dest != state_vu_mnemonic_dest)
+    {
+      *errmsg = _("acc `dest' does not match instruction `dest'");
+      return 0;
+    }
+  *pstr = str;
+  /* Value isn't used, but we must return something.  */
+  return 0;
+}
+
+static void
+print_accdest (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     disassemble_info *info;
+     DVP_INSN *insn;
+     long value;
+{
+  (*info-&gt;fprintf_func) (info-&gt;stream, "acc");
+  u_print_dest (info, insn, state_vu_mnemonic_dest);
+}
+
+/* XYZ operand handling.
+   This simplifies the opmula,opmsub entries by keeping them equivalent to
+   the others.  */
+
+static void
+insert_xyz (opcode, operand, mods, insn, value, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     long value;
+     const char **errmsg;
+{
+  if (state_vu_mnemonic_dest != (VU_DEST_X | VU_DEST_Y | VU_DEST_Z))
+    *errmsg = _("expecting `xyz' for `dest' value");
+}
+
+
+/* W operand handling.
+   This simplifies the clip entry. */
+
+static void
+insert_w (opcode, operand, mods, insn, value, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     long value;
+     const char **errmsg;
+{
+  if (state_vu_mnemonic_bc != VU_SDEST_W)
+    *errmsg = _("expecting `w' for `bc' value");
+}
+
+
+/* F[ST] register using selector in F[ST]F field.
+   Internally, the value is encoded in 7 bits: the 2 bit xyzw indicator
+   followed by the 5 bit register number.  */
+
+static long
+parse_ffstreg (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  char *str = *pstr;
+  char *start;
+  int reg, xyzw;
+
+  if (tolower (str[0]) != 'v'
+      || tolower (str[1]) != 'f')
+    {
+      *errmsg = UNKNOWN_REGISTER;
+      return 0;
+    }
+
+  start = str = str + 2;
+  reg = strtol (start, &amp;str, 10);
+  if (reg &lt; 0 || reg &gt; 31)
+    {
+      *errmsg = _("invalid register number");
+      return 0;
+    }
+  xyzw = u_parse_sdest (&amp;str, errmsg);
+  if (*errmsg)
+    return 0;
+  if (xyzw == -1)
+    {
+      *errmsg = MISSING_DEST;
+      return 0;
+    }
+  if (isalnum ((unsigned char) *str))
+    {
+      *errmsg = INVALID_DEST;
+      return 0;
+    }
+  *pstr = str;
+  return reg | (xyzw &lt;&lt; 5);
+}
+
+static void
+print_ffstreg (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     disassemble_info *info;
+     long value;
+{
+  (*info-&gt;fprintf_func) (info-&gt;stream, "vf%02ld", value &amp; VU_MASK_REG);
+  print_sdest (opcode, operand, mods, insn, info, (value &gt;&gt; 5) &amp; 3);
+}
+
+static void
+insert_ffstreg (opcode, operand, mods, insn, value, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     long value;
+     const char **errmsg;
+{
+  if (operand-&gt;shift == VU_SHIFT_SREG)
+    *insn |= VLFSF (value &gt;&gt; 5) | VS (value);
+  else
+    *insn |= VLFTF (value &gt;&gt; 5) | VT (value);
+}
+
+static long
+extract_ffstreg (opcode, operand, mods, insn, pinvalid)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     int *pinvalid;
+{
+  if (operand-&gt;shift == VU_SHIFT_SREG)
+    return (((*insn &amp; VLFSF (~0)) &gt;&gt; 21) &lt;&lt; 5) | (((*insn) &amp; MS) &gt;&gt; VU_SHIFT_SREG);
+  else
+    return (((*insn &amp; VLFTF (~0)) &gt;&gt; 21) &lt;&lt; 5) | (((*insn) &amp; MS) &gt;&gt; VU_SHIFT_TREG);
+}
+
+/* F register.  */
+
+static long
+parse_freg (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  char *str = *pstr;
+  char *start;
+  long reg;
+
+  if (tolower (str[0]) != 'v'
+      || tolower (str[1]) != 'f')
+    {
+      *errmsg = UNKNOWN_REGISTER;
+      return 0;
+    }
+
+  start = str = str + 2;
+  reg = strtol (start, &amp;str, 10);
+  if (reg &lt; 0 || reg &gt; 31)
+    {
+      *errmsg = INVALID_REGISTER_NUMBER;
+      return 0;
+    }
+  *pstr = str;
+  return reg;
+}
+
+static void
+print_freg (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     disassemble_info *info;
+     long value;
+{
+  (*info-&gt;fprintf_func) (info-&gt;stream, "vf%02ld", value);
+}
+
+/* I register.  */
+
+static long
+parse_ireg (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  char *str = *pstr;
+  char *start;
+  long reg;
+
+  if (tolower (str[0]) != 'v'
+      || tolower (str[1]) != 'i')
+    {
+      *errmsg = UNKNOWN_REGISTER;
+      return 0;
+    }
+
+  start = str = str + 2;
+  reg = strtol (start, &amp;str, 10);
+  if (reg &lt; 0 || reg &gt; 31)
+    {
+      *errmsg = INVALID_REGISTER_NUMBER;
+      return 0;
+    }
+  *pstr = str;
+  return reg;
+}
+
+static void
+print_ireg (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     disassemble_info *info;
+     long value;
+{
+  (*info-&gt;fprintf_func) (info-&gt;stream, "vi%02ld", value);
+}
+
+/* VI01 register.  */
+
+static long
+parse_vi01 (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  char *str = *pstr;
+  char *start;
+  long reg;
+
+  if (tolower (str[0]) != 'v'
+      || tolower (str[1]) != 'i')
+    {
+      *errmsg = UNKNOWN_REGISTER;
+      return 0;
+    }
+
+  start = str = str + 2;
+  reg = strtol (start, &amp;str, 10);
+  if (reg != 1)
+    {
+      *errmsg = _("vi01 required here");
+      return 0;
+    }
+  *pstr = str;
+  return reg;
+}
+
+static void
+print_vi01 (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     disassemble_info *info;
+     long value;
+{
+  (*info-&gt;fprintf_func) (info-&gt;stream, "vi01");
+}
+
+/* Lower instruction 12 bit unsigned immediate.  */
+
+static void
+insert_luimm12 (opcode, operand, mods, insn, value, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     long value;
+     const char **errmsg;
+{
+  *insn |= VLUIMM12TOP ((value &amp; (1 &lt;&lt; 11)) != 0) | VLIMM11 (value);
+}
+
+static long
+extract_luimm12 (opcode, operand, mods, insn, pinvalid)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     int *pinvalid;
+{
+  return (((*insn &amp; MLUIMM12TOP) != 0) &lt;&lt; 11) | VLIMM11 (*insn);
+}
+
+/* Lower instruction 12 bit unsigned immediate, upper 6 bits.  */
+
+static void
+insert_luimm12up6 (opcode, operand, mods, insn, value, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     long value;
+     const char **errmsg;
+{
+  *insn |= VLUIMM12TOP ((value &amp; (1 &lt;&lt; 11)) != 0) | (value &amp; 0x7c0);
+}
+
+/* Lower instruction 15 bit unsigned immediate.  */
+
+static void
+insert_luimm15 (opcode, operand, mods, insn, value, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     long value;
+     const char **errmsg;
+{
+  *insn |= VLUIMM15TOP (value &gt;&gt; 11) | VLIMM11 (value);
+}
+
+static long
+extract_luimm15 (opcode, operand, mods, insn, pinvalid)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     int *pinvalid;
+{
+  return (((*insn &amp; MLUIMM15TOP) &gt;&gt; 21) &lt;&lt; 11) | VLIMM11 (*insn);
+}
+
+/* VIF support.  */
+
+PARSE_FN (vif_ibit);
+PRINT_FN (vif_ibit);
+
+INSERT_FN (vif_wlcl);
+EXTRACT_FN (vif_wlcl);
+
+PARSE_FN (vif_mode);
+PRINT_FN (vif_mode);
+
+PARSE_FN (vif_ability);
+PRINT_FN (vif_ability);
+
+PARSE_FN (vif_mpgloc);
+INSERT_FN (vif_mpgloc);
+
+PARSE_FN (vif_datalen_special);
+INSERT_FN (vif_datalen);
+EXTRACT_FN (vif_datalen);
+
+PARSE_FN (vif_imrubits);
+INSERT_FN (vif_imrubits);
+EXTRACT_FN (vif_imrubits);
+PRINT_FN (vif_imrubits);
+
+PARSE_FN (vif_unpacktype);
+PRINT_FN (vif_unpacktype);
+
+const dvp_operand vif_operands[] =
+{
+  /* place holder (??? not sure if needed) */
+#define VIF_UNUSED 128
+  { 0 },
+
+  /* The I bit.  */
+#define VIF_IBIT (VIF_UNUSED + 1)
+  { 1, 31, 0, DVP_OPERAND_SUFFIX, parse_vif_ibit, 0, 0, print_vif_ibit },
+
+  /* WL value, an 8 bit unsigned immediate, stored in upper 8 bits of
+     immed field.  */
+#define VIF_WL (VIF_IBIT + 1)
+  { 8, 8, 0, 0, 0, insert_vif_wlcl, extract_vif_wlcl, 0 },
+
+  /* CL value, an 8 bit unsigned immediate, stored in lower 8 bits of
+     immed field.  */
+#define VIF_CL (VIF_WL + 1)
+  { 8, 0, 0, 0, 0, insert_vif_wlcl, extract_vif_wlcl, 0 },
+
+  /* An 16 bit unsigned immediate, stored in lower 8 bits of immed field.  */
+#define VIF_UIMM16 (VIF_CL + 1)
+  { 16, 0, 0, 0, 0, 0, 0, 0 },
+
+  /* The mode operand of `stmod'.  */
+#define VIF_MODE (VIF_UIMM16 + 1)
+  { 2, 0, 0, 0, parse_vif_mode, 0, 0, print_vif_mode },
+
+  /* The ability operand of `mskpath3'.  */
+#define VIF_ABILITY (VIF_MODE + 1)
+  { 1, 15, 0, 0, parse_vif_ability, 0, 0, print_vif_ability },
+
+  /* A VU address.  */
+#define VIF_VUADDR (VIF_ABILITY + 1)
+  { 16, 0, 0, 0, 0, 0, 0, 0 },
+
+  /* A 32 bit immediate, appearing in 2nd word.  */
+#define VIF_UIMM32_2 (VIF_VUADDR + 1)
+  { 32, 0, 1, 0, 0, 0, 0, 0 },
+
+  /* A 32 bit immediate, appearing in 3rd word.  */
+#define VIF_UIMM32_3 (VIF_UIMM32_2 + 1)
+  { 32, 0, 2, 0, 0, 0, 0, 0 },
+
+  /* A 32 bit immediate, appearing in 4th word.  */
+#define VIF_UIMM32_4 (VIF_UIMM32_3 + 1)
+  { 32, 0, 3, 0, 0, 0, 0, 0 },
+
+  /* A 32 bit immediate, appearing in 5th word.  */
+#define VIF_UIMM32_5 (VIF_UIMM32_4 + 1)
+  { 32, 0, 4, 0, 0, 0, 0, 0 },
+
+  /* VU address used by mpg insn.  */
+#define VIF_MPGLOC (VIF_UIMM32_5 + 1)
+  { 16, 0, 0, DVP_OPERAND_VU_ADDRESS, parse_vif_mpgloc, insert_vif_mpgloc, 0, 0 },
+
+  /* A variable length data specifier as an expression.  */
+#define VIF_DATALEN (VIF_MPGLOC + 1)
+  { 0, 0, 0, 0, 0, insert_vif_datalen, extract_vif_datalen, 0 },
+
+  /* A variable length data specifier as a file name or '*'.
+     The operand is marked as pc-relative as the length is calculated by
+     emitting a label at the end of the data.  */
+#define VIF_DATALEN_SPECIAL (VIF_DATALEN + 1)
+  { 0, 0, 0, DVP_OPERAND_RELATIVE_BRANCH, parse_vif_datalen_special, insert_vif_datalen, 0, 0 },
+
+  /* The IMRU bits of the unpack insn.  */
+#define VIF_IMRUBITS (VIF_DATALEN_SPECIAL + 1)
+  { 0, 0, 0, DVP_OPERAND_SUFFIX,
+    parse_vif_imrubits, insert_vif_imrubits, extract_vif_imrubits, print_vif_imrubits },
+
+  /* The type of the unpack insn.  */
+#define VIF_UNPACKTYPE (VIF_IMRUBITS + 1)
+  { 4, 24, 0, 0, parse_vif_unpacktype, 0, 0, print_vif_unpacktype },
+
+  /* VU address used by unpack insn.  */
+#define VIF_UNPACKLOC (VIF_UNPACKTYPE + 1)
+  { 10, 0, 0, DVP_OPERAND_UNPACK_ADDRESS, 0, 0, 0, 0 },
+
+/* end of list place holder */
+  { 0 }
+};
+
+/* Some useful operand numbers.  */
+const int vif_operand_mpgloc = DVP_OPERAND_INDEX (VIF_MPGLOC);
+const int vif_operand_datalen_special = DVP_OPERAND_INDEX (VIF_DATALEN_SPECIAL);
+
+/* Field mask values.  */
+#define MVIFCMD 0x7f000000
+#define MVIFUNPACK 0x60000000
+
+/* Field values.  */
+#define VVIFCMD(x) V ((x), 7, 24)
+#define VVIFUNPACK V (0x60, 8, 24)
+
+struct dvp_opcode vif_opcodes[] =
+{
+  { "vifnop",   { VIF_IBIT },                                  0x7fffffff, 0 },
+  { "stcycle",  { VIF_IBIT, SP, VIF_WL, C, VIF_CL },           MVIFCMD, VVIFCMD (1), 0, DVP_OPCODE_IGNORE_DIS },
+  { "stcycl",   { VIF_IBIT, SP, VIF_WL, C, VIF_CL },           MVIFCMD, VVIFCMD (1) },
+  { "offset",   { VIF_IBIT, SP, VIF_UIMM16 },                  MVIFCMD, VVIFCMD (2) },
+  { "base",     { VIF_IBIT, SP, VIF_UIMM16 },                  MVIFCMD, VVIFCMD (3) },
+  { "itop",     { VIF_IBIT, SP, VIF_UIMM16 },                  MVIFCMD, VVIFCMD (4) },
+  { "stmod",    { VIF_IBIT, SP, VIF_MODE },                    MVIFCMD + V (~0, 14, 2), VVIFCMD (5) },
+  { "mskpath3", { VIF_IBIT, SP, VIF_ABILITY },                 MVIFCMD + V (~0, 15, 0), VVIFCMD (6) },
+  { "mark",     { VIF_IBIT, SP, VIF_UIMM16 },                  MVIFCMD, VVIFCMD (7) },
+  { "flushe",   { VIF_IBIT },                                  MVIFCMD, VVIFCMD (16) },
+  { "flusha",   { VIF_IBIT },                                  MVIFCMD, VVIFCMD (19) },
+  /* "flush" must appear after the previous two, longer ones first remember */
+  { "flush",    { VIF_IBIT },                                  MVIFCMD, VVIFCMD (17) },
+  { "mscalf",   { VIF_IBIT, SP, VIF_VUADDR },                  MVIFCMD, VVIFCMD (21) },
+  { "mscal",    { VIF_IBIT, SP, VIF_VUADDR },                  MVIFCMD, VVIFCMD (20) },
+  /* "mscal" must appear after the previous one. */
+  { "mscnt",    { VIF_IBIT },                                  MVIFCMD, VVIFCMD (23) },
+
+  /* 2 word instructions */
+  { "stmask",   { VIF_IBIT, SP, VIF_UIMM32_2 },                MVIFCMD, VVIFCMD (32), 0, VIF_OPCODE_LEN2 },
+
+  /* 5 word instructions */
+  { "strow",    { VIF_IBIT, SP, VIF_UIMM32_2, C, VIF_UIMM32_3, C, VIF_UIMM32_4, C, VIF_UIMM32_5 }, MVIFCMD, VVIFCMD (48), 0, VIF_OPCODE_LEN5 },
+  { "stcol",    { VIF_IBIT, SP, VIF_UIMM32_2, C, VIF_UIMM32_3, C, VIF_UIMM32_4, C, VIF_UIMM32_5 }, MVIFCMD, VVIFCMD (49), 0, VIF_OPCODE_LEN5 },
+
+  /* variable length instructions */
+  { "mpg",      { VIF_IBIT, SP, VIF_MPGLOC, C, VIF_DATALEN_SPECIAL }, MVIFCMD, VVIFCMD (0x4a), 0, VIF_OPCODE_LENVAR + VIF_OPCODE_MPG + DVP_OPCODE_IGNORE_DIS },
+  { "mpg",      { VIF_IBIT, SP, VIF_MPGLOC, C, VIF_DATALEN },         MVIFCMD, VVIFCMD (0x4a), 0, VIF_OPCODE_LENVAR + VIF_OPCODE_MPG },
+
+  /* `directhl' must appear before `direct', longer ones first */
+  { "directhl", { VIF_IBIT, SP, VIF_DATALEN_SPECIAL },  MVIFCMD, VVIFCMD (0x51), 0, VIF_OPCODE_LENVAR + VIF_OPCODE_DIRECT + DVP_OPCODE_IGNORE_DIS },
+  { "directhl", { VIF_IBIT, SP, VIF_DATALEN },          MVIFCMD, VVIFCMD (0x51), 0, VIF_OPCODE_LENVAR + VIF_OPCODE_DIRECT },
+
+  { "direct",   { VIF_IBIT, SP, VIF_DATALEN_SPECIAL },  MVIFCMD, VVIFCMD (0x50), 0, VIF_OPCODE_LENVAR + VIF_OPCODE_DIRECT + DVP_OPCODE_IGNORE_DIS },
+  { "direct",   { VIF_IBIT, SP, VIF_DATALEN },          MVIFCMD, VVIFCMD (0x50), 0, VIF_OPCODE_LENVAR + VIF_OPCODE_DIRECT },
+
+  { "unpack",   { VIF_IMRUBITS, SP, VIF_UNPACKTYPE, C, VIF_UNPACKLOC, C, VIF_DATALEN_SPECIAL }, MVIFUNPACK, VVIFUNPACK, 0, VIF_OPCODE_LENVAR + VIF_OPCODE_UNPACK + DVP_OPCODE_IGNORE_DIS },
+  { "unpack",   { VIF_IMRUBITS, SP, VIF_UNPACKTYPE, C, VIF_UNPACKLOC, C, VIF_DATALEN },         MVIFUNPACK, VVIFUNPACK, 0, VIF_OPCODE_LENVAR + VIF_OPCODE_UNPACK },
+};
+const int vif_opcodes_count = sizeof (vif_opcodes) / sizeof (vif_opcodes[0]);
+
+/* unpack/stcycl macro */
+
+const struct dvp_macro vif_macros[] = {
+  { "unpack${imrubits} ${wl},${cl},${unpacktype},${unpackloc},${datalen}", "stcycl %1,%2\nunpack%0 %3,%4,%5" }
+};
+const int vif_macro_count = sizeof (vif_macros) / sizeof (vif_macros[0]);
+
+/* Length of parsed insn, in 32 bit words, or 0 if unknown.  */
+static int state_vif_len;
+
+/* The value for mpgloc seen.  */
+static int state_vif_mpgloc;
+/* Non-zero if '*' was seen for mpgloc.  */
+static int state_vif_mpgloc_star_p;
+
+/* The most recent WL,CL args to stcycl.
+   HACK WARNING: This is a real kludge because when processing an `unpack'
+   we don't necessarily know what stcycl insn goes with it.
+   For now we punt and assume the last one we assembled.
+   Note that this requires that there be at least one stcycl in the
+   file before any unpack (if not we assume wl &lt;= cl).  */
+static int state_vif_wl = -1, state_vif_cl = -1;
+
+/* The file argument to mpg,direct,directhl,unpack is stored here
+   (in a malloc'd buffer).  */
+static char *state_vif_data_file;
+/* A numeric length for mpg,direct,directhl,unpack is stored here.  */
+static int state_vif_data_len;
+
+/* VIF parse,insert,extract,print helper fns.  */
+
+static long
+parse_vif_ibit (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  char *str = *pstr;
+  int flags = 0;
+
+  if (*str != '[')
+    return 0;
+
+  for (str = str + 1; *str != ']'; ++str)
+    {
+      switch (tolower (*str))
+	{
+	case 'i' : flags = 1; break;
+	default : *errmsg = _("unknown flag"); return 0;
+	}
+    }
+
+  *pstr = str + 1;
+  return flags;
+}
+
+static void
+print_vif_ibit (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     disassemble_info *info;
+     long value;
+{
+  if (value)
+    (*info-&gt;fprintf_func) (info-&gt;stream, "[i]");
+}
+
+/* Insert the wl,cl value into the insn.
+   This is used to record the wl,cl values for subsequent use by an unpack
+   insn.  */
+
+static void
+insert_vif_wlcl (opcode, operand, mods, insn, value, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     long value;
+     const char **errmsg;
+{
+  *insn |= (value &amp; ((1 &lt;&lt; operand-&gt;bits) - 1)) &lt;&lt; operand-&gt;shift;
+  if (operand-&gt;shift == 8)
+    state_vif_wl = value;
+  else
+    state_vif_cl = value;
+}
+
+/* Extract the wl,cl value from the insn.
+   This is used to record the wl,cl values for subsequent use by an unpack
+   insn.  */
+
+static long
+extract_vif_wlcl (opcode, operand, mods, insn, pinvalid)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     int *pinvalid;
+{
+  long value = (*insn &gt;&gt; operand-&gt;shift) &amp; ((1 &lt;&lt; operand-&gt;bits) - 1);
+  if (operand-&gt;shift == 8)
+    state_vif_wl = value;
+  else
+    state_vif_cl = value;
+  return value;
+}
+
+static const keyword stmod_modes[] = {
+  { VIF_MODE_DIRECT, "direct" },
+  { VIF_MODE_ADD,    "add" },
+  { VIF_MODE_ADDROW, "addrow" },
+  { 0, 0 }
+};
+
+static long
+parse_vif_mode (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  int mode;
+  char *str = *pstr;
+  char *start;
+  char c;
+
+  start = str;
+  if (isdigit ((unsigned char) *str))
+    {
+      mode = strtol (start, &amp;str, 0);
+    }
+  else
+    {
+      str = scan_symbol (str);
+      c = *str;
+      *str = 0;
+      mode = lookup_keyword_value (stmod_modes, start, 0);
+      *str = c;
+    }
+  if (mode &gt;= 0 &amp;&amp; mode &lt;= 2)
+    {
+      *pstr = str;
+      return mode;
+    }
+  *errmsg = _("invalid mode");
+  return 0;
+}
+
+static void
+print_vif_mode (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     disassemble_info *info;
+     DVP_INSN *insn;
+     long value;
+{
+  const char *name = lookup_keyword_name (stmod_modes, value);
+
+  if (name)
+    (*info-&gt;fprintf_func) (info-&gt;stream, name);
+  else
+    (*info-&gt;fprintf_func) (info-&gt;stream, "???");
+}
+
+static long
+parse_vif_ability (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  char *str = *pstr;
+
+  if (strncasecmp (str, "disable", 7) == 0)
+    {
+      *pstr += 7;
+      return 1;
+    }
+  else if (strncasecmp (str, "enable", 6) == 0)
+    {
+      *pstr += 6;
+      return 0;
+    }
+  *errmsg = _("invalid ability");
+  return 1;
+}
+
+static void
+print_vif_ability (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     disassemble_info *info;
+     long value;
+{
+  if (! value)
+    (*info-&gt;fprintf_func) (info-&gt;stream, "enable");
+  else
+    (*info-&gt;fprintf_func) (info-&gt;stream, "disable");
+}
+
+/* Parse the mpgloc field.
+   This doesn't do any actual parsing.
+   It exists to record the fact that '*' was seen.  */
+
+static long
+parse_vif_mpgloc (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  if (**pstr == '*')
+    state_vif_mpgloc_star_p = 1;
+  /* Since we don't advance *pstr, the normal expression parser will
+     be called.  */
+  return 0;
+}
+
+static void
+insert_vif_mpgloc (opcode, operand, mods, insn, value, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     long value;
+     const char **errmsg;
+{
+  *insn |= (value &amp; ((1 &lt;&lt; operand-&gt;bits) - 1)) &lt;&lt; operand-&gt;shift;
+  /* If we saw a '*', don't record VALUE - it's meaningless.  */
+  if (! state_vif_mpgloc_star_p)
+    state_vif_mpgloc = value;
+}
+
+/* Parse a file name or '*'.
+   If a file name, the name is stored in state_vif_data_file and result is 0.
+   If a *, result is -1.  */
+
+static long
+parse_vif_datalen_special (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  char *str = *pstr;
+  char *start;
+  int len;
+
+  if (*str == '*')
+    {
+      ++*pstr;
+      return -1;
+    }
+
+  if (*str == '"')
+    {
+      start = ++str;
+      ++str;
+      while (*str &amp;&amp; *str != '"')
+	{
+	  /* FIXME: \ parsing? */
+	  ++str;
+	}
+      if (*str == 0)
+	{
+	  *errmsg = _("file name missing terminating `\"'");
+	  return 0;
+	}
+      len = str - start;
+      state_vif_data_file = xmalloc (len + 1);
+      memcpy (state_vif_data_file, start, len);
+      state_vif_data_file[len] = 0;
+      *pstr = str + 1;
+      return 0;
+    }
+
+  *errmsg = _("invalid data length");
+  return 0;
+}
+
+/* This routine is used for both the mpg and unpack insns which store
+   their length value in the `num' field and the direct/directhl insns
+   which store their length value in the `immediate' field.  */
+
+static void
+insert_vif_datalen (opcode, operand, mods, insn, value, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     long value;
+     const char **errmsg;
+{
+  /* FIXME: The actual insertion of the value in the insn is currently done
+     in tc-dvp.c.  We just record the value.  */
+  /* Perform the max+1 -&gt; 0 conversion.  */
+  if ((opcode-&gt;flags &amp; VIF_OPCODE_MPG) != 0
+      &amp;&amp; value == 256)
+    value = 0;
+  else if ((opcode-&gt;flags &amp; VIF_OPCODE_DIRECT) != 0
+	   &amp;&amp; value == 65536)
+    value = 0;
+  else if ((opcode-&gt;flags &amp; VIF_OPCODE_UNPACK) != 0
+	   &amp;&amp; value == 256)
+    value = 0;
+  state_vif_data_len = value;
+}
+
+/* This routine is used for both the mpg and unpack insns which store
+   their length value in the `num' field and the direct/directhl insns
+   which store their length value in the `immediate' field.  */
+
+static long
+extract_vif_datalen (opcode, operand, mods, insn, pinvalid)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     int *pinvalid;
+{
+  int len;
+
+  switch ((*insn &gt;&gt; 24) &amp; 0x70)
+    {
+    case 0x40 : /* mpg */
+      len = (*insn &gt;&gt; 16) &amp; 0xff;
+      return len ? len : 256;
+    case 0x50 : /* direct,directhl */
+      len = *insn &amp; 0xffff;
+      return len ? len : 65536;
+    case 0x60 : /* unpack */
+    case 0x70 :
+      len = (*insn &gt;&gt; 16) &amp; 0xff;
+      return len ? len : 256;
+    default :
+      return 0;
+    }
+}
+
+static long
+parse_vif_imrubits (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  char *str = *pstr;
+  int flags = 0;
+
+  if (*str != '[')
+    return 0;
+
+  for (str = str + 1; *str != ']'; ++str)
+    {
+      switch (tolower (*str))
+	{
+	case 'i' : flags |= VIF_FLAG_I; break;
+	case 'm' : flags |= VIF_FLAG_M; break;
+	case 'r' : flags |= VIF_FLAG_R; break;
+	case 'u' : flags |= VIF_FLAG_U; break;
+	default : *errmsg = _("unknown vif flag"); return 0;
+	}
+    }
+
+  *pstr = str + 1;
+  return flags;
+}
+
+static void
+insert_vif_imrubits (opcode, operand, mods, insn, value, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     long value;
+     const char **errmsg;
+{
+  if (value &amp; VIF_FLAG_I)
+    *insn |= 0x80000000;
+  if (value &amp; VIF_FLAG_M)
+    *insn |= 0x10000000;
+  if (value &amp; VIF_FLAG_R)
+    *insn |= 0x8000;
+  if (value &amp; VIF_FLAG_U)
+    *insn |= 0x4000;
+}
+
+static long
+extract_vif_imrubits (opcode, operand, mods, insn, pinvalid)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     int *pinvalid;
+{
+  long value = 0;
+  if (*insn &amp; 0x80000000)
+    value |= VIF_FLAG_I;
+  if (*insn &amp; 0x10000000)
+    value |= VIF_FLAG_M;
+  if (*insn &amp; 0x8000)
+    value |= VIF_FLAG_R;
+  if (*insn &amp; 0x4000)
+    value |= VIF_FLAG_U;
+  return value;
+}
+
+static void
+print_vif_imrubits (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     disassemble_info *info;
+     long value;
+{
+  if (value)
+    {
+      (*info-&gt;fprintf_func) (info-&gt;stream, "[");
+      if (value &amp; VIF_FLAG_I)
+	(*info-&gt;fprintf_func) (info-&gt;stream, "i");
+      if (value &amp; VIF_FLAG_M)
+	(*info-&gt;fprintf_func) (info-&gt;stream, "m");
+      if (value &amp; VIF_FLAG_R)
+	(*info-&gt;fprintf_func) (info-&gt;stream, "r");
+      if (value &amp; VIF_FLAG_U)
+	(*info-&gt;fprintf_func) (info-&gt;stream, "u");
+      (*info-&gt;fprintf_func) (info-&gt;stream, "]");
+    }
+}
+
+static const keyword unpack_types[] = {
+  { VIF_UNPACK_S_32, "s_32" },
+  { VIF_UNPACK_S_16, "s_16" },
+  { VIF_UNPACK_S_8, "s_8" },
+  { VIF_UNPACK_V2_32, "v2_32" },
+  { VIF_UNPACK_V2_16, "v2_16" },
+  { VIF_UNPACK_V2_8, "v2_8" },
+  { VIF_UNPACK_V3_32, "v3_32" },
+  { VIF_UNPACK_V3_16, "v3_16" },
+  { VIF_UNPACK_V3_8, "v3_8" },
+  { VIF_UNPACK_V4_32, "v4_32" },
+  { VIF_UNPACK_V4_16, "v4_16" },
+  { VIF_UNPACK_V4_8, "v4_8" },
+  { VIF_UNPACK_V4_5, "v4_5" },
+  { 0, 0 }
+};
+
+static long
+parse_vif_unpacktype (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  int type;
+  char *str = *pstr;
+  char *start;
+  char c;
+
+  start = str;
+  str = scan_symbol (str);
+  c = *str;
+  *str = 0;
+  type = lookup_keyword_value (unpack_types, start, 0);
+  *str = c;
+  if (type != -1)
+    {
+      *pstr = str;
+      return type;
+    }
+  *errmsg = _("invalid unpack type");
+  return 0;
+}
+
+static void
+print_vif_unpacktype (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     disassemble_info *info;
+     long value;
+{
+  const char *name = lookup_keyword_name (unpack_types, value);
+
+  if (name)
+    (*info-&gt;fprintf_func) (info-&gt;stream, name);
+  else
+    (*info-&gt;fprintf_func) (info-&gt;stream, "???");
+}
+
+/* External VIF supporting routines.  */
+
+/* Return length, in 32 bit words, of just parsed vif insn,
+   or 0 if unknown.  */
+
+int
+vif_len ()
+{
+  /* This shouldn't be called unless a vif insn was parsed.
+     Also, we want to catch errors in parsing that don't set this.  */
+  if (state_vif_len == -1)
+    abort ();
+
+  return state_vif_len;
+}
+
+/* Return the length value to use for an unpack instruction, type TYPE,
+   whose data length in bytes is LEN.
+   We do not perform the max + 1 -&gt; 0 transformation.  That's up to the caller.
+   WL,CL are the values to use for those registers.  A value of -1 means to
+   use the internally recorded values.  If the values are still -1, we
+   assume wl &lt;= cl.
+   This means that it is assumed that unpack always requires a preceeding
+   stcycl sufficiently recently that the value we have recorded is correct.
+   FIXME: We assume len % 4 == 0.  */
+
+int
+vif_unpack_len_value (type, wl, cl, len)
+     unpack_type type;
+     int wl,cl;
+     int len;
+{
+  int vn = (type &gt;&gt; 2) &amp; 3;
+  int vl = type &amp; 3;
+  int n, num;
+
+  if (wl &lt; 0)
+    wl = state_vif_wl;
+  if (cl &lt; 0)
+    cl = state_vif_cl;
+  if (wl == -1 || cl == -1)
+    wl = cl = 1;
+
+  if (wl &lt;= cl)
+    {
+      /* data length (in words) len = ((((32 &gt;&gt; vl) * (vn + 1)) * num) / 32)
+	 Thus num = (len / 4) * 32 / ((32 &gt;&gt; vl) * (vn + 1)) */
+      num = (len * 32 / 4) / ((32 &gt;&gt; vl) * (vn + 1));
+    }
+  else /* wl &gt; cl */
+    {
+      /* data length (in words) len = ((((32 &gt;&gt; vl) * (vn + 1)) * n) / 32)
+	 n = CL * (num / WL) + min (num % WL, CL)
+	 Thus n = (len / 4) * 32 / ((32 &gt;&gt; vl) * (vn + 1))
+	 num = (n - delta) * wl / cl;
+	 where `delta' is defined to be "just right".
+	 I'm too bloody tired to do this more cleverly.  */
+      n = (len * 32 / 4) / ((32 &gt;&gt; vl) * (vn + 1));
+      /* Avoid divide by zero.  */
+      if (cl == 0)
+	return 0;
+      /* Note that wl cannot be zero here.
+	 We know that cl &gt; 0 and thus if wl == 0 we would have taken
+	 the `then' part of this if().  */
+      num = n * wl / cl;
+      while (num &gt; 0
+	     &amp;&amp; n != (cl * num / wl) + MIN (num % wl, cl))
+	--num;
+      if (num == 0)
+	{
+	  fprintf (stderr, _("internal error in unpack length calculation"));
+	  abort ();
+	}
+    }
+  return num;
+}
+
+/* Return the data length, in bytes, of an unpack insn of type TYPE,
+   whose `num' field in NUM.
+   If WL,CL are unknown, we assume wl &lt;= cl.  */
+
+int
+vif_unpack_len (type, num)
+     unpack_type type;
+     int num;
+{
+  int vn = (type &gt;&gt; 2) &amp; 3;
+  int vl = type &amp; 3;
+  int wl = state_vif_wl;
+  int cl = state_vif_cl;
+  int n, len;
+
+  if (wl == -1 || cl == -1)
+    wl = cl = 1;
+
+  /* Perform 0 -&gt; max+1 conversion.  */
+  if (num == 0)
+    num = 256;
+  if (wl == 0)
+    wl = 256;
+
+  if (wl &lt;= cl)
+    {
+      /* data length (in words) len = ((((32 &gt;&gt; vl) * (vn + 1)) * num) / 32) */
+      n = num;
+    }
+  else /* wl &gt; cl */
+    {
+      /* data length (in words) len = ((((32 &gt;&gt; vl) * (vn + 1)) * n) / 32)
+	 n = CL * (num / WL) + min (num % WL, CL) */
+      n = cl * num / wl + MIN (num % wl, cl);
+    }
+  /* +31: round up to next word boundary */
+  len = ((((32 &gt;&gt; vl) * (vn + 1)) * n) + 31) / 32;
+  return len * 4;
+}
+
+/* Return the length, in 32 bit words, of a VIF insn.
+   INSN is the first word.
+   The cpu type of the following data is stored in PCPU.  */
+
+int
+vif_insn_len (insn, pcpu)
+     DVP_INSN insn;
+     dvp_cpu *pcpu;
+{
+  unsigned char cmd;
+
+  *pcpu = DVP_VIF;
+
+  /* strip off `i' bit */
+  insn &amp;= 0x7fffffff;
+
+  /* get top byte */
+  cmd = insn &gt;&gt; 24;
+
+  /* see page 11 of cpu2 spec 2.1 for further info */
+  if ((cmd &amp; 0x60) == 0)
+    return 1;
+  if ((cmd &amp; 0x70) == 0x20)
+    return 2;
+  if ((cmd &amp; 0x70) == 0x30)
+    return 5;
+  if ((cmd &amp; 0x70) == 0x40)
+    {
+      /* mpg */
+      int len = (insn &gt;&gt; 16) &amp; 0xff;
+      *pcpu = DVP_VUUP;
+      return 1 + (len == 0 ? 256 : len) * 2;
+    }
+  if ((cmd &amp; 0x70) == 0x50)
+    {
+      /* direct,directhl */
+      int len = insn &amp; 0xffff;
+      *pcpu = DVP_GIF;
+      return 1 + (len == 0 ? 65536 : len) * 4;
+    }
+  if ((cmd &amp; 0x60) == 0x60)
+    {
+      /* unpack */
+      int len = vif_unpack_len (cmd &amp; 15, (insn &gt;&gt; 16) &amp; 0xff);
+      if (len == -1)
+	len = 4; /* FIXME: revisit */
+      return 1 + len / 4;
+    }
+
+  /* unknown insn */
+  return 1;
+}
+
+/* Get the value of mpgloc seen.  */
+
+int
+vif_get_mpgloc ()
+{
+  return state_vif_mpgloc;
+}
+
+/* Return recorded variable data length indicator.
+   This is either a file name or a numeric length.
+   A length of -1 means the caller must compute it.  */
+
+void
+vif_get_var_data (file, len)
+     const char **file;
+     int *len;
+{
+  *file = state_vif_data_file;
+  *len = state_vif_data_len;
+}
+
+/* Return the specified values for wl,cl.  */
+
+void
+vif_get_wl_cl (wlp, clp)
+     int *wlp, *clp;
+{
+  *wlp = state_vif_wl;
+  *clp = state_vif_cl;
+}
+
+/* DMA support.  */
+
+PARSE_FN (dma_flags);
+INSERT_FN (dma_flags);
+EXTRACT_FN (dma_flags);
+PRINT_FN (dma_flags);
+
+INSERT_FN (dma_count);
+EXTRACT_FN (dma_count);
+PRINT_FN (dma_count);
+
+PARSE_FN (dma_data2);
+
+PARSE_FN (dma_addr);
+INSERT_FN (dma_addr);
+EXTRACT_FN (dma_addr);
+PRINT_FN (dma_addr);
+
+const dvp_operand dma_operands[] =
+{
+    /* place holder (??? not sure if needed) */
+#define DMA_UNUSED 128
+    { 0 },
+
+    /* dma tag flag bits */
+#define DMA_FLAGS (DMA_UNUSED + 1)
+    { 0, 0, 0, DVP_OPERAND_SUFFIX,
+      parse_dma_flags, insert_dma_flags, extract_dma_flags, print_dma_flags },
+
+    /* dma data spec */
+#define DMA_COUNT (DMA_FLAGS + 1)
+    { 16, 0, 0, DVP_OPERAND_DMA_COUNT,
+      0, 0 /*insert_dma_count*/,
+      0 /*extract_dma_count*/, 0 /*print_dma_count*/ },
+
+    /* dma autocount modifier */
+#define DMA_AUTOCOUNT (DMA_COUNT + 1)
+    { 0, 0, 0, DVP_OPERAND_AUTOCOUNT, 0, 0, 0, 0 },
+
+    /* dma in-line-data */
+#define DMA_INLINE (DMA_AUTOCOUNT + 1)
+    { 0, 0, 0, DVP_OPERAND_FAKE + DVP_OPERAND_DMA_INLINE, 0, 0, 0, 0 },
+
+    /* dma ref data address */
+#define DMA_ADDR (DMA_INLINE + 1)
+    { 27, 4, 1, DVP_OPERAND_DMA_ADDR + DVP_OPERAND_MIPS_ADDRESS,
+      0 /*parse_dma_addr*/, insert_dma_addr,
+      extract_dma_addr, 0 /*print_dma_addr*/ },
+
+    /* dma next tag spec */
+#define DMA_NEXT (DMA_ADDR + 1)
+    { 27, 4, 1, DVP_OPERAND_DMA_NEXT + DVP_OPERAND_MIPS_ADDRESS,
+      0, insert_dma_addr, extract_dma_addr, 0 /*print_dma_addr*/ },
+
+/* end of list place holder */
+  { 0 }
+};
+
+/* Some useful operand numbers.  */
+const int dma_operand_count = DVP_OPERAND_INDEX (DMA_COUNT);
+const int dma_operand_addr = DVP_OPERAND_INDEX (DMA_ADDR);
+
+struct dvp_opcode dma_opcodes[] =
+{
+  { "dmarefe", { DMA_FLAGS, SP, '*',       C, DMA_AUTOCOUNT, DMA_ADDR },             0x70000000, 0x00000000, 0, DVP_OPCODE_IGNORE_DIS },
+  { "dmarefe", { DMA_FLAGS, SP, DMA_COUNT, C, DMA_ADDR },                            0x70000000, 0x00000000, 0 },
+  { "dmacnt",  { DMA_FLAGS, SP, '*',       DMA_AUTOCOUNT, DMA_INLINE },              0x70000000, 0x10000000, 0, DVP_OPCODE_IGNORE_DIS },
+  { "dmacnt",  { DMA_FLAGS, SP, DMA_COUNT, DMA_INLINE },                             0x70000000, 0x10000000, 0 },
+  { "dmanext", { DMA_FLAGS, SP, '*',       C, DMA_AUTOCOUNT, DMA_INLINE, DMA_NEXT }, 0x70000000, 0x20000000, 0, DVP_OPCODE_IGNORE_DIS },
+  { "dmanext", { DMA_FLAGS, SP, DMA_COUNT, C, DMA_INLINE, DMA_NEXT },                0x70000000, 0x20000000, 0 },
+  { "dmaref",  { DMA_FLAGS, SP, '*',       C, DMA_AUTOCOUNT, DMA_ADDR },             0x70000000, 0x30000000, 0, DVP_OPCODE_IGNORE_DIS },
+  { "dmaref",  { DMA_FLAGS, SP, DMA_COUNT, C, DMA_ADDR },                            0x70000000, 0x30000000, 0 },
+  { "dmarefs", { DMA_FLAGS, SP, '*',       C, DMA_AUTOCOUNT, DMA_ADDR },             0x70000000, 0x40000000, 0, DVP_OPCODE_IGNORE_DIS },
+  { "dmarefs", { DMA_FLAGS, SP, DMA_COUNT, C, DMA_ADDR },                            0x70000000, 0x40000000, 0 },
+  { "dmacall", { DMA_FLAGS, SP, '*',       C, DMA_AUTOCOUNT, DMA_INLINE, DMA_NEXT }, 0x70000000, 0x50000000, 0, DVP_OPCODE_IGNORE_DIS },
+  { "dmacall", { DMA_FLAGS, SP, DMA_COUNT, C, DMA_INLINE, DMA_NEXT },                0x70000000, 0x50000000, 0 },
+  { "dmaret",  { DMA_FLAGS, SP, '*',       DMA_AUTOCOUNT, DMA_INLINE},               0x70000000, 0x60000000, 0, DVP_OPCODE_IGNORE_DIS },
+  { "dmaret",  { DMA_FLAGS, SP, DMA_COUNT, DMA_INLINE },                             0x70000000, 0x60000000, 0 },
+  { "dmaend",  { DMA_FLAGS, SP, '*',       DMA_AUTOCOUNT, DMA_INLINE },              0x70000000, 0x70000000, 0, DVP_OPCODE_IGNORE_DIS },
+  { "dmaend",  { DMA_FLAGS, SP, DMA_COUNT, DMA_INLINE },                             0x70000000, 0x70000000, 0 },
+  { "dmaend",  { DMA_FLAGS },                                                        0x70000000, 0x70000000, 0 },
+};
+const int dma_opcodes_count = sizeof (dma_opcodes) / sizeof (dma_opcodes[0]);
+
+/* DMA parse,insert,extract,print helper fns.  */
+
+static long
+parse_dma_flags (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  char *str = *pstr;
+  int flags = 0;
+
+  if (*str != '[')
+    return 0;
+
+  for (str = str + 1; *str != ']'; ++str)
+    {
+      switch (tolower (*str))
+	{
+	case '0' : flags |= DMA_FLAG_PCE0; break;
+	case '1' : flags |= DMA_FLAG_PCE1; break;
+	case 'i' : flags |= DMA_FLAG_INT; break;
+	case 's' : flags |= DMA_FLAG_SPR; break;
+	default : *errmsg = _("unknown dma flag"); return 0;
+	}
+    }
+
+  *pstr = str + 1;
+  return flags;
+}
+
+static void
+insert_dma_flags (opcode, operand, mods, insn, value, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     long value;
+     const char **errmsg;
+{
+  if (value &amp; DMA_FLAG_PCE0)
+    insn[0] |= 2 &lt;&lt; 26;
+  else if (value &amp; DMA_FLAG_PCE0)
+    insn[0] |= 3 &lt;&lt; 26;
+  if (value &amp; DMA_FLAG_INT)
+    insn[0] |= (1 &lt;&lt; 31);
+  if (value &amp; DMA_FLAG_SPR)
+    insn[1] |= (1 &lt;&lt; 31);
+}
+
+static long
+extract_dma_flags (opcode, operand, mods, insn, pinvalid)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     int *pinvalid;
+{
+  long value = 0;
+  if (((insn[0] &gt;&gt; 26) &amp; 3) == 2)
+     value |= DMA_FLAG_PCE0;
+  if (((insn[0] &gt;&gt; 26) &amp; 3) == 3)
+     value |= DMA_FLAG_PCE0;
+  if (((insn[0] &gt;&gt; 31) &amp; 1) == 1)
+     value |= DMA_FLAG_INT;
+  if (((insn[1] &gt;&gt; 31) &amp; 1) == 1)
+     value |= DMA_FLAG_SPR;
+  return value;
+}
+
+static void
+print_dma_flags (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     disassemble_info *info;
+     long value;
+{
+  if (value)
+    {
+      (*info-&gt;fprintf_func) (info-&gt;stream, "[");
+      if (value &amp; DMA_FLAG_PCE0)
+	(*info-&gt;fprintf_func) (info-&gt;stream, "0");
+      if (value &amp; DMA_FLAG_PCE1)
+	(*info-&gt;fprintf_func) (info-&gt;stream, "1");
+      if (value &amp; DMA_FLAG_INT)
+	(*info-&gt;fprintf_func) (info-&gt;stream, "i");
+      if (value &amp; DMA_FLAG_SPR)
+	(*info-&gt;fprintf_func) (info-&gt;stream, "s");
+      (*info-&gt;fprintf_func) (info-&gt;stream, "]");
+    }
+}
+
+
+static void
+insert_dma_count (opcode, operand, mods, insn, value, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     long value;
+     const char **errmsg;
+{
+}
+
+static long
+extract_dma_count (opcode, operand, mods, insn, pinvalid)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     int *pinvalid;
+{
+  return 0;
+}
+
+static void
+print_dma_count (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     disassemble_info *info;
+     long value;
+{
+  (*info-&gt;fprintf_func) (info-&gt;stream, "???");
+}
+
+static long
+parse_dma_addr (opcode, operand, mods, pstr, errmsg)
+    const dvp_opcode *opcode;
+    const dvp_operand *operand;
+    int mods;
+    char **pstr;
+    const char **errmsg;
+{
+    return 0;
+}
+
+static void
+insert_dma_addr (opcode, operand, mods, insn, value, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     long value;
+     const char **errmsg;
+{
+  int word;
+
+  if (mods &amp; DVP_MOD_THIS_WORD)
+    word = 0;
+  else if (operand-&gt;word)
+    word = operand-&gt;word;
+  else
+    word = operand-&gt;shift / 32;
+
+  /* The lower 4 bits are cut off and the value begins at bit 4.  */
+  insn[word] |= value &amp; 0x7ffffff0;
+}
+
+static long
+extract_dma_addr (opcode, operand, mods, insn, pinvalid)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     int *pinvalid;
+{
+  int word;
+
+  if (mods &amp; DVP_MOD_THIS_WORD)
+    word = 0;
+  else if (operand-&gt;word)
+    word = operand-&gt;word;
+  else
+    word = operand-&gt;shift / 32;
+
+  return insn[word] &amp; 0x7ffffff0;
+}
+
+static void
+print_dma_addr (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     disassemble_info *info;
+     long value;
+{
+  (*info-&gt;fprintf_func) (info-&gt;stream, "???");
+}
+
+/* GIF support.  */
+
+PARSE_FN (gif_prim);
+INSERT_FN (gif_prim);
+EXTRACT_FN (gif_prim);
+PRINT_FN (gif_prim);
+
+PARSE_FN (gif_regs);
+INSERT_FN (gif_regs);
+EXTRACT_FN (gif_regs);
+PRINT_FN (gif_regs);
+
+PARSE_FN (gif_nloop);
+INSERT_FN (gif_nloop);
+EXTRACT_FN (gif_nloop);
+PRINT_FN (gif_nloop);
+
+PARSE_FN (gif_eop);
+EXTRACT_FN (gif_eop);
+PRINT_FN (gif_eop);
+
+/* Bit numbering:
+
+    insn[0]    insn[1]     insn[2]     insn[3]
+   31 ... 0 | 63 ... 32 | 95 ... 64 | 127 ... 96  */
+
+const dvp_operand gif_operands[] =
+{
+  /* place holder (??? not sure if needed) */
+#define GIF_UNUSED 128
+  { 0 },
+
+  /* PRIM=foo operand */
+#define GIF_PRIM (GIF_UNUSED + 1)
+  { 11, 47, 0, 0, parse_gif_prim, insert_gif_prim, extract_gif_prim, print_gif_prim },
+
+  /* REGS=foo operand */
+#define GIF_REGS (GIF_PRIM + 1)
+  { 64, 0, 0, 0, parse_gif_regs, insert_gif_regs, extract_gif_regs, print_gif_regs },
+
+  /* NLOOP=foo operand */
+#define GIF_NLOOP (GIF_REGS + 1)
+  { 15, 0, 0, 0, parse_gif_nloop, insert_gif_nloop, extract_gif_nloop, print_gif_nloop },
+
+  /* EOP operand */
+#define GIF_EOP (GIF_NLOOP + 1)
+  { 1, 15, 0, 0, parse_gif_eop, 0, extract_gif_eop, print_gif_eop },
+
+/* end of list place holder */
+  { 0 }
+};
+
+/* Some useful operand numbers.  */
+const int gif_operand_nloop = DVP_OPERAND_INDEX (GIF_NLOOP);
+
+/* GIF opcode values.  */
+#define VGIFOP(x) (((x) &amp; 3) &lt;&lt; 26)
+#define VGIFNREGS(x) (((x) &amp; 15) &lt;&lt; 28)
+
+/* GIF opcode masks.  */
+#define MGIFOP VGIFOP (~0)
+#define MGIFNREGS VGIFNREGS (~0)
+
+struct dvp_opcode gif_opcodes[] =
+{
+  /* Some of these may take optional arguments.
+     The way this is handled is to have multiple table entries, those with and
+     those without the optional arguments.
+     !!! The order here is important.  The code that scans this table assumes
+     that if it reaches the end of a syntax string there is nothing more to
+     parse.  This means that longer versions of instructions must appear before
+     shorter ones.  Otherwise the text at the "end" of a longer one may be
+     interpreted as junk when the parser is using a shorter version of the
+     syntax string.  */
+
+  { "gifpacked", { SP, GIF_PRIM, C, GIF_REGS, C, GIF_NLOOP, C, GIF_EOP }, MGIFOP, VGIFOP (0), 1 },
+  { "gifpacked", { SP, GIF_REGS, C, GIF_NLOOP, C, GIF_EOP },              MGIFOP, VGIFOP (0), 1 },
+  { "gifpacked", { SP, GIF_PRIM, C, GIF_REGS, C, GIF_EOP },               MGIFOP, VGIFOP (0), 1 },
+  { "gifpacked", { SP, GIF_PRIM, C, GIF_REGS, C, GIF_NLOOP },             MGIFOP, VGIFOP (0), 1 },
+  { "gifpacked", { SP, GIF_REGS, C, GIF_EOP },                            MGIFOP, VGIFOP (0), 1 },
+  { "gifpacked", { SP, GIF_REGS, C, GIF_NLOOP },                          MGIFOP, VGIFOP (0), 1 },
+  { "gifpacked", { SP, GIF_PRIM, C, GIF_REGS },                           MGIFOP, VGIFOP (0), 1 },
+  { "gifpacked", { SP, GIF_REGS },                                        MGIFOP, VGIFOP (0), 1 },
+
+  { "gifreglist", { SP, GIF_REGS, C, GIF_NLOOP, C, GIF_EOP }, MGIFOP, VGIFOP (1), 1 },
+  { "gifreglist", { SP, GIF_REGS, C, GIF_EOP },               MGIFOP, VGIFOP (1), 1 },
+  { "gifreglist", { SP, GIF_REGS, C, GIF_NLOOP },             MGIFOP, VGIFOP (1), 1 },
+  { "gifreglist", { SP, GIF_REGS },                           MGIFOP, VGIFOP (1), 1 },
+
+  { "gifimage", { SP, GIF_NLOOP, C, GIF_EOP }, MGIFOP, VGIFOP (2), 1 },
+  { "gifimage", { SP, GIF_EOP },               MGIFOP, VGIFOP (2), 1 },
+  { "gifimage", { SP, GIF_NLOOP },             MGIFOP, VGIFOP (2), 1 },
+  { "gifimage", { 0 },                         MGIFOP, VGIFOP (2), 1 },
+};
+const int gif_opcodes_count = sizeof (gif_opcodes) / sizeof (gif_opcodes[0]);
+
+/* GIF parsing/printing state.  */
+
+static int state_gif_nregs;
+static int state_gif_regs[16];
+static int state_gif_nloop;
+
+/* GIF parse,insert,extract,print helper fns.  */
+
+static long
+parse_gif_prim (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  char *str = *pstr;
+  char *start;
+  long prim;
+
+  if (strncasecmp (str, "prim=", 5) != 0)
+    {
+      *errmsg = _("missing PRIM spec");
+      return 0;
+    }
+  str += 5;
+  start = str;
+  prim = strtol (start, &amp;str, 0);
+  if (str == start)
+    {
+      *errmsg = _("missing PRIM spec");
+      return 0;
+    }
+  *pstr = str;
+  return prim;
+}
+
+static void
+insert_gif_prim (opcode, operand, mods, insn, value, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     long value;
+     const char **errmsg;
+{
+  int word = operand-&gt;shift / 32;
+  /* Chop off unwanted bits.  */
+  insn[word] |= (value &amp; ((1 &lt;&lt; operand-&gt;bits) - 1)) &lt;&lt; operand-&gt;shift % 32;
+  /* Set the PRE bit.  */
+  insn[word] |= GIF_PRE;
+}
+
+static long
+extract_gif_prim (opcode, operand, mods, insn, pinvalid)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     int *pinvalid;
+{
+  int word = operand-&gt;shift / 32;
+  if (! (insn[word] &amp; GIF_PRE))
+    {
+      /* The prim register isn't used.  Mark as invalid so this choice is
+	 skipped as a possibility for disassembly.  */
+      *pinvalid = 1;
+      return -1;
+    }
+  return (insn[word] &gt;&gt; operand-&gt;shift % 32) &amp; ((1 &lt;&lt; operand-&gt;bits) - 1);
+}
+
+static void
+print_gif_prim (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     disassemble_info *info;
+     long value;
+{
+  if (value != -1)
+    (*info-&gt;fprintf_func) (info-&gt;stream, "prim=0x%lx", value);
+}
+
+static const keyword gif_regs[] = {
+  { GIF_REG_PRIM,    "prim" },
+  { GIF_REG_RGBAQ,   "rgbaq" },
+  { GIF_REG_ST,      "st" },
+  { GIF_REG_UV,      "uv" },
+  { GIF_REG_XYZF2,   "xyzf2" },
+  { GIF_REG_XYZ2,    "xyz2" },
+  { GIF_REG_TEX0_1,  "tex0_1" },
+  { GIF_REG_TEX0_2,  "tex0_2" },
+  { GIF_REG_CLAMP_1, "clamp_1" },
+  { GIF_REG_CLAMP_2, "clamp_2" },
+  { GIF_REG_XYZF,    "xyzf" },
+  /* 11 is unused.  Should it ever appear we want to disassemble it somehow
+     so we give it a name anyway.  */
+  { GIF_REG_UNUSED11, "unused11" },
+  { GIF_REG_XYZF3,   "xyzf3" },
+  { GIF_REG_XYZ3,    "xyz3" },
+  { GIF_REG_A_D,     "a_d" },
+  { GIF_REG_NOP,     "nop" },
+  { 0, 0 }
+};
+
+/* Parse a REGS= spec.
+   The result is the number of registers parsed.
+   The selected registers are recorded internally in a static
+   variable for use later by the insert routine.  */
+
+static long
+parse_gif_regs (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  char *str = *pstr;
+  char *start;
+  char c;
+  int reg,nregs;
+
+  if (strncasecmp (str, "regs=", 5) != 0)
+    {
+      *errmsg = _("missing REGS spec");
+      return 0;
+    }
+  str += 5;
+  SKIP_BLANKS (str);
+  if (*str != '{')
+    {
+      *errmsg = _("missing '{' in REGS spec");
+      return 0;
+    }
+  ++str;
+
+  nregs = 0;
+  while (*str &amp;&amp; *str != '}')
+    {
+      if (nregs == 16)
+	{
+	  *errmsg = _("too many registers");
+	  return 0;
+	}
+
+      /* Pick out the register name.  */
+      SKIP_BLANKS (str);
+      start = str;
+      str = scan_symbol (str);
+      if (str == start)
+	{
+	  *errmsg = _("invalid REG");
+	  return 0;
+	}
+
+      /* Look it up in the table.  */
+      c = *str;
+      *str = 0;
+      reg = lookup_keyword_value (gif_regs, start, 0);
+      *str = c;
+      if (reg == -1)
+	{
+	  *errmsg = _("invalid REG");
+	  return 0;
+	}
+
+      /* Tuck the register number away for later use.  */
+      state_gif_regs[nregs++] = reg;
+
+      /* Prepare for the next one.  */
+      SKIP_BLANKS (str);
+      if (*str == ',')
+	++str;
+      else if (*str != '}')
+	break;
+    }
+  if (*str != '}')
+    {
+      *errmsg = _("missing '}' in REGS spec");
+      return 0;
+    }
+
+  *pstr = str + 1;
+  return nregs;
+}
+
+static void
+insert_gif_regs (opcode, operand, mods, insn, value, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     long value;
+     const char **errmsg;
+{
+  int i;
+  DVP_INSN *p;
+
+  state_gif_nregs = value;
+
+  /* Registers are stored in word 2,3 (0-origin) in memory.
+     Each word is processed from the lower bit numbers upwards,
+     and the words are stored little endian.  We must record each word
+     in host-endian form as the word will be swapped to target endianness
+     when written out.  */
+
+  p = insn + 2;
+  for (i = 0; i &lt; state_gif_nregs; ++i)
+    {
+      /* Move to next word?  */
+      if (i == 8)
+	++p;
+
+      *p |= state_gif_regs[i] &lt;&lt; (i * 4);
+    }
+
+  insn[1] |= VGIFNREGS (state_gif_nregs);
+}
+
+static long
+extract_gif_regs (opcode, operand, mods, insn, pinvalid)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     int *pinvalid;
+{
+  state_gif_nregs = (insn[1] &amp; MGIFNREGS) &gt;&gt; 28;
+  return state_gif_nregs;
+}
+
+static void
+print_gif_regs (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     disassemble_info *info;
+     long value;
+{
+  /* VALUE is the number of registers [returned by the extract handler].  */
+  int i;
+  DVP_INSN *p;
+
+  /* See insert_gif_regs for an explanation of how the regs are stored.  */
+
+  (*info-&gt;fprintf_func) (info-&gt;stream, "regs={");
+
+  p = insn + 2;
+  for (i = 0; i &lt; value; ++i)
+    {
+      int reg;
+
+      /* Move to next word?  */
+      if (i == 8)
+	++p;
+
+      reg = (*p &gt;&gt; (i * 4)) &amp; 15;
+
+      (*info-&gt;fprintf_func) (info-&gt;stream, "%s",
+			     lookup_keyword_name (gif_regs, reg));
+      if (i + 1 != value)
+	(*info-&gt;fprintf_func) (info-&gt;stream, ",");
+    }
+
+  (*info-&gt;fprintf_func) (info-&gt;stream, "}");
+}
+
+static long
+parse_gif_nloop (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  char *str = *pstr;
+  char *start;
+  int nloop;
+
+  if (strncasecmp (str, "nloop=", 6) != 0)
+    {
+      *errmsg = _("missing NLOOP spec");
+      return 0;
+    }
+  str += 6;
+  SKIP_BLANKS (str);
+  start = str;
+  nloop = strtol (start, &amp;str, 10);
+  if (str == start)
+    {
+      *errmsg = _("invalid NLOOP spec");
+      return 0;
+    }
+  *pstr = str;
+  return nloop;
+}
+
+static void
+insert_gif_nloop (opcode, operand, mods, insn, value, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     long value;
+     const char **errmsg;
+{
+  int word = operand-&gt;shift / 32;
+  insn[word] |= (value &amp; ((1 &lt;&lt; operand-&gt;bits) - 1)) &lt;&lt; operand-&gt;shift % 32;
+  /* Tuck the value away for later use.  */
+  state_gif_nloop = value;
+}
+
+static long
+extract_gif_nloop (opcode, operand, mods, insn, pinvalid)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     int *pinvalid;
+{
+  long value;
+  int word = operand-&gt;shift / 32;
+  value = (insn[word] &gt;&gt; operand-&gt;shift % 32) &amp; ((1 &lt;&lt; operand-&gt;bits) - 1);
+  /* Tuck the value away for later use.  */
+  state_gif_nloop = value;
+  return value;
+}
+
+static void
+print_gif_nloop (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     disassemble_info *info;
+     long value;
+{
+  (*info-&gt;fprintf_func) (info-&gt;stream, "nloop=%ld", value);
+}
+
+static long
+parse_gif_eop (opcode, operand, mods, pstr, errmsg)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     char **pstr;
+     const char **errmsg;
+{
+  if (strncasecmp (*pstr, "eop", 3) == 0)
+    {
+      *pstr += 3;
+      return 1;
+    }
+  *errmsg = _("missing `EOP'");
+  return 0;
+}
+
+static long
+extract_gif_eop (opcode, operand, mods, insn, pinvalid)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     int *pinvalid;
+{
+  long value;
+  int word = operand-&gt;shift / 32;
+  value = (insn[word] &gt;&gt; operand-&gt;shift % 32) &amp; ((1 &lt;&lt; operand-&gt;bits) - 1);
+  /* If EOP=0, mark this choice as invalid so it's not used for
+     disassembly.  */
+  if (! value)
+    *pinvalid = 1;
+  return value;
+}
+
+static void
+print_gif_eop (opcode, operand, mods, insn, info, value)
+     const dvp_opcode *opcode;
+     const dvp_operand *operand;
+     int mods;
+     DVP_INSN *insn;
+     disassemble_info *info;
+     long value;
+{
+  if (value)
+    (*info-&gt;fprintf_func) (info-&gt;stream, "eop");
+}
+
+/* External GIF support routines.  */
+
+int
+gif_nloop ()
+{
+  return state_gif_nloop;
+}
+
+int
+gif_nregs ()
+{
+  return state_gif_nregs;
+}
+
+/* Init fns.
+   These are called before doing each of the respective activities.  */
+
+/* Called by the assembler before parsing an instruction.  */
+
+void
+dvp_opcode_init_parse ()
+{
+  state_vu_mnemonic_dest = -1;
+  state_vu_mnemonic_bc = -1;
+  state_vif_mpgloc = -1;
+  state_vif_mpgloc_star_p = 0;
+  state_vif_len = -1;
+  state_vif_data_file = NULL;
+  state_vif_data_len = 0;
+  state_gif_nregs = -1;
+  state_gif_nloop = -1;
+}
+
+/* Called by the disassembler before printing an instruction.  */
+
+void
+dvp_opcode_init_print ()
+{
+  state_vu_mnemonic_dest = -1;
+  state_vu_mnemonic_bc = -1;
+  state_vif_len = -1;
+  state_gif_nregs = -1;
+  state_gif_nloop = -1;
+}
+
+/* Indexed by first letter of opcode.  Points to chain of opcodes with same
+   first letter.  */
+/* ??? One can certainly use a better hash.  Later.  */
+static dvp_opcode *upper_opcode_map[26 + 1];
+static dvp_opcode *lower_opcode_map[26 + 1];
+
+/* Indexed by insn code.  Points to chain of opcodes with same insn code.  */
+static dvp_opcode *upper_icode_map[(1 &lt;&lt; DVP_ICODE_HASH_SIZE) - 1];
+static dvp_opcode *lower_icode_map[(1 &lt;&lt; DVP_ICODE_HASH_SIZE) - 1];
+
+/* Initialize any tables that need it.
+   Must be called once at start up (or when first needed).
+
+   FLAGS is currently unused but is intended to control initialization.  */
+
+void
+dvp_opcode_init_tables (flags)
+     int flags;
+{
+  static int init_p = 0;
+
+  /* We may be intentionally called more than once (for example gdb will call
+     us each time the user switches cpu).  These tables only need to be init'd
+     once though.  */
+  /* ??? We can remove the need for dvp_opcode_supported by taking it into
+     account here, but I'm not sure I want to do that yet (if ever).  */
+  if (!init_p)
+    {
+      int i;
+
+      /* Upper VU table.  */
+
+      memset (upper_opcode_map, 0, sizeof (upper_opcode_map));
+      memset (upper_icode_map, 0, sizeof (upper_icode_map));
+      /* Scan the table backwards so macros appear at the front.  */
+      for (i = vu_upper_opcodes_count - 1; i &gt;= 0; --i)
+	{
+	  int opcode_hash = DVP_HASH_UPPER_OPCODE (vu_upper_opcodes[i].mnemonic);
+	  int icode_hash = DVP_HASH_UPPER_ICODE (vu_upper_opcodes[i].value);
+
+	  vu_upper_opcodes[i].next_asm = upper_opcode_map[opcode_hash];
+	  upper_opcode_map[opcode_hash] = &amp;vu_upper_opcodes[i];
+
+	  vu_upper_opcodes[i].next_dis = upper_icode_map[icode_hash];
+	  upper_icode_map[icode_hash] = &amp;vu_upper_opcodes[i];
+	}
+
+      /* Lower VU table.  */
+
+      memset (lower_opcode_map, 0, sizeof (lower_opcode_map));
+      memset (lower_icode_map, 0, sizeof (lower_icode_map));
+      /* Scan the table backwards so macros appear at the front.  */
+      for (i = vu_lower_opcodes_count - 1; i &gt;= 0; --i)
+	{
+	  int opcode_hash = DVP_HASH_LOWER_OPCODE (vu_lower_opcodes[i].mnemonic);
+	  int icode_hash = DVP_HASH_LOWER_ICODE (vu_lower_opcodes[i].value);
+
+	  vu_lower_opcodes[i].next_asm = lower_opcode_map[opcode_hash];
+	  lower_opcode_map[opcode_hash] = &amp;vu_lower_opcodes[i];
+
+	  vu_lower_opcodes[i].next_dis = lower_icode_map[icode_hash];
+	  lower_icode_map[icode_hash] = &amp;vu_lower_opcodes[i];
+	}
+
+      /* FIXME: We just hash everything to the same value for the rest.
+	 Quick hack while other things are worked on.  */
+
+      /* VIF table.  */
+
+      for (i = vif_opcodes_count - 2; i &gt;= 0; --i)
+	{
+	  vif_opcodes[i].next_asm = &amp; vif_opcodes[i+1];
+	  vif_opcodes[i].next_dis = &amp; vif_opcodes[i+1];
+	}
+
+      /* DMA table.  */
+
+      for (i = dma_opcodes_count - 2; i &gt;= 0; --i)
+	{
+	  dma_opcodes[i].next_asm = &amp; dma_opcodes[i+1];
+	  dma_opcodes[i].next_dis = &amp; dma_opcodes[i+1];
+	}
+
+      /* GIF table.  */
+
+      for (i = gif_opcodes_count - 2; i &gt;= 0; --i)
+	{
+	  gif_opcodes[i].next_asm = &amp; gif_opcodes[i+1];
+	  gif_opcodes[i].next_dis = &amp; gif_opcodes[i+1];
+	}
+
+      init_p = 1;
+    }
+}
+
+/* Return the first insn in the chain for assembling upper INSN.  */
+
+const dvp_opcode *
+vu_upper_opcode_lookup_asm (insn)
+     const char *insn;
+{
+  return upper_opcode_map[DVP_HASH_UPPER_OPCODE (insn)];
+}
+
+/* Return the first insn in the chain for disassembling upper INSN.  */
+
+const dvp_opcode *
+vu_upper_opcode_lookup_dis (insn)
+     DVP_INSN insn;
+{
+  return upper_icode_map[DVP_HASH_UPPER_ICODE (insn)];
+}
+
+/* Return the first insn in the chain for assembling lower INSN.  */
+
+const dvp_opcode *
+vu_lower_opcode_lookup_asm (insn)
+     const char *insn;
+{
+  return lower_opcode_map[DVP_HASH_LOWER_OPCODE (insn)];
+}
+
+/* Return the first insn in the chain for disassembling lower INSN.  */
+
+const dvp_opcode *
+vu_lower_opcode_lookup_dis (insn)
+     DVP_INSN insn;
+{
+  return lower_icode_map[DVP_HASH_LOWER_ICODE (insn)];
+}
+
+/* Return the first insn in the chain for assembling lower INSN.  */
+
+const dvp_opcode *
+vif_opcode_lookup_asm (insn)
+     const char *insn;
+{
+  return &amp;vif_opcodes[0];
+}
+
+/* Return the first insn in the chain for disassembling lower INSN.  */
+
+const dvp_opcode *
+vif_opcode_lookup_dis (insn)
+     DVP_INSN insn;
+{
+  return &amp;vif_opcodes[0];
+}
+
+/* Return the first insn in the chain for assembling lower INSN.  */
+
+const dvp_opcode *
+dma_opcode_lookup_asm (insn)
+     const char *insn;
+{
+  return &amp;dma_opcodes[0];
+}
+
+/* Return the first insn in the chain for disassembling lower INSN.  */
+
+const dvp_opcode *
+dma_opcode_lookup_dis (insn)
+     DVP_INSN insn;
+{
+  return &amp;dma_opcodes[0];
+}
+
+/* Return the first insn in the chain for assembling lower INSN.  */
+
+const dvp_opcode *
+gif_opcode_lookup_asm (insn)
+     const char *insn;
+{
+  return &amp;gif_opcodes[0];
+}
+
+/* Return the first insn in the chain for disassembling lower INSN.  */
+
+const dvp_opcode *
+gif_opcode_lookup_dis (insn)
+     DVP_INSN insn;
+{
+  return &amp;gif_opcodes[0];
+}
+
+/* Misc. utilities.  */
+
+/* Scan a symbol and return a pointer to one past the end.  */
+
+static char *
+scan_symbol (sym)
+     char *sym;
+{
+  while (*sym &amp;&amp; issymchar (*sym))
+    ++sym;
+  return sym;
+}
+
+/* Given a keyword, look up its value, or -1 if not found.  */
+
+static int
+lookup_keyword_value (table, name, case_sensitive_p)
+     const keyword *table;
+     const char *name;
+     int case_sensitive_p;
+{
+  const keyword *p;
+
+  if (case_sensitive_p)
+    {
+      for (p = table; p-&gt;name; ++p)
+	if (strcmp (name, p-&gt;name) == 0)
+	  return p-&gt;value;
+    }
+  else
+    {
+      for (p = table; p-&gt;name; ++p)
+	if (strcasecmp (name, p-&gt;name) == 0)
+	  return p-&gt;value;
+    }
+
+  return -1;
+}
+
+/* Given a keyword's value, look up its name, or NULL if not found.  */
+
+static const char *
+lookup_keyword_name (table, value)
+     const keyword *table;
+     int value;
+{
+  const keyword *p;
+
+  for (p = table; p-&gt;name; ++p)
+    if (value == p-&gt;value)
+      return p-&gt;name;
+
+  return NULL;
+}
+
+/* Macro insn support.  */
+
+/* Given a string, see if it's a macro insn and return the expanded form.
+   If not a macro insn, return NULL.
+   The expansion is done in malloc'd space.
+   It is up to the caller to free it.  */
+
+char *
+dvp_expand_macro (mactable, tabsize, insn)
+     const dvp_macro * mactable;
+     int tabsize;
+     char *insn;
+{
+  const dvp_macro * m, *mend;
+  char * operands[10];
+  int oplens[10];
+  int noperands = 0;
+
+  for (m = mactable, mend = mactable + tabsize; m &lt; mend; ++m)
+    {
+      const char * p = m-&gt;template;
+      char * ip = insn;
+
+      for (;;)
+	{
+	  while (*p &amp;&amp; *p == *ip)
+	    ++p, ++ip;
+
+	  /* Did we find a complete match?  */
+	  if (*p == 0 &amp;&amp; *ip == 0)
+	    {
+	      int total_len = strlen (m-&gt;result);
+	      int i;
+	      char * result;
+
+	      for (i = 0; i &lt; noperands; ++i)
+		total_len += strlen (operands[i]);
+	      total_len += 1 + 10  /* slop */;
+	      result = xmalloc (total_len);
+	      for (ip = result, p = m-&gt;result; *p; )
+		{
+		  if (*p == '%')
+		    {
+		      /* Ok, we shouldn't assume max 10 operands.  */
+		      int opnum = *++p - '0';
+		      memcpy (ip, operands[opnum], oplens[opnum]);
+		      ++p;
+		      ip += oplens[opnum];
+		    }
+		  else
+		    {
+		      *ip++ = *p++;
+		    }
+		}
+	      if (ip - result &gt;= total_len)
+		abort ();
+	      *ip = 0;
+	      return result;
+	    }
+
+	  /* Is this an operand?  */
+	  if (*p == '$' &amp;&amp; p[1] == '{')
+	    {
+	      if (strncmp (p + 2, "imrubits}", 9) == 0)
+		{
+		  if (*ip == '[')
+		    {
+		      char *q = ip;
+		      while (*q &amp;&amp; *q != ']')
+			++q;
+		      if (! *q)
+			return NULL;
+		      ++q;
+		      operands[noperands] = ip;
+		      oplens[noperands++] = q - ip;
+		      ip = q;
+		    }
+		  else
+		    {
+		      operands[noperands] = "";
+		      oplens[noperands++] = 0;
+		    }
+		}
+	      else if (strncmp (p + 2, "wl}", 3) == 0
+		       || strncmp (p + 2, "cl}", 3) == 0
+		       || strncmp (p + 2, "unpacktype}", 11) == 0
+		       || strncmp (p + 2, "unpackloc}", 10) == 0
+		       || strncmp (p + 2, "datalen}", 8) == 0)
+		{
+		  char *q = ip;
+		  while (*q &amp;&amp; *q != ',')
+		    ++q;
+		  operands[noperands] = ip;
+		  oplens[noperands++] = q - ip;
+		  ip = q;
+		}
+	      else
+		abort ();
+
+	      /* Skip to end of operand in template.  */
+	      p = strchr (p, '}');
+	      if (! p)
+		abort ();
+	      ++p;
+	    }
+	  else
+	    break;
+	}
+    }
+
+  return NULL;
+}
diff -burN orig.binutils-2.14/opcodes/mips-dis.c binutils-2.14/opcodes/mips-dis.c
--- orig.binutils-2.14/opcodes/mips-dis.c	2003-04-08 04:14:47.000000000 -0300
+++ binutils-2.14/opcodes/mips-dis.c	2007-04-29 04:00:33.000000000 -0300
@@ -345,6 +345,8 @@
     mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "vr5500",	1, bfd_mach_mips5500, CPU_VR5500, ISA_MIPS4,
     mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
+  { "r5900",    1, bfd_mach_mips5900, CPU_R5900,  ISA_MIPS3,
+    mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "r6000",	1, bfd_mach_mips6000, CPU_R6000, ISA_MIPS2,
     mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
   { "r8000",	1, bfd_mach_mips8000, CPU_R8000, ISA_MIPS4,
@@ -685,10 +687,12 @@
 	case ')':
 	case '[':
 	case ']':
+	case '+':
+	case '-':
 	  (*info-&gt;fprintf_func) (info-&gt;stream, "%c", *d);
 	  break;
 
-	case '+':
+	case '*':
 	  /* Extension character; switch for second char.  */
 	  d++;
 	  switch (*d)
@@ -870,6 +874,140 @@
 				 mips_fpr_names[(l &gt;&gt; OP_SH_FS) &amp; OP_MASK_FS]);
 	  break;
 
+	case '0':
+          (*info-&gt;fprintf_func) (info-&gt;stream, "%d",
+                                 /* get bits 6-10 and sign extend */
+                                 (((l &gt;&gt; 6) &amp; 0x1f) ^ 0x10) - 0x10);
+        break;
+
+	case '#':
+	  /* suffix character, suffix is the next character in the argument string */
+	  d++;
+
+	  if(*d == '\0')
+	    {
+	      /* xgettext:c-format */
+	      (*info-&gt;fprintf_func) (info-&gt;stream,
+				     _("# internal error, incomplete argument suffix (+)"));
+	      return;
+	    }
+	  
+	  /* print suffix from argument string */
+	  (*info-&gt;fprintf_func) (info-&gt;stream, "%c", *d);
+	  break;
+
+	case '9':
+	  (*info-&gt;fprintf_func) (info-&gt;stream, "vi27");
+          break;
+
+	case '1':
+	  (*info-&gt;fprintf_func) (info-&gt;stream, "vf%02d",
+                                 (l &gt;&gt; OP_SH_FT) &amp; OP_MASK_FT);
+	  break;
+	case '2':
+	  (*info-&gt;fprintf_func) (info-&gt;stream, "vf%02d",
+                                 (l &gt;&gt; OP_SH_FS) &amp; OP_MASK_FS);
+	  break;
+	case '3':
+	  (*info-&gt;fprintf_func) (info-&gt;stream, "vf%02d",
+                                 (l &gt;&gt; OP_SH_FD) &amp; OP_MASK_FD);
+	  break;
+      
+        case '4':
+          (*info-&gt;fprintf_func) (info-&gt;stream, "vi%02d",
+                                 (l &gt;&gt; OP_SH_FT) &amp; OP_MASK_FT);
+          break;
+        case '5':
+          (*info-&gt;fprintf_func) (info-&gt;stream, "vi%02d",
+                                 (l &gt;&gt; OP_SH_FS) &amp; OP_MASK_FS);
+          break;
+        case '6':
+          (*info-&gt;fprintf_func) (info-&gt;stream, "vi%02d",
+                                 (l &gt;&gt; OP_SH_FD) &amp; OP_MASK_FD);
+          break;
+        case '7':
+          (*info-&gt;fprintf_func) (info-&gt;stream, "vf%02d",
+                                 (l &gt;&gt; OP_SH_FT) &amp; OP_MASK_FT);
+          switch ((l &gt;&gt; 23) &amp; 0x3)
+            {
+              case 0:
+                (*info-&gt;fprintf_func) (info-&gt;stream, "x");
+                break;
+              case 1:
+                (*info-&gt;fprintf_func) (info-&gt;stream, "y");
+                break;
+              case 2:
+                (*info-&gt;fprintf_func) (info-&gt;stream, "z");
+                break;
+              case 3:
+                (*info-&gt;fprintf_func) (info-&gt;stream, "w");
+                break;
+            }
+          break;
+        case '=':
+          break;
+        case ';':
+          (*info-&gt;fprintf_func) (info-&gt;stream, ".xyz\t");
+          break;
+    
+        case '&amp;':
+	  /* don't print extension if it's .xyzw */
+	  if ( ((l &gt;&gt; 21) &amp; 0xf) != 0xf)
+	    {
+	      (*info-&gt;fprintf_func) (info-&gt;stream, ".");
+	      if (l &amp; (1 &lt;&lt; 24))
+		(*info-&gt;fprintf_func) (info-&gt;stream, "x");
+	      if (l &amp; (1 &lt;&lt; 23))
+		(*info-&gt;fprintf_func) (info-&gt;stream, "y");
+	      if (l &amp; (1 &lt;&lt; 22))
+		(*info-&gt;fprintf_func) (info-&gt;stream, "z");
+	      if (l &amp; (1 &lt;&lt; 21))
+		(*info-&gt;fprintf_func) (info-&gt;stream, "w");
+	    }
+	  (*info-&gt;fprintf_func) (info-&gt;stream, "\t");
+          break;
+    
+        case '8':
+          (*info-&gt;fprintf_func) (info-&gt;stream, "vf%02d",
+                                 (l &gt;&gt; OP_SH_FS) &amp; OP_MASK_FS);
+          switch ((l &gt;&gt; 21) &amp; 0x3)
+            {
+              case 0:
+                (*info-&gt;fprintf_func) (info-&gt;stream, "x");
+                break;
+              case 1:
+                (*info-&gt;fprintf_func) (info-&gt;stream, "y");
+                break;
+              case 2:
+                (*info-&gt;fprintf_func) (info-&gt;stream, "z");
+                break;
+              case 3:
+                (*info-&gt;fprintf_func) (info-&gt;stream, "w");
+                break;
+            }
+          break;
+        case '!':
+          (*info-&gt;fprintf_func) (info-&gt;stream, "I");
+          break;
+    
+        case '^':
+          (*info-&gt;fprintf_func) (info-&gt;stream, "^");
+          break;
+    
+        case '_':
+          (*info-&gt;fprintf_func) (info-&gt;stream, "R");
+          break;
+    
+        case '@':
+          (*info-&gt;fprintf_func) (info-&gt;stream, "ACC");
+          break;
+    
+        case 'g':
+          delta = (l &gt;&gt; 6) &amp; 0x7fff;
+          delta &lt;&lt;= 3;
+          (*info-&gt;print_address_func) (delta, info);
+          break;
+    
 	case 'T':
 	case 'W':
 	  (*info-&gt;fprintf_func) (info-&gt;stream, "%s",
@@ -1107,8 +1245,12 @@
 
 	      d = op-&gt;args;
 	      if (d != NULL &amp;&amp; *d != '\0')
-		{
+               { /* If this is an opcode completer, then do not emit
+		      a tab after the opcode. */
+		  if (*d != '&amp;' &amp;&amp; *d != ';')
 		  (*info-&gt;fprintf_func) (info-&gt;stream, "\t");
+
+                 /* Parse and print arguments. */
 		  print_insn_args (d, word, memaddr, info);
 		}
 
@@ -1138,6 +1280,19 @@
   bfd_byte buffer[INSNLEN];
   int status;
 
+#ifdef ARCH_dvp  
+  {
+    /* bfd_mach_dvp_p is a macro which may evaluate its arguments more than  
+       once.  Since dvp_mach_type is a function, ensure it's only called  
+       once.  */
+    int mach = dvp_info_mach_type (info);
+
+    if (bfd_mach_dvp_p (info-&gt;mach)
+        || bfd_mach_dvp_p (mach))
+      return print_insn_dvp (memaddr, info);
+  }
+#endif  
+
   set_default_mips_dis_options (info);
   parse_mips_dis_options (info-&gt;disassembler_options);
 
diff -burN orig.binutils-2.14/opcodes/mips-opc.c binutils-2.14/opcodes/mips-opc.c
--- orig.binutils-2.14/opcodes/mips-opc.c	2002-12-31 21:06:13.000000000 -0400
+++ binutils-2.14/opcodes/mips-opc.c	2007-04-29 04:00:33.000000000 -0300
@@ -101,6 +101,7 @@
 #define L1	INSN_4010
 #define V1	(INSN_4100 | INSN_4111 | INSN_4120)
 #define T3      INSN_3900
+#define T5	INSN_5900
 #define M1	INSN_10000
 #define SB1     INSN_SB1
 #define N411	INSN_4111
@@ -110,12 +111,14 @@
 #define N55	INSN_5500
 
 #define G1      (T3             \
+		|T5		\
                  )
 
 #define G2      (T3             \
                  )
 
 #define G3      (I4             \
+		|T5		\
                  )
 
 /* The order of overloaded instructions matters.  Label arguments and
@@ -169,6 +172,7 @@
 {"add.qh",  "X,Y,Q",	0x7820000b, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
 {"adda.ob", "Y,Q",	0x78000037, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX|SB1	},
 {"adda.qh", "Y,Q",	0x78200037, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX	},
+{"adda.s",  "S,T",      0x46000018, 0xffe007ff, RD_S|RD_T|FP_S,         T5      },
 {"addi",    "t,r,j",	0x20000000, 0xfc000000,	WR_t|RD_s,		I1	},
 {"addiu",   "t,r,j",	0x24000000, 0xfc000000,	WR_t|RD_s,		I1	},
 {"addl.ob", "Y,Q",	0x78000437, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX|SB1	},
@@ -273,7 +277,7 @@
 {"bnel",    "s,t,p",	0x54000000, 0xfc000000,	CBL|RD_s|RD_t, 		I2|T3	},
 {"bnel",    "s,I,p",	0,    (int) M_BNEL_I,	INSN_MACRO,		I2|T3	},
 {"break",   "",		0x0000000d, 0xffffffff,	TRAP,			I1	},
-{"break",   "B",        0x0000000d, 0xfc00003f, TRAP,           	I32     },
+{"break",   "B",        0x0000000d, 0xfc00003f, TRAP,           	I32|T5  },
 {"break",   "c",	0x0000000d, 0xfc00ffff,	TRAP,			I1	},
 {"break",   "c,q",	0x0000000d, 0xfc00003f,	TRAP,			I1	},
 {"c.f.d",   "S,T",	0x46200030, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I1	},
@@ -355,7 +359,13 @@
 {"c.ngl.ps","M,S,T",	0x46c0003b, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
 {"c.lt.d",  "S,T",	0x4620003c, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I1	},
 {"c.lt.d",  "M,S,T",    0x4620003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   I4|I32	},
-{"c.lt.s",  "S,T",	0x4600003c, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_S,	I1	},
+  /* The r5900 has a different bit pattern for the c.lt.s instruction. 
+     In order for the disassembler to be able to locate the correct pattern 
+     its bit mask (0x46000034) must appear before other patterns with the 
+     same bit mask.  In order for the assembler to work, all patterns with 
+     the same name must appear consecutively.  Hence the c.lt.s patterns 
+     appear here, out of their natural order.  */
+{"c.lt.s",  "S,T",      0x46000034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   T5      },
 {"c.lt.s",  "M,S,T",    0x4600003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   I4|I32	},
 {"c.lt.ob", "Y,Q",	0x78000004, 0xfc2007ff,	WR_CC|RD_S|RD_T|FP_D,	MX|SB1	},
 {"c.lt.ob", "S,T",	0x4ac00004, 0xffe007ff,	WR_CC|RD_S|RD_T,	N54	},
@@ -372,7 +382,8 @@
 {"c.nge.ps","M,S,T",	0x46c0003d, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
 {"c.le.d",  "S,T",	0x4620003e, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I1	},
 {"c.le.d",  "M,S,T",    0x4620003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   I4|I32	},
-{"c.le.s",  "S,T",	0x4600003e, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_S,	I1	},
+  /* Same comment as for the c.lt.s instruction.  */
+{"c.le.s",  "S,T",      0x46000036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   T5      },
 {"c.le.s",  "M,S,T",    0x4600003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   I4|I32	},
 {"c.le.ob", "Y,Q",	0x78000005, 0xfc2007ff,	WR_CC|RD_S|RD_T|FP_D,	MX|SB1	},
 {"c.le.ob", "S,T",	0x4ac00005, 0xffe007ff,	WR_CC|RD_S|RD_T,	N54	},
@@ -443,14 +454,24 @@
 {"cfc0",    "t,G",	0x40400000, 0xffe007ff,	LCD|WR_t|RD_C0,		I1	},
 {"cfc1",    "t,G",	0x44400000, 0xffe007ff,	LCD|WR_t|RD_C1|FP_S,	I1	},
 {"cfc1",    "t,S",	0x44400000, 0xffe007ff,	LCD|WR_t|RD_C1|FP_S,	I1	},
+{"cfc2",    "t,5",      0x48400000, 0xffe007ff, LCD|WR_t|RD_C2,         T5      },
 {"cfc2",    "t,G",	0x48400000, 0xffe007ff,	LCD|WR_t|RD_C2,		I1	},
+{"cfc2.i",  "t,5",      0x48400001, 0xffe007ff, LCD|WR_t|RD_C2,         T5      },
+{"cfc2.i",  "t,G",	0x48400001, 0xffe007ff, LCD|WR_t|RD_C2,         T5      },
+{"cfc2.ni", "t,5",      0x48400000, 0xffe007ff, LCD|WR_t|RD_C2,         T5      },
+{"cfc2.ni", "t,G",	0x48400000, 0xffe007ff, LCD|WR_t|RD_C2,         T5      },
 {"cfc3",    "t,G",	0x4c400000, 0xffe007ff,	LCD|WR_t|RD_C3,		I1	},
 {"clo",     "U,s",      0x70000021, 0xfc0007ff, WR_d|WR_t|RD_s, 	I32|N55 },
 {"clz",     "U,s",      0x70000020, 0xfc0007ff, WR_d|WR_t|RD_s, 	I32|N55 },
 {"ctc0",    "t,G",	0x40c00000, 0xffe007ff,	COD|RD_t|WR_CC,		I1	},
 {"ctc1",    "t,G",	0x44c00000, 0xffe007ff,	COD|RD_t|WR_CC|FP_S,	I1	},
 {"ctc1",    "t,S",	0x44c00000, 0xffe007ff,	COD|RD_t|WR_CC|FP_S,	I1	},
+{"ctc2",    "t,5",	0x48c00000, 0xffe007ff,	COD|RD_t|WR_CC,		T5	},
 {"ctc2",    "t,G",	0x48c00000, 0xffe007ff,	COD|RD_t|WR_CC,		I1	},
+{"ctc2.i",  "t,5",	0x48c00001, 0xffe007ff, COD|RD_t|WR_CC,         T5      },
+{"ctc2.i",  "t,G",	0x48c00001, 0xffe007ff, COD|RD_t|WR_CC,         T5      },
+{"ctc2.ni", "t,5",	0x48c00000, 0xffe007ff, COD|RD_t|WR_CC,         T5      },
+{"ctc2.ni", "t,G",	0x48c00000, 0xffe007ff, COD|RD_t|WR_CC,         T5      },
 {"ctc3",    "t,G",	0x4cc00000, 0xffe007ff,	COD|RD_t|WR_CC,		I1	},
 {"cvt.d.l", "D,S",	0x46a00021, 0xffff003f,	WR_D|RD_S|FP_D,		I3	},
 {"cvt.d.s", "D,S",	0x46000021, 0xffff003f,	WR_D|RD_S|FP_D|FP_S,	I1	},
@@ -489,6 +510,7 @@
 {"ddivu",   "z,s,t",    0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO,      I3      },
 {"ddivu",   "d,v,t",	0,    (int) M_DDIVU_3,	INSN_MACRO,		I3	},
 {"ddivu",   "d,v,I",	0,    (int) M_DDIVU_3I,	INSN_MACRO,		I3	},
+{"di",      "",         0x42000039, 0xffffffff, WR_C0,                  T5      },
 {"di",      "",		0x41606000, 0xffffffff,	WR_t|WR_C0,		I33	},
 {"di",      "t",	0x41606000, 0xffe0ffff,	WR_t|WR_C0,		I33	},
 /* The MIPS assembler treats the div opcode with two operands as
@@ -499,6 +521,8 @@
 {"div",     "z,t",      0x0000001a, 0xffe0ffff, RD_s|RD_t|WR_HILO,      I1      },
 {"div",     "d,v,t",	0,    (int) M_DIV_3,	INSN_MACRO,		I1	},
 {"div",     "d,v,I",	0,    (int) M_DIV_3I,	INSN_MACRO,		I1	},
+{"div1",    "z,s,t",    0x7000001a, 0xfc00ffff, RD_s|RD_t|WR_HI|WR_LO,  T5      },
+{"div1",    "s,t",      0x7000001a, 0xffe0ffff, RD_s|RD_t|WR_HI|WR_LO,  T5      },
 {"div.d",   "D,V,T",	0x46200003, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	I1	},
 {"div.s",   "D,V,T",	0x46000003, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	I1	},
 {"div.ps",  "D,V,T",	0x46c00003, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	SB1	},
@@ -507,6 +531,8 @@
 {"divu",    "z,t",      0x0000001b, 0xffe0ffff, RD_s|RD_t|WR_HILO,      I1      },
 {"divu",    "d,v,t",	0,    (int) M_DIVU_3,	INSN_MACRO,		I1	},
 {"divu",    "d,v,I",	0,    (int) M_DIVU_3I,	INSN_MACRO,		I1	},
+{"divu1",   "z,s,t",    0x7000001b, 0xfc00ffff, RD_s|RD_t|WR_HI|WR_LO,  T5      },
+{"divu1",   "s,t",      0x7000001b, 0xffe0ffff, RD_s|RD_t|WR_HI|WR_LO,  T5      },
 {"dla",     "t,A(b)",	0,    (int) M_DLA_AB,	INSN_MACRO,		I3	},
 {"dli",     "t,j",      0x24000000, 0xffe00000, WR_t,			I3	}, /* addiu */
 {"dli",	    "t,i",	0x34000000, 0xffe00000, WR_t,			I3	}, /* ori */
@@ -521,15 +547,22 @@
 {"dmaccus", "d,s,t",	0x00000469, 0xfc0007ff,	RD_s|RD_t|WR_LO|WR_d,	N412	},
 {"dmadd16", "s,t",      0x00000029, 0xfc00ffff, RD_s|RD_t|MOD_LO,       N411    },
 {"dmfc0",   "t,G",	0x40200000, 0xffe007ff, LCD|WR_t|RD_C0,		I3	},
-{"dmfc0",   "t,+D",     0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, 	I64     },
+{"dmfc0",   "t,*D",     0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, 	I64     },
 {"dmfc0",   "t,G,H",    0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, 	I64     },
 {"dmtc0",   "t,G",	0x40a00000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC,	I3	},
-{"dmtc0",   "t,+D",     0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC,   I64     },
+{"dmtc0",   "t,*D",     0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC,   I64     },
 {"dmtc0",   "t,G,H",    0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC,   I64     },
 {"dmfc1",   "t,S",	0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_S,	I3	},
 {"dmfc1",   "t,G",      0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_S,     I3      },
 {"dmtc1",   "t,S",	0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_S,	I3	},
 {"dmtc1",   "t,G",      0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_S,     I3      },
+/* qmfc2/qmtc2 appear out of order here so that they match before dmfc2/dmtc2 on R5900. */
+{"qmfc2",   "t,2",      0x48200000, 0xffe007ff, 0,                      T5      },
+{"qmfc2.ni", "t,2",     0x48200000, 0xffe007ff, 0,                      T5      },
+{"qmfc2.i", "t,2",      0x48200001, 0xffe007ff, 0,                      T5      },
+{"qmtc2",   "t,2",      0x48a00000, 0xffe007ff, 0,                      T5      },
+{"qmtc2.ni", "t,2",     0x48a00000, 0xffe007ff, 0,                      T5      },
+{"qmtc2.i", "t,2",      0x48a00001, 0xffe007ff, 0,                      T5      },
 {"dmfc2",   "t,G",      0x48200000, 0xffe007ff, LCD|WR_t|RD_C2, 	I3      },
 {"dmfc2",   "t,G,H",    0x48200000, 0xffe007f8, LCD|WR_t|RD_C2, 	I64     },
 {"dmtc2",   "t,G",      0x48a00000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC,   I3      },
@@ -581,10 +614,11 @@
 {"dsub",    "d,v,I",	0,    (int) M_DSUB_I,	INSN_MACRO,		I3	},
 {"dsubu",   "d,v,t",	0x0000002f, 0xfc0007ff,	WR_d|RD_s|RD_t,		I3	},
 {"dsubu",   "d,v,I",	0,    (int) M_DSUBU_I,	INSN_MACRO,		I3	},
+{"ei",      "",         0x42000038, 0xffffffff, WR_C0,                  T5      },
 {"ei",      "",		0x41606020, 0xffffffff,	WR_t|WR_C0,		I33	},
 {"ei",      "t",	0x41606020, 0xffe0ffff,	WR_t|WR_C0,		I33	},
-{"eret",    "",         0x42000018, 0xffffffff, 0,      		I3|I32	},
-{"ext",     "t,r,+A,+C", 0x7c000000, 0xfc00003f, WR_t|RD_s,    		I33	},
+{"eret",    "",         0x42000018, 0xffffffff, 0,      		I3|I32|T5},
+{"ext",     "t,r,*A,*C", 0x7c000000, 0xfc00003f, WR_t|RD_s,    		I33	},
 {"floor.l.d", "D,S",	0x4620000b, 0xffff003f, WR_D|RD_S|FP_D,		I3	},
 {"floor.l.s", "D,S",	0x4600000b, 0xffff003f, WR_D|RD_S|FP_S,		I3	},
 {"floor.w.d", "D,S",	0x4620000f, 0xffff003f, WR_D|RD_S|FP_D,		I2	},
@@ -593,7 +627,7 @@
 {"flushd",  "",		0xbc020000, 0xffffffff, 0, 			L1	},
 {"flushid", "",		0xbc030000, 0xffffffff, 0, 			L1	},
 {"hibernate","",        0x42000023, 0xffffffff,	0, 			V1	},
-{"ins",     "t,r,+A,+B", 0x7c000004, 0xfc00003f, WR_t|RD_s,    		I33	},
+{"ins",     "t,r,*A,*B", 0x7c000004, 0xfc00003f, WR_t|RD_s,    		I33	},
 {"jr",      "s",	0x00000008, 0xfc1fffff,	UBD|RD_s,		I1	},
 {"jr.hb",   "s",	0x00000408, 0xfc1fffff,	UBD|RD_s,		I33	},
 {"j",       "s",	0x00000008, 0xfc1fffff,	UBD|RD_s,		I1	}, /* jr */
@@ -631,8 +665,10 @@
 {"ldc1",    "T,A(b)",	0,    (int) M_LDC1_AB,	INSN_MACRO,		I2	},
 {"ldc1",    "E,A(b)",	0,    (int) M_LDC1_AB,	INSN_MACRO,		I2	},
 {"l.d",     "T,o(b)",	0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D,	I2	}, /* ldc1 */
-{"l.d",     "T,o(b)",	0,    (int) M_L_DOB,	INSN_MACRO,		I1	},
-{"l.d",     "T,A(b)",	0,    (int) M_L_DAB,	INSN_MACRO,		I1	},
+{"l.d",     "T,o(b)",	0,    (int) M_L_DOB,	INSN_MACRO,		I1|T5	},
+{"l.d",     "T,A(b)",	0,    (int) M_L_DAB,	INSN_MACRO,		I1|T5	},
+/* lqc2 appears out of order here so that it matches before ldc2 on R5900 */
+{"lqc2",    "1,o(b)",   0xd8000000, 0xfc000000, 0,                      T5      },
 {"ldc2",    "E,o(b)",	0xd8000000, 0xfc000000, CLD|RD_b|WR_CC,		I2	},
 {"ldc2",    "E,A(b)",	0,    (int) M_LDC2_AB,	INSN_MACRO,		I2	},
 {"ldc3",    "E,o(b)",	0xdc000000, 0xfc000000, CLD|RD_b|WR_CC,		I2	},
@@ -657,6 +693,7 @@
 {"lld",     "t,A(b)",	0,    (int) M_LLD_AB,	INSN_MACRO,		I3	},
 {"lui",     "t,u",	0x3c000000, 0xffe00000,	WR_t,			I1	},
 {"luxc1",   "D,t(b)",	0x4c000005, 0xfc00f83f, LDD|WR_D|RD_t|RD_b,	I5|N55	},
+{"lq",      "t,o(b)",   0x78000000, 0xfc000000, WR_t|RD_b,              T5      },
 {"lw",      "t,o(b)",	0x8c000000, 0xfc000000,	LDD|RD_b|WR_t,		I1	},
 {"lw",      "t,A(b)",	0,    (int) M_LW_AB,	INSN_MACRO,		I1	},
 {"lwc0",    "E,o(b)",	0xc0000000, 0xfc000000,	CLD|RD_b|WR_CC,		I1	},
@@ -698,25 +735,35 @@
 {"madu",    "s,t",      0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO,     P3      },
 {"madd.d",  "D,R,S,T",	0x4c000021, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D,    I4	},
 {"madd.s",  "D,R,S,T",	0x4c000020, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S,    I4	},
+{"madd.s",  "D,S,T",    0x4600001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S,    T5      },
 {"madd.ps", "D,R,S,T",	0x4c000026, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D,    I5	},
 {"madd",    "s,t",      0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO,           L1 },
 {"madd",    "s,t",      0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO,          I32|N55},
 {"madd",    "s,t",      0x70000000, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M,      G1 },
 {"madd",    "d,s,t",    0x70000000, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, G1 },
+{"madd1",   "s,t",      0x70000020, 0xfc00ffff, RD_s|RD_t|WR_HI|WR_LO,       T5 },
+{"madd1",   "d,s,t",    0x70000020, 0xfc0007ff, RD_s|RD_t|WR_HI|WR_LO|WR_d,  T5 },
+{"madd16",  "s,t",      0x00000028, 0xfc00ffff, RD_s|RD_t|MOD_HILO,          N411 },
+{"madda.s", "S,T",      0x4600001e, 0xffe007ff, RD_S|RD_T|FP_S,              T5   }, 
 {"maddu",   "s,t",      0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO,           L1 },
 {"maddu",   "s,t",      0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO,          I32|N55},
 {"maddu",   "s,t",      0x70000001, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M,      G1	},
 {"maddu",   "d,s,t",    0x70000001, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, G1	},
-{"madd16",  "s,t",      0x00000028, 0xfc00ffff, RD_s|RD_t|MOD_HILO,	N411    },
+{"maddu1",  "s,t",      0x70000021, 0xfc00ffff, RD_s|RD_t|WR_HI|WR_LO,       T5 },
+{"maddu1",  "d,s,t",    0x70000021, 0xfc0007ff, RD_s|RD_t|WR_HI|WR_LO|WR_d,  T5 },
 {"max.ob",  "X,Y,Q",	0x78000007, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
 {"max.ob",  "D,S,T",	0x4ac00007, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
 {"max.ob",  "D,S,T[e]",	0x48000007, 0xfe20003f,	WR_D|RD_S|RD_T,		N54	},
 {"max.ob",  "D,S,k",	0x4bc00007, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
 {"max.qh",  "X,Y,Q",	0x78200007, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
+{"max.s",   "D,S,T",    0x46000028, 0xffe0003f, WR_D|RD_S|RD_T|FP_S,    T5      },
 {"mfpc",    "t,P",	0x4000c801, 0xffe0ffc1,	LCD|WR_t|RD_C0,		M1|N5	},
+{"mfpc",    "t,P",      0x4000c801, 0xffe0ffc1, RD_C0|WR_t,             T5      },
 {"mfps",    "t,P",	0x4000c800, 0xffe0ffc1,	LCD|WR_t|RD_C0,		M1|N5	},
+{"mfps",    "t,P",      0x4000c800, 0xffe0ffc1, WR_t|RD_C0,             T5      },
+{"mfbpc",   "t",        0x4000c000, 0xffe0ffff, WR_t|RD_C0,             T5      },
 {"mfc0",    "t,G",	0x40000000, 0xffe007ff,	LCD|WR_t|RD_C0,		I1	},
-{"mfc0",    "t,+D",     0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, 	I32     },
+{"mfc0",    "t,*D",     0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, 	I32     },
 {"mfc0",    "t,G,H",    0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, 	I32     },
 {"mfc1",    "t,S",	0x44000000, 0xffe007ff,	LCD|WR_t|RD_S|FP_S,	I1	},
 {"mfc1",    "t,G",	0x44000000, 0xffe007ff,	LCD|WR_t|RD_S|FP_S,	I1	},
@@ -727,14 +774,24 @@
 {"mfhc2",   "t,i",	0x48600000, 0xffe00000,	LCD|WR_t|RD_C2,		I33	},
 {"mfc3",    "t,G",	0x4c000000, 0xffe007ff,	LCD|WR_t|RD_C3,		I1	},
 {"mfc3",    "t,G,H",    0x4c000000, 0xffe007f8, LCD|WR_t|RD_C3, 	I32     },
+{"mfdab",   "t",        0x4000c004, 0xffe0ffff, RD_C0|WR_t,             T5      },
+{"mfdabm",  "t",        0x4000c005, 0xffe0ffff, RD_C0|WR_t,             T5      },
 {"mfdr",    "t,G",	0x7000003d, 0xffe007ff,	LCD|WR_t|RD_C0,		N5      },
+{"mfdvb",   "t",        0x4000c006, 0xffe0ffff, RD_C0|WR_t,             T5      },
+{"mfdvbm",  "t",        0x4000c007, 0xffe0ffff, RD_C0|WR_t,             T5      },
 {"mfhi",    "d",	0x00000010, 0xffff07ff,	WR_d|RD_HI,		I1	},
+{"mfhi1",   "d",        0x70000010, 0xffff07ff, WR_d|RD_HI,             T5      },
+{"mfiab",   "t",        0x4000c002, 0xffe0ffff, RD_C0|WR_t,             T5      },
+{"mfiabm",  "t",        0x4000c003, 0xffe0ffff, RD_C0|WR_t,             T5      },
 {"mflo",    "d",	0x00000012, 0xffff07ff,	WR_d|RD_LO,		I1	},
+{"mflo1",   "d",        0x70000012, 0xffff07ff, WR_d|RD_LO,             T5      },
+{"mfsa",    "d",        0x00000028, 0xffff07ff, WR_d,                   T5      },
 {"min.ob",  "X,Y,Q",	0x78000006, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
 {"min.ob",  "D,S,T",	0x4ac00006, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
 {"min.ob",  "D,S,T[e]",	0x48000006, 0xfe20003f,	WR_D|RD_S|RD_T,		N54	},
 {"min.ob",  "D,S,k",	0x4bc00006, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
 {"min.qh",  "X,Y,Q",	0x78200006, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
+{"min.s",   "D,S,T",    0x46000029, 0xffe0003f, WR_D|RD_S|RD_T|FP_S,    T5      },
 {"mov.d",   "D,S",	0x46200006, 0xffff003f,	WR_D|RD_S|FP_D,		I1	},
 {"mov.s",   "D,S",	0x46000006, 0xffff003f,	WR_D|RD_S|FP_S,		I1	},
 {"mov.ps",  "D,S",	0x46c00006, 0xffff003f,	WR_D|RD_S|FP_D,		I5	},
@@ -744,7 +801,7 @@
 {"movf.l",  "X,Y,N",	0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,	MX|SB1	},
 {"movf.s",  "D,S,N",    0x46000011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S,   I4|I32	},
 {"movf.ps", "D,S,N",	0x46c00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,	I5	},
-{"movn",    "d,v,t",    0x0000000b, 0xfc0007ff, WR_d|RD_s|RD_t, 	I4|I32	},
+{"movn",    "d,v,t",    0x0000000b, 0xfc0007ff, WR_d|RD_s|RD_t, 	I4|I32|T5	},
 {"ffc",     "d,v",	0x0000000b, 0xfc1f07ff,	WR_d|RD_s,		L1	},
 {"movn.d",  "D,S,t",    0x46200013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    I4|I32	},
 {"movn.l",  "D,S,t",    0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    MX|SB1	},
@@ -757,7 +814,7 @@
 {"movt.l",  "X,Y,N",    0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,   MX|SB1	},
 {"movt.s",  "D,S,N",    0x46010011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S,   I4|I32	},
 {"movt.ps", "D,S,N",	0x46c10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,	I5	},
-{"movz",    "d,v,t",    0x0000000a, 0xfc0007ff, WR_d|RD_s|RD_t, 	I4|I32	},
+{"movz",    "d,v,t",    0x0000000a, 0xfc0007ff, WR_d|RD_s|RD_t, 	I4|I32|T5	},
 {"ffs",     "d,v",	0x0000000a, 0xfc1f07ff,	WR_d|RD_s,		L1	},
 {"movz.d",  "D,S,t",    0x46200012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    I4|I32	},
 {"movz.l",  "D,S,t",    0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    MX|SB1	},
@@ -772,15 +829,20 @@
 {"msgn.qh", "X,Y,Q",	0x78200000, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
 {"msub.d",  "D,R,S,T",	0x4c000029, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I4	},
 {"msub.s",  "D,R,S,T",	0x4c000028, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, I4	},
+{"msub.s",  "D,S,T",    0x4600001d, 0xffe0003f, WR_D|RD_S|RD_T|FP_S,    T5      },
 {"msub.ps", "D,R,S,T",	0x4c00002e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I5	},
 {"msub",    "s,t",      0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO,	L1    	},
 {"msub",    "s,t",      0x70000004, 0xfc00ffff, RD_s|RD_t|MOD_HILO,     I32|N55 },
+{"msuba.s", "S,T",      0x4600001f, 0xffe007ff, RD_S|RD_T|FP_S,         T5      },
 {"msubu",   "s,t",      0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO,	L1	},
 {"msubu",   "s,t",      0x70000005, 0xfc00ffff, RD_s|RD_t|MOD_HILO,     I32|N55	},
 {"mtpc",    "t,P",	0x4080c801, 0xffe0ffc1,	COD|RD_t|WR_C0,		M1|N5	},
+{"mtpc",    "t,P",      0x4080c801, 0xffe0ffc1, RD_t|WR_C0,             T5      },
 {"mtps",    "t,P",	0x4080c800, 0xffe0ffc1,	COD|RD_t|WR_C0,		M1|N5	},
+{"mtps",    "t,P",      0x4080c800, 0xffe0ffc1, RD_t|WR_C0,             T5      },
+{"mtbpc",   "t",        0x4080c000, 0xffe0ffff, WR_C0|RD_t,             T5      },
 {"mtc0",    "t,G",	0x40800000, 0xffe007ff,	COD|RD_t|WR_C0|WR_CC,	I1	},
-{"mtc0",    "t,+D",     0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC,   I32     },
+{"mtc0",    "t,*D",     0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC,   I32     },
 {"mtc0",    "t,G,H",    0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC,   I32     },
 {"mtc1",    "t,S",	0x44800000, 0xffe007ff,	COD|RD_t|WR_S|FP_S,	I1	},
 {"mtc1",    "t,G",	0x44800000, 0xffe007ff,	COD|RD_t|WR_S|FP_S,	I1	},
@@ -792,8 +854,19 @@
 {"mtc3",    "t,G",	0x4c800000, 0xffe007ff,	COD|RD_t|WR_C3|WR_CC,	I1	},
 {"mtc3",    "t,G,H",    0x4c800000, 0xffe007f8, COD|RD_t|WR_C3|WR_CC,   I32     },
 {"mtdr",    "t,G",	0x7080003d, 0xffe007ff,	COD|RD_t|WR_C0,		N5	},
+{"mtdab",   "t",        0x4080c004, 0xffe0ffff, WR_C0|RD_t,             T5      },
+{"mtdabm",  "t",        0x4080c005, 0xffe0ffff, WR_C0|RD_t,             T5      },
+{"mtdvb",   "t",        0x4080c006, 0xffe0ffff, WR_C0|RD_t,             T5      },
+{"mtdvbm",  "t",        0x4080c007, 0xffe0ffff, WR_C0|RD_t,             T5      },
 {"mthi",    "s",	0x00000011, 0xfc1fffff,	RD_s|WR_HI,		I1	},
+{"mthi1",   "s",        0x70000011, 0xfc1fffff, RD_s|WR_HI,             T5      },
+{"mtiab",   "t",        0x4080c002, 0xffe0ffff, WR_C0|RD_t,             T5      },
+{"mtiabm",  "t",        0x4080c003, 0xffe0ffff, WR_C0|RD_t,             T5      },
 {"mtlo",    "s",	0x00000013, 0xfc1fffff,	RD_s|WR_LO,		I1	},
+{"mtlo1",   "s",        0x70000013, 0xfc1fffff, RD_s|WR_LO,             T5      },
+{"mtsa",    "s",        0x00000029, 0xfc1fffff, RD_s,                   T5      },
+{"mtsab",   "s,j",      0x04180000, 0xfc1f0000, RD_s,                   T5      },
+{"mtsah",   "s,j",      0x04190000, 0xfc1f0000, RD_s,                   T5      },
 {"mul.d",   "D,V,T",	0x46200002, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	I1	},
 {"mul.s",   "D,V,T",	0x46000002, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	I1	},
 {"mul.ob",  "X,Y,Q",	0x78000030, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
@@ -811,6 +884,7 @@
 {"mula.ob", "S,T[e]",	0x48000033, 0xfe2007ff,	WR_CC|RD_S|RD_T,	N54	},
 {"mula.ob", "S,k",	0x4bc00033, 0xffe007ff,	WR_CC|RD_S|RD_T,	N54	},
 {"mula.qh", "Y,Q",	0x78200033, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX	},
+{"mula.s",  "S,T",      0x4600001a, 0xffe007ff, RD_S|RD_T|FP_S,         T5      },
 {"mulhi",   "d,s,t",	0x00000258, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	N5	},
 {"mulhiu",  "d,s,t",	0x00000259, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	N5	},
 {"mull.ob", "Y,Q",	0x78000433, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D, MX|SB1	},
@@ -839,8 +913,12 @@
 {"mulsl.qh", "Y,Q",	0x78200432, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX	},
 {"mult",    "s,t",      0x00000018, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, I1	},
 {"mult",    "d,s,t",    0x00000018, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, G1	},
+{"mult1",   "s,t",      0x70000018, 0xfc00ffff, RD_s|RD_t|WR_HI|WR_LO,  T5      },
+{"mult1",   "d,s,t",    0x70000018, 0xfc0007ff, RD_s|RD_t|WR_HI|WR_LO|WR_d, T5  },
 {"multu",   "s,t",      0x00000019, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, I1	},
 {"multu",   "d,s,t",    0x00000019, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, G1	},
+{"multu1",  "s,t",      0x70000019, 0xfc00ffff, RD_s|RD_t|WR_HI|WR_LO,  T5      },
+{"multu1",  "d,s,t",    0x70000019, 0xfc0007ff, RD_s|RD_t|WR_HI|WR_LO|WR_d, T5  },
 {"mulu",    "d,s,t",	0x00000059, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	N5	},
 {"neg",     "d,w",	0x00000022, 0xffe007ff,	WR_d|RD_t,		I1	}, /* sub 0 */
 {"negu",    "d,w",	0x00000023, 0xffe007ff,	WR_d|RD_t,		I1	}, /* subu 0 */
@@ -872,7 +950,49 @@
 {"ori",     "t,r,i",	0x34000000, 0xfc000000,	WR_t|RD_s,		I1	},
 {"pabsdiff.ob", "X,Y,Q",0x78000009, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	SB1	},
 {"pabsdiffc.ob", "Y,Q",	0x78000035, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	SB1	},
+{"pabsh",   "d,t",      0x70000168, 0xffe007ff, WR_d|RD_t,              T5      },
+{"pabsw",   "d,t",      0x70000068, 0xffe007ff, WR_d|RD_t,              T5      },
+{"paddb",   "d,v,t",    0x70000208, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"paddh",   "d,v,t",    0x70000108, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"paddw",   "d,v,t",    0x70000008, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"paddsb",  "d,v,t",    0x70000608, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"paddsh",  "d,v,t",    0x70000508, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"paddsw",  "d,v,t",    0x70000408, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"paddub",  "d,v,t",    0x70000628, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"padduh",  "d,v,t",    0x70000528, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"padduw",  "d,v,t",    0x70000428, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"padsbh",  "d,v,t",    0x70000128, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"pand",    "d,v,t",    0x70000489, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
 {"pavg.ob", "X,Y,Q",	0x78000008, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	SB1	},
+{"pceqb",   "d,v,t",    0x700002a8, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"pceqh",   "d,v,t",    0x700001a8, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"pceqw",   "d,v,t",    0x700000a8, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"pcgtb",   "d,v,t",    0x70000288, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"pcgth",   "d,v,t",    0x70000188, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"pcgtw",   "d,v,t",    0x70000088, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"pcpyh",   "d,t",      0x700006e9, 0xffe007ff, WR_d|RD_t,              T5      },
+{"pcpyld",  "d,v,t",    0x70000389, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"pcpyud",  "d,v,t",    0x700003a9, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"pdivbw",  "s,t",      0x70000749, 0xfc00ffff, RD_s|RD_t|WR_HI|WR_LO,  T5      },
+{"pdivuw",  "s,t",      0x70000369, 0xfc00ffff, RD_s|RD_t|WR_HI|WR_LO,  T5      },
+{"pdivw",   "s,t",      0x70000349, 0xfc00ffff, RD_s|RD_t|WR_HI|WR_LO,  T5      },
+{"pexch",   "d,t",      0x700006a9, 0xffe007ff, WR_d|RD_t,              T5      },
+{"pexcw",   "d,t",      0x700007a9, 0xffe007ff, WR_d|RD_t,              T5      },
+{"pexeh",   "d,t",      0x70000689, 0xffe007ff, WR_d|RD_t,              T5      },
+{"pexoh",   "d,t",      0x70000689, 0xffe007ff, WR_d|RD_t,              T5      },
+{"pexew",   "d,t",      0x70000789, 0xffe007ff, WR_d|RD_t,              T5      },
+{"pexow",   "d,t",      0x70000789, 0xffe007ff, WR_d|RD_t,              T5      },
+{"pext5",   "d,t",      0x70000788, 0xffe007ff, WR_d|RD_t,              T5      },
+{"pextlb",  "d,v,t",    0x70000688, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"pextlh",  "d,v,t",    0x70000588, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"pextlw",  "d,v,t",    0x70000488, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"pextub",  "d,v,t",    0x700006a8, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"pextuh",  "d,v,t",    0x700005a8, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"pextuw",  "d,v,t",    0x700004a8, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"phmadh",  "d,v,t",    0x70000449, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HI|WR_LO, T5  },
+{"phmsbh",  "d,v,t",    0x70000549, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HI|WR_LO, T5  },
+{"phmaddh", "d,v,t",    0x70000449, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HI|WR_LO, T5  },
+{"phmsubh", "d,v,t",    0x70000549, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HI|WR_LO, T5  },
 {"pickf.ob", "X,Y,Q",	0x78000002, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
 {"pickf.ob", "D,S,T",	0x4ac00002, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
 {"pickf.ob", "D,S,T[e]",0x48000002, 0xfe20003f,	WR_D|RD_S|RD_T,		N54	},
@@ -883,11 +1003,65 @@
 {"pickt.ob", "D,S,T[e]",0x48000003, 0xfe20003f,	WR_D|RD_S|RD_T,		N54	},
 {"pickt.ob", "D,S,k",	0x4bc00003, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
 {"pickt.qh", "X,Y,Q",	0x78200003, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
+{"pinth",   "d,v,t",    0x70000289, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"pinteh",  "d,v,t",    0x700002a9, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"pintoh",  "d,v,t",    0x700002a9, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
 {"pll.ps",  "D,V,T",	0x46c0002c, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	I5	},
 {"plu.ps",  "D,V,T",	0x46c0002d, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	I5	},
+{"plzcw",   "d,v",      0x70000004, 0xfc1f07ff, WR_d|RD_s,              T5      },
+{"pmaddh",  "d,v,t",    0x70000409, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HI|WR_LO, T5  },
+{"pmadduw", "d,v,t",    0x70000029, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HI|WR_LO, T5  },
+{"pmaddw",  "d,v,t",    0x70000009, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HI|WR_LO, T5  },
+{"pmaxh",   "d,v,t",    0x700001c8, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"pmaxw",   "d,v,t",    0x700000c8, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"pmfhi",   "d",        0x70000209, 0xffff07ff, WR_d|RD_HI,             T5      },
+{"pmflo",   "d",        0x70000249, 0xffff07ff, WR_d|RD_LO,             T5      },
+{"pmfhl.lw", "d",       0x70000030, 0xffff07ff, WR_d|RD_LO|RD_HI,       T5      },
+{"pmfhl.uw", "d",       0x70000070, 0xffff07ff, WR_d|RD_LO|RD_HI,       T5      },
+{"pmfhl.slw", "d",      0x700000b0, 0xffff07ff, WR_d|RD_LO|RD_HI,       T5      },
+{"pmfhl.lh", "d",       0x700000f0, 0xffff07ff, WR_d|RD_LO|RD_HI,       T5      },
+{"pmfhl.sh", "d",       0x70000130, 0xffff07ff, WR_d|RD_LO|RD_HI,       T5      },
+{"pminh",   "d,v,t",    0x700001e8, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"pminw",   "d,v,t",    0x700000e8, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"pmsubh",  "d,v,t",    0x70000509, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HI|WR_LO, T5  },
+{"pmsubw",  "d,v,t",    0x70000109, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HI|WR_LO, T5  },
+{"pmthi",   "v",        0x70000229, 0xfc1fffff, WR_HI|RD_s,             T5      },
+{"pmtlo",   "v",        0x70000269, 0xfc1fffff, WR_LO|RD_s,             T5      },
+{"pmthl.lw", "v",       0x70000031, 0xfc1fffff, WR_HI|WR_LO|RD_s,       T5      },
+{"pmulth",  "d,v,t",    0x70000709, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HI|WR_LO, T5  },
+{"pmultuw", "d,v,t",    0x70000329, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HI|WR_LO, T5  },
+{"pmultw",  "d,v,t",    0x70000309, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HI|WR_LO, T5  },
+{"pnor",    "d,v,t",    0x700004e9, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"por",     "d,v,t",    0x700004a9, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"ppac5",   "d,t",      0x700007c8, 0xffe007ff, WR_d|RD_t,              T5      },
+{"ppacb",   "d,v,t",    0x700006c8, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"ppach",   "d,v,t",    0x700005c8, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"ppacw",   "d,v,t",    0x700004c8, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
   /* pref and prefx are at the start of the table.  */
+{"prevh",   "d,t",      0x700006c9, 0xffe007ff, WR_d|RD_t,              T5      },
+{"prot3w",  "d,t",      0x700007c9, 0xffe007ff, WR_d|RD_t,              T5      },
+{"psllh",   "d,t,&lt;",    0x70000034, 0xffe0003f, WR_d|RD_t,              T5      },
+{"psllvw",  "d,t,s",    0x70000089, 0xfc0007ff, WR_d|RD_t|RD_s,         T5      },
+{"psllw",   "d,t,&lt;",    0x7000003c, 0xffe0003f, WR_d|RD_t,              T5      },
+{"psrah",   "d,t,&lt;",    0x70000037, 0xffe0003f, WR_d|RD_t,              T5      },
+{"psravw",  "d,t,s",    0x700000e9, 0xfc0007ff, WR_d|RD_t|RD_s,         T5      },
+{"psraw",   "d,t,&lt;",    0x7000003f, 0xffe0003f, WR_d|RD_t,              T5      },
+{"psrlh",   "d,t,&lt;",    0x70000036, 0xffe0003f, WR_d|RD_t,              T5      },
+{"psrlvw",  "d,t,s",    0x700000c9, 0xfc0007ff, WR_d|RD_t|RD_s,         T5      },
+{"psrlw",   "d,t,&lt;",    0x7000003e, 0xffe0003f, WR_d|RD_t,              T5      },
+{"psubb",   "d,v,t",    0x70000248, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"psubh",   "d,v,t",    0x70000148, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"psubsb",  "d,v,t",    0x70000648, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"psubsh",  "d,v,t",    0x70000548, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"psubsw",  "d,v,t",    0x70000448, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"psubub",  "d,v,t",    0x70000668, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"psubuh",  "d,v,t",    0x70000568, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"psubuw",  "d,v,t",    0x70000468, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"psubw",   "d,v,t",    0x70000048, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
 {"pul.ps",  "D,V,T",	0x46c0002e, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	I5	},
 {"puu.ps",  "D,V,T",	0x46c0002f, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	I5	},
+{"pxor",    "d,v,t",    0x700004c9, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
+{"qfsrv",   "d,v,t",    0x700006e8, 0xfc0007ff, WR_d|RD_s|RD_t,         T5      },
 {"rach.ob", "X",	0x7a00003f, 0xfffff83f,	WR_D|RD_MACC|FP_D,	MX|SB1	},
 {"rach.ob", "D",	0x4a00003f, 0xfffff83f,	WR_D,			N54	},
 {"rach.qh", "X",	0x7a20003f, 0xfffff83f,	WR_D|RD_MACC|FP_D,	MX	},
@@ -939,6 +1113,7 @@
 {"rsqrt.d", "D,S",	0x46200016, 0xffff003f, WR_D|RD_S|FP_D,		I4	},
 {"rsqrt.ps","D,S",	0x46c00016, 0xffff003f, WR_D|RD_S|FP_D,		SB1	},
 {"rsqrt.s", "D,S",	0x46000016, 0xffff003f, WR_D|RD_S|FP_S,		I4	},
+{"rsqrt.s", "D,S,T",    0x46000016, 0xffe0003f, WR_D|RD_S|FP_S,         T5      },
 {"rsqrt1.d",  "D,S",	0x4620001e, 0xffff003f,	WR_D|RD_S|FP_D,		M3D	},
 {"rsqrt1.ps", "D,S",	0x46c0001e, 0xffff003f,	WR_D|RD_S|FP_S,		M3D	},
 {"rsqrt1.s",  "D,S",	0x4600001e, 0xffff003f,	WR_D|RD_S|FP_S,		M3D	},
@@ -967,13 +1142,15 @@
 {"sdc1",    "E,o(b)",	0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D,	I2	},
 {"sdc1",    "T,A(b)",	0,    (int) M_SDC1_AB,	INSN_MACRO,		I2	},
 {"sdc1",    "E,A(b)",	0,    (int) M_SDC1_AB,	INSN_MACRO,		I2	},
+/* sqc2 appears out of order here so that it matches before ldc2 on R5900 */
+{"sqc2",    "1,o(b)",   0xf8000000, 0xfc000000, 0,                      T5      },
 {"sdc2",    "E,o(b)",	0xf8000000, 0xfc000000, SM|RD_C2|RD_b,		I2	},
 {"sdc2",    "E,A(b)",	0,    (int) M_SDC2_AB,	INSN_MACRO,		I2	},
 {"sdc3",    "E,o(b)",	0xfc000000, 0xfc000000, SM|RD_C3|RD_b,		I2	},
 {"sdc3",    "E,A(b)",	0,    (int) M_SDC3_AB,	INSN_MACRO,		I2	},
 {"s.d",     "T,o(b)",	0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D,	I2	},
-{"s.d",     "T,o(b)",	0,    (int) M_S_DOB,	INSN_MACRO,		I1	},
-{"s.d",     "T,A(b)",	0,    (int) M_S_DAB,	INSN_MACRO,		I1	},
+{"s.d",     "T,o(b)",	0,    (int) M_S_DOB,	INSN_MACRO,		I1|T5	},
+{"s.d",     "T,A(b)",	0,    (int) M_S_DAB,	INSN_MACRO,		I1|T5	},
 {"sdl",     "t,o(b)",	0xb0000000, 0xfc000000,	SM|RD_t|RD_b,		I3	},
 {"sdl",     "t,A(b)",	0,    (int) M_SDL_AB,	INSN_MACRO,		I3	},
 {"sdr",     "t,o(b)",	0xb4000000, 0xfc000000,	SM|RD_t|RD_b,		I3	},
@@ -1028,7 +1205,9 @@
 {"sltu",    "d,v,I",	0,    (int) M_SLTU_I,	INSN_MACRO,		I1	},
 {"sne",     "d,v,t",	0,    (int) M_SNE,	INSN_MACRO,		I1	},
 {"sne",     "d,v,I",	0,    (int) M_SNE_I,	INSN_MACRO,		I1	},
+{"sq",      "t,o(b)",   0x7c000000, 0xfc000000, SM|RD_t|RD_b,           T5      },
 {"sqrt.d",  "D,S",	0x46200004, 0xffff003f, WR_D|RD_S|FP_D,		I2	},
+{"sqrt.s",  "D,T",      0x46000004, 0xffe0f83f, WR_D|RD_S|FP_S,         T5      },
 {"sqrt.s",  "D,S",	0x46000004, 0xffff003f, WR_D|RD_S|FP_S,		I2	},
 {"sqrt.ps", "D,S",	0x46c00004, 0xffff003f, WR_D|RD_S|FP_D,		SB1	},
 {"srav",    "d,t,s",	0x00000007, 0xfc0007ff,	WR_d|RD_t|RD_s,		I1	},
@@ -1056,6 +1235,7 @@
 {"sub.qh",  "X,Y,Q",	0x7820000a, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
 {"suba.ob", "Y,Q",	0x78000036, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX|SB1	},
 {"suba.qh", "Y,Q",	0x78200036, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX	},
+{"suba.s",  "S,T",      0x46000019, 0xffe007ff, RD_S|RD_T|FP_S,         T5      },
 {"subl.ob", "Y,Q",	0x78000436, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX|SB1	},
 {"subl.qh", "Y,Q",	0x78200436, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX	},
 {"subu",    "d,v,t",	0x00000023, 0xfc0007ff,	WR_d|RD_s|RD_t,		I1	},
@@ -1086,8 +1266,8 @@
 {"invalidate", "t,A(b)",0,    (int) M_SWR_AB,	INSN_MACRO,		I2	}, /* as swr */
 {"swxc1",   "S,t(b)",   0x4c000008, 0xfc0007ff, SM|RD_S|RD_t|RD_b,	I4	},
 {"sync",    "",		0x0000000f, 0xffffffff,	INSN_SYNC,		I2|G1	},
-{"sync.p",  "",		0x0000040f, 0xffffffff,	INSN_SYNC,		I2	},
-{"sync.l",  "",		0x0000000f, 0xffffffff,	INSN_SYNC,		I2	},
+{"sync.p",  "",		0x0000040f, 0xffffffff,	INSN_SYNC,		I2|T5	},
+{"sync.l",  "",		0x0000000f, 0xffffffff,	INSN_SYNC,		I2|T5	},
 {"synci",   "o(b)",	0x041f0000, 0xfc1f0000,	SM|RD_b,		I33	},
 {"syscall", "",		0x0000000c, 0xffffffff,	TRAP,			I1	},
 {"syscall", "B",	0x0000000c, 0xfc00003f,	TRAP,			I1	},
@@ -1130,6 +1310,9 @@
 {"trunc.w.d", "D,S",	0x4620000d, 0xffff003f, WR_D|RD_S|FP_D,		I2	},
 {"trunc.w.d", "D,S,x",	0x4620000d, 0xffff003f, WR_D|RD_S|FP_D,		I2	},
 {"trunc.w.d", "D,S,t",	0,    (int) M_TRUNCWD,	INSN_MACRO,		I1	},
+  /* The r5900 has a different bit pattern for the trunc.w.s instruction. */
+{"trunc.w.s", "D,S",    0x46000024, 0xffff003f, WR_D|RD_S|FP_S,         T5	}, /* same as */
+{"trunc.w.s", "D,S,x",  0x46000024, 0xffff003f, WR_D|RD_S|FP_S,         T5	}, /* cvt.w.s */
 {"trunc.w.s", "D,S",	0x4600000d, 0xffff003f,	WR_D|RD_S|FP_S,		I2	},
 {"trunc.w.s", "D,S,x",	0x4600000d, 0xffff003f,	WR_D|RD_S|FP_S,		I2	},
 {"trunc.w.s", "D,S,t",	0,    (int) M_TRUNCWS,	INSN_MACRO,		I1	},
@@ -1147,6 +1330,132 @@
 {"ush",     "t,A(b)",	0,    (int) M_USH_A,	INSN_MACRO,		I1	},
 {"usw",     "t,o(b)",	0,    (int) M_USW,	INSN_MACRO,		I1	},
 {"usw",     "t,A(b)",	0,    (int) M_USW_A,	INSN_MACRO,		I1	},
+{"vabs",    "&amp;1=,2=",   0x4a0001fd, 0xfe0007ff, 0,                      T5      },
+{"vadd",    "&amp;3=,2=,1=", 0x4a000028, 0xfe00003f,        0,              T5      },
+{"vaddi",   "&amp;3=,2=,!", 0x4a000022, 0xfe1f003f, 0,                      T5      },
+{"vaddq",   "&amp;3=,2=,^", 0x4a000020, 0xfe1f003f, 0,                      T5      },
+{"vaddw",   "&amp;3=,2=,1#w", 0x4a000003, 0xfe00003f,       0,              T5      },
+{"vaddx",   "&amp;3=,2=,1#x", 0x4a000000, 0xfe00003f,       0,              T5      },
+{"vaddy",   "&amp;3=,2=,1#y", 0x4a000001, 0xfe00003f,       0,              T5      },
+{"vaddz",   "&amp;3=,2=,1#z", 0x4a000002, 0xfe00003f,       0,              T5      },
+{"vadda",   "&amp;@=,1=,2=",  0x4a0002bc, 0xfe0007ff,       0,              T5      },
+{"vaddai",  "&amp;@=,2=,!", 0x4a00023e, 0xfe1f07ff, 0,                      T5      },
+{"vaddaq",  "&amp;@=,2=,^", 0x4a00023c, 0xfe1f07ff, 0,                      T5      },
+{"vaddaw",  "&amp;@=,2=,1#w", 0x4a00003f, 0xfe0007ff,       0,              T5      },
+{"vaddax",  "&amp;@=,2=,1#x", 0x4a00003c, 0xfe0007ff,       0,              T5      },
+{"vadday",  "&amp;@=,2=,1#y", 0x4a00003d, 0xfe0007ff,       0,              T5      },
+{"vaddaz",  "&amp;@=,2=,1#z", 0x4a00003e, 0xfe0007ff,       0,              T5      },
+{"vcallms", "g",        0x4a000038, 0xffe0003f, 0,                      T5      },
+{"vcallmsr", "9",       0x4a00d839, 0xffffffff, 0,                      T5      },
+{"vclipw",  "&amp;2=,1#w",  0x4a0001ff, 0xfe0007ff, 0,                      T5      },
+{"vdiv",    "^,8,7",    0x4a0003bc, 0xfe0007ff, 0,                      T5      },
+{"vftoi0",  "&amp;1=,2=",   0x4a00017c, 0xfe0007ff, 0,                      T5      },
+{"vftoi4",  "&amp;1=,2=",   0x4a00017d, 0xfe0007ff, 0,                      T5      },
+{"vftoi12", "&amp;1=,2=",   0x4a00017e, 0xfe0007ff, 0,                      T5      },
+{"vftoi15", "&amp;1=,2=",   0x4a00017f, 0xfe0007ff, 0,                      T5      },
+{"viadd",   "6,5,4",    0x4a000030, 0xffe0003f, 0,                      T5      },
+{"viaddi",  "4,5,0",    0x4a000032, 0xffe0003f, 0,                      T5      },
+{"viand",   "6,5,4",    0x4a000034, 0xffe0003f, 0,                      T5      },
+{"vilwr.w", "4,(5)",    0x4a2003fe, 0xffe007ff, 0,                      T5      },
+{"vilwr.x", "4,(5)",    0x4b0003fe, 0xffe007ff, 0,                      T5      },
+{"vilwr.y", "4,(5)",    0x4a8003fe, 0xffe007ff, 0,                      T5      },
+{"vilwr.z", "4,(5)",    0x4a4003fe, 0xffe007ff, 0,                      T5      },
+{"vior",    "6,5,4",    0x4a000035, 0xffe0003f, 0,                      T5      },
+{"viswr.w", "4,(5)",    0x4a2003ff, 0xffe007ff, 0,                      T5      },
+{"viswr.x", "4,(5)",    0x4b0003ff, 0xffe007ff, 0,                      T5      },
+{"viswr.y", "4,(5)",    0x4a8003ff, 0xffe007ff, 0,                      T5      },
+{"viswr.z", "4,(5)",    0x4a4003ff, 0xffe007ff, 0,                      T5      },
+{"visub",   "6,5,4",    0x4a000031, 0xffe0003f, 0,                      T5      },
+{"vitof0",  "&amp;1=,2=",   0x4a00013c, 0xfe0007ff, 0,                      T5      },
+{"vitof4",  "&amp;1=,2=",   0x4a00013d, 0xfe0007ff, 0,                      T5      },
+{"vitof12", "&amp;1=,2=",   0x4a00013e, 0xfe0007ff, 0,                      T5      },
+{"vitof15", "&amp;1=,2=",   0x4a00013f, 0xfe0007ff, 0,                      T5      },
+{"vlqd",    "&amp;1=,(--5)=", 0x4a00037e, 0xfe0007ff,       0,              T5      },
+{"vlqi",    "&amp;1=,(5++)=", 0x4a00037c, 0xfe0007ff,       0,              T5      },
+{"vmadd",   "&amp;3=,2=,1=",  0x4a000029, 0xfe00003f,       0,              T5      },
+{"vmaddi",  "&amp;3=,2=,!", 0x4a000023, 0xfe1f003f, 0,                      T5      },
+{"vmaddq",  "&amp;3=,2=,^", 0x4a000021, 0xfe1f003f, 0,                      T5      },
+{"vmaddw",  "&amp;3=,2=,1#w", 0x4a00000b, 0xfe00003f,       0,              T5      },
+{"vmaddx",  "&amp;3=,2=,1#x", 0x4a000008, 0xfe00003f,       0,              T5      },
+{"vmaddy",  "&amp;3=,2=,1#y", 0x4a000009, 0xfe00003f,       0,              T5      },
+{"vmaddz",  "&amp;3=,2=,1#z", 0x4a00000a, 0xfe00003f,       0,              T5      },
+{"vmadda",  "&amp;@=,2=,1=",  0x4a0002bd, 0xfe0007ff,       0,              T5      },
+{"vmaddai", "&amp;@=,2=,!", 0x4a00023f, 0xfe1f07ff, 0,                      T5      },
+{"vmaddaq", "&amp;@=,2=,^", 0x4a00023d, 0xfe1f07ff, 0,                      T5      },
+{"vmaddaw", "&amp;@=,2=,1#w", 0x4a0000bf, 0xfe0007ff,       0,              T5      },
+{"vmaddax", "&amp;@=,2=,1#x", 0x4a0000bc, 0xfe0007ff,       0,              T5      },
+{"vmadday", "&amp;@=,2=,1#y", 0x4a0000bd, 0xfe0007ff,       0,              T5      },
+{"vmaddaz", "&amp;@=,2=,1#z", 0x4a0000be, 0xfe0007ff,       0,              T5      },
+{"vmax",    "&amp;3=,2=,1=",  0x4a00002b, 0xfe00003f,       0,              T5      },
+{"vmaxi",   "&amp;3=,2=,!", 0x4a00001d, 0xfe1f003f, 0,                      T5      },
+{"vmaxw",   "&amp;3=,2=,1#w", 0x4a000013, 0xfe00003f,       0,              T5      },
+{"vmaxx",   "&amp;3=,2=,1#x", 0x4a000010, 0xfe00003f,       0,              T5      },
+{"vmaxy",   "&amp;3=,2=,1#y", 0x4a000011, 0xfe00003f,       0,              T5      },
+{"vmaxz",   "&amp;3=,2=,1#z", 0x4a000012, 0xfe00003f,       0,              T5      },
+{"vmfir",   "&amp;1=,5",    0x4a0003fd, 0xfe0007ff, 0,                      T5      },
+{"vmini",   "&amp;3=,2=,1=",  0x4a00002f, 0xfe00003f,       0,              T5      },
+{"vminii",  "&amp;3=,2=,!", 0x4a00001f, 0xfe1f003f, 0,                      T5      },
+{"vminiw",  "&amp;3=,2=,1#w", 0x4a000017, 0xfe00003f,       0,              T5      },
+{"vminix",  "&amp;3=,2=,1#x", 0x4a000014, 0xfe00003f,       0,              T5      },
+{"vminiy",  "&amp;3=,2=,1#y", 0x4a000015, 0xfe00003f,       0,              T5      },
+{"vminiz",  "&amp;3=,2=,1#z", 0x4a000016, 0xfe00003f,       0,              T5      },
+{"vmove",   "&amp;1=,2=",   0x4a00033c, 0xfe0007ff, 0,                      T5      },
+{"vmr32",   "&amp;1=,2=",   0x4a00033d, 0xfe0007ff, 0,                      T5      },
+{"vmsub",   "&amp;3=,2=,1=",  0x4a00002d, 0xfe00003f,       0,              T5      },
+{"vmsubi",  "&amp;3=,2=,!", 0x4a000027, 0xfe1f003f, 0,                      T5      },
+{"vmsubq",  "&amp;3=,2=,^", 0x4a000025, 0xfe1f003f, 0,                      T5      },
+{"vmsubw",  "&amp;3=,2=,1#w", 0x4a00000f, 0xfe00003f,       0,              T5      },
+{"vmsubx",  "&amp;3=,2=,1#x", 0x4a00000c, 0xfe00003f,       0,              T5      },
+{"vmsuby",  "&amp;3=,2=,1#y", 0x4a00000d, 0xfe00003f,       0,              T5      },
+{"vmsubz",  "&amp;3=,2=,1#z", 0x4a00000e, 0xfe00003f,       0,              T5      },
+{"vmsuba",  "&amp;@=,1=,2=",  0x4a0002fd, 0xfe0007ff,       0,              T5      },
+{"vmsubai", "&amp;@=,2=,!", 0x4a00027f, 0xfe1f07ff, 0,                      T5      },
+{"vmsubaq", "&amp;@=,2=,^", 0x4a00027d, 0xfe1f07ff, 0,                      T5      },
+{"vmsubaw", "&amp;@=,2=,1#w", 0x4a0000ff, 0xfe0007ff,       0,              T5      },
+{"vmsubax", "&amp;@=,2=,1#x", 0x4a0000fc, 0xfe0007ff,       0,              T5      },
+{"vmsubay", "&amp;@=,2=,1#y", 0x4a0000fd, 0xfe0007ff,       0,              T5      },
+{"vmsubaz", "&amp;@=,2=,1#z", 0x4a0000fe, 0xfe0007ff,       0,              T5      },
+{"vmtir",   "4,8",      0x4a0003fc, 0xff8007ff, 0,                      T5      },
+{"vmul",    "&amp;3=,2=,1=",  0x4a00002a, 0xfe00003f,       0,              T5      },
+{"vmuli",   "&amp;3=,2=,!", 0x4a00001e, 0xfe1f003f, 0,                      T5      },
+{"vmulq",   "&amp;3=,2=,^", 0x4a00001c, 0xfe1f003f, 0,                      T5      },
+{"vmulw",   "&amp;3=,2=,1#w", 0x4a00001b, 0xfe00003f,       0,              T5      },
+{"vmulx",   "&amp;3=,2=,1#x", 0x4a000018, 0xfe00003f,       0,              T5      },
+{"vmuly",   "&amp;3=,2=,1#y", 0x4a000019, 0xfe00003f,       0,              T5      },
+{"vmulz",   "&amp;3=,2=,1#z", 0x4a00001a, 0xfe00003f,       0,              T5      },
+{"vmula",   "&amp;@=,2=,1=",  0x4a0002be, 0xfe0007ff,       0,              T5      },
+{"vmulai",  "&amp;@=,2=,!", 0x4a0001fe, 0xfe1f07ff, 0,                      T5      },
+{"vmulaq",  "&amp;@=,2=,+", 0x4a0001fc, 0xfe1f07ff, 0,                      T5      },
+{"vmulaw",  "&amp;@=,2=,1#w", 0x4a0001bf, 0xfe0007ff,       0,              T5      },
+{"vmulax",  "&amp;@=,2=,1#x", 0x4a0001bc, 0xfe0007ff,       0,              T5      },
+{"vmulay",  "&amp;@=,2=,1#y", 0x4a0001bd, 0xfe0007ff,       0,              T5      },
+{"vmulaz",  "&amp;@=,2=,1#z", 0x4a0001be, 0xfe0007ff,       0,              T5      },
+{"vnop",    "",         0x4a0002ff, 0xffffffff, 0,                      T5      },
+{"vopmula", ";@=,2=,1=", 0x4bc002fe, 0xffe007ff,        0,              T5      },
+{"vopmsub", ";3=,2=,1=", 0x4bc0002e, 0xffe0003f,        0,              T5      },
+{"vrget",   "&amp;1=,_",    0x4a00043d, 0xfe00ffff, 0,                      T5      },
+{"vrinit",  "_,8",      0x4a00043e, 0xff9f07ff, 0,                      T5      },
+{"vrnext",  "&amp;1=,_",    0x4a00043c, 0xfe00ffff, 0,                      T5      },
+{"vrsqrt",  "^,8,7",    0x4a0003be, 0xfe0007ff, 0,                      T5      },
+{"vrxor",   "_,8",      0x4a00043f, 0xff9f07ff, 0,                      T5      },
+{"vsqd",    "&amp;2=,(--4)=", 0x4a00037f, 0xfe0007ff,       0,              T5      },
+{"vsqi",    "&amp;2=,(4++)=", 0x4a00037d, 0xfe0007ff,       0,              T5      },
+{"vsqrt",   "^,7",      0x4a2003bd, 0xfe60ffff, 0,                      T5      },
+{"vsub",    "&amp;3=,2=,1=",  0x4a00002c, 0xfe00003f,       0,              T5      },
+{"vsubi",   "&amp;3=,2=,!", 0x4a000026, 0xfe1f003f, 0,                      T5      },
+{"vsubq",   "&amp;3=,2=,^", 0x4a000024, 0xfe1f003f, 0,                      T5      },
+{"vsubw",   "&amp;3=,2=,1#w", 0x4a000007, 0xfe00003f,       0,              T5      },
+{"vsubx",   "&amp;3=,2=,1#x", 0x4a000004, 0xfe00003f,       0,              T5      },
+{"vsuby",   "&amp;3=,2=,1#y", 0x4a000005, 0xfe00003f,       0,              T5      },
+{"vsubz",   "&amp;3=,2=,1#z", 0x4a000006, 0xfe00003f,       0,              T5      },
+{"vsuba",   "&amp;@=,2=,1=",  0x4a0002fc, 0xfe0007ff,       0,              T5      },
+{"vsubai",  "&amp;@=,2=,!", 0x4a00027e, 0xfe1f07ff, 0,                      T5      },
+{"vsubaq",  "&amp;@=,2=,^", 0x4a00027c, 0xfe1f07ff, 0,                      T5      },
+{"vsubaw",  "&amp;@=,2=,1#w", 0x4a00007f, 0xfe0007ff,       0,              T5      },
+{"vsubax",  "&amp;@=,2=,1#x", 0x4a00007c, 0xfe0007ff,       0,              T5      },
+{"vsubay",  "&amp;@=,2=,1#y", 0x4a00007d, 0xfe0007ff,       0,              T5      },
+{"vsubaz",  "&amp;@=,2=,1#z", 0x4a00007e, 0xfe0007ff,       0,              T5      },
+{"vwaitq",  "",         0x4a0003bf, 0xffffffff, 0,                      T5      },
 {"wach.ob", "Y",	0x7a00003e, 0xffff07ff,	WR_MACC|RD_S|FP_D,	MX|SB1	},
 {"wach.ob", "S",	0x4a00003e, 0xffff07ff,	RD_S,			N54	},
 {"wach.qh", "Y",	0x7a20003e, 0xffff07ff,	WR_MACC|RD_S|FP_D,	MX	},
</pre></body></html>