[ bfd/ChangeLog ]
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index 9eae5e39604e606c55ca28f69d405036027a7dd9..788a34b5ba6130f9be3bd02faff5909e5d74095d 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-mips.c -- assemble code for a MIPS chip.
    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006 Free Software Foundation, Inc.
    Contributed by the OSF and Ralph Campbell.
    Written by Keith Knowles and Ralph Campbell, working independently.
    Modified for ECOFF and R4000 support by Ian Lance Taylor of Cygnus
@@ -28,8 +28,6 @@
 #include "subsegs.h"
 #include "safe-ctype.h"
 
-#include <stdarg.h>
-
 #include "opcode/mips.h"
 #include "itbl-ops.h"
 #include "dwarf2dbg.h"
@@ -150,7 +148,7 @@ struct mips_cl_insn
   /* True if this entry cannot be moved from its current position.  */
   unsigned int fixed_p : 1;
 
-  /* True if this instruction occured in a .set noreorder block.  */
+  /* True if this instruction occurred in a .set noreorder block.  */
   unsigned int noreorder_p : 1;
 
   /* True for mips16 instructions that jump to an absolute address.  */
@@ -193,6 +191,9 @@ struct mips_set_options
      command line options, and based on the default architecture.  */
   int ase_mips3d;
   int ase_mdmx;
+  int ase_smartmips;
+  int ase_dsp;
+  int ase_mt;
   /* Whether we are assembling for the mips16 processor.  0 if we are
      not, 1 if we are, and -1 if the value has not been initialized.
      Changed by `.set mips16' and `.set nomips16', and the -mips16 and
@@ -243,7 +244,7 @@ static int file_mips_fp32 = -1;
 
 static struct mips_set_options mips_opts =
 {
-  ISA_UNKNOWN, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, CPU_UNKNOWN, FALSE
+  ISA_UNKNOWN, -1, -1, 0, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, CPU_UNKNOWN, FALSE
 };
 
 /* These variables are filled in with the masks of registers used.
@@ -259,6 +260,11 @@ static int file_mips_isa = ISA_UNKNOWN;
    command line (e.g., by -march).  */
 static int file_ase_mips16;
 
+#define ISA_SUPPORTS_MIPS16E (mips_opts.isa == ISA_MIPS32              \
+                             || mips_opts.isa == ISA_MIPS32R2          \
+                             || mips_opts.isa == ISA_MIPS64            \
+                             || mips_opts.isa == ISA_MIPS64R2)
+
 /* True if -mips3d was passed or implied by arguments passed on the
    command line (e.g., by -march).  */
 static int file_ase_mips3d;
@@ -267,6 +273,29 @@ static int file_ase_mips3d;
    command line (e.g., by -march).  */
 static int file_ase_mdmx;
 
+/* True if -msmartmips was passed or implied by arguments passed on the
+   command line (e.g., by -march).  */
+static int file_ase_smartmips;
+
+#define ISA_SUPPORTS_SMARTMIPS (mips_opts.isa == ISA_MIPS32            \
+                               || mips_opts.isa == ISA_MIPS32R2)
+
+/* True if -mdsp was passed or implied by arguments passed on the
+   command line (e.g., by -march).  */
+static int file_ase_dsp;
+
+#define ISA_SUPPORTS_DSP_ASE (mips_opts.isa == ISA_MIPS32R2            \
+                             || mips_opts.isa == ISA_MIPS64R2)
+
+#define ISA_SUPPORTS_DSP64_ASE (mips_opts.isa == ISA_MIPS64R2)
+
+/* True if -mmt was passed or implied by arguments passed on the
+   command line (e.g., by -march).  */
+static int file_ase_mt;
+
+#define ISA_SUPPORTS_MT_ASE (mips_opts.isa == ISA_MIPS32R2             \
+                            || mips_opts.isa == ISA_MIPS64R2)
+
 /* The argument of the -march= flag.  The architecture we are assembling.  */
 static int file_mips_arch = CPU_UNKNOWN;
 static const char *mips_arch_string;
@@ -283,41 +312,61 @@ static int mips_32bitmode = 0;
 #define ABI_NEEDS_32BIT_REGS(ABI) ((ABI) == O32_ABI)
 
 /* Likewise 64-bit registers.  */
-#define ABI_NEEDS_64BIT_REGS(ABI) \
-  ((ABI) == N32_ABI              \
-   || (ABI) == N64_ABI           \
+#define ABI_NEEDS_64BIT_REGS(ABI)      \
+  ((ABI) == N32_ABI                    \
+   || (ABI) == N64_ABI                 \
    || (ABI) == O64_ABI)
 
-/*  Return true if ISA supports 64 bit gp register instructions.  */
-#define ISA_HAS_64BIT_REGS(ISA) (    \
-   (ISA) == ISA_MIPS3                \
-   || (ISA) == ISA_MIPS4             \
-   || (ISA) == ISA_MIPS5             \
-   || (ISA) == ISA_MIPS64            \
-   || (ISA) == ISA_MIPS64R2          \
-   )
+/*  Return true if ISA supports 64 bit wide gp registers.  */
+#define ISA_HAS_64BIT_REGS(ISA)                \
+  ((ISA) == ISA_MIPS3                  \
+   || (ISA) == ISA_MIPS4               \
+   || (ISA) == ISA_MIPS5               \
+   || (ISA) == ISA_MIPS64              \
+   || (ISA) == ISA_MIPS64R2)
+
+/*  Return true if ISA supports 64 bit wide float registers.  */
+#define ISA_HAS_64BIT_FPRS(ISA)                \
+  ((ISA) == ISA_MIPS3                  \
+   || (ISA) == ISA_MIPS4               \
+   || (ISA) == ISA_MIPS5               \
+   || (ISA) == ISA_MIPS32R2            \
+   || (ISA) == ISA_MIPS64              \
+   || (ISA) == ISA_MIPS64R2)
 
 /* Return true if ISA supports 64-bit right rotate (dror et al.)
    instructions.  */
-#define ISA_HAS_DROR(ISA) (    \
-   (ISA) == ISA_MIPS64R2       \
-   )
+#define ISA_HAS_DROR(ISA)              \
+  ((ISA) == ISA_MIPS64R2)
 
 /* Return true if ISA supports 32-bit right rotate (ror et al.)
    instructions.  */
-#define ISA_HAS_ROR(ISA) (     \
-   (ISA) == ISA_MIPS32R2       \
-   || (ISA) == ISA_MIPS64R2    \
-   )
+#define ISA_HAS_ROR(ISA)               \
+  ((ISA) == ISA_MIPS32R2               \
+   || (ISA) == ISA_MIPS64R2            \
+   || mips_opts.ase_smartmips)
+
+/* Return true if ISA supports single-precision floats in odd registers.  */
+#define ISA_HAS_ODD_SINGLE_FPR(ISA)    \
+  ((ISA) == ISA_MIPS32                 \
+   || (ISA) == ISA_MIPS32R2            \
+   || (ISA) == ISA_MIPS64              \
+   || (ISA) == ISA_MIPS64R2)
+
+/* Return true if ISA supports move to/from high part of a 64-bit
+   floating-point register. */
+#define ISA_HAS_MXHC1(ISA)             \
+  ((ISA) == ISA_MIPS32R2               \
+   || (ISA) == ISA_MIPS64R2)
 
 #define HAVE_32BIT_GPRS                                   \
-    (mips_opts.gp32 || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+    (mips_opts.gp32 || !ISA_HAS_64BIT_REGS (mips_opts.isa))
 
 #define HAVE_32BIT_FPRS                            \
-    (mips_opts.fp32 || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+    (mips_opts.fp32 || !ISA_HAS_64BIT_FPRS (mips_opts.isa))
 
-#define HAVE_64BIT_GPRS (! HAVE_32BIT_GPRS)
-#define HAVE_64BIT_FPRS (! HAVE_32BIT_FPRS)
+#define HAVE_64BIT_GPRS (!HAVE_32BIT_GPRS)
+#define HAVE_64BIT_FPRS (!HAVE_32BIT_FPRS)
 
 #define HAVE_NEWABI (mips_abi == N32_ABI || mips_abi == N64_ABI)
 
@@ -357,14 +406,6 @@ static int mips_32bitmode = 0;
    (strncmp (TARGET_CPU, "mips16", sizeof ("mips16") - 1) == 0         \
     || strncmp (TARGET_CANONICAL, "mips-lsi-elf", sizeof ("mips-lsi-elf") - 1) == 0)
 
-/* Return true if the given CPU supports the MIPS3D ASE.  */
-#define CPU_HAS_MIPS3D(cpu)    ((cpu) == CPU_SB1      \
-                                )
-
-/* Return true if the given CPU supports the MDMX ASE.  */
-#define CPU_HAS_MDMX(cpu)      (FALSE                 \
-                                )
-
 /* True if CPU has a dror instruction.  */
 #define CPU_HAS_DROR(CPU)      ((CPU) == CPU_VR5400 || (CPU) == CPU_VR5500)
 
@@ -1000,11 +1041,18 @@ static int validate_mips_insn (const struct mips_opcode *);
 struct mips_cpu_info
 {
   const char *name;           /* CPU or ISA name.  */
-  int is_isa;                 /* Is this an ISA?  (If 0, a CPU.) */
+  int flags;                  /* ASEs available, or ISA flag.  */
   int isa;                    /* ISA level.  */
   int cpu;                    /* CPU number (default CPU if ISA).  */
 };
 
+#define MIPS_CPU_IS_ISA                0x0001  /* Is this an ISA?  (If 0, a CPU.) */
+#define MIPS_CPU_ASE_SMARTMIPS 0x0002  /* CPU implements SmartMIPS ASE */
+#define MIPS_CPU_ASE_DSP       0x0004  /* CPU implements DSP ASE */
+#define MIPS_CPU_ASE_MT                0x0008  /* CPU implements MT ASE */
+#define MIPS_CPU_ASE_MIPS3D    0x0010  /* CPU implements MIPS-3D ASE */
+#define MIPS_CPU_ASE_MDMX      0x0020  /* CPU implements MDMX ASE */
+
 static const struct mips_cpu_info *mips_parse_cpu (const char *, const char *);
 static const struct mips_cpu_info *mips_cpu_info_from_isa (int);
 static const struct mips_cpu_info *mips_cpu_info_from_arch (int);
@@ -1055,6 +1103,8 @@ static const pseudo_typeS mips_pseudo_table[] =
   {"half", s_cons, 1},
   {"dword", s_cons, 3},
   {"weakext", s_mips_weakext, 0},
+  {"origin", s_org, 0},
+  {"repeat", s_rept, 0},
 
   /* These pseudo-ops are defined in read.c, but must be overridden
      here for one reason or another.  */
@@ -1118,8 +1168,8 @@ struct insn_label_list
   symbolS *label;
 };
 
-static struct insn_label_list *insn_labels;
 static struct insn_label_list *free_insn_labels;
+#define label_list tc_segment_info_data
 
 static void mips_clear_insn_labels (void);
 
@@ -1127,12 +1177,19 @@ static inline void
 mips_clear_insn_labels (void)
 {
   register struct insn_label_list **pl;
+  segment_info_type *si;
 
-  for (pl = &free_insn_labels; *pl != NULL; pl = &(*pl)->next)
-    ;
-  *pl = insn_labels;
-  insn_labels = NULL;
+  if (now_seg)
+    {
+      for (pl = &free_insn_labels; *pl != NULL; pl = &(*pl)->next)
+       ;
+      
+      si = seg_info (now_seg);
+      *pl = si->label_list;
+      si->label_list = NULL;
+    }
 }
+
 \f
 static char *expr_end;
 
@@ -1173,6 +1230,12 @@ mips_target_format (void)
     case bfd_target_coff_flavour:
       return "pe-mips";
     case bfd_target_elf_flavour:
+#ifdef TE_VXWORKS
+      if (!HAVE_64BIT_OBJECTS && !HAVE_NEWABI)
+       return (target_big_endian
+               ? "elf32-bigmips-vxworks"
+               : "elf32-littlemips-vxworks");
+#endif
 #ifdef TE_TMIPS
       /* This is traditional mips.  */
       return (target_big_endian
@@ -1369,16 +1432,312 @@ init_vr4120_conflicts (void)
 #undef CONFLICT
 }
 
-/* This function is called once, at assembler startup time.  It should
-   set up all the tables, etc. that the MD part of the assembler will need.  */
+struct regname {
+  const char *name;
+  unsigned int num;
+};
+
+#define RTYPE_MASK     0x1ff00
+#define RTYPE_NUM      0x00100
+#define RTYPE_FPU      0x00200
+#define RTYPE_FCC      0x00400
+#define RTYPE_VEC      0x00800
+#define RTYPE_GP       0x01000
+#define RTYPE_CP0      0x02000
+#define RTYPE_PC       0x04000
+#define RTYPE_ACC      0x08000
+#define RTYPE_CCC      0x10000
+#define RNUM_MASK      0x000ff
+#define RWARN          0x80000
+
+#define GENERIC_REGISTER_NUMBERS \
+    {"$0",     RTYPE_NUM | 0},  \
+    {"$1",     RTYPE_NUM | 1},  \
+    {"$2",     RTYPE_NUM | 2},  \
+    {"$3",     RTYPE_NUM | 3},  \
+    {"$4",     RTYPE_NUM | 4},  \
+    {"$5",     RTYPE_NUM | 5},  \
+    {"$6",     RTYPE_NUM | 6},  \
+    {"$7",     RTYPE_NUM | 7},  \
+    {"$8",     RTYPE_NUM | 8},  \
+    {"$9",     RTYPE_NUM | 9},  \
+    {"$10",    RTYPE_NUM | 10}, \
+    {"$11",    RTYPE_NUM | 11}, \
+    {"$12",    RTYPE_NUM | 12}, \
+    {"$13",    RTYPE_NUM | 13}, \
+    {"$14",    RTYPE_NUM | 14}, \
+    {"$15",    RTYPE_NUM | 15}, \
+    {"$16",    RTYPE_NUM | 16}, \
+    {"$17",    RTYPE_NUM | 17}, \
+    {"$18",    RTYPE_NUM | 18}, \
+    {"$19",    RTYPE_NUM | 19}, \
+    {"$20",    RTYPE_NUM | 20}, \
+    {"$21",    RTYPE_NUM | 21}, \
+    {"$22",    RTYPE_NUM | 22}, \
+    {"$23",    RTYPE_NUM | 23}, \
+    {"$24",    RTYPE_NUM | 24}, \
+    {"$25",    RTYPE_NUM | 25}, \
+    {"$26",    RTYPE_NUM | 26}, \
+    {"$27",    RTYPE_NUM | 27}, \
+    {"$28",    RTYPE_NUM | 28}, \
+    {"$29",    RTYPE_NUM | 29}, \
+    {"$30",    RTYPE_NUM | 30}, \
+    {"$31",    RTYPE_NUM | 31} 
+
+#define FPU_REGISTER_NAMES       \
+    {"$f0",    RTYPE_FPU | 0},  \
+    {"$f1",    RTYPE_FPU | 1},  \
+    {"$f2",    RTYPE_FPU | 2},  \
+    {"$f3",    RTYPE_FPU | 3},  \
+    {"$f4",    RTYPE_FPU | 4},  \
+    {"$f5",    RTYPE_FPU | 5},  \
+    {"$f6",    RTYPE_FPU | 6},  \
+    {"$f7",    RTYPE_FPU | 7},  \
+    {"$f8",    RTYPE_FPU | 8},  \
+    {"$f9",    RTYPE_FPU | 9},  \
+    {"$f10",   RTYPE_FPU | 10}, \
+    {"$f11",   RTYPE_FPU | 11}, \
+    {"$f12",   RTYPE_FPU | 12}, \
+    {"$f13",   RTYPE_FPU | 13}, \
+    {"$f14",   RTYPE_FPU | 14}, \
+    {"$f15",   RTYPE_FPU | 15}, \
+    {"$f16",   RTYPE_FPU | 16}, \
+    {"$f17",   RTYPE_FPU | 17}, \
+    {"$f18",   RTYPE_FPU | 18}, \
+    {"$f19",   RTYPE_FPU | 19}, \
+    {"$f20",   RTYPE_FPU | 20}, \
+    {"$f21",   RTYPE_FPU | 21}, \
+    {"$f22",   RTYPE_FPU | 22}, \
+    {"$f23",   RTYPE_FPU | 23}, \
+    {"$f24",   RTYPE_FPU | 24}, \
+    {"$f25",   RTYPE_FPU | 25}, \
+    {"$f26",   RTYPE_FPU | 26}, \
+    {"$f27",   RTYPE_FPU | 27}, \
+    {"$f28",   RTYPE_FPU | 28}, \
+    {"$f29",   RTYPE_FPU | 29}, \
+    {"$f30",   RTYPE_FPU | 30}, \
+    {"$f31",   RTYPE_FPU | 31}
+
+#define FPU_CONDITION_CODE_NAMES \
+    {"$fcc0",  RTYPE_FCC | 0},  \
+    {"$fcc1",  RTYPE_FCC | 1},  \
+    {"$fcc2",  RTYPE_FCC | 2},  \
+    {"$fcc3",  RTYPE_FCC | 3},  \
+    {"$fcc4",  RTYPE_FCC | 4},  \
+    {"$fcc5",  RTYPE_FCC | 5},  \
+    {"$fcc6",  RTYPE_FCC | 6},  \
+    {"$fcc7",  RTYPE_FCC | 7}
+
+#define COPROC_CONDITION_CODE_NAMES         \
+    {"$cc0",   RTYPE_FCC | RTYPE_CCC | 0}, \
+    {"$cc1",   RTYPE_FCC | RTYPE_CCC | 1}, \
+    {"$cc2",   RTYPE_FCC | RTYPE_CCC | 2}, \
+    {"$cc3",   RTYPE_FCC | RTYPE_CCC | 3}, \
+    {"$cc4",   RTYPE_FCC | RTYPE_CCC | 4}, \
+    {"$cc5",   RTYPE_FCC | RTYPE_CCC | 5}, \
+    {"$cc6",   RTYPE_FCC | RTYPE_CCC | 6}, \
+    {"$cc7",   RTYPE_FCC | RTYPE_CCC | 7}
+
+#define N32N64_SYMBOLIC_REGISTER_NAMES \
+    {"$a4",    RTYPE_GP | 8},  \
+    {"$a5",    RTYPE_GP | 9},  \
+    {"$a6",    RTYPE_GP | 10}, \
+    {"$a7",    RTYPE_GP | 11}, \
+    {"$ta0",   RTYPE_GP | 8},  /* alias for $a4 */ \
+    {"$ta1",   RTYPE_GP | 9},  /* alias for $a5 */ \
+    {"$ta2",   RTYPE_GP | 10}, /* alias for $a6 */ \
+    {"$ta3",   RTYPE_GP | 11}, /* alias for $a7 */ \
+    {"$t0",    RTYPE_GP | 12}, \
+    {"$t1",    RTYPE_GP | 13}, \
+    {"$t2",    RTYPE_GP | 14}, \
+    {"$t3",    RTYPE_GP | 15}
+
+#define O32_SYMBOLIC_REGISTER_NAMES \
+    {"$t0",    RTYPE_GP | 8},  \
+    {"$t1",    RTYPE_GP | 9},  \
+    {"$t2",    RTYPE_GP | 10}, \
+    {"$t3",    RTYPE_GP | 11}, \
+    {"$t4",    RTYPE_GP | 12}, \
+    {"$t5",    RTYPE_GP | 13}, \
+    {"$t6",    RTYPE_GP | 14}, \
+    {"$t7",    RTYPE_GP | 15}, \
+    {"$ta0",   RTYPE_GP | 12}, /* alias for $t4 */ \
+    {"$ta1",   RTYPE_GP | 13}, /* alias for $t5 */ \
+    {"$ta2",   RTYPE_GP | 14}, /* alias for $t6 */ \
+    {"$ta3",   RTYPE_GP | 15}  /* alias for $t7 */ 
+
+/* Remaining symbolic register names */
+#define SYMBOLIC_REGISTER_NAMES \
+    {"$zero",  RTYPE_GP | 0},  \
+    {"$at",    RTYPE_GP | 1},  \
+    {"$AT",    RTYPE_GP | 1},  \
+    {"$v0",    RTYPE_GP | 2},  \
+    {"$v1",    RTYPE_GP | 3},  \
+    {"$a0",    RTYPE_GP | 4},  \
+    {"$a1",    RTYPE_GP | 5},  \
+    {"$a2",    RTYPE_GP | 6},  \
+    {"$a3",    RTYPE_GP | 7},  \
+    {"$s0",    RTYPE_GP | 16}, \
+    {"$s1",    RTYPE_GP | 17}, \
+    {"$s2",    RTYPE_GP | 18}, \
+    {"$s3",    RTYPE_GP | 19}, \
+    {"$s4",    RTYPE_GP | 20}, \
+    {"$s5",    RTYPE_GP | 21}, \
+    {"$s6",    RTYPE_GP | 22}, \
+    {"$s7",    RTYPE_GP | 23}, \
+    {"$t8",    RTYPE_GP | 24}, \
+    {"$t9",    RTYPE_GP | 25}, \
+    {"$k0",    RTYPE_GP | 26}, \
+    {"$kt0",   RTYPE_GP | 26}, \
+    {"$k1",    RTYPE_GP | 27}, \
+    {"$kt1",   RTYPE_GP | 27}, \
+    {"$gp",    RTYPE_GP | 28}, \
+    {"$sp",    RTYPE_GP | 29}, \
+    {"$s8",    RTYPE_GP | 30}, \
+    {"$fp",    RTYPE_GP | 30}, \
+    {"$ra",    RTYPE_GP | 31}
+
+#define MIPS16_SPECIAL_REGISTER_NAMES \
+    {"$pc",    RTYPE_PC | 0}
+
+#define MDMX_VECTOR_REGISTER_NAMES \
+    /* {"$v0", RTYPE_VEC | 0},  clash with REG 2 above */ \
+    /* {"$v1", RTYPE_VEC | 1},  clash with REG 3 above */ \
+    {"$v2",    RTYPE_VEC | 2},  \
+    {"$v3",    RTYPE_VEC | 3},  \
+    {"$v4",    RTYPE_VEC | 4},  \
+    {"$v5",    RTYPE_VEC | 5},  \
+    {"$v6",    RTYPE_VEC | 6},  \
+    {"$v7",    RTYPE_VEC | 7},  \
+    {"$v8",    RTYPE_VEC | 8},  \
+    {"$v9",    RTYPE_VEC | 9},  \
+    {"$v10",   RTYPE_VEC | 10}, \
+    {"$v11",   RTYPE_VEC | 11}, \
+    {"$v12",   RTYPE_VEC | 12}, \
+    {"$v13",   RTYPE_VEC | 13}, \
+    {"$v14",   RTYPE_VEC | 14}, \
+    {"$v15",   RTYPE_VEC | 15}, \
+    {"$v16",   RTYPE_VEC | 16}, \
+    {"$v17",   RTYPE_VEC | 17}, \
+    {"$v18",   RTYPE_VEC | 18}, \
+    {"$v19",   RTYPE_VEC | 19}, \
+    {"$v20",   RTYPE_VEC | 20}, \
+    {"$v21",   RTYPE_VEC | 21}, \
+    {"$v22",   RTYPE_VEC | 22}, \
+    {"$v23",   RTYPE_VEC | 23}, \
+    {"$v24",   RTYPE_VEC | 24}, \
+    {"$v25",   RTYPE_VEC | 25}, \
+    {"$v26",   RTYPE_VEC | 26}, \
+    {"$v27",   RTYPE_VEC | 27}, \
+    {"$v28",   RTYPE_VEC | 28}, \
+    {"$v29",   RTYPE_VEC | 29}, \
+    {"$v30",   RTYPE_VEC | 30}, \
+    {"$v31",   RTYPE_VEC | 31}
+
+#define MIPS_DSP_ACCUMULATOR_NAMES \
+    {"$ac0",   RTYPE_ACC | 0}, \
+    {"$ac1",   RTYPE_ACC | 1}, \
+    {"$ac2",   RTYPE_ACC | 2}, \
+    {"$ac3",   RTYPE_ACC | 3}
+
+static const struct regname reg_names[] = {
+  GENERIC_REGISTER_NUMBERS,
+  FPU_REGISTER_NAMES,
+  FPU_CONDITION_CODE_NAMES,
+  COPROC_CONDITION_CODE_NAMES,
+
+  /* The $txx registers depends on the abi,
+     these will be added later into the symbol table from
+     one of the tables below once mips_abi is set after 
+     parsing of arguments from the command line. */
+  SYMBOLIC_REGISTER_NAMES,
+
+  MIPS16_SPECIAL_REGISTER_NAMES,
+  MDMX_VECTOR_REGISTER_NAMES,
+  MIPS_DSP_ACCUMULATOR_NAMES,
+  {0, 0}
+};
+
+static const struct regname reg_names_o32[] = {
+  O32_SYMBOLIC_REGISTER_NAMES,
+  {0, 0}
+};
+
+static const struct regname reg_names_n32n64[] = {
+  N32N64_SYMBOLIC_REGISTER_NAMES,
+  {0, 0}
+};
+
+static int
+reg_lookup (char **s, unsigned int types, unsigned int *regnop)
+{
+  symbolS *symbolP;
+  char *e;
+  char save_c;
+  int reg = -1;
+
+  /* Find end of name.  */
+  e = *s;
+  if (is_name_beginner (*e))
+    ++e;
+  while (is_part_of_name (*e))
+    ++e;
+
+  /* Terminate name.  */
+  save_c = *e;
+  *e = '\0';
+
+  /* Look for a register symbol.  */
+  if ((symbolP = symbol_find (*s)) && S_GET_SEGMENT (symbolP) == reg_section)
+    {
+      int r = S_GET_VALUE (symbolP);
+      if (r & types)
+       reg = r & RNUM_MASK;
+      else if ((types & RTYPE_VEC) && (r & ~1) == (RTYPE_GP | 2))
+       /* Convert GP reg $v0/1 to MDMX reg $v0/1!  */
+       reg = (r & RNUM_MASK) - 2;
+    }
+  /* Else see if this is a register defined in an itbl entry.  */
+  else if ((types & RTYPE_GP) && itbl_have_entries)
+    {
+      char *n = *s;
+      unsigned long r;
+
+      if (*n == '$')
+       ++n;
+      if (itbl_get_reg_val (n, &r))
+       reg = r & RNUM_MASK;
+    }
+
+  /* Advance to next token if a register was recognised.  */
+  if (reg >= 0)
+    *s = e;
+  else if (types & RWARN)
+    as_warn ("Unrecognized register name `%s'", *s);
+
+  *e = save_c;
+  if (regnop)
+    *regnop = reg;
+  return reg >= 0;
+}
+
+/* This function is called once, at assembler startup time.  It should set up
+   all the tables, etc. that the MD part of the assembler will need.  */
 
 void
 md_begin (void)
 {
-  register const char *retval = NULL;
+  const char *retval = NULL;
   int i = 0;
   int broken = 0;
 
+  if (mips_pic != NO_PIC)
+    {
+      if (g_switch_seen && g_switch_value != 0)
+       as_bad (_("-G may not be used in position-independent code"));
+      g_switch_value = 0;
+    }
+
   if (! bfd_set_arch_mach (stdoutput, bfd_arch_mips, file_mips_arch))
     as_warn (_("Could not set architecture and machine"));
 
@@ -1450,46 +1809,20 @@ md_begin (void)
 
   /* We add all the general register names to the symbol table.  This
      helps us detect invalid uses of them.  */
-  for (i = 0; i < 32; i++)
-    {
-      char buf[5];
-
-      sprintf (buf, "$%d", i);
-      symbol_table_insert (symbol_new (buf, reg_section, i,
+  for (i = 0; reg_names[i].name; i++) 
+    symbol_table_insert (symbol_new (reg_names[i].name, reg_section,
+                                    reg_names[i].num, // & RNUM_MASK,
+                                    &zero_address_frag));
+  if (HAVE_NEWABI)
+    for (i = 0; reg_names_n32n64[i].name; i++) 
+      symbol_table_insert (symbol_new (reg_names_n32n64[i].name, reg_section,
+                                      reg_names_n32n64[i].num, // & RNUM_MASK,
                                       &zero_address_frag));
-    }
-  symbol_table_insert (symbol_new ("$ra", reg_section, RA,
-                                  &zero_address_frag));
-  symbol_table_insert (symbol_new ("$fp", reg_section, FP,
-                                  &zero_address_frag));
-  symbol_table_insert (symbol_new ("$sp", reg_section, SP,
-                                  &zero_address_frag));
-  symbol_table_insert (symbol_new ("$gp", reg_section, GP,
-                                  &zero_address_frag));
-  symbol_table_insert (symbol_new ("$at", reg_section, AT,
-                                  &zero_address_frag));
-  symbol_table_insert (symbol_new ("$kt0", reg_section, KT0,
-                                  &zero_address_frag));
-  symbol_table_insert (symbol_new ("$kt1", reg_section, KT1,
-                                  &zero_address_frag));
-  symbol_table_insert (symbol_new ("$zero", reg_section, ZERO,
-                                  &zero_address_frag));
-  symbol_table_insert (symbol_new ("$pc", reg_section, -1,
-                                  &zero_address_frag));
-
-  /* If we don't add these register names to the symbol table, they
-     may end up being added as regular symbols by operand(), and then
-     make it to the object file as undefined in case they're not
-     regarded as local symbols.  They're local in o32, since `$' is a
-     local symbol prefix, but not in n32 or n64.  */
-  for (i = 0; i < 8; i++)
-    {
-      char buf[6];
-
-      sprintf (buf, "$fcc%i", i);
-      symbol_table_insert (symbol_new (buf, reg_section, -1,
+  else
+    for (i = 0; reg_names_o32[i].name; i++) 
+      symbol_table_insert (symbol_new (reg_names_o32[i].name, reg_section,
+                                      reg_names_o32[i].num, // & RNUM_MASK,
                                       &zero_address_frag));
-    }
 
   mips_no_prev_insn ();
 
@@ -1504,12 +1837,14 @@ md_begin (void)
 
   bfd_set_gp_size (stdoutput, g_switch_value);
 
-  if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+#ifdef OBJ_ELF
+  if (IS_ELF)
     {
-      /* On a native system, sections must be aligned to 16 byte
-        boundaries.  When configured for an embedded ELF target, we
-        don't bother.  */
-      if (strcmp (TARGET_OS, "elf") != 0)
+      /* On a native system other than VxWorks, sections must be aligned
+        to 16 byte boundaries.  When configured for an embedded ELF
+        target, we don't bother.  */
+      if (strcmp (TARGET_OS, "elf") != 0
+         && strcmp (TARGET_OS, "vxworks") != 0)
        {
          (void) bfd_set_section_alignment (stdoutput, text_section, 4);
          (void) bfd_set_section_alignment (stdoutput, data_section, 4);
@@ -1541,9 +1876,7 @@ md_begin (void)
            bfd_set_section_flags (stdoutput, sec, flags);
            bfd_set_section_alignment (stdoutput, sec, HAVE_NEWABI ? 3 : 2);
 
-#ifdef OBJ_ELF
            mips_regmask_frag = frag_more (sizeof (Elf32_External_RegInfo));
-#endif
          }
        else
          {
@@ -1553,7 +1886,6 @@ md_begin (void)
            bfd_set_section_flags (stdoutput, sec, flags);
            bfd_set_section_alignment (stdoutput, sec, 3);
 
-#ifdef OBJ_ELF
            /* Set up the option header.  */
            {
              Elf_Internal_Options opthdr;
@@ -1570,7 +1902,6 @@ md_begin (void)
 
              mips_regmask_frag = frag_more (sizeof (Elf64_External_RegInfo));
            }
-#endif
          }
 
        if (ECOFF_DEBUGGING)
@@ -1580,8 +1911,7 @@ md_begin (void)
                                          SEC_HAS_CONTENTS | SEC_READONLY);
            (void) bfd_set_section_alignment (stdoutput, sec, 2);
          }
-#ifdef OBJ_ELF
-       else if (OUTPUT_FLAVOR == bfd_target_elf_flavour && mips_flag_pdr)
+       else if (mips_flag_pdr)
          {
            pdr_seg = subseg_new (".pdr", (subsegT) 0);
            (void) bfd_set_section_flags (stdoutput, pdr_seg,
@@ -1589,11 +1919,11 @@ md_begin (void)
                                          | SEC_DEBUGGING);
            (void) bfd_set_section_alignment (stdoutput, pdr_seg, 2);
          }
-#endif
 
        subseg_set (seg, subseg);
       }
     }
+#endif /* OBJ_ELF */
 
   if (! ECOFF_DEBUGGING)
     md_obj_begin ();
@@ -1662,16 +1992,18 @@ md_assemble (char *str)
 }
 
 /* Return true if the given relocation might need a matching %lo().
-   Note that R_MIPS_GOT16 relocations only need a matching %lo() when
-   applied to local symbols.  */
+   This is only "might" because SVR4 R_MIPS_GOT16 relocations only
+   need a matching %lo() when applied to local symbols.  */
 
 static inline bfd_boolean
 reloc_needs_lo_p (bfd_reloc_code_real_type reloc)
 {
   return (HAVE_IN_PLACE_ADDENDS
          && (reloc == BFD_RELOC_HI16_S
-             || reloc == BFD_RELOC_MIPS_GOT16
-             || reloc == BFD_RELOC_MIPS16_HI16_S));
+             || reloc == BFD_RELOC_MIPS16_HI16_S
+             /* VxWorks R_MIPS_GOT16 relocs never need a matching %lo();
+                all GOT16 relocations evaluate to "G".  */
+             || (reloc == BFD_RELOC_MIPS_GOT16 && mips_pic != VXWORKS_PIC)));
 }
 
 /* Return true if the given fixup is followed by a matching R_MIPS_LO16
@@ -1790,10 +2122,11 @@ reg_needs_delay (unsigned int reg)
 static void
 mips_move_labels (void)
 {
+  segment_info_type *si = seg_info (now_seg);
   struct insn_label_list *l;
   valueT val;
 
-  for (l = insn_labels; l != NULL; l = l->next)
+  for (l = si->label_list; l != NULL; l = l->next)
     {
       assert (S_GET_SEGMENT (l->label) == now_seg);
       symbol_set_frag (l->label, frag_now);
@@ -1805,6 +2138,28 @@ mips_move_labels (void)
     }
 }
 
+static bfd_boolean
+s_is_linkonce (symbolS *sym, segT from_seg)
+{
+  bfd_boolean linkonce = FALSE;
+  segT symseg = S_GET_SEGMENT (sym);
+
+  if (symseg != from_seg && !S_IS_LOCAL (sym))
+    {
+      if ((bfd_get_section_flags (stdoutput, symseg) & SEC_LINK_ONCE))
+       linkonce = TRUE;
+#ifdef OBJ_ELF
+      /* The GNU toolchain uses an extension for ELF: a section
+        beginning with the magic string .gnu.linkonce is a
+        linkonce section.  */
+      if (strncmp (segment_name (symseg), ".gnu.linkonce",
+                  sizeof ".gnu.linkonce" - 1) == 0)
+       linkonce = TRUE;
+#endif
+    }
+  return linkonce;
+}
+
 /* Mark instruction labels in mips16 mode.  This permits the linker to
    handle them specially, such as generating jalx instructions when
    needed.  We also make them odd for the duration of the assembly, in
@@ -1816,21 +2171,29 @@ mips_move_labels (void)
 static void
 mips16_mark_labels (void)
 {
-  if (mips_opts.mips16)
-    {
-      struct insn_label_list *l;
-      valueT val;
+  segment_info_type *si = seg_info (now_seg);
+  struct insn_label_list *l;
 
-      for (l = insn_labels; l != NULL; l = l->next)
-       {
-#ifdef OBJ_ELF
-         if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
-           S_SET_OTHER (l->label, STO_MIPS16);
+  if (!mips_opts.mips16)
+    return;
+
+  for (l = si->label_list; l != NULL; l = l->next)
+   {
+      symbolS *label = l->label;
+
+#if defined(OBJ_ELF) || defined(OBJ_MAYBE_ELF)
+      if (IS_ELF)
+       S_SET_OTHER (label, STO_MIPS16);
 #endif
-         val = S_GET_VALUE (l->label);
-         if ((val & 1) == 0)
-           S_SET_VALUE (l->label, val + 1);
-       }
+      if ((S_GET_VALUE (label) & 1) == 0
+       /* Don't adjust the address if the label is global or weak, or
+          in a link-once section, since we'll be emitting symbol reloc
+          references to it which will be patched up by the linker, and
+          the final value of the symbol may or may not be MIPS16.  */
+         && ! S_IS_WEAK (label)
+         && ! S_IS_EXTERNAL (label)
+         && ! s_is_linkonce (label, now_seg))
+       S_SET_VALUE (label, S_GET_VALUE (label) | 1);
     }
 }
 
@@ -2155,9 +2518,10 @@ static void
 append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
             bfd_reloc_code_real_type *reloc_type)
 {
-  register unsigned long prev_pinfo, pinfo;
+  unsigned long prev_pinfo, pinfo;
   relax_stateT prev_insn_frag_type = 0;
   bfd_boolean relaxed_branch = FALSE;
+  segment_info_type *si = seg_info (now_seg);
 
   /* Mark instruction labels in mips16 mode.  */
   mips16_mark_labels ();
@@ -2295,9 +2659,10 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
           && ! ip->use_extend
           && *reloc_type != BFD_RELOC_MIPS16_JMP)
     {
-      /* Make sure there is enough room to swap this instruction with
-         a following jump instruction.  */
-      frag_grow (6);
+      if ((pinfo & INSN_UNCOND_BRANCH_DELAY) == 0)
+       /* Make sure there is enough room to swap this instruction with
+          a following jump instruction.  */
+       frag_grow (6);
       add_fixed_insn (ip);
     }
   else
@@ -2371,9 +2736,6 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
              if ((address_expr->X_add_number & 3) != 0)
                as_bad (_("jump to misaligned address (0x%lx)"),
                        (unsigned long) address_expr->X_add_number);
-             if (address_expr->X_add_number & ~0xfffffff)
-               as_bad (_("jump address range overflow (0x%lx)"),
-                       (unsigned long) address_expr->X_add_number);
              ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0x3ffffff;
              break;
 
@@ -2381,9 +2743,6 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
              if ((address_expr->X_add_number & 3) != 0)
                as_bad (_("jump to misaligned address (0x%lx)"),
                        (unsigned long) address_expr->X_add_number);
-             if (address_expr->X_add_number & ~0xfffffff)
-               as_bad (_("jump address range overflow (0x%lx)"),
-                       (unsigned long) address_expr->X_add_number);
              ip->insn_opcode |=
                (((address_expr->X_add_number & 0x7c0000) << 3)
                 | ((address_expr->X_add_number & 0xf800000) >> 7)
@@ -2391,7 +2750,16 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
              break;
 
            case BFD_RELOC_16_PCREL_S2:
-             goto need_reloc;
+             if ((address_expr->X_add_number & 3) != 0)
+               as_bad (_("branch to misaligned address (0x%lx)"),
+                       (unsigned long) address_expr->X_add_number);
+             if (mips_relax_branch)
+               goto need_reloc;
+             if ((address_expr->X_add_number + 0x20000) & ~0x3ffff)
+               as_bad (_("branch address range overflow (0x%lx)"),
+                       (unsigned long) address_expr->X_add_number);
+             ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0xffff;
+             break;
 
            default:
              internalError ();
@@ -2570,7 +2938,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
                 whether there is a label on this instruction.  If
                 there are any branches to anything other than a
                 label, users must use .set noreorder.  */
-             || insn_labels != NULL
+             || si->label_list != NULL
              /* If the previous instruction is in a variant frag
                 other than this branch's one, we cannot do the swap.
                 This does not apply to the mips16, which uses variant
@@ -2674,12 +3042,26 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
                 sync.p, we can not swap.  */
              || (prev_pinfo & INSN_SYNC))
            {
-             /* We could do even better for unconditional branches to
-                portions of this object file; we could pick up the
-                instruction at the destination, put it in the delay
-                slot, and bump the destination address.  */
-             insert_into_history (0, 1, ip);
-             emit_nop ();
+             if (mips_opts.mips16
+                 && (pinfo & INSN_UNCOND_BRANCH_DELAY)
+                 && (pinfo & (MIPS16_INSN_READ_X | MIPS16_INSN_READ_31))
+                 && ISA_SUPPORTS_MIPS16E)
+               {
+                 /* Convert MIPS16 jr/jalr into a "compact" jump.  */
+                 ip->insn_opcode |= 0x0080;
+                 install_insn (ip);
+                 insert_into_history (0, 1, ip);
+               } 
+             else
+               {
+                 /* We could do even better for unconditional branches to
+                    portions of this object file; we could pick up the
+                    instruction at the destination, put it in the delay
+                    slot, and bump the destination address.  */
+                 insert_into_history (0, 1, ip);
+                 emit_nop ();
+               }
+               
              if (mips_relax.sequence)
                mips_relax.sizes[mips_relax.sequence - 1] += 4;
            }
@@ -2690,7 +3072,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
              if (mips_opts.mips16)
                {
                  know (delay.frag == ip->frag);
-                 move_insn (ip, delay.frag, delay.where);
+                  move_insn (ip, delay.frag, delay.where);
                  move_insn (&delay, ip->frag, ip->where + insn_length (ip));
                }
              else if (relaxed_branch)
@@ -2946,12 +3328,13 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
   assert (strcmp (name, mo->name) == 0);
 
   /* Search until we get a match for NAME.  It is assumed here that
-     macros will never generate MDMX or MIPS-3D instructions.  */
+     macros will never generate MDMX, MIPS-3D, DSP or MT instructions.  */
   while (strcmp (fmt, mo->args) != 0
         || mo->pinfo == INSN_MACRO
         || !OPCODE_IS_MEMBER (mo,
                               (mips_opts.isa
-                               | (file_ase_mips16 ? INSN_MIPS16 : 0)),
+                               | (mips_opts.mips16 ? INSN_MIPS16 : 0)
+                               | (mips_opts.ase_smartmips ? INSN_SMARTMIPS : 0)),
                               mips_opts.arch)
         || (mips_opts.arch == CPU_R4650 && (mo->pinfo & FP_D) != 0))
     {
@@ -3103,15 +3486,22 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
 
        case 'p':
          assert (ep != NULL);
+
          /*
           * This allows macro() to pass an immediate expression for
           * creating short branches without creating a symbol.
-          * Note that the expression still might come from the assembly
-          * input, in which case the value is not checked for range nor
-          * is a relocation entry generated (yuck).
+          *
+          * We don't allow branch relaxation for these branches, as
+          * they should only appear in ".set nomacro" anyway.
           */
          if (ep->X_op == O_constant)
            {
+             if ((ep->X_add_number & 3) != 0)
+               as_bad (_("branch to misaligned address (0x%lx)"),
+                       (unsigned long) ep->X_add_number);
+             if ((ep->X_add_number + 0x20000) & ~0x3ffff)
+               as_bad (_("branch address range overflow (0x%lx)"),
+                       (unsigned long) ep->X_add_number);
              insn.insn_opcode |= (ep->X_add_number >> 2) & 0xffff;
              ep = NULL;
            }
@@ -3125,7 +3515,11 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
          continue;
 
        case 'C':
-         insn.insn_opcode |= va_arg (args, unsigned long);
+         INSERT_OPERAND (COPZ, insn, va_arg (args, unsigned long));
+         continue;
+
+       case 'k':
+         INSERT_OPERAND (CACHE, insn, va_arg (args, unsigned long));
          continue;
 
        default:
@@ -3209,7 +3603,7 @@ mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
 
            regno = va_arg (args, int);
            regno = ((regno & 7) << 2) | ((regno & 0x18) >> 3);
-           insn.insn_opcode |= regno << MIPS16OP_SH_REG32R;
+           MIPS16_INSERT_OPERAND (REG32R, insn, regno);
          }
          continue;
 
@@ -3558,7 +3952,7 @@ load_register (int reg, expressionS *ep, int dbl)
       char value[32];
 
       sprintf_vma (value, ep->X_add_number);
-      as_bad (_("Number (%s) larger than 32 bits"), value);
+      as_bad (_("Number (0x%s) larger than 32 bits"), value);
       macro_build (ep, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
       return;
     }
@@ -3846,7 +4240,7 @@ load_address (int reg, expressionS *ep, int *used_at)
            relax_end ();
        }
     }
-  else if (mips_pic == SVR4_PIC && ! mips_big_got)
+  else if (!mips_big_got)
     {
       expressionS ex;
 
@@ -3907,7 +4301,7 @@ load_address (int reg, expressionS *ep, int *used_at)
            }
        }
     }
-  else if (mips_pic == SVR4_PIC)
+  else if (mips_big_got)
     {
       expressionS ex;
 
@@ -4102,7 +4496,7 @@ add_got_offset_hilo (int dest, expressionS *local, int tmp)
 static void
 macro (struct mips_cl_insn *ip)
 {
-  register int treg, sreg, dreg, breg;
+  int treg, sreg, dreg, breg;
   int tempreg;
   int mask;
   int used_at = 0;
@@ -4959,7 +5353,7 @@ macro (struct mips_cl_insn *ip)
                relax_end ();
            }
        }
-      else if (mips_pic == SVR4_PIC && ! mips_big_got && ! HAVE_NEWABI)
+      else if (!mips_big_got && !HAVE_NEWABI)
        {
          int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT16;
 
@@ -4995,7 +5389,9 @@ macro (struct mips_cl_insn *ip)
 
          if (offset_expr.X_add_number == 0)
            {
-             if (breg == 0 && (call || tempreg == PIC_CALL_REG))
+             if (mips_pic == SVR4_PIC
+                 && breg == 0
+                 && (call || tempreg == PIC_CALL_REG))
                lw_reloc_type = (int) BFD_RELOC_MIPS_CALL16;
 
              relax_start (offset_expr.X_add_symbol);
@@ -5052,7 +5448,7 @@ macro (struct mips_cl_insn *ip)
              used_at = 1;
            }
        }
-      else if (mips_pic == SVR4_PIC && ! mips_big_got && HAVE_NEWABI)
+      else if (!mips_big_got && HAVE_NEWABI)
        {
          int add_breg_early = 0;
 
@@ -5155,7 +5551,7 @@ macro (struct mips_cl_insn *ip)
                           BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
            }
        }
-      else if (mips_pic == SVR4_PIC && ! HAVE_NEWABI)
+      else if (mips_big_got && !HAVE_NEWABI)
        {
          int gpdelay;
          int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16;
@@ -5312,7 +5708,7 @@ macro (struct mips_cl_insn *ip)
            }
          relax_end ();
        }
-      else if (mips_pic == SVR4_PIC && HAVE_NEWABI)
+      else if (mips_big_got && HAVE_NEWABI)
        {
          int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16;
          int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16;
@@ -5445,13 +5841,13 @@ macro (struct mips_cl_insn *ip)
     case M_JAL_2:
       if (mips_pic == NO_PIC)
        macro_build (NULL, "jalr", "d,s", dreg, sreg);
-      else if (mips_pic == SVR4_PIC)
+      else
        {
          if (sreg != PIC_CALL_REG)
            as_warn (_("MIPS PIC call to register other than $25"));
 
          macro_build (NULL, "jalr", "d,s", dreg, sreg);
-         if (HAVE_NEWABI)
+         if (mips_pic == SVR4_PIC && !HAVE_NEWABI)
            {
              if (mips_cprestore_offset < 0)
                as_warn (_("No .cprestore pseudo-op used in PIC code"));
@@ -5477,8 +5873,6 @@ macro (struct mips_cl_insn *ip)
                }
            }
        }
-      else
-       abort ();
 
       break;
 
@@ -5614,6 +6008,8 @@ macro (struct mips_cl_insn *ip)
                }
            }
        }
+      else if (mips_pic == VXWORKS_PIC)
+       as_bad (_("Non-PIC jump used in PIC library"));
       else
        abort ();
 
@@ -5750,6 +6146,9 @@ macro (struct mips_cl_insn *ip)
     case M_SCD_AB:
       s = "scd";
       goto st;
+    case M_CACHE_AB:
+      s = "cache";
+      goto st;
     case M_SDC1_AB:
       if (mips_opts.arch == CPU_R4650)
        {
@@ -5787,6 +6186,8 @@ macro (struct mips_cl_insn *ip)
          || mask == M_L_DAB
          || mask == M_S_DAB)
        fmt = "T,o(b)";
+      else if (mask == M_CACHE_AB)
+       fmt = "k,o(b)";
       else if (coproc)
        fmt = "E,o(b)";
       else
@@ -5805,7 +6206,7 @@ macro (struct mips_cl_insn *ip)
          char value [32];
 
          sprintf_vma (value, offset_expr.X_add_number);
-         as_bad (_("Number (%s) larger than 32 bits"), value);
+         as_bad (_("Number (0x%s) larger than 32 bits"), value);
        }
 
       /* A constant expression in PIC code can be handled just as it
@@ -5974,7 +6375,7 @@ macro (struct mips_cl_insn *ip)
                relax_end ();
            }
        }
-      else if (mips_pic == SVR4_PIC && ! mips_big_got)
+      else if (!mips_big_got)
        {
          int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT16;
 
@@ -6028,7 +6429,7 @@ macro (struct mips_cl_insn *ip)
                         tempreg, tempreg, breg);
          macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg);
        }
-      else if (mips_pic == SVR4_PIC && ! HAVE_NEWABI)
+      else if (mips_big_got && !HAVE_NEWABI)
        {
          int gpdelay;
 
@@ -6077,7 +6478,7 @@ macro (struct mips_cl_insn *ip)
                         tempreg, tempreg, breg);
          macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg);
        }
-      else if (mips_pic == SVR4_PIC && HAVE_NEWABI)
+      else if (mips_big_got && HAVE_NEWABI)
        {
          /* If this is a reference to an external symbol, we want
               lui      $tempreg,<sym>          (BFD_RELOC_MIPS_GOT_HI16)
@@ -6197,14 +6598,12 @@ macro (struct mips_cl_insn *ip)
          macro_build_lui (&offset_expr, AT);
          used_at = 1;
        }
-      else if (mips_pic == SVR4_PIC)
+      else
        {
          macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", AT,
                       BFD_RELOC_MIPS_GOT16, mips_gp_register);
          used_at = 1;
        }
-      else
-       abort ();
 
       /* Now we load the register(s).  */
       if (HAVE_64BIT_GPRS)
@@ -6276,7 +6675,7 @@ macro (struct mips_cl_insn *ip)
        {
          assert (strcmp (s, RDATA_SECTION_NAME) == 0);
          used_at = 1;
-         if (mips_pic == SVR4_PIC)
+         if (mips_pic != NO_PIC)
            macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", AT,
                         BFD_RELOC_MIPS_GOT16, mips_gp_register);
          else
@@ -6399,7 +6798,7 @@ macro (struct mips_cl_insn *ip)
          char value [32];
 
          sprintf_vma (value, offset_expr.X_add_number);
-         as_bad (_("Number (%s) larger than 32 bits"), value);
+         as_bad (_("Number (0x%s) larger than 32 bits"), value);
        }
 
       /* Even on a big endian machine $fn comes before $fn+1.  We have
@@ -6495,7 +6894,7 @@ macro (struct mips_cl_insn *ip)
          if (mips_relax.sequence)
            relax_end ();
        }
-      else if (mips_pic == SVR4_PIC && ! mips_big_got)
+      else if (!mips_big_got)
        {
          /* If this is a reference to an external symbol, we want
               lw       $at,<sym>($gp)          (BFD_RELOC_MIPS_GOT16)
@@ -6542,7 +6941,7 @@ macro (struct mips_cl_insn *ip)
 
          mips_optimize = hold_mips_optimize;
        }
-      else if (mips_pic == SVR4_PIC)
+      else if (mips_big_got)
        {
          int gpdelay;
 
@@ -6701,7 +7100,7 @@ macro (struct mips_cl_insn *ip)
 static void
 macro2 (struct mips_cl_insn *ip)
 {
-  register int treg, sreg, dreg, breg;
+  int treg, sreg, dreg, breg;
   int tempreg;
   int mask;
   int used_at;
@@ -7746,6 +8145,10 @@ validate_mips_insn (const struct mips_opcode *opc)
       case '+':
        switch (c = *p++)
          {
+         case '1': USE_BITS (OP_MASK_UDI1,     OP_SH_UDI1);    break;
+         case '2': USE_BITS (OP_MASK_UDI2,     OP_SH_UDI2);    break;
+         case '3': USE_BITS (OP_MASK_UDI3,     OP_SH_UDI3);    break;
+         case '4': USE_BITS (OP_MASK_UDI4,     OP_SH_UDI4);    break;
          case 'A': USE_BITS (OP_MASK_SHAMT,    OP_SH_SHAMT);   break;
          case 'B': USE_BITS (OP_MASK_INSMSB,   OP_SH_INSMSB);  break;
          case 'C': USE_BITS (OP_MASK_EXTMSBD,  OP_SH_EXTMSBD); break;
@@ -7756,6 +8159,9 @@ validate_mips_insn (const struct mips_opcode *opc)
          case 'G': USE_BITS (OP_MASK_EXTMSBD,  OP_SH_EXTMSBD); break;
          case 'H': USE_BITS (OP_MASK_EXTMSBD,  OP_SH_EXTMSBD); break;
          case 'I': break;
+         case 't': USE_BITS (OP_MASK_RT,       OP_SH_RT);      break;
+         case 'T': USE_BITS (OP_MASK_RT,       OP_SH_RT);
+                   USE_BITS (OP_MASK_SEL,      OP_SH_SEL);     break;
          default:
            as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
                    c, opc->name, opc->args);
@@ -7817,6 +8223,22 @@ validate_mips_insn (const struct mips_opcode *opc)
       case '%': USE_BITS (OP_MASK_VECALIGN,    OP_SH_VECALIGN); break;
       case '[': break;
       case ']': break;
+      case '3': USE_BITS (OP_MASK_SA3,         OP_SH_SA3);     break;
+      case '4': USE_BITS (OP_MASK_SA4,         OP_SH_SA4);     break;
+      case '5': USE_BITS (OP_MASK_IMM8,        OP_SH_IMM8);    break;
+      case '6': USE_BITS (OP_MASK_RS,          OP_SH_RS);      break;
+      case '7': USE_BITS (OP_MASK_DSPACC,      OP_SH_DSPACC);  break;
+      case '8': USE_BITS (OP_MASK_WRDSP,       OP_SH_WRDSP);   break;
+      case '9': USE_BITS (OP_MASK_DSPACC_S,    OP_SH_DSPACC_S);break;
+      case '0': USE_BITS (OP_MASK_DSPSFT,      OP_SH_DSPSFT);  break;
+      case '\'': USE_BITS (OP_MASK_RDDSP,      OP_SH_RDDSP);   break;
+      case ':': USE_BITS (OP_MASK_DSPSFT_7,    OP_SH_DSPSFT_7);break;
+      case '@': USE_BITS (OP_MASK_IMM10,       OP_SH_IMM10);   break;
+      case '!': USE_BITS (OP_MASK_MT_U,                OP_SH_MT_U);    break;
+      case '$': USE_BITS (OP_MASK_MT_H,                OP_SH_MT_H);    break;
+      case '*': USE_BITS (OP_MASK_MTACC_T,     OP_SH_MTACC_T); break;
+      case '&': USE_BITS (OP_MASK_MTACC_D,     OP_SH_MTACC_D); break;
+      case 'g': USE_BITS (OP_MASK_RD,          OP_SH_RD);      break;
       default:
        as_bad (_("internal: bad mips opcode (unknown operand type `%c'): %s %s"),
                c, opc->name, opc->args);
@@ -7832,6 +8254,62 @@ validate_mips_insn (const struct mips_opcode *opc)
   return 1;
 }
 
+/* UDI immediates.  */
+struct mips_immed {
+  char         type;
+  unsigned int shift;
+  unsigned long        mask;
+  const char * desc;
+};
+
+static const struct mips_immed mips_immed[] = {
+  { '1',       OP_SH_UDI1,     OP_MASK_UDI1,           0},
+  { '2',       OP_SH_UDI2,     OP_MASK_UDI2,           0},
+  { '3',       OP_SH_UDI3,     OP_MASK_UDI3,           0},
+  { '4',       OP_SH_UDI4,     OP_MASK_UDI4,           0},
+  { 0,0,0,0 }
+};
+
+/* Check whether an odd floating-point register is allowed.  */
+static int
+mips_oddfpreg_ok (const struct mips_opcode *insn, int argnum)
+{
+  const char *s = insn->name;
+
+  if (insn->pinfo == INSN_MACRO)
+    /* Let a macro pass, we'll catch it later when it is expanded.  */
+    return 1;
+
+  if (ISA_HAS_ODD_SINGLE_FPR (mips_opts.isa))
+    {
+      /* Allow odd registers for single-precision ops.  */
+      switch (insn->pinfo & (FP_S | FP_D))
+       {
+       case FP_S:
+       case 0:
+         return 1;     /* both single precision - ok */
+       case FP_D:
+         return 0;     /* both double precision - fail */
+       default:
+         break;
+       }
+
+      /* Cvt.w.x and cvt.x.w allow an odd register for a 'w' or 's' operand.  */
+      s = strchr (insn->name, '.');
+      if (argnum == 2)
+       s = s != NULL ? strchr (s + 1, '.') : NULL;
+      return (s != NULL && (s[1] == 'w' || s[1] == 's'));
+    } 
+
+  /* Single-precision coprocessor loads and moves are OK too.  */
+  if ((insn->pinfo & FP_S)
+      && (insn->pinfo & (INSN_COPROC_MEMORY_DELAY | INSN_STORE_MEMORY
+                        | INSN_LOAD_COPROC_DELAY | INSN_COPROC_MOVE_DELAY)))
+    return 1;
+
+  return 0;
+}
+
 /* This routine assembles an instruction into its binary format.  As a
    side effect, it sets one of the global variables imm_reloc or
    offset_reloc to the type of relocation to do if one of the operands
@@ -7851,6 +8329,9 @@ mips_ip (char *str, struct mips_cl_insn *ip)
   unsigned int limlo, limhi;
   char *s_reset;
   char save_c = 0;
+  offsetT min_range, max_range;
+  int argnum;
+  unsigned int rtype;
 
   insn_error = NULL;
 
@@ -7911,9 +8392,17 @@ mips_ip (char *str, struct mips_cl_insn *ip)
 
       if (OPCODE_IS_MEMBER (insn,
                            (mips_opts.isa
+                            /* We don't check for mips_opts.mips16 here since
+                               we want to allow jalx if -mips16 was specified
+                               on the command line.  */
                             | (file_ase_mips16 ? INSN_MIPS16 : 0)
                             | (mips_opts.ase_mdmx ? INSN_MDMX : 0)
-                            | (mips_opts.ase_mips3d ? INSN_MIPS3D : 0)),
+                            | (mips_opts.ase_dsp ? INSN_DSP : 0)
+                            | ((mips_opts.ase_dsp && ISA_SUPPORTS_DSP64_ASE)
+                               ? INSN_DSP64 : 0)
+                            | (mips_opts.ase_mt ? INSN_MT : 0)
+                            | (mips_opts.ase_mips3d ? INSN_MIPS3D : 0)
+                            | (mips_opts.ase_smartmips ? INSN_SMARTMIPS : 0)),
                            mips_opts.arch))
        ok = TRUE;
       else
@@ -7952,6 +8441,7 @@ mips_ip (char *str, struct mips_cl_insn *ip)
 
       create_insn (ip, insn);
       insn_error = NULL;
+      argnum = 1;
       for (args = insn->args;; ++args)
        {
          int is_mdmx;
@@ -7965,7 +8455,213 @@ mips_ip (char *str, struct mips_cl_insn *ip)
                return;
              break;
 
+           case '3': /* dsp 3-bit unsigned immediate in bit 21 */
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+             if (imm_expr.X_add_number & ~OP_MASK_SA3)
+               {
+                 as_bad (_("DSP immediate not in range 0..%d (%lu)"),
+                         OP_MASK_SA3, (unsigned long) imm_expr.X_add_number);
+               }
+             INSERT_OPERAND (SA3, *ip, imm_expr.X_add_number);
+             imm_expr.X_op = O_absent;
+             s = expr_end;
+             continue;
+
+           case '4': /* dsp 4-bit unsigned immediate in bit 21 */
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+             if (imm_expr.X_add_number & ~OP_MASK_SA4)
+               {
+                 as_bad (_("DSP immediate not in range 0..%d (%lu)"),
+                         OP_MASK_SA4, (unsigned long) imm_expr.X_add_number);
+               }
+             INSERT_OPERAND (SA4, *ip, imm_expr.X_add_number);
+             imm_expr.X_op = O_absent;
+             s = expr_end;
+             continue;
+
+           case '5': /* dsp 8-bit unsigned immediate in bit 16 */
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+             if (imm_expr.X_add_number & ~OP_MASK_IMM8)
+               {
+                 as_bad (_("DSP immediate not in range 0..%d (%lu)"),
+                         OP_MASK_IMM8, (unsigned long) imm_expr.X_add_number);
+               }
+             INSERT_OPERAND (IMM8, *ip, imm_expr.X_add_number);
+             imm_expr.X_op = O_absent;
+             s = expr_end;
+             continue;
+
+           case '6': /* dsp 5-bit unsigned immediate in bit 21 */
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+             if (imm_expr.X_add_number & ~OP_MASK_RS)
+               {
+                 as_bad (_("DSP immediate not in range 0..%d (%lu)"),
+                         OP_MASK_RS, (unsigned long) imm_expr.X_add_number);
+               }
+             INSERT_OPERAND (RS, *ip, imm_expr.X_add_number);
+             imm_expr.X_op = O_absent;
+             s = expr_end;
+             continue;
+
+           case '7': /* four dsp accumulators in bits 11,12 */ 
+             if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
+                 s[3] >= '0' && s[3] <= '3')
+               {
+                 regno = s[3] - '0';
+                 s += 4;
+                 INSERT_OPERAND (DSPACC, *ip, regno);
+                 continue;
+               }
+             else
+               as_bad (_("Invalid dsp acc register"));
+             break;
+
+           case '8': /* dsp 6-bit unsigned immediate in bit 11 */
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+             if (imm_expr.X_add_number & ~OP_MASK_WRDSP)
+               {
+                 as_bad (_("DSP immediate not in range 0..%d (%lu)"),
+                         OP_MASK_WRDSP,
+                         (unsigned long) imm_expr.X_add_number);
+               }
+             INSERT_OPERAND (WRDSP, *ip, imm_expr.X_add_number);
+             imm_expr.X_op = O_absent;
+             s = expr_end;
+             continue;
+
+           case '9': /* four dsp accumulators in bits 21,22 */
+             if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
+                 s[3] >= '0' && s[3] <= '3')
+               {
+                 regno = s[3] - '0';
+                 s += 4;
+                 INSERT_OPERAND (DSPACC_S, *ip, regno);
+                 continue;
+               }
+             else
+               as_bad (_("Invalid dsp acc register"));
+             break;
+
+           case '0': /* dsp 6-bit signed immediate in bit 20 */
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+             min_range = -((OP_MASK_DSPSFT + 1) >> 1);
+             max_range = ((OP_MASK_DSPSFT + 1) >> 1) - 1;
+             if (imm_expr.X_add_number < min_range ||
+                 imm_expr.X_add_number > max_range)
+               {
+                 as_bad (_("DSP immediate not in range %ld..%ld (%ld)"),
+                         (long) min_range, (long) max_range,
+                         (long) imm_expr.X_add_number);
+               }
+             INSERT_OPERAND (DSPSFT, *ip, imm_expr.X_add_number);
+             imm_expr.X_op = O_absent;
+             s = expr_end;
+             continue;
+
+           case '\'': /* dsp 6-bit unsigned immediate in bit 16 */
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+             if (imm_expr.X_add_number & ~OP_MASK_RDDSP)
+               {
+                 as_bad (_("DSP immediate not in range 0..%d (%lu)"),
+                         OP_MASK_RDDSP,
+                         (unsigned long) imm_expr.X_add_number);
+               }
+             INSERT_OPERAND (RDDSP, *ip, imm_expr.X_add_number);
+             imm_expr.X_op = O_absent;
+             s = expr_end;
+             continue;
+
+           case ':': /* dsp 7-bit signed immediate in bit 19 */
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+             min_range = -((OP_MASK_DSPSFT_7 + 1) >> 1);
+             max_range = ((OP_MASK_DSPSFT_7 + 1) >> 1) - 1;
+             if (imm_expr.X_add_number < min_range ||
+                 imm_expr.X_add_number > max_range)
+               {
+                 as_bad (_("DSP immediate not in range %ld..%ld (%ld)"),
+                         (long) min_range, (long) max_range,
+                         (long) imm_expr.X_add_number);
+               }
+             INSERT_OPERAND (DSPSFT_7, *ip, imm_expr.X_add_number);
+             imm_expr.X_op = O_absent;
+             s = expr_end;
+             continue;
+
+           case '@': /* dsp 10-bit signed immediate in bit 16 */
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+             min_range = -((OP_MASK_IMM10 + 1) >> 1);
+             max_range = ((OP_MASK_IMM10 + 1) >> 1) - 1;
+             if (imm_expr.X_add_number < min_range ||
+                 imm_expr.X_add_number > max_range)
+               {
+                 as_bad (_("DSP immediate not in range %ld..%ld (%ld)"),
+                         (long) min_range, (long) max_range,
+                         (long) imm_expr.X_add_number);
+               }
+             INSERT_OPERAND (IMM10, *ip, imm_expr.X_add_number);
+             imm_expr.X_op = O_absent;
+             s = expr_end;
+             continue;
+
+            case '!': /* MT usermode flag bit.  */
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+             if (imm_expr.X_add_number & ~OP_MASK_MT_U)
+               as_bad (_("MT usermode bit not 0 or 1 (%lu)"),
+                       (unsigned long) imm_expr.X_add_number);
+             INSERT_OPERAND (MT_U, *ip, imm_expr.X_add_number);
+             imm_expr.X_op = O_absent;
+             s = expr_end;
+             continue;
+
+            case '$': /* MT load high flag bit.  */
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+             if (imm_expr.X_add_number & ~OP_MASK_MT_H)
+               as_bad (_("MT load high bit not 0 or 1 (%lu)"),
+                       (unsigned long) imm_expr.X_add_number);
+             INSERT_OPERAND (MT_H, *ip, imm_expr.X_add_number);
+             imm_expr.X_op = O_absent;
+             s = expr_end;
+             continue;
+
+           case '*': /* four dsp accumulators in bits 18,19 */ 
+             if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
+                 s[3] >= '0' && s[3] <= '3')
+               {
+                 regno = s[3] - '0';
+                 s += 4;
+                 INSERT_OPERAND (MTACC_T, *ip, regno);
+                 continue;
+               }
+             else
+               as_bad (_("Invalid dsp/smartmips acc register"));
+             break;
+
+           case '&': /* four dsp accumulators in bits 13,14 */ 
+             if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
+                 s[3] >= '0' && s[3] <= '3')
+               {
+                 regno = s[3] - '0';
+                 s += 4;
+                 INSERT_OPERAND (MTACC_D, *ip, regno);
+                 continue;
+               }
+             else
+               as_bad (_("Invalid dsp/smartmips acc register"));
+             break;
+
            case ',':
+             ++argnum;
              if (*s++ == *args)
                continue;
              s--;
@@ -8011,6 +8707,34 @@ mips_ip (char *str, struct mips_cl_insn *ip)
            case '+':           /* Opcode extension character.  */
              switch (*++args)
                {
+               case '1':       /* UDI immediates.  */
+               case '2':
+               case '3':
+               case '4':
+                 {
+                   const struct mips_immed *imm = mips_immed;
+
+                   while (imm->type && imm->type != *args)
+                     ++imm;
+                   if (! imm->type)
+                     internalError ();
+                   my_getExpression (&imm_expr, s);
+                   check_absolute_expr (ip, &imm_expr);
+                   if ((unsigned long) imm_expr.X_add_number & ~imm->mask)
+                     {
+                       as_warn (_("Illegal %s number (%lu, 0x%lx)"),
+                                imm->desc ? imm->desc : ip->insn_mo->name,
+                                (unsigned long) imm_expr.X_add_number,
+                                (unsigned long) imm_expr.X_add_number);
+                             imm_expr.X_add_number &= imm->mask;
+                     }
+                   ip->insn_opcode |= ((unsigned long) imm_expr.X_add_number
+                                       << imm->shift);
+                   imm_expr.X_op = O_absent;
+                   s = expr_end;
+                 }
+                 continue;
+                 
                case 'A':               /* ins/ext position, becomes LSB.  */
                  limlo = 0;
                  limhi = 31;
@@ -8117,13 +8841,41 @@ do_msbd:
                  s = expr_end;
                  continue;
 
-               default:
-                 as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
-                   *args, insn->name, insn->args);
-                 /* Further processing is fruitless.  */
-                 return;
-               }
-             break;
+               case 'T': /* Coprocessor register.  */
+                 /* +T is for disassembly only; never match.  */
+                 break;
+
+               case 't': /* Coprocessor register number.  */
+                 if (s[0] == '$' && ISDIGIT (s[1]))
+                   {
+                     ++s;
+                     regno = 0;
+                     do
+                       {
+                         regno *= 10;
+                         regno += *s - '0';
+                         ++s;
+                       }
+                     while (ISDIGIT (*s));
+                     if (regno > 31)
+                       as_bad (_("Invalid register number (%d)"), regno);
+                     else
+                       {
+                         INSERT_OPERAND (RT, *ip, regno);
+                         continue;
+                       }
+                   }
+                 else
+                   as_bad (_("Invalid coprocessor 0 register number"));
+                 break;
+
+               default:
+                 as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
+                   *args, insn->name, insn->args);
+                 /* Further processing is fruitless.  */
+                 return;
+               }
+             break;
 
            case '<':           /* must be at least one digit */
              /*
@@ -8172,8 +8924,9 @@ do_msbd:
            case 'c':           /* break code */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
-             if ((unsigned long) imm_expr.X_add_number > 1023)
-               as_warn (_("Illegal break code (%lu)"),
+             if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE)
+               as_warn (_("Code for %s not in range 0..1023 (%lu)"),
+                        ip->insn_mo->name,
                         (unsigned long) imm_expr.X_add_number);
              INSERT_OPERAND (CODE, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
@@ -8183,8 +8936,9 @@ do_msbd:
            case 'q':           /* lower break code */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
-             if ((unsigned long) imm_expr.X_add_number > 1023)
-               as_warn (_("Illegal lower break code (%lu)"),
+             if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE2)
+               as_warn (_("Lower code for %s not in range 0..1023 (%lu)"),
+                        ip->insn_mo->name,
                         (unsigned long) imm_expr.X_add_number);
              INSERT_OPERAND (CODE2, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
@@ -8195,7 +8949,8 @@ do_msbd:
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE20)
-               as_warn (_("Illegal 20-bit code (%lu)"),
+               as_warn (_("Code for %s not in range 0..1048575 (%lu)"),
+                        ip->insn_mo->name,
                         (unsigned long) imm_expr.X_add_number);
              INSERT_OPERAND (CODE20, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
@@ -8205,13 +8960,13 @@ do_msbd:
            case 'C':           /* Coprocessor code */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
-             if ((unsigned long) imm_expr.X_add_number >= (1 << 25))
+             if ((unsigned long) imm_expr.X_add_number > OP_MASK_COPZ)
                {
                  as_warn (_("Coproccesor code > 25 bits (%lu)"),
                           (unsigned long) imm_expr.X_add_number);
-                 imm_expr.X_add_number &= ((1 << 25) - 1);
+                 imm_expr.X_add_number &= OP_MASK_COPZ;
                }
-             ip->insn_opcode |= imm_expr.X_add_number;
+             INSERT_OPERAND (COPZ, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              s = expr_end;
              continue;
@@ -8220,14 +8975,17 @@ do_msbd:
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE19)
-               as_warn (_("Illegal 19-bit code (%lu)"),
-                        (unsigned long) imm_expr.X_add_number);
+               {
+                 as_warn (_("Illegal 19-bit code (%lu)"),
+                          (unsigned long) imm_expr.X_add_number);
+                 imm_expr.X_add_number &= OP_MASK_CODE19;
+               }
              INSERT_OPERAND (CODE19, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              s = expr_end;
              continue;
 
-           case 'P':           /* Performance register */
+           case 'P':           /* Performance register */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if (imm_expr.X_add_number != 0 && imm_expr.X_add_number != 1)
@@ -8238,6 +8996,20 @@ do_msbd:
              s = expr_end;
              continue;
 
+           case 'G':           /* Coprocessor destination register.  */
+             if (((ip->insn_opcode >> OP_SH_OP) & OP_MASK_OP) == OP_OP_COP0)
+               ok = reg_lookup (&s, RTYPE_NUM | RTYPE_CP0, &regno);
+             else
+               ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, &regno);
+             INSERT_OPERAND (RD, *ip, regno);
+             if (ok) 
+               {
+                 lastregno = regno;
+                 continue;
+               }
+             else
+               break;
+
            case 'b':           /* base register */
            case 'd':           /* destination register */
            case 's':           /* source register */
@@ -8246,106 +9018,22 @@ do_msbd:
            case 'v':           /* both dest and source */
            case 'w':           /* both dest and target */
            case 'E':           /* coprocessor target register */
-           case 'G':           /* coprocessor destination register */
            case 'K':           /* 'rdhwr' destination register */
            case 'x':           /* ignore register name */
            case 'z':           /* must be zero register */
            case 'U':           /* destination register (clo/clz).  */
-             s_reset = s;
-             if (s[0] == '$')
+           case 'g':           /* coprocessor destination register */
+             s_reset = s;            
+             if (*args == 'E' || *args == 'K')
+               ok = reg_lookup (&s, RTYPE_NUM, &regno);
+             else
+               {
+                 ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, &regno);
+                 if (regno == AT && ! mips_opts.noat)
+                   as_warn ("Used $at without \".set noat\"");
+               }
+             if (ok)
                {
-
-                 if (ISDIGIT (s[1]))
-                   {
-                     ++s;
-                     regno = 0;
-                     do
-                       {
-                         regno *= 10;
-                         regno += *s - '0';
-                         ++s;
-                       }
-                     while (ISDIGIT (*s));
-                     if (regno > 31)
-                       as_bad (_("Invalid register number (%d)"), regno);
-                   }
-                 else if (*args == 'E' || *args == 'G' || *args == 'K')
-                   goto notreg;
-                 else
-                   {
-                     if (s[1] == 'r' && s[2] == 'a')
-                       {
-                         s += 3;
-                         regno = RA;
-                       }
-                     else if (s[1] == 'f' && s[2] == 'p')
-                       {
-                         s += 3;
-                         regno = FP;
-                       }
-                     else if (s[1] == 's' && s[2] == 'p')
-                       {
-                         s += 3;
-                         regno = SP;
-                       }
-                     else if (s[1] == 'g' && s[2] == 'p')
-                       {
-                         s += 3;
-                         regno = GP;
-                       }
-                     else if (s[1] == 'a' && s[2] == 't')
-                       {
-                         s += 3;
-                         regno = AT;
-                       }
-                     else if (s[1] == 'k' && s[2] == 't' && s[3] == '0')
-                       {
-                         s += 4;
-                         regno = KT0;
-                       }
-                     else if (s[1] == 'k' && s[2] == 't' && s[3] == '1')
-                       {
-                         s += 4;
-                         regno = KT1;
-                       }
-                     else if (s[1] == 'z' && s[2] == 'e' && s[3] == 'r' && s[4] == 'o')
-                       {
-                         s += 5;
-                         regno = ZERO;
-                       }
-                     else if (itbl_have_entries)
-                       {
-                         char *p, *n;
-                         unsigned long r;
-
-                         p = s + 1;    /* advance past '$' */
-                         n = itbl_get_field (&p);  /* n is name */
-
-                         /* See if this is a register defined in an
-                            itbl entry.  */
-                         if (itbl_get_reg_val (n, &r))
-                           {
-                             /* Get_field advances to the start of
-                                the next field, so we need to back
-                                rack to the end of the last field.  */
-                             if (p)
-                               s = p - 1;
-                             else
-                               s = strchr (s, '\0');
-                             regno = r;
-                           }
-                         else
-                           goto notreg;
-                       }
-                     else
-                       goto notreg;
-                   }
-                 if (regno == AT
-                     && ! mips_opts.noat
-                     && *args != 'E'
-                     && *args != 'G'
-                     && *args != 'K')
-                   as_warn (_("Used $at without \".set noat\""));
                  c = *args;
                  if (*s == ' ')
                    ++s;
@@ -8375,6 +9063,7 @@ do_msbd:
                    case 'd':
                    case 'G':
                    case 'K':
+                   case 'g':
                      INSERT_OPERAND (RD, *ip, regno);
                      break;
                    case 'U':
@@ -8410,7 +9099,6 @@ do_msbd:
                  lastregno = regno;
                  continue;
                }
-           notreg:
              switch (*args++)
                {
                case 'r':
@@ -8463,34 +9151,22 @@ do_msbd:
            case 'R':           /* floating point source register */
            case 'V':
            case 'W':
+             rtype = RTYPE_FPU;
+             if (is_mdmx
+                 || (mips_opts.ase_mdmx
+                     && (ip->insn_mo->pinfo & FP_D)
+                     && (ip->insn_mo->pinfo & (INSN_COPROC_MOVE_DELAY
+                                               | INSN_COPROC_MEMORY_DELAY
+                                               | INSN_LOAD_COPROC_DELAY
+                                               | INSN_LOAD_MEMORY_DELAY
+                                               | INSN_STORE_MEMORY))))
+               rtype |= RTYPE_VEC;
              s_reset = s;
-             /* Accept $fN for FP and MDMX register numbers, and in
-                 addition accept $vN for MDMX register numbers.  */
-             if ((s[0] == '$' && s[1] == 'f' && ISDIGIT (s[2]))
-                 || (is_mdmx != 0 && s[0] == '$' && s[1] == 'v'
-                     && ISDIGIT (s[2])))
+             if (reg_lookup (&s, rtype, &regno))
                {
-                 s += 2;
-                 regno = 0;
-                 do
-                   {
-                     regno *= 10;
-                     regno += *s - '0';
-                     ++s;
-                   }
-                 while (ISDIGIT (*s));
-
-                 if (regno > 31)
-                   as_bad (_("Invalid float register number (%d)"), regno);
-
                  if ((regno & 1) != 0
                      && HAVE_32BIT_FPRS
-                     && ! (strcmp (str, "mtc1") == 0
-                           || strcmp (str, "mfc1") == 0
-                           || strcmp (str, "lwc1") == 0
-                           || strcmp (str, "swc1") == 0
-                           || strcmp (str, "l.s") == 0
-                           || strcmp (str, "s.s") == 0))
+                     && ! mips_oddfpreg_ok (ip->insn_mo, argnum))
                    as_warn (_("Float register should be even, was %d"),
                             regno);
 
@@ -8752,15 +9428,14 @@ do_msbd:
                        break;
                      }
                    new_seg = subseg_new (newname, (subsegT) 0);
-                   if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+                   if (IS_ELF)
                      bfd_set_section_flags (stdoutput, new_seg,
                                             (SEC_ALLOC
                                              | SEC_LOAD
                                              | SEC_READONLY
                                              | SEC_DATA));
                    frag_align (*args == 'l' ? 2 : 3, 0, 0);
-                   if (OUTPUT_FLAVOR == bfd_target_elf_flavour
-                       && strcmp (TARGET_OS, "elf") != 0)
+                   if (IS_ELF && strcmp (TARGET_OS, "elf") != 0)
                      record_alignment (new_seg, 4);
                    else
                      record_alignment (new_seg, *args == 'l' ? 2 : 3);
@@ -8878,19 +9553,11 @@ do_msbd:
 
            case 'N':           /* 3 bit branch condition code */
            case 'M':           /* 3 bit compare condition code */
-             if (strncmp (s, "$fcc", 4) != 0)
+             rtype = RTYPE_CCC;
+             if (ip->insn_mo->pinfo & (FP_D| FP_S))
+               rtype |= RTYPE_FCC;
+             if (!reg_lookup (&s, rtype, &regno))
                break;
-             s += 4;
-             regno = 0;
-             do
-               {
-                 regno *= 10;
-                 regno += *s - '0';
-                 ++s;
-               }
-             while (ISDIGIT (*s));
-             if (regno > 7)
-               as_bad (_("Invalid condition code register $fcc%d"), regno);
              if ((strcmp(str + strlen(str) - 3, ".ps") == 0
                   || strcmp(str + strlen(str) - 5, "any2f") == 0
                   || strcmp(str + strlen(str) - 5, "any2t") == 0)
@@ -8987,6 +9654,8 @@ do_msbd:
     }
 }
 
+#define SKIP_SPACE_TABS(S) { while (*(S) == ' ' || *(S) == '\t') ++(S); }
+
 /* This routine assembles an instruction into its binary format when
    assembling for the mips16.  As a side effect, it sets one of the
    global variables imm_reloc or offset_reloc to the type of
@@ -9055,8 +9724,38 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
   argsstart = s;
   for (;;)
     {
+      bfd_boolean ok;
+
       assert (strcmp (insn->name, str) == 0);
 
+      if (OPCODE_IS_MEMBER (insn, mips_opts.isa, mips_opts.arch))
+       ok = TRUE;
+      else
+       ok = FALSE;
+
+      if (! ok)
+       {
+         if (insn + 1 < &mips16_opcodes[bfd_mips16_num_opcodes]
+             && strcmp (insn->name, insn[1].name) == 0)
+           {
+             ++insn;
+             continue;
+           }
+         else
+           {
+             if (!insn_error)
+               {
+                 static char buf[100];
+                 sprintf (buf,
+                          _("opcode not supported on this processor: %s (%s)"),
+                          mips_cpu_info_from_arch (mips_opts.arch)->name,
+                          mips_cpu_info_from_isa (mips_opts.isa)->name);
+                 insn_error = buf;
+               }
+             return;
+           }
+       }
+
       create_insn (ip, insn);
       imm_expr.X_op = O_absent;
       imm_reloc[0] = BFD_RELOC_UNUSED;
@@ -9169,70 +9868,19 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
            case 'R':
            case 'X':
            case 'Y':
-             if (s[0] != '$')
-               break;
-             s_reset = s;
-             if (ISDIGIT (s[1]))
+             s_reset = s;
+             if (!reg_lookup (&s, RTYPE_NUM | RTYPE_GP, &regno))
                {
-                 ++s;
-                 regno = 0;
-                 do
-                   {
-                     regno *= 10;
-                     regno += *s - '0';
-                     ++s;
-                   }
-                 while (ISDIGIT (*s));
-                 if (regno > 31)
-                   {
-                     as_bad (_("invalid register number (%d)"), regno);
-                     regno = 2;
-                   }
-               }
-             else
-               {
-                 if (s[1] == 'r' && s[2] == 'a')
-                   {
-                     s += 3;
-                     regno = RA;
-                   }
-                 else if (s[1] == 'f' && s[2] == 'p')
-                   {
-                     s += 3;
-                     regno = FP;
-                   }
-                 else if (s[1] == 's' && s[2] == 'p')
-                   {
-                     s += 3;
-                     regno = SP;
-                   }
-                 else if (s[1] == 'g' && s[2] == 'p')
-                   {
-                     s += 3;
-                     regno = GP;
-                   }
-                 else if (s[1] == 'a' && s[2] == 't')
-                   {
-                     s += 3;
-                     regno = AT;
-                   }
-                 else if (s[1] == 'k' && s[2] == 't' && s[3] == '0')
-                   {
-                     s += 4;
-                     regno = KT0;
-                   }
-                 else if (s[1] == 'k' && s[2] == 't' && s[3] == '1')
-                   {
-                     s += 4;
-                     regno = KT1;
-                   }
-                 else if (s[1] == 'z' && s[2] == 'e' && s[3] == 'r' && s[4] == 'o')
+                 if (c == 'v' || c == 'w')
                    {
-                     s += 5;
-                     regno = ZERO;
+                     if (c == 'v')
+                       MIPS16_INSERT_OPERAND (RX, *ip, lastregno);
+                     else
+                       MIPS16_INSERT_OPERAND (RY, *ip, lastregno);
+                     ++args;
+                     continue;
                    }
-                 else
-                   break;
+                 break;
                }
 
              if (*s == ' ')
@@ -9438,29 +10086,18 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                  mask = 7 << 3;
                while (*s != '\0')
                  {
-                   int freg, reg1, reg2;
+                   unsigned int freg, reg1, reg2;
 
                    while (*s == ' ' || *s == ',')
                      ++s;
-                   if (*s != '$')
-                     {
-                       as_bad (_("can't parse register list"));
-                       break;
-                     }
-                   ++s;
-                   if (*s != 'f')
+                   if (reg_lookup (&s, RTYPE_GP | RTYPE_NUM, &reg1))
                      freg = 0;
+                   else if (reg_lookup (&s, RTYPE_FPU, &reg1))
+                     freg = 1;
                    else
                      {
-                       freg = 1;
-                       ++s;
-                     }
-                   reg1 = 0;
-                   while (ISDIGIT (*s))
-                     {
-                       reg1 *= 10;
-                       reg1 += *s - '0';
-                       ++s;
+                       as_bad (_("can't parse register list"));
+                       break;
                      }
                    if (*s == ' ')
                      ++s;
@@ -9469,25 +10106,11 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                    else
                      {
                        ++s;
-                       if (*s != '$')
-                         break;
-                       ++s;
-                       if (freg)
+                       if (!reg_lookup (&s, freg ? RTYPE_FPU 
+                                        : (RTYPE_GP | RTYPE_NUM), &reg2))
                          {
-                           if (*s == 'f')
-                             ++s;
-                           else
-                             {
-                               as_bad (_("invalid register list"));
-                               break;
-                             }
-                         }
-                       reg2 = 0;
-                       while (ISDIGIT (*s))
-                         {
-                           reg2 *= 10;
-                           reg2 += *s - '0';
-                           ++s;
+                           as_bad (_("invalid register list"));
+                           break;
                          }
                      }
                    if (freg && reg1 == 0 && reg2 == 0 && c == 'L')
@@ -9520,6 +10143,171 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
              }
            continue;
 
+           case 'm':           /* Register list for save insn.  */
+           case 'M':           /* Register list for restore insn.  */
+             {
+               int opcode = 0;
+               int framesz = 0, seen_framesz = 0;
+               int args = 0, statics = 0, sregs = 0;
+
+               while (*s != '\0')
+                 {
+                   unsigned int reg1, reg2;
+
+                   SKIP_SPACE_TABS (s);
+                   while (*s == ',')
+                     ++s;
+                   SKIP_SPACE_TABS (s);
+
+                   my_getExpression (&imm_expr, s);
+                   if (imm_expr.X_op == O_constant)
+                     {
+                       /* Handle the frame size.  */
+                       if (seen_framesz)
+                         {
+                           as_bad (_("more than one frame size in list"));
+                           break;
+                         }
+                       seen_framesz = 1;
+                       framesz = imm_expr.X_add_number;
+                       imm_expr.X_op = O_absent;
+                       s = expr_end;
+                       continue;
+                     }
+
+                   if (! reg_lookup (&s, RTYPE_GP | RTYPE_NUM, &reg1))
+                     {
+                       as_bad (_("can't parse register list"));
+                       break;
+                     }
+
+                   while (*s == ' ')
+                     ++s;
+
+                   if (*s != '-')
+                     reg2 = reg1;
+                   else
+                     {
+                       ++s;
+                       if (! reg_lookup (&s, RTYPE_GP | RTYPE_NUM, &reg2)
+                           || reg2 < reg1)
+                         {
+                           as_bad (_("can't parse register list"));
+                           break;
+                         }
+                     }
+
+                   while (reg1 <= reg2)
+                     {
+                       if (reg1 >= 4 && reg1 <= 7)
+                         {
+                           if (c == 'm' && !seen_framesz)
+                               /* args $a0-$a3 */
+                               args |= 1 << (reg1 - 4);
+                           else
+                               /* statics $a0-$a3 */
+                               statics |= 1 << (reg1 - 4);
+                         }
+                       else if ((reg1 >= 16 && reg1 <= 23) || reg1 == 30)
+                         {
+                           /* $s0-$s8 */
+                           sregs |= 1 << ((reg1 == 30) ? 8 : (reg1 - 16));
+                         }
+                       else if (reg1 == 31)
+                         {
+                           /* Add $ra to insn.  */
+                           opcode |= 0x40;
+                         }
+                       else
+                         {
+                           as_bad (_("unexpected register in list"));
+                           break;
+                         }
+                       if (++reg1 == 24)
+                         reg1 = 30;
+                     }
+                 }
+
+               /* Encode args/statics combination.  */
+               if (args & statics)
+                 as_bad (_("arg/static registers overlap"));
+               else if (args == 0xf)
+                 /* All $a0-$a3 are args.  */
+                 opcode |= MIPS16_ALL_ARGS << 16;
+               else if (statics == 0xf)
+                 /* All $a0-$a3 are statics.  */
+                 opcode |= MIPS16_ALL_STATICS << 16;
+               else 
+                 {
+                   int narg = 0, nstat = 0;
+
+                   /* Count arg registers.  */
+                   while (args & 0x1)
+                     {
+                       args >>= 1;
+                       narg++;
+                     }
+                   if (args != 0)
+                     as_bad (_("invalid arg register list"));
+
+                   /* Count static registers.  */
+                   while (statics & 0x8)
+                     {
+                       statics = (statics << 1) & 0xf;
+                       nstat++;
+                     }
+                   if (statics != 0) 
+                     as_bad (_("invalid static register list"));
+
+                   /* Encode args/statics.  */
+                   opcode |= ((narg << 2) | nstat) << 16;
+                 }
+
+               /* Encode $s0/$s1.  */
+               if (sregs & (1 << 0))           /* $s0 */
+                 opcode |= 0x20;
+               if (sregs & (1 << 1))           /* $s1 */
+                 opcode |= 0x10;
+               sregs >>= 2;
+
+               if (sregs != 0)
+                 {
+                   /* Count regs $s2-$s8.  */
+                   int nsreg = 0;
+                   while (sregs & 1)
+                     {
+                       sregs >>= 1;
+                       nsreg++;
+                     }
+                   if (sregs != 0)
+                     as_bad (_("invalid static register list"));
+                   /* Encode $s2-$s8. */
+                   opcode |= nsreg << 24;
+                 }
+
+               /* Encode frame size.  */
+               if (!seen_framesz)
+                 as_bad (_("missing frame size"));
+               else if ((framesz & 7) != 0 || framesz < 0
+                        || framesz > 0xff * 8)
+                 as_bad (_("invalid frame size"));
+               else if (framesz != 128 || (opcode >> 16) != 0)
+                 {
+                   framesz /= 8;
+                   opcode |= (((framesz & 0xf0) << 16)
+                            | (framesz & 0x0f));
+                 }
+
+               /* Finally build the instruction.  */
+               if ((opcode >> 16) != 0 || framesz == 0)
+                 {
+                   ip->use_extend = TRUE;
+                   ip->extend = opcode >> 16;
+                 }
+               ip->insn_opcode |= opcode & 0x7f;
+             }
+           continue;
+
            case 'e':           /* extend code */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
@@ -9625,7 +10413,7 @@ mips16_immed (char *file, unsigned int line, int type, offsetT val,
              unsigned long *insn, bfd_boolean *use_extend,
              unsigned short *extend)
 {
-  register const struct mips16_immed_operand *op;
+  const struct mips16_immed_operand *op;
   int mintiny, maxtiny;
   bfd_boolean needext;
 
@@ -10027,9 +10815,21 @@ struct option md_longopts[] =
   {"mdmx", no_argument, NULL, OPTION_MDMX},
 #define OPTION_NO_MDMX (OPTION_ASE_BASE + 5)
   {"no-mdmx", no_argument, NULL, OPTION_NO_MDMX},
+#define OPTION_DSP (OPTION_ASE_BASE + 6)
+  {"mdsp", no_argument, NULL, OPTION_DSP},
+#define OPTION_NO_DSP (OPTION_ASE_BASE + 7)
+  {"mno-dsp", no_argument, NULL, OPTION_NO_DSP},
+#define OPTION_MT (OPTION_ASE_BASE + 8)
+  {"mmt", no_argument, NULL, OPTION_MT},
+#define OPTION_NO_MT (OPTION_ASE_BASE + 9)
+  {"mno-mt", no_argument, NULL, OPTION_NO_MT},
+#define OPTION_SMARTMIPS (OPTION_ASE_BASE + 10)
+  {"msmartmips", no_argument, NULL, OPTION_SMARTMIPS},
+#define OPTION_NO_SMARTMIPS (OPTION_ASE_BASE + 11)
+  {"mno-smartmips", no_argument, NULL, OPTION_NO_SMARTMIPS},
 
   /* Old-style architecture options.  Don't add more of these.  */
-#define OPTION_COMPAT_ARCH_BASE (OPTION_ASE_BASE + 6)
+#define OPTION_COMPAT_ARCH_BASE (OPTION_ASE_BASE + 12)
 #define OPTION_M4650 (OPTION_COMPAT_ARCH_BASE + 0)
   {"m4650", no_argument, NULL, OPTION_M4650},
 #define OPTION_NO_M4650 (OPTION_COMPAT_ARCH_BASE + 1)
@@ -10126,6 +10926,8 @@ struct option md_longopts[] =
   {"mpdr", no_argument, NULL, OPTION_PDR},
 #define OPTION_NO_PDR     (OPTION_ELF_BASE + 10)
   {"mno-pdr", no_argument, NULL, OPTION_NO_PDR},
+#define OPTION_MVXWORKS_PIC (OPTION_ELF_BASE + 11)
+  {"mvxworks-pic", no_argument, NULL, OPTION_MVXWORKS_PIC},
 #endif /* OBJ_ELF */
 
   {NULL, no_argument, NULL, 0}
@@ -10281,6 +11083,22 @@ md_parse_option (int c, char *arg)
       mips_opts.ase_mdmx = 0;
       break;
 
+    case OPTION_DSP:
+      mips_opts.ase_dsp = 1;
+      break;
+
+    case OPTION_NO_DSP:
+      mips_opts.ase_dsp = 0;
+      break;
+
+    case OPTION_MT:
+      mips_opts.ase_mt = 1;
+      break;
+
+    case OPTION_NO_MT:
+      mips_opts.ase_mt = 0;
+      break;
+
     case OPTION_MIPS16:
       mips_opts.mips16 = 1;
       mips_no_prev_insn ();
@@ -10299,6 +11117,14 @@ md_parse_option (int c, char *arg)
       mips_opts.ase_mips3d = 0;
       break;
 
+    case OPTION_SMARTMIPS:
+      mips_opts.ase_smartmips = 1;
+      break;
+
+    case OPTION_NO_SMARTMIPS:
+      mips_opts.ase_smartmips = 0;
+      break;
+
     case OPTION_FIX_VR4120:
       mips_fix_vr4120 = 1;
       break;
@@ -10344,23 +11170,17 @@ md_parse_option (int c, char *arg)
         select SVR4_PIC, and -non_shared to select no PIC.  This is
         intended to be compatible with Irix 5.  */
     case OPTION_CALL_SHARED:
-      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+      if (!IS_ELF)
        {
          as_bad (_("-call_shared is supported only for ELF format"));
          return 0;
        }
       mips_pic = SVR4_PIC;
       mips_abicalls = TRUE;
-      if (g_switch_seen && g_switch_value != 0)
-       {
-         as_bad (_("-G may not be used with SVR4 PIC code"));
-         return 0;
-       }
-      g_switch_value = 0;
       break;
 
     case OPTION_NON_SHARED:
-      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+      if (!IS_ELF)
        {
          as_bad (_("-non_shared is supported only for ELF format"));
          return 0;
@@ -10369,8 +11189,8 @@ md_parse_option (int c, char *arg)
       mips_abicalls = FALSE;
       break;
 
-      /* The -xgot option tells the assembler to use 32 offsets when
-         accessing the got in SVR4_PIC mode.  It is for Irix
+      /* The -xgot option tells the assembler to use 32 bit offsets
+         when accessing the got in SVR4_PIC mode.  It is for Irix
          compatibility.  */
     case OPTION_XGOT:
       mips_big_got = 1;
@@ -10380,18 +11200,13 @@ md_parse_option (int c, char *arg)
     case 'G':
       g_switch_value = atoi (arg);
       g_switch_seen = 1;
-      if (mips_pic == SVR4_PIC && g_switch_value != 0)
-       {
-         as_bad (_("-G may not be used with SVR4 PIC code"));
-         return 0;
-       }
       break;
 
 #ifdef OBJ_ELF
       /* The -32, -n32 and -64 options are shortcuts for -mabi=32, -mabi=n32
         and -mabi=64.  */
     case OPTION_32:
-      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+      if (!IS_ELF)
        {
          as_bad (_("-32 is supported for ELF format only"));
          return 0;
@@ -10400,7 +11215,7 @@ md_parse_option (int c, char *arg)
       break;
 
     case OPTION_N32:
-      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+      if (!IS_ELF)
        {
          as_bad (_("-n32 is supported for ELF format only"));
          return 0;
@@ -10409,13 +11224,13 @@ md_parse_option (int c, char *arg)
       break;
 
     case OPTION_64:
-      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+      if (!IS_ELF)
        {
          as_bad (_("-64 is supported for ELF format only"));
          return 0;
        }
       mips_abi = N64_ABI;
-      if (! support_64bit_objects())
+      if (!support_64bit_objects())
        as_fatal (_("No compiled in support for 64 bit object file format"));
       break;
 #endif /* OBJ_ELF */
@@ -10438,7 +11253,7 @@ md_parse_option (int c, char *arg)
 
 #ifdef OBJ_ELF
     case OPTION_MABI:
-      if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+      if (!IS_ELF)
        {
          as_bad (_("-mabi is supported for ELF format only"));
          return 0;
@@ -10490,6 +11305,10 @@ md_parse_option (int c, char *arg)
     case OPTION_NO_PDR:
       mips_flag_pdr = FALSE;
       break;
+
+    case OPTION_MVXWORKS_PIC:
+      mips_pic = VXWORKS_PIC;
+      break;
 #endif /* OBJ_ELF */
 
     default:
@@ -10606,14 +11425,43 @@ mips_after_parse_args (void)
                        || !ISA_HAS_64BIT_REGS (mips_opts.isa));
     }
 
-  /* ??? GAS treats single-float processors as though they had 64-bit
-     float registers (although it complains when double-precision
-     instructions are used).  As things stand, saying they have 32-bit
-     registers would lead to spurious "register must be even" messages.
-     So here we assume float registers are always the same size as
-     integer ones, unless the user says otherwise.  */
-  if (file_mips_fp32 < 0)
-    file_mips_fp32 = file_mips_gp32;
+  switch (file_mips_fp32)
+    {
+    default:
+    case -1:
+      /* No user specified float register size.
+        ??? GAS treats single-float processors as though they had 64-bit
+        float registers (although it complains when double-precision
+        instructions are used).  As things stand, saying they have 32-bit
+        registers would lead to spurious "register must be even" messages.
+        So here we assume float registers are never smaller than the
+        integer ones.  */
+      if (file_mips_gp32 == 0)
+       /* 64-bit integer registers implies 64-bit float registers.  */
+       file_mips_fp32 = 0;
+      else if ((mips_opts.ase_mips3d > 0 || mips_opts.ase_mdmx > 0)
+              && ISA_HAS_64BIT_FPRS (mips_opts.isa))
+       /* -mips3d and -mdmx imply 64-bit float registers, if possible.  */
+       file_mips_fp32 = 0;
+      else
+       /* 32-bit float registers.  */
+       file_mips_fp32 = 1;
+      break;
+
+    /* The user specified the size of the float registers.  Check if it
+       agrees with the ABI and ISA.  */
+    case 0:
+      if (!ISA_HAS_64BIT_FPRS (mips_opts.isa))
+       as_bad (_("-mfp64 used with a 32-bit fpu"));
+      else if (ABI_NEEDS_32BIT_REGS (mips_abi)
+              && !ISA_HAS_MXHC1 (mips_opts.isa))
+       as_warn (_("-mfp64 used with a 32-bit ABI"));
+      break;
+    case 1:
+      if (ABI_NEEDS_64BIT_REGS (mips_abi))
+       as_warn (_("-mfp32 used with a 64-bit ABI"));
+      break;
+    }
 
   /* End of GCC-shared inference code.  */
 
@@ -10632,14 +11480,42 @@ mips_after_parse_args (void)
   if (mips_opts.mips16 == -1)
     mips_opts.mips16 = (CPU_HAS_MIPS16 (file_mips_arch)) ? 1 : 0;
   if (mips_opts.ase_mips3d == -1)
-    mips_opts.ase_mips3d = (CPU_HAS_MIPS3D (file_mips_arch)) ? 1 : 0;
+    mips_opts.ase_mips3d = ((arch_info->flags & MIPS_CPU_ASE_MIPS3D)
+                           && file_mips_fp32 == 0) ? 1 : 0;
+  if (mips_opts.ase_mips3d && file_mips_fp32 == 1)
+    as_bad (_("-mfp32 used with -mips3d"));
+
   if (mips_opts.ase_mdmx == -1)
-    mips_opts.ase_mdmx = (CPU_HAS_MDMX (file_mips_arch)) ? 1 : 0;
+    mips_opts.ase_mdmx = ((arch_info->flags & MIPS_CPU_ASE_MDMX)
+                         && file_mips_fp32 == 0) ? 1 : 0;
+  if (mips_opts.ase_mdmx && file_mips_fp32 == 1)
+    as_bad (_("-mfp32 used with -mdmx"));
+
+  if (mips_opts.ase_smartmips == -1)
+    mips_opts.ase_smartmips = (arch_info->flags & MIPS_CPU_ASE_SMARTMIPS) ? 1 : 0;
+  if (mips_opts.ase_smartmips && !ISA_SUPPORTS_SMARTMIPS)
+      as_warn ("%s ISA does not support SmartMIPS", 
+              mips_cpu_info_from_isa (mips_opts.isa)->name);
+
+  if (mips_opts.ase_dsp == -1)
+    mips_opts.ase_dsp = (arch_info->flags & MIPS_CPU_ASE_DSP) ? 1 : 0;
+  if (mips_opts.ase_dsp && !ISA_SUPPORTS_DSP_ASE)
+      as_warn ("%s ISA does not support DSP ASE", 
+              mips_cpu_info_from_isa (mips_opts.isa)->name);
+
+  if (mips_opts.ase_mt == -1)
+    mips_opts.ase_mt = (arch_info->flags & MIPS_CPU_ASE_MT) ? 1 : 0;
+  if (mips_opts.ase_mt && !ISA_SUPPORTS_MT_ASE)
+      as_warn ("%s ISA does not support MT ASE", 
+              mips_cpu_info_from_isa (mips_opts.isa)->name);
 
   file_mips_isa = mips_opts.isa;
   file_ase_mips16 = mips_opts.mips16;
   file_ase_mips3d = mips_opts.ase_mips3d;
   file_ase_mdmx = mips_opts.ase_mdmx;
+  file_ase_smartmips = mips_opts.ase_smartmips;
+  file_ase_dsp = mips_opts.ase_dsp;
+  file_ase_mt = mips_opts.ase_mt;
   mips_opts.gp32 = file_mips_gp32;
   mips_opts.fp32 = file_mips_fp32;
 
@@ -10696,7 +11572,7 @@ mips_frob_file_before_adjust (void)
 }
 
 /* Sort any unmatched HI16 and GOT16 relocs so that they immediately precede
-   the corresponding LO16 reloc.  This is called before md_apply_fix3 and
+   the corresponding LO16 reloc.  This is called before md_apply_fix and
    tc_gen_reloc.  Unmatched relocs can only be generated by use of explicit
    relocation operators.
 
@@ -10835,87 +11711,10 @@ mips_force_relocation (fixS *fixp)
   return 0;
 }
 
-/* This hook is called before a fix is simplified.  We don't really
-   decide whether to skip a fix here.  Rather, we turn global symbols
-   used as branch targets into local symbols, such that they undergo
-   simplification.  We can only do this if the symbol is defined and
-   it is in the same section as the branch.  If this doesn't hold, we
-   emit a better error message than just saying the relocation is not
-   valid for the selected object format.
-
-   FIXP is the fix-up we're going to try to simplify, SEG is the
-   segment in which the fix up occurs.  The return value should be
-   non-zero to indicate the fix-up is valid for further
-   simplifications.  */
-
-int
-mips_validate_fix (struct fix *fixP, asection *seg)
-{
-  /* There's a lot of discussion on whether it should be possible to
-     use R_MIPS_PC16 to represent branch relocations.  The outcome
-     seems to be that it can, but gas/bfd are very broken in creating
-     RELA relocations for this, so for now we only accept branches to
-     symbols in the same section.  Anything else is of dubious value,
-     since there's no guarantee that at link time the symbol would be
-     in range.  Even for branches to local symbols this is arguably
-     wrong, since it we assume the symbol is not going to be
-     overridden, which should be possible per ELF library semantics,
-     but then, there isn't a dynamic relocation that could be used to
-     this effect, and the target would likely be out of range as well.
-
-     Unfortunately, it seems that there is too much code out there
-     that relies on branches to symbols that are global to be resolved
-     as if they were local, like the IRIX tools do, so we do it as
-     well, but with a warning so that people are reminded to fix their
-     code.  If we ever get back to using R_MIPS_PC16 for branch
-     targets, this entire block should go away (and probably the
-     whole function).  */
-
-  if (fixP->fx_r_type == BFD_RELOC_16_PCREL_S2
-      && ((OUTPUT_FLAVOR == bfd_target_ecoff_flavour
-          || OUTPUT_FLAVOR == bfd_target_elf_flavour)
-         || bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16_PCREL_S2) == NULL)
-      && fixP->fx_addsy)
-    {
-      if (! S_IS_DEFINED (fixP->fx_addsy))
-       {
-         as_bad_where (fixP->fx_file, fixP->fx_line,
-                       _("Cannot branch to undefined symbol."));
-         /* Avoid any further errors about this fixup.  */
-         fixP->fx_done = 1;
-       }
-      else if (S_GET_SEGMENT (fixP->fx_addsy) != seg)
-       {
-         as_bad_where (fixP->fx_file, fixP->fx_line,
-                       _("Cannot branch to symbol in another section."));
-         fixP->fx_done = 1;
-       }
-      else if (S_IS_EXTERNAL (fixP->fx_addsy))
-       {
-         symbolS *sym = fixP->fx_addsy;
-
-         if (mips_pic == SVR4_PIC)
-           as_warn_where (fixP->fx_file, fixP->fx_line,
-                          _("Pretending global symbol used as branch target is local."));
-
-         fixP->fx_addsy = symbol_create (S_GET_NAME (sym),
-                                         S_GET_SEGMENT (sym),
-                                         S_GET_VALUE (sym),
-                                         symbol_get_frag (sym));
-         copy_symbol_attributes (fixP->fx_addsy, sym);
-         S_CLEAR_EXTERNAL (fixP->fx_addsy);
-         assert (symbol_resolved_p (sym));
-         symbol_mark_resolved (fixP->fx_addsy);
-       }
-    }
-
-  return 1;
-}
-
 /* Apply a fixup to the object file.  */
 
 void
-md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
+md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 {
   bfd_byte *buf;
   long insn;
@@ -10936,7 +11735,7 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 
   buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where);
 
-  assert (! fixP->fx_pcrel);
+  assert (!fixP->fx_pcrel || fixP->fx_r_type == BFD_RELOC_16_PCREL_S2);
 
   /* Don't treat parts of a composite relocation as done.  There are two
      reasons for this:
@@ -10948,7 +11747,7 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
         constants.  The easiest way of dealing with the pathological
         exceptions is to generate a relocation against STN_UNDEF and
         leave everything up to the linker.  */
-  if (fixP->fx_addsy == NULL && fixP->fx_tcbit == 0)
+  if (fixP->fx_addsy == NULL && !fixP->fx_pcrel && fixP->fx_tcbit == 0)
     fixP->fx_done = 1;
 
   switch (fixP->fx_r_type)
@@ -10993,7 +11792,6 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_MIPS16_GPREL:
     case BFD_RELOC_MIPS16_HI16:
     case BFD_RELOC_MIPS16_HI16_S:
-      assert (! fixP->fx_pcrel);
       /* Nothing needed to do. The value comes from the reloc entry */
       break;
 
@@ -11063,7 +11861,7 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_16_PCREL_S2:
       if ((*valP & 0x3) != 0)
        as_bad_where (fixP->fx_file, fixP->fx_line,
-                     _("Branch to odd address (%lx)"), (long) *valP);
+                     _("Branch to misaligned address (%lx)"), (long) *valP);
 
       /*
        * We need to save the bits in the instruction since fixup_segment()
@@ -11173,8 +11971,8 @@ mips_align (int to, int fill, symbolS *label)
 static void
 s_align (int x ATTRIBUTE_UNUSED)
 {
-  register int temp;
-  register long temp_fill;
+  int temp;
+  long temp_fill;
   long max_alignment = 15;
 
   /*
@@ -11206,9 +12004,11 @@ s_align (int x ATTRIBUTE_UNUSED)
     temp_fill = 0;
   if (temp)
     {
+      segment_info_type *si = seg_info (now_seg);
+      struct insn_label_list *l = si->label_list;
+      /* Auto alignment should be switched on by next section change */
       auto_align = 1;
-      mips_align (temp, (int) temp_fill,
-                 insn_labels != NULL ? insn_labels->label : NULL);
+      mips_align (temp, (int) temp_fill, l != NULL ? l->label : NULL);
     }
   else
     {
@@ -11230,7 +12030,8 @@ s_change_sec (int sec)
      as it would not be appropriate to use it in the section changing
      functions in read.c, since obj-elf.c intercepts those.  FIXME:
      This should be cleaner, somehow.  */
-  obj_elf_section_change_hook ();
+  if (IS_ELF)
+    obj_elf_section_change_hook ();
 #endif
 
   mips_emit_delays ();
@@ -11250,7 +12051,7 @@ s_change_sec (int sec)
     case 'r':
       seg = subseg_new (RDATA_SECTION_NAME,
                        (subsegT) get_absolute_expression ());
-      if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+      if (IS_ELF)
        {
          bfd_set_section_flags (stdoutput, seg, (SEC_ALLOC | SEC_LOAD
                                                  | SEC_READONLY | SEC_RELOC
@@ -11263,7 +12064,7 @@ s_change_sec (int sec)
 
     case 's':
       seg = subseg_new (".sdata", (subsegT) get_absolute_expression ());
-      if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+      if (IS_ELF)
        {
          bfd_set_section_flags (stdoutput, seg,
                                 SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA);
@@ -11289,7 +12090,7 @@ s_change_section (int ignore ATTRIBUTE_UNUSED)
   int section_entry_size;
   int section_alignment;
 
-  if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+  if (!IS_ELF)
     return;
 
   section_name = input_line_pointer;
@@ -11334,7 +12135,7 @@ s_change_section (int ignore ATTRIBUTE_UNUSED)
 
      There's nothing really harmful in this, since bfd will correct
      SHT_PROGBITS to SHT_MIPS_DWARF before writing out the file.  But it
-     means that, for backwards compatibiltiy, the special_section entries
+     means that, for backwards compatibility, the special_section entries
      for dwarf sections must use SHT_PROGBITS rather than SHT_MIPS_DWARF.
 
      Even so, we shouldn't force users of the MIPS .section syntax to
@@ -11361,9 +12162,11 @@ mips_enable_auto_align (void)
 static void
 s_cons (int log_size)
 {
+  segment_info_type *si = seg_info (now_seg);
+  struct insn_label_list *l = si->label_list;
   symbolS *label;
 
-  label = insn_labels != NULL ? insn_labels->label : NULL;
+  label = l != NULL ? l->label : NULL;
   mips_emit_delays ();
   if (log_size > 0 && auto_align)
     mips_align (log_size, 0, label);
@@ -11374,9 +12177,11 @@ s_cons (int log_size)
 static void
 s_float_cons (int type)
 {
+  segment_info_type *si = seg_info (now_seg);
+  struct insn_label_list *l = si->label_list;
   symbolS *label;
 
-  label = insn_labels != NULL ? insn_labels->label : NULL;
+  label = l != NULL ? l->label : NULL;
 
   mips_emit_delays ();
 
@@ -11407,35 +12212,50 @@ s_mips_globl (int x ATTRIBUTE_UNUSED)
   symbolS *symbolP;
   flagword flag;
 
-  name = input_line_pointer;
-  c = get_symbol_end ();
-  symbolP = symbol_find_or_make (name);
-  *input_line_pointer = c;
-  SKIP_WHITESPACE ();
-
-  /* On Irix 5, every global symbol that is not explicitly labelled as
-     being a function is apparently labelled as being an object.  */
-  flag = BSF_OBJECT;
-
-  if (! is_end_of_line[(unsigned char) *input_line_pointer])
+  do
     {
-      char *secname;
-      asection *sec;
-
-      secname = input_line_pointer;
+      name = input_line_pointer;
       c = get_symbol_end ();
-      sec = bfd_get_section_by_name (stdoutput, secname);
-      if (sec == NULL)
-       as_bad (_("%s: no such section"), secname);
+      symbolP = symbol_find_or_make (name);
+      S_SET_EXTERNAL (symbolP);
+
       *input_line_pointer = c;
+      SKIP_WHITESPACE ();
 
-      if (sec != NULL && (sec->flags & SEC_CODE) != 0)
-       flag = BSF_FUNCTION;
-    }
+      /* On Irix 5, every global symbol that is not explicitly labelled as
+         being a function is apparently labelled as being an object.  */
+      flag = BSF_OBJECT;
 
-  symbol_get_bfdsym (symbolP)->flags |= flag;
+      if (!is_end_of_line[(unsigned char) *input_line_pointer]
+         && (*input_line_pointer != ','))
+       {
+         char *secname;
+         asection *sec;
+
+         secname = input_line_pointer;
+         c = get_symbol_end ();
+         sec = bfd_get_section_by_name (stdoutput, secname);
+         if (sec == NULL)
+           as_bad (_("%s: no such section"), secname);
+         *input_line_pointer = c;
+
+         if (sec != NULL && (sec->flags & SEC_CODE) != 0)
+           flag = BSF_FUNCTION;
+       }
+
+      symbol_get_bfdsym (symbolP)->flags |= flag;
+
+      c = *input_line_pointer;
+      if (c == ',')
+       {
+         input_line_pointer++;
+         SKIP_WHITESPACE ();
+         if (is_end_of_line[(unsigned char) *input_line_pointer])
+           c = '\n';
+       }
+    }
+  while (c == ',');
 
-  S_SET_EXTERNAL (symbolP);
   demand_empty_rest_of_line ();
 }
 
@@ -11548,12 +12368,43 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
     {
       mips_opts.nobopt = 1;
     }
+  else if (strcmp (name, "gp=default") == 0)
+    mips_opts.gp32 = file_mips_gp32;
+  else if (strcmp (name, "gp=32") == 0)
+    mips_opts.gp32 = 1;
+  else if (strcmp (name, "gp=64") == 0)
+    {
+      if (!ISA_HAS_64BIT_REGS (mips_opts.isa))
+       as_warn ("%s isa does not support 64-bit registers",
+                mips_cpu_info_from_isa (mips_opts.isa)->name);
+      mips_opts.gp32 = 0;
+    }
+  else if (strcmp (name, "fp=default") == 0)
+    mips_opts.fp32 = file_mips_fp32;
+  else if (strcmp (name, "fp=32") == 0)
+    mips_opts.fp32 = 1;
+  else if (strcmp (name, "fp=64") == 0)
+    {
+      if (!ISA_HAS_64BIT_FPRS (mips_opts.isa))
+       as_warn ("%s isa does not support 64-bit floating point registers",
+                mips_cpu_info_from_isa (mips_opts.isa)->name);
+      mips_opts.fp32 = 0;
+    }
   else if (strcmp (name, "mips16") == 0
           || strcmp (name, "MIPS-16") == 0)
     mips_opts.mips16 = 1;
   else if (strcmp (name, "nomips16") == 0
           || strcmp (name, "noMIPS-16") == 0)
     mips_opts.mips16 = 0;
+  else if (strcmp (name, "smartmips") == 0)
+    {
+      if (!ISA_SUPPORTS_SMARTMIPS)
+       as_warn ("%s ISA does not support SmartMIPS ASE", 
+                mips_cpu_info_from_isa (mips_opts.isa)->name);
+      mips_opts.ase_smartmips = 1;
+    }
+  else if (strcmp (name, "nosmartmips") == 0)
+    mips_opts.ase_smartmips = 0;
   else if (strcmp (name, "mips3d") == 0)
     mips_opts.ase_mips3d = 1;
   else if (strcmp (name, "nomips3d") == 0)
@@ -11562,6 +12413,24 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
     mips_opts.ase_mdmx = 1;
   else if (strcmp (name, "nomdmx") == 0)
     mips_opts.ase_mdmx = 0;
+  else if (strcmp (name, "dsp") == 0)
+    {
+      if (!ISA_SUPPORTS_DSP_ASE)
+       as_warn ("%s ISA does not support DSP ASE", 
+                mips_cpu_info_from_isa (mips_opts.isa)->name);
+      mips_opts.ase_dsp = 1;
+    }
+  else if (strcmp (name, "nodsp") == 0)
+    mips_opts.ase_dsp = 0;
+  else if (strcmp (name, "mt") == 0)
+    {
+      if (!ISA_SUPPORTS_MT_ASE)
+       as_warn ("%s ISA does not support MT ASE", 
+                mips_cpu_info_from_isa (mips_opts.isa)->name);
+      mips_opts.ase_mt = 1;
+    }
+  else if (strcmp (name, "nomt") == 0)
+    mips_opts.ase_mt = 0;
   else if (strncmp (name, "mips", 4) == 0 || strncmp (name, "arch=", 5) == 0)
     {
       int reset = 0;
@@ -11987,6 +12856,8 @@ s_gpvalue (int ignore ATTRIBUTE_UNUSED)
 static void
 s_gpword (int ignore ATTRIBUTE_UNUSED)
 {
+  segment_info_type *si;
+  struct insn_label_list *l;
   symbolS *label;
   expressionS ex;
   char *p;
@@ -11998,7 +12869,9 @@ s_gpword (int ignore ATTRIBUTE_UNUSED)
       return;
     }
 
-  label = insn_labels != NULL ? insn_labels->label : NULL;
+  si = seg_info (now_seg);
+  l = si->label_list;
+  label = l != NULL ? l->label : NULL;
   mips_emit_delays ();
   if (auto_align)
     mips_align (2, 0, label);
@@ -12023,6 +12896,8 @@ s_gpword (int ignore ATTRIBUTE_UNUSED)
 static void
 s_gpdword (int ignore ATTRIBUTE_UNUSED)
 {
+  segment_info_type *si;
+  struct insn_label_list *l;
   symbolS *label;
   expressionS ex;
   char *p;
@@ -12034,7 +12909,9 @@ s_gpdword (int ignore ATTRIBUTE_UNUSED)
       return;
     }
 
-  label = insn_labels != NULL ? insn_labels->label : NULL;
+  si = seg_info (now_seg);
+  l = si->label_list;
+  label = l != NULL ? l->label : NULL;
   mips_emit_delays ();
   if (auto_align)
     mips_align (3, 0, label);
@@ -12171,73 +13048,11 @@ s_mips_weakext (int ignore ATTRIBUTE_UNUSED)
 int
 tc_get_register (int frame)
 {
-  int reg;
+  unsigned int reg;
 
   SKIP_WHITESPACE ();
-  if (*input_line_pointer++ != '$')
-    {
-      as_warn (_("expected `$'"));
-      reg = ZERO;
-    }
-  else if (ISDIGIT (*input_line_pointer))
-    {
-      reg = get_absolute_expression ();
-      if (reg < 0 || reg >= 32)
-       {
-         as_warn (_("Bad register number"));
-         reg = ZERO;
-       }
-    }
-  else
-    {
-      if (strncmp (input_line_pointer, "ra", 2) == 0)
-       {
-         reg = RA;
-         input_line_pointer += 2;
-       }
-      else if (strncmp (input_line_pointer, "fp", 2) == 0)
-       {
-         reg = FP;
-         input_line_pointer += 2;
-       }
-      else if (strncmp (input_line_pointer, "sp", 2) == 0)
-       {
-         reg = SP;
-         input_line_pointer += 2;
-       }
-      else if (strncmp (input_line_pointer, "gp", 2) == 0)
-       {
-         reg = GP;
-         input_line_pointer += 2;
-       }
-      else if (strncmp (input_line_pointer, "at", 2) == 0)
-       {
-         reg = AT;
-         input_line_pointer += 2;
-       }
-      else if (strncmp (input_line_pointer, "kt0", 3) == 0)
-       {
-         reg = KT0;
-         input_line_pointer += 3;
-       }
-      else if (strncmp (input_line_pointer, "kt1", 3) == 0)
-       {
-         reg = KT1;
-         input_line_pointer += 3;
-       }
-      else if (strncmp (input_line_pointer, "zero", 4) == 0)
-       {
-         reg = ZERO;
-         input_line_pointer += 4;
-       }
-      else
-       {
-         as_warn (_("Unrecognized register name"));
-         reg = ZERO;
-         while (ISALNUM(*input_line_pointer))
-          input_line_pointer++;
-       }
-    }
+  if (! reg_lookup (&input_line_pointer, RWARN | RTYPE_NUM | RTYPE_GP, &reg))
+    reg = 0;
   if (frame)
     {
       mips_frame_reg = reg != 0 ? reg : SP;
@@ -12327,6 +13142,8 @@ nopic_need_relax (symbolS *sym, int before_relaxing)
          change = (strcmp (segname, ".sdata") != 0
                    && strcmp (segname, ".sbss") != 0
                    && strncmp (segname, ".sdata.", 7) != 0
+                   && strncmp (segname, ".sbss.", 6) != 0
+                   && strncmp (segname, ".gnu.linkonce.sb.", 17) != 0
                    && strncmp (segname, ".gnu.linkonce.s.", 16) != 0);
        }
       return change;
@@ -12343,15 +13160,13 @@ static bfd_boolean
 pic_need_relax (symbolS *sym, asection *segtype)
 {
   asection *symsec;
-  bfd_boolean linkonce;
 
   /* Handle the case of a symbol equated to another symbol.  */
   while (symbol_equated_reloc_p (sym))
     {
       symbolS *n;
 
-      /* It's possible to get a loop here in a badly written
-        program.  */
+      /* It's possible to get a loop here in a badly written program.  */
       n = symbol_get_value_expression (sym)->X_add_symbol;
       if (n == sym)
        break;
@@ -12360,31 +13175,14 @@ pic_need_relax (symbolS *sym, asection *segtype)
 
   symsec = S_GET_SEGMENT (sym);
 
-  /* duplicate the test for LINK_ONCE sections as in adjust_reloc_syms */
-  linkonce = FALSE;
-  if (symsec != segtype && ! S_IS_LOCAL (sym))
-    {
-      if ((bfd_get_section_flags (stdoutput, symsec) & SEC_LINK_ONCE)
-         != 0)
-       linkonce = TRUE;
-
-      /* The GNU toolchain uses an extension for ELF: a section
-        beginning with the magic string .gnu.linkonce is a linkonce
-        section.  */
-      if (strncmp (segment_name (symsec), ".gnu.linkonce",
-                  sizeof ".gnu.linkonce" - 1) == 0)
-       linkonce = TRUE;
-    }
-
   /* This must duplicate the test in adjust_reloc_syms.  */
   return (symsec != &bfd_und_section
          && symsec != &bfd_abs_section
-         && ! bfd_is_com_section (symsec)
-         && !linkonce
+         && !bfd_is_com_section (symsec)
+         && !s_is_linkonce (sym, segtype)
 #ifdef OBJ_ELF
          /* A global or weak symbol is treated as external.  */
-         && (OUTPUT_FLAVOR != bfd_target_elf_flavour
-             || (! S_IS_WEAK (sym) && ! S_IS_EXTERNAL (sym)))
+         && (!IS_ELF || (! S_IS_WEAK (sym) && ! S_IS_EXTERNAL (sym)))
 #endif
          );
 }
@@ -12397,7 +13195,7 @@ static int
 mips16_extended_frag (fragS *fragp, asection *sec, long stretch)
 {
   int type;
-  register const struct mips16_immed_operand *op;
+  const struct mips16_immed_operand *op;
   offsetT val;
   int mintiny, maxtiny;
   segT symsec;
@@ -12679,6 +13477,9 @@ md_estimate_size_before_relax (fragS *fragp, asection *segtype)
     change = nopic_need_relax (fragp->fr_symbol, 0);
   else if (mips_pic == SVR4_PIC)
     change = pic_need_relax (fragp->fr_symbol, segtype);
+  else if (mips_pic == VXWORKS_PIC)
+    /* For vxworks, GOT16 relocations never have a corresponding LO16.  */
+    change = 0;
   else
     abort ();
 
@@ -12697,11 +13498,6 @@ md_estimate_size_before_relax (fragS *fragp, asection *segtype)
 int
 mips_fix_adjustable (fixS *fixp)
 {
-  /* Don't adjust MIPS16 jump relocations, so we don't have to worry
-     about the format of the offset in the .o file. */
-  if (fixp->fx_r_type == BFD_RELOC_MIPS16_JMP)
-    return 0;
-
   if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
       || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     return 0;
@@ -12733,7 +13529,7 @@ mips_fix_adjustable (fixS *fixp)
 #ifdef OBJ_ELF
   /* Don't adjust relocations against mips16 symbols, so that the linker
      can find them if it needs to set up a stub.  */
-  if (OUTPUT_FLAVOR == bfd_target_elf_flavour
+  if (IS_ELF
       && S_GET_OTHER (fixp->fx_addsy) == STO_MIPS16
       && fixp->fx_subsy == NULL)
     return 0;
@@ -12758,8 +13554,28 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
-  assert (! fixp->fx_pcrel);
-  reloc->addend = fixp->fx_addnumber;
+  if (fixp->fx_pcrel)
+    {
+      assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2);
+
+      /* At this point, fx_addnumber is "symbol offset - pcrel address".
+        Relocations want only the symbol offset.  */
+      reloc->addend = fixp->fx_addnumber + reloc->address;
+      if (!IS_ELF)
+       {
+         /* A gruesome hack which is a result of the gruesome gas
+            reloc handling.  What's worse, for COFF (as opposed to
+            ECOFF), we might need yet another copy of reloc->address.
+            See bfd_install_relocation.  */
+         reloc->addend += reloc->address;
+       }
+    }
+  else
+    reloc->addend = fixp->fx_addnumber;
+
+  /* Handle relocs adjusted against a section symbol.  */
+  if (fixp->fx_r_type == BFD_RELOC_MIPS16_JMP)
+    reloc->addend += fixp->fx_offset;
 
   /* Since the old MIPS ELF ABI uses Rel instead of Rela, encode the vtable
      entry to be used in the relocation's section offset.  */
@@ -12771,18 +13587,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
 
   code = fixp->fx_r_type;
 
-  /* To support a PC relative reloc, we used a Cygnus extension.
-     We check for that here to make sure that we don't let such a
-     reloc escape normally.  (FIXME: This was formerly used by
-     embedded-PIC support, but is now used by branch handling in
-     general.  That probably should be fixed.)  */
-  if ((OUTPUT_FLAVOR == bfd_target_ecoff_flavour
-       || OUTPUT_FLAVOR == bfd_target_elf_flavour)
-      && code == BFD_RELOC_16_PCREL_S2)
-    reloc->howto = NULL;
-  else
-    reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
-
+  reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
   if (reloc->howto == NULL)
     {
       as_bad_where (fixp->fx_file, fixp->fx_line,
@@ -12859,8 +13664,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
          exp.X_add_number = fragp->fr_offset;
 
          fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
-                             4, &exp, 1,
-                             BFD_RELOC_16_PCREL_S2);
+                             4, &exp, TRUE, BFD_RELOC_16_PCREL_S2);
          fixp->fx_file = fragp->fr_file;
          fixp->fx_line = fragp->fr_line;
 
@@ -12977,7 +13781,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
              exp.X_add_number = fragp->fr_offset;
 
              fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
-                                 4, &exp, 0, BFD_RELOC_MIPS_JMP);
+                                 4, &exp, FALSE, BFD_RELOC_MIPS_JMP);
              fixp->fx_file = fragp->fr_file;
              fixp->fx_line = fragp->fr_line;
 
@@ -12999,7 +13803,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
                }
 
              fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
-                                 4, &exp, 0, BFD_RELOC_MIPS_GOT16);
+                                 4, &exp, FALSE, BFD_RELOC_MIPS_GOT16);
              fixp->fx_file = fragp->fr_file;
              fixp->fx_line = fragp->fr_line;
 
@@ -13017,7 +13821,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
              insn = HAVE_64BIT_ADDRESSES ? 0x64210000 : 0x24210000;
 
              fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
-                                 4, &exp, 0, BFD_RELOC_LO16);
+                                 4, &exp, FALSE, BFD_RELOC_LO16);
              fixp->fx_file = fragp->fr_file;
              fixp->fx_line = fragp->fr_line;
 
@@ -13046,7 +13850,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
   if (RELAX_MIPS16_P (fragp->fr_subtype))
     {
       int type;
-      register const struct mips16_immed_operand *op;
+      const struct mips16_immed_operand *op;
       bfd_boolean small, ext;
       offsetT val;
       bfd_byte *buf;
@@ -13200,7 +14004,7 @@ mips_frob_file_after_relocs (void)
   asymbol **syms;
   unsigned int count, i;
 
-  if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+  if (!IS_ELF)
     return;
 
   syms = bfd_get_outsymbols (stdoutput);
@@ -13228,6 +14032,7 @@ mips_frob_file_after_relocs (void)
 void
 mips_define_label (symbolS *sym)
 {
+  segment_info_type *si = seg_info (now_seg);
   struct insn_label_list *l;
 
   if (free_insn_labels == NULL)
@@ -13239,8 +14044,12 @@ mips_define_label (symbolS *sym)
     }
 
   l->label = sym;
-  l->next = insn_labels;
-  insn_labels = l;
+  l->next = si->label_list;
+  si->label_list = l;
+
+#ifdef OBJ_ELF
+  dwarf2_emit_label (sym);
+#endif
 }
 \f
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
@@ -13296,6 +14105,10 @@ mips_elf_final_processing (void)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_CPIC;
 
   /* Set MIPS ELF flags for ASEs.  */
+  /* We may need to define a new flag for DSP ASE, and set this flag when
+     file_ase_dsp is true.  */
+  /* We may need to define a new flag for MT ASE, and set this flag when
+     file_ase_mt is true.  */
   if (file_ase_mips16)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_M16;
 #if 0 /* XXX FIXME */
@@ -13324,6 +14137,12 @@ mips_elf_final_processing (void)
 
   if (mips_32bitmode)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_32BITMODE;
+
+#if 0 /* XXX FIXME */
+  /* 32 bit code with 64 bit FP registers.  */
+  if (!file_mips_fp32 && ABI_NEEDS_32BIT_REGS (mips_abi))
+    elf_elfheader (stdoutput)->e_flags |= ???;
+#endif
 }
 
 #endif /* OBJ_ELF || OBJ_MAYBE_ELF */
@@ -13541,8 +14360,7 @@ s_mips_end (int x ATTRIBUTE_UNUSED)
     }
 
   /* Generate a .pdr section.  */
-  if (OUTPUT_FLAVOR == bfd_target_elf_flavour && ! ECOFF_DEBUGGING
-      && mips_flag_pdr)
+  if (IS_ELF && !ECOFF_DEBUGGING && mips_flag_pdr)
     {
       segT saved_seg = now_seg;
       subsegT saved_subseg = now_subseg;
@@ -13636,7 +14454,7 @@ static void
 s_mips_frame (int ignore ATTRIBUTE_UNUSED)
 {
 #ifdef OBJ_ELF
-  if (OUTPUT_FLAVOR == bfd_target_elf_flavour && ! ECOFF_DEBUGGING)
+  if (IS_ELF && !ECOFF_DEBUGGING)
     {
       long val;
 
@@ -13679,7 +14497,7 @@ static void
 s_mips_mask (int reg_type)
 {
 #ifdef OBJ_ELF
-  if (OUTPUT_FLAVOR == bfd_target_elf_flavour && ! ECOFF_DEBUGGING)
+  if (IS_ELF && !ECOFF_DEBUGGING)
     {
       long mask, off;
 
@@ -13726,64 +14544,94 @@ s_mips_mask (int reg_type)
 static const struct mips_cpu_info mips_cpu_info_table[] =
 {
   /* Entries for generic ISAs */
-  { "mips1",          1,      ISA_MIPS1,      CPU_R3000 },
-  { "mips2",          1,      ISA_MIPS2,      CPU_R6000 },
-  { "mips3",          1,      ISA_MIPS3,      CPU_R4000 },
-  { "mips4",          1,      ISA_MIPS4,      CPU_R8000 },
-  { "mips5",          1,      ISA_MIPS5,      CPU_MIPS5 },
-  { "mips32",         1,      ISA_MIPS32,     CPU_MIPS32 },
-  { "mips32r2",       1,      ISA_MIPS32R2,   CPU_MIPS32R2 },
-  { "mips64",         1,      ISA_MIPS64,     CPU_MIPS64 },
-  { "mips64r2",       1,      ISA_MIPS64R2,   CPU_MIPS64R2 },
+  { "mips1",          MIPS_CPU_IS_ISA,         ISA_MIPS1,      CPU_R3000 },
+  { "mips2",          MIPS_CPU_IS_ISA,         ISA_MIPS2,      CPU_R6000 },
+  { "mips3",          MIPS_CPU_IS_ISA,         ISA_MIPS3,      CPU_R4000 },
+  { "mips4",          MIPS_CPU_IS_ISA,         ISA_MIPS4,      CPU_R8000 },
+  { "mips5",          MIPS_CPU_IS_ISA,         ISA_MIPS5,      CPU_MIPS5 },
+  { "mips32",         MIPS_CPU_IS_ISA,         ISA_MIPS32,     CPU_MIPS32 },
+  { "mips32r2",       MIPS_CPU_IS_ISA,         ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "mips64",         MIPS_CPU_IS_ISA,         ISA_MIPS64,     CPU_MIPS64 },
+  { "mips64r2",       MIPS_CPU_IS_ISA,         ISA_MIPS64R2,   CPU_MIPS64R2 },
 
   /* MIPS I */
-  { "r3000",          0,      ISA_MIPS1,      CPU_R3000 },
-  { "r2000",          0,      ISA_MIPS1,      CPU_R3000 },
-  { "r3900",          0,      ISA_MIPS1,      CPU_R3900 },
+  { "r3000",          0,                       ISA_MIPS1,      CPU_R3000 },
+  { "r2000",          0,                       ISA_MIPS1,      CPU_R3000 },
+  { "r3900",          0,                       ISA_MIPS1,      CPU_R3900 },
 
   /* MIPS II */
-  { "r6000",          0,      ISA_MIPS2,      CPU_R6000 },
+  { "r6000",          0,                       ISA_MIPS2,      CPU_R6000 },
 
   /* MIPS III */
-  { "r4000",          0,      ISA_MIPS3,      CPU_R4000 },
-  { "r4010",          0,      ISA_MIPS2,      CPU_R4010 },
-  { "vr4100",         0,      ISA_MIPS3,      CPU_VR4100 },
-  { "vr4111",         0,      ISA_MIPS3,      CPU_R4111 },
-  { "vr4120",         0,      ISA_MIPS3,      CPU_VR4120 },
-  { "vr4130",         0,      ISA_MIPS3,      CPU_VR4120 },
-  { "vr4181",         0,      ISA_MIPS3,      CPU_R4111 },
-  { "vr4300",         0,      ISA_MIPS3,      CPU_R4300 },
-  { "r4400",          0,      ISA_MIPS3,      CPU_R4400 },
-  { "r4600",          0,      ISA_MIPS3,      CPU_R4600 },
-  { "orion",          0,      ISA_MIPS3,      CPU_R4600 },
-  { "r4650",          0,      ISA_MIPS3,      CPU_R4650 },
+  { "r4000",          0,                       ISA_MIPS3,      CPU_R4000 },
+  { "r4010",          0,                       ISA_MIPS2,      CPU_R4010 },
+  { "vr4100",         0,                       ISA_MIPS3,      CPU_VR4100 },
+  { "vr4111",         0,                       ISA_MIPS3,      CPU_R4111 },
+  { "vr4120",         0,                       ISA_MIPS3,      CPU_VR4120 },
+  { "vr4130",         0,                       ISA_MIPS3,      CPU_VR4120 },
+  { "vr4181",         0,                       ISA_MIPS3,      CPU_R4111 },
+  { "vr4300",         0,                       ISA_MIPS3,      CPU_R4300 },
+  { "r4400",          0,                       ISA_MIPS3,      CPU_R4400 },
+  { "r4600",          0,                       ISA_MIPS3,      CPU_R4600 },
+  { "orion",          0,                       ISA_MIPS3,      CPU_R4600 },
+  { "r4650",          0,                       ISA_MIPS3,      CPU_R4650 },
 
   /* MIPS IV */
-  { "r8000",          0,      ISA_MIPS4,      CPU_R8000 },
-  { "r10000",         0,      ISA_MIPS4,      CPU_R10000 },
-  { "r12000",         0,      ISA_MIPS4,      CPU_R12000 },
-  { "vr5000",         0,      ISA_MIPS4,      CPU_R5000 },
-  { "vr5400",         0,      ISA_MIPS4,      CPU_VR5400 },
-  { "vr5500",         0,      ISA_MIPS4,      CPU_VR5500 },
-  { "rm5200",         0,      ISA_MIPS4,      CPU_R5000 },
-  { "rm5230",         0,      ISA_MIPS4,      CPU_R5000 },
-  { "rm5231",         0,      ISA_MIPS4,      CPU_R5000 },
-  { "rm5261",         0,      ISA_MIPS4,      CPU_R5000 },
-  { "rm5721",         0,      ISA_MIPS4,      CPU_R5000 },
-  { "rm7000",         0,      ISA_MIPS4,      CPU_RM7000 },
-  { "rm9000",         0,      ISA_MIPS4,      CPU_RM9000 },
+  { "r8000",          0,                       ISA_MIPS4,      CPU_R8000 },
+  { "r10000",         0,                       ISA_MIPS4,      CPU_R10000 },
+  { "r12000",         0,                       ISA_MIPS4,      CPU_R12000 },
+  { "vr5000",         0,                       ISA_MIPS4,      CPU_R5000 },
+  { "vr5400",         0,                       ISA_MIPS4,      CPU_VR5400 },
+  { "vr5500",         0,                       ISA_MIPS4,      CPU_VR5500 },
+  { "rm5200",         0,                       ISA_MIPS4,      CPU_R5000 },
+  { "rm5230",         0,                       ISA_MIPS4,      CPU_R5000 },
+  { "rm5231",         0,                       ISA_MIPS4,      CPU_R5000 },
+  { "rm5261",         0,                       ISA_MIPS4,      CPU_R5000 },
+  { "rm5721",         0,                       ISA_MIPS4,      CPU_R5000 },
+  { "rm7000",         0,                       ISA_MIPS4,      CPU_RM7000 },
+  { "rm9000",         0,                       ISA_MIPS4,      CPU_RM9000 },
 
   /* MIPS 32 */
-  { "4kc",            0,      ISA_MIPS32,     CPU_MIPS32 },
-  { "4km",            0,      ISA_MIPS32,     CPU_MIPS32 },
-  { "4kp",            0,      ISA_MIPS32,     CPU_MIPS32 },
+  { "4kc",            0,                       ISA_MIPS32,     CPU_MIPS32 },
+  { "4km",            0,                       ISA_MIPS32,     CPU_MIPS32 },
+  { "4kp",            0,                       ISA_MIPS32,     CPU_MIPS32 },
+  { "4ksc",           MIPS_CPU_ASE_SMARTMIPS,  ISA_MIPS32,     CPU_MIPS32 },
+
+  /* MIPS 32 Release 2 */
+  { "4kec",           0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "4kem",           0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "4kep",           0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "4ksd",           MIPS_CPU_ASE_SMARTMIPS,  ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "m4k",            0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "m4kp",           0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "24k",            0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "24kc",           0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "24kf",           0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "24kx",           0,                       ISA_MIPS32R2,   CPU_MIPS32R2 },
+  /* 24ke is a 24k with DSP ASE, other ASEs are optional.  */
+  { "24ke",           MIPS_CPU_ASE_DSP,                ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "24kec",          MIPS_CPU_ASE_DSP,                ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "24kef",          MIPS_CPU_ASE_DSP,                ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "24kex",          MIPS_CPU_ASE_DSP,                ISA_MIPS32R2,   CPU_MIPS32R2 },
+  /* 34k is a 24k with MT ASE, other ASEs are optional.  */
+  { "34kc",           MIPS_CPU_ASE_MT,         ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "34kf",           MIPS_CPU_ASE_MT,         ISA_MIPS32R2,   CPU_MIPS32R2 },
+  { "34kx",           MIPS_CPU_ASE_MT,         ISA_MIPS32R2,   CPU_MIPS32R2 },
 
   /* MIPS 64 */
-  { "5kc",            0,      ISA_MIPS64,     CPU_MIPS64 },
-  { "20kc",           0,      ISA_MIPS64,     CPU_MIPS64 },
+  { "5kc",            0,                       ISA_MIPS64,     CPU_MIPS64 },
+  { "5kf",            0,                       ISA_MIPS64,     CPU_MIPS64 },
+  { "20kc",           MIPS_CPU_ASE_MIPS3D,     ISA_MIPS64,     CPU_MIPS64 },
+
+  /* MIPS 64 Release 2 */
+  { "25kf",           MIPS_CPU_ASE_MIPS3D,     ISA_MIPS64R2,   CPU_MIPS64R2 },
 
   /* Broadcom SB-1 CPU core */
-  { "sb1",            0,      ISA_MIPS64,     CPU_SB1 },
+  { "sb1",            MIPS_CPU_ASE_MIPS3D | MIPS_CPU_ASE_MDMX,
+                                               ISA_MIPS64,     CPU_SB1 },
+  /* Broadcom SB-1A CPU core */
+  { "sb1a",           MIPS_CPU_ASE_MIPS3D | MIPS_CPU_ASE_MDMX,
+                                               ISA_MIPS64,     CPU_SB1 },
 
   /* End marker */
   { NULL, 0, 0, 0 }
@@ -13898,7 +14746,7 @@ mips_cpu_info_from_isa (int isa)
   int i;
 
   for (i = 0; mips_cpu_info_table[i].name != NULL; i++)
-    if (mips_cpu_info_table[i].is_isa
+    if ((mips_cpu_info_table[i].flags & MIPS_CPU_IS_ISA)
        && isa == mips_cpu_info_table[i].isa)
       return (&mips_cpu_info_table[i]);
 
@@ -13992,6 +14840,15 @@ MIPS options:\n\
 -mips16                        generate mips16 instructions\n\
 -no-mips16             do not generate mips16 instructions\n"));
   fprintf (stream, _("\
+-msmartmips            generate smartmips instructions\n\
+-mno-smartmips         do not generate smartmips instructions\n"));  
+  fprintf (stream, _("\
+-mdsp                  generate DSP instructions\n\
+-mno-dsp               do not generate DSP instructions\n"));
+  fprintf (stream, _("\
+-mmt                   generate MT instructions\n\
+-mno-mt                        do not generate MT instructions\n"));
+  fprintf (stream, _("\
 -mfix-vr4120           work around certain VR4120 errata\n\
 -mfix-vr4130           work around VR4130 mflo/mfhi errata\n\
 -mgp32                 use 32-bit GPRs, regardless of the chosen ISA\n\
@@ -14061,3 +14918,14 @@ mips_cfi_frame_initial_instructions (void)
   cfi_add_CFA_def_cfa_register (SP);
 }
 
+int
+tc_mips_regname_to_dw2regnum (char *regname)
+{
+  unsigned int regnum = -1;
+  unsigned int reg;
+
+  if (reg_lookup (&regname, RTYPE_GP | RTYPE_NUM, &reg))
+    regnum = reg;
+
+  return regnum;
+}
This page took 0.078294 seconds and 4 git commands to generate.