[ gas/ChangeLog ]
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index 3108d0aa62801ba497d43f8e2814191a93dcb31d..d19a14987c25f1e77b7dc65f9a45d1dbc2a6ab08 100644 (file)
@@ -274,17 +274,23 @@ static int file_ase_mdmx;
    command line (e.g., by -march).  */
 static int file_ase_smartmips;
 
-#define ISA_SUPPORT_SMARTMIPS (mips_opts.isa == ISA_MIPS32       \
-                              || mips_opts.isa == ISA_MIPS32R2)
+#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)
+
 /* 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;
@@ -301,42 +307,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    \
-   || mips_opts.ase_smartmips  \
-   )
+#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)
 
@@ -1027,11 +1052,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);
@@ -1402,8 +1434,297 @@ 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)
@@ -1490,46 +1811,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 ();
 
@@ -1544,6 +1839,7 @@ md_begin (void)
 
   bfd_set_gp_size (stdoutput, g_switch_value);
 
+#ifdef OBJ_ELF
   if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
     {
       /* On a native system other than VxWorks, sections must be aligned
@@ -1582,9 +1878,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
          {
@@ -1594,7 +1888,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;
@@ -1611,7 +1904,6 @@ md_begin (void)
 
              mips_regmask_frag = frag_more (sizeof (Elf64_External_RegInfo));
            }
-#endif
          }
 
        if (ECOFF_DEBUGGING)
@@ -1621,7 +1913,6 @@ 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)
          {
            pdr_seg = subseg_new (".pdr", (subsegT) 0);
@@ -1630,11 +1921,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 ();
@@ -3015,7 +3306,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...)
         || 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))
@@ -7952,6 +8243,46 @@ static const struct mips_immed mips_immed[] = {
   { 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
@@ -7972,6 +8303,8 @@ mips_ip (char *str, struct mips_cl_insn *ip)
   char *s_reset;
   char save_c = 0;
   offsetT min_range, max_range;
+  int argnum;
+  unsigned int rtype;
 
   insn_error = NULL;
 
@@ -8032,6 +8365,9 @@ 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_dsp ? INSN_DSP : 0)
@@ -8076,6 +8412,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;
@@ -8492,11 +8829,11 @@ do_msbd:
                  s = expr_end;
                  continue;
 
-               case 'T': /* Coprocessor register */
+               case 'T': /* Coprocessor register */
                  /* +T is for disassembly only; never match.  */
                  break;
 
-               case 't': /* Coprocessor register number */
+               case 't': /* Coprocessor register number */
                  if (s[0] == '$' && ISDIGIT (s[1]))
                    {
                      ++s;
@@ -8630,7 +8967,7 @@ do_msbd:
              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)
@@ -8641,6 +8978,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);
+             ip->insn_opcode |= regno << OP_SH_RD;
+             if (ok) 
+               {
+                 lastregno = regno;
+                 continue;
+               }
+             else
+               break;
+
            case 'b':           /* base register */
            case 'd':           /* destination register */
            case 's':           /* source register */
@@ -8649,106 +9000,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).  */
            case 'g':           /* coprocessor destination register */
-             s_reset = s;
-             if (s[0] == '$')
+             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;
@@ -8814,7 +9081,6 @@ do_msbd:
                  lastregno = regno;
                  continue;
                }
-           notreg:
              switch (*args++)
                {
                case 'r':
@@ -8867,40 +9133,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
-                           || strcmp (str, "mftc1") == 0
-                           || strcmp (str, "mfthc1") == 0
-                           || strcmp (str, "cftc1") == 0
-                           || strcmp (str, "mttc1") == 0
-                           || strcmp (str, "mtthc1") == 0
-                           || strcmp (str, "cttc1") == 0))
+                     && ! mips_oddfpreg_ok (ip->insn_mo, argnum))
                    as_warn (_("Float register should be even, was %d"),
                             regno);
 
@@ -9288,19 +9536,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)
@@ -9467,8 +9707,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;
@@ -9581,70 +9851,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')
+                       ip->insn_opcode |= lastregno << MIPS16OP_SH_RX;
+                     else
+                       ip->insn_opcode |= lastregno << MIPS16OP_SH_RY;
+                     ++args;
+                     continue;
                    }
-                 else
-                   break;
+                 break;
                }
 
              if (*s == ' ')
@@ -9850,29 +10069,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;
@@ -9881,25 +10089,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')
@@ -9964,39 +10158,26 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
                        continue;
                      }
 
-                   if (*s != '$')
+                   if (! reg_lookup (&s, RTYPE_GP | RTYPE_NUM, &reg1))
                      {
                        as_bad (_("can't parse register list"));
                        break;
                      }
-                   ++s;
 
-                   reg1 = 0;
-                   while (ISDIGIT (*s))
-                     {
-                       reg1 *= 10;
-                       reg1 += *s - '0';
-                       ++s;
-                     }
-                   SKIP_SPACE_TABS (s);
+                   while (*s == ' ')
+                     ++s;
+
                    if (*s != '-')
                      reg2 = reg1;
                    else
                      {
                        ++s;
-                       if (*s != '$')
+                       if (! reg_lookup (&s, RTYPE_GP | RTYPE_NUM, &reg2)
+                           || reg2 < reg1)
                          {
                            as_bad (_("can't parse register list"));
                            break;
                          }
-                       ++s;
-                       reg2 = 0;
-                       while (ISDIGIT (*s))
-                         {
-                           reg2 *= 10;
-                           reg2 += *s - '0';
-                           ++s;
-                         }
                      }
 
                    while (reg1 <= reg2)
@@ -11227,14 +11408,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.  */
 
@@ -11253,13 +11463,36 @@ 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 = ((CPU_HAS_MIPS3D (file_mips_arch)
+                            || (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 = ((CPU_HAS_MDMX (file_mips_arch)
+                          || (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 = (CPU_HAS_DSP (file_mips_arch)) ? 1 : 0;
+    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 = (CPU_HAS_MT (file_mips_arch)) ? 1 : 0;
+    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;
@@ -12113,6 +12346,28 @@ 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;
@@ -12121,7 +12376,7 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
     mips_opts.mips16 = 0;
   else if (strcmp (name, "smartmips") == 0)
     {
-      if (!ISA_SUPPORT_SMARTMIPS)
+      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;
@@ -12137,11 +12392,21 @@ s_mipsset (int x ATTRIBUTE_UNUSED)
   else if (strcmp (name, "nomdmx") == 0)
     mips_opts.ase_mdmx = 0;
   else if (strcmp (name, "dsp") == 0)
-    mips_opts.ase_dsp = 1;
+    {
+      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)
-    mips_opts.ase_mt = 1;
+    {
+      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)
@@ -12753,73 +13018,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;
@@ -13921,6 +14124,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 */
@@ -14323,72 +14532,90 @@ 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 },
-
-  /* MIPS32 Release 2 */
-  { "m4k",            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 },
+  { "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 },
-  { "5kf",            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",            0,                       ISA_MIPS64,     CPU_SB1 },
 
   /* End marker */
   { NULL, 0, 0, 0 }
@@ -14503,7 +14730,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]);
 
@@ -14675,3 +14902,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.048193 seconds and 4 git commands to generate.