2000-01-13 Clinton Popetz <cpopetz@cygnus.com>
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index 33d1a683310bd3bd30bd37f8794d5ce6dffbf84b..723357a8706fbf2e7b59aeeeeb3e0f7852205937 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-mips.c -- assemble code for a MIPS chip.
-   Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1993, 94, 95, 96, 97, 98, 1999 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
@@ -54,7 +54,6 @@ static int mips_output_flavor () { return OUTPUT_FLAVOR; }
 #undef S_GET_SIZE
 #undef S_SET_ALIGN
 #undef S_SET_SIZE
-#undef TARGET_SYMBOL_FIELDS
 #undef obj_frob_file
 #undef obj_frob_file_after_relocs
 #undef obj_frob_symbol
@@ -194,68 +193,77 @@ static int file_mips_isa;
 /* The CPU type as a number: 2000, 3000, 4000, 4400, etc.  */
 static int mips_cpu = -1;
 
-/* Whether the 4650 instructions (mad/madu) are permitted.  */
-static int mips_4650 = -1;
+/* The argument of the -mabi= flag. */
+static char* mips_abi_string = 0;
+
+/* Wether we should mark the file EABI64 or EABI32. */
+static int mips_eabi64 = 0;
+
+/* If they asked for mips1 or mips2 and a cpu that is
+   mips3 or greater, then mark the object file 32BITMODE. */
+static int mips_32bitmode = 0;
+
+/* Some ISA's have delay slots for instructions which read or write
+   from a coprocessor (eg. mips1-mips3); some don't (eg mips4).
+   Return true if instructions marked INSN_LOAD_COPROC_DELAY, 
+   INSN_COPROC_MOVE_DELAY, or INSN_WRITE_COND_CODE actually have a
+   delay slot in this ISA.  The uses of this macro assume that any
+   ISA that has delay slots for one of these, has them for all.  They
+   also assume that ISAs which don't have delays for these insns, don't
+   have delays for the INSN_LOAD_MEMORY_DELAY instructions either. */
+#define ISA_HAS_COPROC_DELAYS(ISA) (        \
+   (ISA) == 1                               \
+   || (ISA) == 2                            \
+   || (ISA) == 3                            \
+   )
+
+/*  Return true if ISA supports 64 bit gp register instructions. */
+#define ISA_HAS_64BIT_REGS(ISA) (    \
+   (ISA) == 3                        \
+   || (ISA) == 4                     \
+   )
 
-/* Whether the 4010 instructions are permitted.  */
-static int mips_4010 = -1;
-
-/* Whether the 4100 MADD16 and DMADD16 are permitted. */
-static int mips_4100 = -1;
+/* Whether the processor uses hardware interlocks to protect 
+   reads from the HI and LO registers, and thus does not
+   require nops to be inserted.
 
-/* start-sanitize-vr5400 */
-/* Whether NEC vr5400 instructions are permitted. */
-static int mips_5400 = -1;
+   FIXME: GCC makes a distinction between -mcpu=FOO and -mFOO:
+   -mcpu=FOO schedules for FOO, but still produces code that meets the
+   requirements of MIPS ISA I.  For example, it won't generate any
+   FOO-specific instructions, and it will still assume that any
+   scheduling hazards described in MIPS ISA I are there, even if FOO
+   has interlocks.  -mFOO gives GCC permission to generate code that
+   will only run on a FOO; it will generate FOO-specific instructions,
+   and assume interlocks provided by a FOO.
 
-/* end-sanitize-vr5400 */
-/* start-sanitize-r5900 */
-/* Whether Toshiba r5900 instructions are permitted. */
-static int mips_5900 = -1;
+   However, GAS currently doesn't make this distinction; before Jan 28
+   1999, GAS's -mcpu=FOO implied -mFOO, which violates GCC's
+   assumptions.  The GCC driver passes these flags through to GAS, so
+   if GAS actually does anything that doesn't meet MIPS ISA I with
+   -mFOO, then GCC's -mcpu=FOO flag isn't going to work.
 
-/* end-sanitize-r5900 */
-/* Whether Toshiba r3900 instructions are permitted. */
-static int mips_3900 = -1;
+   And furthermore, it did not assume that -mFOO implied -mcpu=FOO,
+   which seems senseless --- why generate code which will only run on
+   a FOO, but schedule for something else?
 
-/* start-sanitize-tx49 */
-/* Whether Toshiba r4900 instructions are permitted. */
-static int mips_4900 = -1;
+   So now, at least, -mcpu=FOO and -mFOO are exactly equivalent.
 
-/* end-sanitize-tx49 */
-/* start-sanitize-tx19 */
-/* The tx19 (r1900) is a mips16 decoder with a tx39(r3900) behind it.
-   The tx19 related options and configuration bits are handled by 
-   the tx39 flags. */
-/* end-sanitize-tx19 */
+   -- Jim Blandy <jimb@cygnus.com> */
 
-/* Whether the processor uses hardware interlocks to protect 
-   reads from the HI and LO registers, and thus does not
-   require nops to be inserted.  */
-#define hilo_interlocks (mips_4010 || mips_cpu == 4300 || mips_3900 \
-                         /* start-sanitize-tx49 */                  \
-                         || mips_cpu == 4900 || mips_4900           \
-                         /* end-sanitize-tx49 */                    \
-                        /* start-sanitize-vr5400 */                \
-                        || mips_cpu == 5400                        \
-                        /* end-sanitize-vr5400 */                  \
+#define hilo_interlocks (mips_cpu == 4010                           \
                          )
 
 /* Whether the processor uses hardware interlocks to protect reads
    from the GPRs, and thus does not require nops to be inserted.  */
-#define gpr_interlocks (mips_opts.isa >= 2 || mips_3900)
-/* start-sanitize-vr5400 */
-#undef gpr_interlocks
-#define gpr_interlocks (mips_opts.isa >= 2 || mips_3900 || mips_5400)
-/* end-sanitize-vr5400 */
-
+#define gpr_interlocks \
+  (mips_opts.isa != 1  \
+   || mips_cpu == 3900)
 
 /* As with other "interlocks" this is used by hardware that has FP
    (co-processor) interlocks.  */
 /* Itbl support may require additional care here. */
-#define cop_interlocks (mips_cpu == 4300)
-/* start-sanitize-vr5400 */
-#undef cop_interlocks
-#define cop_interlocks (mips_cpu == 4300 || mips_cpu == 5400)
-/* end-sanitize-vr5400 */
+#define cop_interlocks (mips_cpu == 4300                            \
+                       )
 
 /* MIPS PIC level.  */
 
@@ -306,8 +314,9 @@ static int g_switch_seen = 0;
    better.
 
    This function can only provide a guess, but it seems to work for
-   gcc output.  If it guesses wrong, the only loss should be in
-   efficiency; it shouldn't introduce any bugs.
+   gcc output.  It needs to guess right for gcc, otherwise gcc
+   will put what it thinks is a GP-relative instruction in a branch
+   delay slot.
 
    I don't know if a fix is needed for the SVR4_PIC mode.  I've only
    fixed it for the non-PIC mode.  KR 95/04/07  */
@@ -594,9 +603,9 @@ static const int mips16_to_32_reg_map[] =
 
 #ifdef __STDC__
 #define internalError() \
-    as_fatal ("internal Error, line %d, %s", __LINE__, __FILE__)
+    as_fatal (_("internal Error, line %d, %s"), __LINE__, __FILE__)
 #else
-#define internalError() as_fatal ("MIPS internal Error");
+#define internalError() as_fatal (_("MIPS internal Error"));
 #endif
 
 enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG };
@@ -659,12 +668,16 @@ static void s_insn PARAMS ((int));
 static void md_obj_begin PARAMS ((void));
 static void md_obj_end PARAMS ((void));
 static long get_number PARAMS ((void));
-static void s_ent PARAMS ((int));
-static void s_mipsend PARAMS ((int));
-static void s_file PARAMS ((int));
+static void s_mips_ent PARAMS ((int));
+static void s_mips_end PARAMS ((int));
+static void s_mips_frame PARAMS ((int));
+static void s_mips_mask PARAMS ((int));
 static void s_mips_stab PARAMS ((int));
+static void s_mips_weakext PARAMS ((int));
+static void s_file PARAMS ((int));
 static int mips16_extended_frag PARAMS ((fragS *, asection *, long));
 
+
 static int validate_mips_insn PARAMS ((const struct mips_opcode *));
 \f
 /* Pseudo-op table.
@@ -683,7 +696,7 @@ static int validate_mips_insn PARAMS ((const struct mips_opcode *));
    not MIPS CPU specific, but are also not specific to the object file
    format.  This file is probably the best place to define them, but
    they are not currently supported: .asm0, .endr, .lab, .repeat,
-   .struct, .weakext.  */
+   .struct.  */
 
 static const pseudo_typeS mips_pseudo_table[] =
 {
@@ -707,6 +720,7 @@ static const pseudo_typeS mips_pseudo_table[] =
   {"err", s_err, 0},
   {"half", s_cons, 1},
   {"dword", s_cons, 3},
+  {"weakext", s_mips_weakext, 0},
 
  /* These pseudo-ops are defined in read.c, but must be overridden
      here for one reason or another.  */
@@ -733,16 +747,16 @@ static const pseudo_typeS mips_pseudo_table[] =
 static const pseudo_typeS mips_nonecoff_pseudo_table[] = {
  /* These pseudo-ops should be defined by the object file format.
     However, a.out doesn't support them, so we have versions here.  */
-  {"aent", s_ent, 1},
+  {"aent", s_mips_ent, 1},
   {"bgnb", s_ignore, 0},
-  {"end", s_mipsend, 0},
+  {"end", s_mips_end, 0},
   {"endb", s_ignore, 0},
-  {"ent", s_ent, 0},
+  {"ent", s_mips_ent, 0},
   {"file", s_file, 0},
-  {"fmask", s_ignore, 'F'},
-  {"frame", s_ignore, 0},
+  {"fmask", s_mips_mask, 'F'},
+  {"frame", s_mips_frame, 0},
   {"loc", s_ignore, 0},
-  {"mask", s_ignore, 'R'},
+  {"mask", s_mips_mask, 'R'},
   {"verstamp", s_ignore, 0},
   { 0 },
 };
@@ -802,6 +816,12 @@ static boolean imm_unmatched_hi;
 
 static boolean mips16_small, mips16_ext;
 
+#ifdef MIPS_STABS_ELF
+/* The pdr segment for per procedure frame/regmask info */
+
+static segT pdr_seg;
+#endif
+
 /*
  * 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.
@@ -815,6 +835,7 @@ md_begin ()
   const char *cpu;
   char *a = NULL;
   int broken = 0;
+  int mips_isa_from_cpu;
 
   cpu = TARGET_CPU;
   if (strcmp (cpu + (sizeof TARGET_CPU) - 3, "el") == 0)
@@ -833,10 +854,10 @@ md_begin ()
 
       if (strcmp (cpu, "mips") == 0)
         {
-          if (mips_opts.isa < 0)
-            mips_cpu = 3000;   
+         if (mips_opts.isa < 0)
+           mips_cpu = 3000;   
 
-          else if (mips_opts.isa == 2)
+         else if (mips_opts.isa == 2)
             mips_cpu = 6000;
 
           else if (mips_opts.isa == 3)
@@ -851,10 +872,6 @@ md_begin ()
       
       else if (strcmp (cpu, "r3900") == 0
                || strcmp (cpu, "mipstx39") == 0
-               /* start-sanitize-tx19 */
-               || strcmp (cpu, "r1900") == 0
-               || strcmp (cpu, "mipstx19") == 0
-               /* end-sanitize-tx19 */
                )
         mips_cpu = 3900;
 
@@ -880,32 +897,21 @@ md_begin ()
       else if (strcmp (cpu, "mips64vr4300") == 0)
         mips_cpu = 4300;
 
+      else if (strcmp (cpu, "mips64vr4111") == 0)
+        mips_cpu = 4111;
+
       else if (strcmp (cpu, "mips64vr4100") == 0)
         mips_cpu = 4100;
 
       else if (strcmp (cpu, "r4010") == 0)
         mips_cpu = 4010;
 
-      /* start-sanitize-tx49 */
-      else if (strcmp (cpu, "mips64tx49") == 0)
-        mips_cpu = 4900;
-      /* end-sanitize-tx49 */
 
       else if (strcmp (cpu, "r5000") == 0
               || strcmp (cpu, "mips64vr5000") == 0)
         mips_cpu = 5000;
 
-      /* start-sanitize-vr5400 */
-      else if (strcmp (cpu, "r5400") == 0
-              || strcmp (cpu, "mips64vr5400") == 0)
-       mips_cpu = 5400;
-      /* end-sanitize-vr5400 */
 
-      /* start-sanitize-r5900 */
-      else if (strcmp (cpu, "r5900") == 0
-              || strcmp (cpu, "mips64r5900") == 0)
-        mips_cpu = 5900;
-      /* end-sanitize-r5900 */
 
       else if (strcmp (cpu, "r8000") == 0
               || strcmp (cpu, "mips4") == 0)
@@ -921,40 +927,37 @@ md_begin ()
         mips_cpu = 3000;
     }
 
+  if (mips_cpu == 3000
+      || mips_cpu == 3900)
+    mips_isa_from_cpu = 1;
+
+  else if (mips_cpu == 6000
+          || mips_cpu == 4010)
+    mips_isa_from_cpu = 2;
+
+  else if (mips_cpu == 4000
+          || mips_cpu == 4100
+          || mips_cpu == 4111
+          || mips_cpu == 4400
+          || mips_cpu == 4300
+          || mips_cpu == 4600
+          || mips_cpu == 4650)
+    mips_isa_from_cpu = 3;
+
+  else if (mips_cpu == 5000
+          || mips_cpu == 8000
+               || mips_cpu == 10000)
+    mips_isa_from_cpu = 4;
+
+  else
+    mips_isa_from_cpu = -1;
+
   if (mips_opts.isa == -1)
     {
-      if (mips_cpu == 3000
-          || mips_cpu == 3900)
-        mips_opts.isa = 1;
-
-      else if (mips_cpu == 6000
-               || mips_cpu == 4010)
-        mips_opts.isa = 2;
-
-      else if (mips_cpu == 4000
-               || mips_cpu == 4100
-               || mips_cpu == 4400
-               || mips_cpu == 4300
-               || mips_cpu == 4600
-               /* start-sanitize-tx49 */
-               || mips_cpu == 4900
-               /* end-sanitize-tx49 */
-               /* start-sanitize-r5900 */
-               || mips_cpu == 5900
-               /* end-sanitize-r5900 */
-               || mips_cpu == 4650)
-        mips_opts.isa = 3;
-
-      else if (mips_cpu == 5000
-               /* start-sanitize-vr5400 */
-               || mips_cpu == 5400
-               /* end-sanitize-vr5400 */
-               || mips_cpu == 8000
-               || mips_cpu == 10000)
-        mips_opts.isa = 4;
-      
+      if (mips_isa_from_cpu != -1)
+       mips_opts.isa = mips_isa_from_cpu;
       else
-        mips_opts.isa = 1;
+       mips_opts.isa = 1;
     }
 
   if (mips_opts.mips16 < 0)
@@ -965,34 +968,6 @@ md_begin ()
        mips_opts.mips16 = 0;
     }
 
-  if (mips_4650 < 0)
-    mips_4650 = (mips_cpu == 4650);
-
-  if (mips_4010 < 0)
-    mips_4010 = (mips_cpu == 4010);
-
-  if (mips_4100 < 0)
-    mips_4100 = (mips_cpu == 4100);
-
-  /* start-sanitize-vr5400 */
-  if (mips_5400 < 0)
-    mips_5400 = (mips_cpu == 5400);
-  /* end-sanitize-vr5400 */
-
-  /* start-sanitize-r5900 */
-  if (mips_5900 < 0)
-    mips_5900 = (mips_cpu == 5900);
-  /* end-sanitize-r5900 */
-
-  if (mips_3900 < 0)
-    mips_3900 = (mips_cpu == 3900);
-
-  /* start-sanitize-tx49 */
-  if (mips_4900 < 0)
-    mips_4900 = (mips_cpu == 4900);
-
-  /* end-sanitize-tx49 */
-
   /* End of TARGET_CPU processing, get rid of malloced memory
      if necessary. */
   cpu = NULL;
@@ -1002,26 +977,49 @@ md_begin ()
     a = NULL;
     }
 
-  if (mips_opts.isa < 2 && mips_trap)
-    as_bad ("trap exception not supported at ISA 1");
+  if (mips_opts.isa == 1 && mips_trap)
+    as_bad (_("trap exception not supported at ISA 1"));
 
-  switch (mips_opts.isa)
+  /* Set the EABI kind based on the ISA before the user gets
+     to change the ISA with directives.  This isn't really
+     the best, but then neither is basing the abi on the isa. */     
+  if (ISA_HAS_64BIT_REGS (mips_opts.isa)
+      && mips_abi_string
+      && 0 == strcmp (mips_abi_string,"eabi"))
+    mips_eabi64 = 1;
+
+  if (mips_cpu != 0 && mips_cpu != -1)
     {
-    case 1:
-      ok = bfd_set_arch_mach (stdoutput, bfd_arch_mips, 3000);
-      break;
-    case 2:
-      ok = bfd_set_arch_mach (stdoutput, bfd_arch_mips, 6000);
-      break;
-    case 3:
-      ok = bfd_set_arch_mach (stdoutput, bfd_arch_mips, 4000);
-      break;
-    case 4:
-      ok = bfd_set_arch_mach (stdoutput, bfd_arch_mips, 8000);
-      break;
+      ok = bfd_set_arch_mach (stdoutput, bfd_arch_mips, mips_cpu);
+      
+      /* If they asked for mips1 or mips2 and a cpu that is
+        mips3 or greater, then mark the object file 32BITMODE. */
+      if (mips_isa_from_cpu != -1
+         && ! ISA_HAS_64BIT_REGS (mips_opts.isa) 
+         && ISA_HAS_64BIT_REGS (mips_isa_from_cpu))
+       mips_32bitmode = 1;
     }
+  else
+    {
+      switch (mips_opts.isa)
+       {
+       case 1:
+         ok = bfd_set_arch_mach (stdoutput, bfd_arch_mips, 3000);
+         break;
+       case 2:
+         ok = bfd_set_arch_mach (stdoutput, bfd_arch_mips, 6000);
+         break;
+       case 3:
+         ok = bfd_set_arch_mach (stdoutput, bfd_arch_mips, 4000);
+         break;
+       case 4:
+         ok = bfd_set_arch_mach (stdoutput, bfd_arch_mips, 8000);
+         break;
+       }
+    }
+
   if (! ok)
-    as_warn ("Could not set architecture and machine");
+    as_warn (_("Could not set architecture and machine"));
 
   file_mips_isa = mips_opts.isa;
 
@@ -1034,10 +1032,10 @@ md_begin ()
       retval = hash_insert (op_hash, name, (PTR) &mips_opcodes[i]);
       if (retval != NULL)
        {
-         fprintf (stderr, "internal error: can't hash `%s': %s\n",
+         fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
                   mips_opcodes[i].name, retval);
          /* Probably a memory allocation problem?  Give up now.  */
-         as_fatal ("Broken assembler.  No assembly attempted.");
+         as_fatal (_("Broken assembler.  No assembly attempted."));
        }
       do
        {
@@ -1060,7 +1058,7 @@ md_begin ()
 
       retval = hash_insert (mips16_op_hash, name, (PTR) &mips16_opcodes[i]);
       if (retval != NULL)
-       as_fatal ("internal: can't hash `%s': %s",
+       as_fatal (_("internal: can't hash `%s': %s"),
                  mips16_opcodes[i].name, retval);
       do
        {
@@ -1068,7 +1066,7 @@ md_begin ()
              && ((mips16_opcodes[i].match & mips16_opcodes[i].mask)
                  != mips16_opcodes[i].match))
            {
-             fprintf (stderr, "internal error: bad mips16 opcode: %s %s\n",
+             fprintf (stderr, _("internal error: bad mips16 opcode: %s %s\n"),
                       mips16_opcodes[i].name, mips16_opcodes[i].args);
              broken = 1;
            }
@@ -1079,7 +1077,7 @@ md_begin ()
     }
 
   if (broken)
-    as_fatal ("Broken assembler.  No assembly attempted.");
+    as_fatal (_("Broken assembler.  No assembly attempted."));
 
   /* We add all the general register names to the symbol table.  This
      helps us detect invalid uses of them.  */
@@ -1198,6 +1196,13 @@ md_begin ()
            (void) bfd_set_section_alignment (stdoutput, sec, 2);
          }
 
+#ifdef MIPS_STABS_ELF
+       pdr_seg = subseg_new (".pdr", (subsegT) 0);
+       (void) bfd_set_section_flags (stdoutput, pdr_seg,
+                            SEC_READONLY | SEC_RELOC | SEC_DEBUGGING);
+       (void) bfd_set_section_alignment (stdoutput, pdr_seg, 2);
+#endif
+
        subseg_set (seg, subseg);
       }
     }
@@ -1230,7 +1235,7 @@ md_assemble (str)
   else
     {
       mips_ip (str, &insn);
-      DBG(("returned from mips_ip(%s) insn_opcode = 0x%x\n"
+      DBG((_("returned from mips_ip(%s) insn_opcode = 0x%x\n")
                str, insn.insn_opcode));
     }
 
@@ -1350,7 +1355,7 @@ reg_needs_delay (reg)
 
   prev_pinfo = prev_insn.insn_mo->pinfo;
   if (! mips_opts.noreorder
-      && mips_opts.isa < 4
+      && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
       && ((prev_pinfo & INSN_LOAD_COPROC_DELAY)
          || (! gpr_interlocks
              && (prev_pinfo & INSN_LOAD_MEMORY_DELAY))))
@@ -1389,8 +1394,8 @@ mips16_mark_labels ()
          if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
            S_SET_OTHER (l->label, STO_MIPS16);
 #endif
-         if ((l->label->sy_value.X_add_number & 1) == 0)
-           ++l->label->sy_value.X_add_number;
+         if ((S_GET_VALUE (l->label) & 1) == 0)
+           S_SET_VALUE (l->label, S_GET_VALUE (l->label) + 1);
        }
     }
 }
@@ -1453,7 +1458,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
       /* The previous insn might require a delay slot, depending upon
         the contents of the current insn.  */
       if (! mips_opts.mips16
-         && mips_opts.isa < 4
+         && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
          && (((prev_pinfo & INSN_LOAD_COPROC_DELAY)
                && ! cop_interlocks)
              || (! gpr_interlocks
@@ -1473,10 +1478,10 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
            ++nops;
        }
       else if (! mips_opts.mips16
-              && mips_opts.isa < 4
+              && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
               && (((prev_pinfo & INSN_COPROC_MOVE_DELAY)
                     && ! cop_interlocks)
-                  || (mips_opts.isa < 2
+                  || (mips_opts.isa == 1
                       && (prev_pinfo & INSN_COPROC_MEMORY_DELAY))))
        {
          /* A generic coprocessor delay.  The previous instruction
@@ -1532,7 +1537,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
            }
        }
       else if (! mips_opts.mips16
-              && mips_opts.isa < 4
+              && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
               && (prev_pinfo & INSN_WRITE_COND_CODE)
                && ! cop_interlocks)
        {
@@ -1550,21 +1555,48 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
        {
          /* The previous instruction reads the LO register; if the
             current instruction writes to the LO register, we must
-            insert two NOPS.  Some newer processors have interlocks.  */
-         if (! hilo_interlocks
+            insert two NOPS.  Some newer processors have interlocks. 
+            Also the tx39's multiply instructions can be exectuted 
+             immediatly after a read from HI/LO (without the delay),
+             though the tx39's divide insns still do require the 
+            delay. */
+         if (! (hilo_interlocks
+                || (mips_cpu == 3900 && (pinfo & INSN_MULT)))
              && (mips_optimize == 0
                  || (pinfo & INSN_WRITE_LO)))
            nops += 2;
+         /* Most mips16 branch insns don't have a delay slot.
+            If a read from LO is immediately followed by a branch
+            to a write to LO we have a read followed by a write
+            less than 2 insns away.  We assume the target of
+            a branch might be a write to LO, and insert a nop
+            between a read and an immediately following branch. */
+         else if (mips_opts.mips16
+                  && (mips_optimize == 0
+                      || (pinfo & MIPS16_INSN_BRANCH)))
+           nops += 1;
        }
       else if (prev_insn.insn_mo->pinfo & INSN_READ_HI)
        {
          /* The previous instruction reads the HI register; if the
             current instruction writes to the HI register, we must
-            insert a NOP.  Some newer processors have interlocks.  */
-         if (! hilo_interlocks
+            insert a NOP.  Some newer processors have interlocks.
+            Also the note tx39's multiply above. */
+         if (! (hilo_interlocks
+                || (mips_cpu == 3900 && (pinfo & INSN_MULT)))
              && (mips_optimize == 0
                  || (pinfo & INSN_WRITE_HI)))
            nops += 2;
+         /* Most mips16 branch insns don't have a delay slot.
+            If a read from HI is immediately followed by a branch
+            to a write to HI we have a read followed by a write
+            less than 2 insns away.  We assume the target of
+            a branch might be a write to HI, and insert a nop
+            between a read and an immediately following branch. */
+         else if (mips_opts.mips16
+                  && (mips_optimize == 0
+                      || (pinfo & MIPS16_INSN_BRANCH)))
+           nops += 1;
        }
 
       /* If the previous instruction was in a noreorder section, then
@@ -1582,17 +1614,19 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
         instruction, we must check for these cases compared to the
         instruction previous to the previous instruction.  */
       if ((! mips_opts.mips16
-          && mips_opts.isa < 4
+          && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
           && (prev_prev_insn.insn_mo->pinfo & INSN_COPROC_MOVE_DELAY)
           && (prev_prev_insn.insn_mo->pinfo & INSN_WRITE_COND_CODE)
           && (pinfo & INSN_READ_COND_CODE)
           && ! cop_interlocks)
          || ((prev_prev_insn.insn_mo->pinfo & INSN_READ_LO)
              && (pinfo & INSN_WRITE_LO)
-             && ! hilo_interlocks)
+             && ! (hilo_interlocks
+                   || (mips_cpu == 3900 && (pinfo & INSN_MULT))))
          || ((prev_prev_insn.insn_mo->pinfo & INSN_READ_HI)
              && (pinfo & INSN_WRITE_HI)
-             && ! hilo_interlocks))
+             && ! (hilo_interlocks
+                   || (mips_cpu == 3900 && (pinfo & INSN_MULT)))))
        prev_prev_nop = 1;
       else
        prev_prev_nop = 0;
@@ -1643,11 +1677,11 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
          for (l = insn_labels; l != NULL; l = l->next)
            {
              assert (S_GET_SEGMENT (l->label) == now_seg);
-             l->label->sy_frag = frag_now;
+             symbol_set_frag (l->label, frag_now);
              S_SET_VALUE (l->label, (valueT) frag_now_fix ());
              /* mips16 text labels are stored as odd.  */
              if (mips_opts.mips16)
-               ++l->label->sy_value.X_add_number;
+               S_SET_VALUE (l->label, S_GET_VALUE (l->label) + 1);
            }
 
 #ifndef NO_ECOFF_DEBUGGING
@@ -1724,7 +1758,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
       if (mips_opts.mips16
          && mips_opts.noreorder
          && (prev_pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
-       as_warn ("extended instruction in delay slot");
+       as_warn (_("extended instruction in delay slot"));
 
       f = frag_more (4);
     }
@@ -1746,14 +1780,14 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
 
            case BFD_RELOC_MIPS_JMP:
              if ((address_expr->X_add_number & 3) != 0)
-               as_bad ("jump to misaligned address (0x%lx)",
+               as_bad (_("jump to misaligned address (0x%lx)"),
                        (unsigned long) address_expr->X_add_number);
              ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0x3ffffff;
              break;
 
            case BFD_RELOC_MIPS16_JMP:
              if ((address_expr->X_add_number & 3) != 0)
-               as_bad ("jump to misaligned address (0x%lx)",
+               as_bad (_("jump to misaligned address (0x%lx)"),
                        (unsigned long) address_expr->X_add_number);
              ip->insn_opcode |=
                (((address_expr->X_add_number & 0x7c0000) << 3)
@@ -1761,6 +1795,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                 | ((address_expr->X_add_number & 0x3fffc) >> 2));
              break;
 
+
            case BFD_RELOC_16_PCREL_S2:
              goto need_reloc;
 
@@ -1929,19 +1964,20 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                 we can not swap, and I don't feel like handling that
                 case.  */
              || (! mips_opts.mips16
-                 && mips_opts.isa < 4
+                 && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
                  && (pinfo & INSN_READ_COND_CODE))
              /* We can not swap with an instruction that requires a
                 delay slot, becase the target of the branch might
                 interfere with that instruction.  */
              || (! mips_opts.mips16
-                 && mips_opts.isa < 4
+                 && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
                  && (prev_pinfo
               /* Itbl support may require additional care here. */
                      & (INSN_LOAD_COPROC_DELAY
                         | INSN_COPROC_MOVE_DELAY
                         | INSN_WRITE_COND_CODE)))
-             || (! hilo_interlocks
+             || (! (hilo_interlocks
+                    || (mips_cpu == 3900 && (pinfo & INSN_MULT)))
                  && (prev_pinfo
                      & (INSN_READ_LO
                         | INSN_READ_HI)))
@@ -1949,7 +1985,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                  && ! gpr_interlocks
                  && (prev_pinfo & INSN_LOAD_MEMORY_DELAY))
              || (! mips_opts.mips16
-                 && mips_opts.isa < 2
+                 && mips_opts.isa == 1
                   /* Itbl support may require additional care here. */
                  && (prev_pinfo & INSN_COPROC_MEMORY_DELAY))
              /* We can not swap with a branch instruction.  */
@@ -2054,7 +2090,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                 delay, and sets a register that the branch reads, we
                 can not swap.  */
              || (! mips_opts.mips16
-                 && mips_opts.isa < 4
+                 && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
               /* Itbl support may require additional care here. */
                  && ((prev_prev_insn.insn_mo->pinfo & INSN_LOAD_COPROC_DELAY)
                      || (! gpr_interlocks
@@ -2080,7 +2116,10 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
              /* If the previous instruction had a fixup in mips16
                  mode, we can not swap.  This normally means that the
                  previous instruction was a 4 byte branch anyhow.  */
-             || (mips_opts.mips16 && prev_insn_fixp))
+             || (mips_opts.mips16 && prev_insn_fixp)
+             /* If the previous instruction is a sync, sync.l, or 
+                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
@@ -2213,6 +2252,16 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
 
   /* We just output an insn, so the next one doesn't have a label.  */
   mips_clear_insn_labels ();
+
+  /* We must ensure that a fixup associated with an unmatched %hi
+     reloc does not become a variant frag.  Otherwise, the
+     rearrangement of %hi relocs in frob_file may confuse
+     tc_gen_reloc.  */
+  if (unmatched_hi)
+    {
+      frag_wane (frag_now);
+      frag_new (0);
+    }
 }
 
 /* This function forgets that there was any previous instruction or
@@ -2257,7 +2306,7 @@ mips_emit_delays (insns)
 
       nops = 0;
       if ((! mips_opts.mips16
-          && mips_opts.isa < 4
+          && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
           && (! cop_interlocks
                && (prev_insn.insn_mo->pinfo
                    & (INSN_LOAD_COPROC_DELAY
@@ -2272,14 +2321,14 @@ mips_emit_delays (insns)
              && (prev_insn.insn_mo->pinfo 
                   & INSN_LOAD_MEMORY_DELAY))
          || (! mips_opts.mips16
-             && mips_opts.isa < 2
+             && mips_opts.isa == 1
              && (prev_insn.insn_mo->pinfo
                  & INSN_COPROC_MEMORY_DELAY)))
        {
           /* Itbl support may require additional care here. */
          ++nops;
          if ((! mips_opts.mips16
-              && mips_opts.isa < 4
+              && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
               && (! cop_interlocks
                    && prev_insn.insn_mo->pinfo & INSN_WRITE_COND_CODE))
              || (! hilo_interlocks
@@ -2291,7 +2340,7 @@ mips_emit_delays (insns)
            nops = 0;
        }
       else if ((! mips_opts.mips16
-               && mips_opts.isa < 4
+               && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
                && (! cop_interlocks
                     && prev_prev_insn.insn_mo->pinfo & INSN_WRITE_COND_CODE))
               || (! hilo_interlocks
@@ -2332,11 +2381,11 @@ mips_emit_delays (insns)
          for (l = insn_labels; l != NULL; l = l->next)
            {
              assert (S_GET_SEGMENT (l->label) == now_seg);
-             l->label->sy_frag = frag_now;
+             symbol_set_frag (l->label, frag_now);
              S_SET_VALUE (l->label, (valueT) frag_now_fix ());
              /* mips16 text labels are stored as odd.  */
              if (mips_opts.mips16)
-               ++l->label->sy_value.X_add_number;
+               S_SET_VALUE (l->label, S_GET_VALUE (l->label) + 1);
            }
        }
     }
@@ -2375,7 +2424,6 @@ macro_build (place, counter, ep, name, fmt, va_alist)
   struct mips_cl_insn insn;
   bfd_reloc_code_real_type r;
   va_list args;
-  int insn_isa;
 
 #ifdef USE_STDARG
   va_start (args, fmt);
@@ -2389,7 +2437,7 @@ macro_build (place, counter, ep, name, fmt, va_alist)
    * to generate a better warning message here...
    */
   if (mips_opts.warn_about_macros && place == NULL && *counter == 1)
-    as_warn ("Macro instruction expanded into multiple instructions");
+    as_warn (_("Macro instruction expanded into multiple instructions"));
 
   if (place == NULL)
     *counter += 1;             /* bump instruction counter */
@@ -2409,44 +2457,10 @@ macro_build (place, counter, ep, name, fmt, va_alist)
   /* Search until we get a match for NAME.  */
   while (1)
     {
-      if ((insn.insn_mo->membership & INSN_ISA) == INSN_ISA1)
-       insn_isa = 1;
-      else if ((insn.insn_mo->membership & INSN_ISA) == INSN_ISA2)
-       insn_isa = 2;
-      else if ((insn.insn_mo->membership & INSN_ISA) == INSN_ISA3)
-       insn_isa = 3;
-      else if ((insn.insn_mo->membership & INSN_ISA) == INSN_ISA4)
-       insn_isa = 4;
-      else
-       insn_isa = 15;
-
       if (strcmp (fmt, insn.insn_mo->args) == 0
          && insn.insn_mo->pinfo != INSN_MACRO
-         && (insn_isa <= mips_opts.isa
-             || (mips_4650
-                 && (insn.insn_mo->membership & INSN_4650) != 0)
-             || (mips_4010
-                 && (insn.insn_mo->membership & INSN_4010) != 0)
-             || (mips_4100
-                 && (insn.insn_mo->membership & INSN_4100) != 0)
-             /* start-sanitize-tx49 */
-             || (mips_4900
-                 && (insn.insn_mo->membership & INSN_4900) != 0)
-             /* end-sanitize-tx49 */
-             /* start-sanitize-r5900 */
-             || (mips_5900
-                 && (insn.insn_mo->membership & INSN_5900) != 0)
-             /* end-sanitize-r5900 */
-             /* start-sanitize-vr5400 */
-             || (mips_5400
-                 && (insn.insn_mo->membership & INSN_5400) != 0)
-             /* end-sanitize-vr5400 */
-             || (mips_3900
-                 && (insn.insn_mo->membership & INSN_3900) != 0))
-         /* start-sanitize-r5900 */
-         && (! mips_5900 || (insn.insn_mo->pinfo & FP_D) == 0)
-         /* end-sanitize-r5900 */
-         && (! mips_4650 || (insn.insn_mo->pinfo & FP_D) == 0))
+         && OPCODE_IS_MEMBER (insn.insn_mo, mips_opts.isa, mips_cpu)
+         && (mips_cpu != 4650 || (insn.insn_mo->pinfo & FP_D) == 0))
        break;
 
       ++insn.insn_mo;
@@ -2504,6 +2518,10 @@ macro_build (place, counter, ep, name, fmt, va_alist)
          insn.insn_opcode |= va_arg (args, int) << 6;
          continue;
 
+       case 'q':
+         insn.insn_opcode |= va_arg (args, int) << 6;
+         continue;
+
        case 'b':
        case 's':
        case 'r':
@@ -2570,6 +2588,10 @@ macro_build (place, counter, ep, name, fmt, va_alist)
          r = BFD_RELOC_MIPS_JMP;
          continue;
 
+       case 'C':
+         insn.insn_opcode |= va_arg (args, unsigned long);
+         continue;
+
        default:
          internalError ();
        }
@@ -2757,7 +2779,7 @@ macro_build_lui (place, counter, ep, regnum)
    * to generate a better warning message here...
    */
   if (mips_opts.warn_about_macros && place == NULL && *counter == 1)
-    as_warn ("Macro instruction expanded into multiple instructions");
+    as_warn (_("Macro instruction expanded into multiple instructions"));
 
   if (place == NULL)
     *counter += 1;             /* bump instruction counter */
@@ -2810,9 +2832,9 @@ check_absolute_expr (ip, ex)
      expressionS *ex;
 {
   if (ex->X_op == O_big)
-    as_bad ("unsupported large constant");
+    as_bad (_("unsupported large constant"));
   else if (ex->X_op != O_constant)
-    as_bad ("Instruction %s requires absolute expression", ip->insn_mo->name);
+    as_bad (_("Instruction %s requires absolute expression"), ip->insn_mo->name);
 }
 
 /* Count the leading zeroes by performing a binary chop. This is a
@@ -2937,9 +2959,9 @@ load_register (counter, reg, ep, dbl)
                    || ! ep->X_unsigned
                    || sizeof (ep->X_add_number) > 4
                    || (ep->X_add_number & 0x80000000) == 0))
-              || ((mips_opts.isa < 3 || ! dbl)
+              || ((! ISA_HAS_64BIT_REGS (mips_opts.isa) || ! dbl)
                   && (ep->X_add_number &~ (offsetT) 0xffffffff) == 0)
-              || (mips_opts.isa < 3
+              || (! ISA_HAS_64BIT_REGS (mips_opts.isa)
                   && ! dbl
                   && ((ep->X_add_number &~ (offsetT) 0xffffffff)
                       == ~ (offsetT) 0xffffffff)))
@@ -2956,9 +2978,9 @@ load_register (counter, reg, ep, dbl)
 
   /* The value is larger than 32 bits.  */
 
-  if (mips_opts.isa < 3)
+  if (! ISA_HAS_64BIT_REGS (mips_opts.isa))
     {
-      as_bad ("Number larger than 32 bits");
+      as_bad (_("Number larger than 32 bits"));
       macro_build ((char *) NULL, counter, ep, "addiu", "t,r,j", reg, 0,
                   (int) BFD_RELOC_LO16);
       return;
@@ -2979,7 +3001,7 @@ load_register (counter, reg, ep, dbl)
       if (ep->X_add_number == 3)
        generic_bignum[3] = 0;
       else if (ep->X_add_number > 4)
-       as_bad ("Number larger than 64 bits");
+       as_bad (_("Number larger than 64 bits"));
       lo32.X_op = O_constant;
       lo32.X_add_number = generic_bignum[0] + (generic_bignum[1] << 16);
       hi32.X_op = O_constant;
@@ -3171,7 +3193,7 @@ load_address (counter, reg, ep)
   if (ep->X_op != O_constant
       && ep->X_op != O_symbol)
     {
-      as_bad ("expression too complex");
+      as_bad (_("expression too complex"));
       ep->X_op = O_constant;
     }
 
@@ -3196,7 +3218,9 @@ load_address (counter, reg, ep)
        {
          frag_grow (20);
          macro_build ((char *) NULL, counter, ep,
-                      mips_opts.isa < 3 ? "addiu" : "daddiu",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "addiu" : "daddiu"),
                       "t,r,j", reg, GP, (int) BFD_RELOC_MIPS_GPREL);
          p = frag_var (rs_machine_dependent, 8, 0,
                        RELAX_ENCODE (4, 8, 0, 4, 0,
@@ -3207,7 +3231,9 @@ load_address (counter, reg, ep)
       if (p != NULL)
        p += 4;
       macro_build (p, counter, ep,
-                  mips_opts.isa < 3 ? "addiu" : "daddiu",
+                  ((bfd_arch_bits_per_address (stdoutput) == 32
+                    || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                   ? "addiu" : "daddiu"),
                   "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
     }
   else if (mips_pic == SVR4_PIC && ! mips_big_got)
@@ -3225,22 +3251,28 @@ load_address (counter, reg, ep)
       ep->X_add_number = 0;
       frag_grow (20);
       macro_build ((char *) NULL, counter, ep,
-                  mips_opts.isa < 3 ? "lw" : "ld",
+                  ((bfd_arch_bits_per_address (stdoutput) == 32
+                    || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                   ? "lw" : "ld"),
                   "t,o(b)", reg, (int) BFD_RELOC_MIPS_GOT16, GP);
       macro_build ((char *) NULL, counter, (expressionS *) NULL, "nop", "");
       p = frag_var (rs_machine_dependent, 4, 0,
                    RELAX_ENCODE (0, 4, -8, 0, 0, mips_opts.warn_about_macros),
                    ep->X_add_symbol, (offsetT) 0, (char *) NULL);
       macro_build (p, counter, ep,
-                  mips_opts.isa < 3 ? "addiu" : "daddiu",
+                  ((bfd_arch_bits_per_address (stdoutput) == 32
+                    || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                   ? "addiu" : "daddiu"),
                   "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
       if (ex.X_add_number != 0)
        {
          if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000)
-           as_bad ("PIC code offset overflow (max 16 signed bits)");
+           as_bad (_("PIC code offset overflow (max 16 signed bits)"));
          ex.X_op = O_constant;
          macro_build ((char *) NULL, counter, &ex,
-                      mips_opts.isa < 3 ? "addiu" : "daddiu",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "addiu" : "daddiu"),
                       "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
        }
     }
@@ -3269,10 +3301,14 @@ load_address (counter, reg, ep)
       macro_build ((char *) NULL, counter, ep, "lui", "t,u", reg,
                   (int) BFD_RELOC_MIPS_GOT_HI16);
       macro_build ((char *) NULL, counter, (expressionS *) NULL,
-                  mips_opts.isa < 3 ? "addu" : "daddu",
+                  ((bfd_arch_bits_per_address (stdoutput) == 32
+                    || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                   ? "addu" : "daddu"),
                   "d,v,t", reg, reg, GP);
       macro_build ((char *) NULL, counter, ep,
-                  mips_opts.isa < 3 ? "lw" : "ld",
+                  ((bfd_arch_bits_per_address (stdoutput) == 32
+                    || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                   ? "lw" : "ld"),
                   "t,o(b)", reg, (int) BFD_RELOC_MIPS_GOT_LO16, reg);
       p = frag_var (rs_machine_dependent, 12 + off, 0,
                    RELAX_ENCODE (12, 12 + off, off, 8 + off, 0,
@@ -3288,21 +3324,27 @@ load_address (counter, reg, ep)
          p += 4;
        }
       macro_build (p, counter, ep,
-                  mips_opts.isa < 3 ? "lw" : "ld",
+                  ((bfd_arch_bits_per_address (stdoutput) == 32
+                    || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                   ? "lw" : "ld"),
                   "t,o(b)", reg, (int) BFD_RELOC_MIPS_GOT16, GP);
       p += 4;
       macro_build (p, counter, (expressionS *) NULL, "nop", "");
       p += 4;
       macro_build (p, counter, ep,
-                  mips_opts.isa < 3 ? "addiu" : "daddiu",
+                  ((bfd_arch_bits_per_address (stdoutput) == 32
+                    || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                   ? "addiu" : "daddiu"),
                   "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
       if (ex.X_add_number != 0)
        {
          if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000)
-           as_bad ("PIC code offset overflow (max 16 signed bits)");
+           as_bad (_("PIC code offset overflow (max 16 signed bits)"));
          ex.X_op = O_constant;
          macro_build ((char *) NULL, counter, &ex,
-                      mips_opts.isa < 3 ? "addiu" : "daddiu",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "addiu" : "daddiu"),
                       "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
        }
     }
@@ -3312,7 +3354,9 @@ load_address (counter, reg, ep)
           addiu        $reg,$gp,<sym>          (BFD_RELOC_MIPS_GPREL)
         */
       macro_build ((char *) NULL, counter, ep,
-                  mips_opts.isa < 3 ? "addiu" : "daddiu",
+                  ((bfd_arch_bits_per_address (stdoutput) == 32
+                    || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                   ? "addiu" : "daddiu"),
                   "t,r,j", reg, GP, (int) BFD_RELOC_MIPS_GPREL);
     }
   else
@@ -3354,6 +3398,7 @@ macro (ip)
   int dbl = 0;
   int coproc = 0;
   int lr = 0;
+  int imm = 0;
   offsetT maxnum;
   int off;
   bfd_reloc_code_real_type r;
@@ -3518,7 +3563,7 @@ macro (ip)
     case M_BGT_I:
       /* check for > max integer */
       maxnum = 0x7fffffff;
-      if (mips_opts.isa >= 3 && sizeof (maxnum) > 4)
+      if (ISA_HAS_64BIT_REGS (mips_opts.isa) && sizeof (maxnum) > 4)
        {
          maxnum <<= 16;
          maxnum |= 0xffff;
@@ -3527,25 +3572,25 @@ macro (ip)
        }
       if (imm_expr.X_op == O_constant
          && imm_expr.X_add_number >= maxnum
-         && (mips_opts.isa < 3 || sizeof (maxnum) > 4))
+         && (! ISA_HAS_64BIT_REGS (mips_opts.isa) || sizeof (maxnum) > 4))
        {
        do_false:
          /* result is always false */
          if (! likely)
            {
-             as_warn ("Branch %s is always false (nop)", ip->insn_mo->name);
+             as_warn (_("Branch %s is always false (nop)"), ip->insn_mo->name);
              macro_build ((char *) NULL, &icnt, NULL, "nop", "", 0);
            }
          else
            {
-             as_warn ("Branch likely %s is always false", ip->insn_mo->name);
+             as_warn (_("Branch likely %s is always false"), ip->insn_mo->name);
              macro_build ((char *) NULL, &icnt, &offset_expr, "bnel",
                           "s,t,p", 0, 0);
            }
          return;
        }
       if (imm_expr.X_op != O_constant)
-       as_bad ("Unsupported large constant");
+       as_bad (_("Unsupported large constant"));
       imm_expr.X_add_number++;
       /* FALLTHROUGH */
     case M_BGE_I:
@@ -3567,7 +3612,7 @@ macro (ip)
          return;
        }
       maxnum = 0x7fffffff;
-      if (mips_opts.isa >= 3 && sizeof (maxnum) > 4)
+      if (ISA_HAS_64BIT_REGS (mips_opts.isa) && sizeof (maxnum) > 4)
        {
          maxnum <<= 16;
          maxnum |= 0xffff;
@@ -3577,11 +3622,11 @@ macro (ip)
       maxnum = - maxnum - 1;
       if (imm_expr.X_op == O_constant
          && imm_expr.X_add_number <= maxnum
-         && (mips_opts.isa < 3 || sizeof (maxnum) > 4))
+         && (! ISA_HAS_64BIT_REGS (mips_opts.isa) || sizeof (maxnum) > 4))
        {
        do_true:
          /* result is always true */
-         as_warn ("Branch %s is always true", ip->insn_mo->name);
+         as_warn (_("Branch %s is always true"), ip->insn_mo->name);
          macro_build ((char *) NULL, &icnt, &offset_expr, "b", "p");
          return;
        }
@@ -3614,12 +3659,12 @@ macro (ip)
       likely = 1;
     case M_BGTU_I:
       if (sreg == 0
-         || (mips_opts.isa < 3
+         || (! ISA_HAS_64BIT_REGS (mips_opts.isa)
              && imm_expr.X_op == O_constant
              && imm_expr.X_add_number == 0xffffffff))
        goto do_false;
       if (imm_expr.X_op != O_constant)
-       as_bad ("Unsupported large constant");
+       as_bad (_("Unsupported large constant"));
       imm_expr.X_add_number++;
       /* FALLTHROUGH */
     case M_BGEU_I:
@@ -3710,7 +3755,7 @@ macro (ip)
       likely = 1;
     case M_BLE_I:
       maxnum = 0x7fffffff;
-      if (mips_opts.isa >= 3 && sizeof (maxnum) > 4)
+      if (ISA_HAS_64BIT_REGS (mips_opts.isa) && sizeof (maxnum) > 4)
        {
          maxnum <<= 16;
          maxnum |= 0xffff;
@@ -3719,10 +3764,10 @@ macro (ip)
        }
       if (imm_expr.X_op == O_constant
          && imm_expr.X_add_number >= maxnum
-         && (mips_opts.isa < 3 || sizeof (maxnum) > 4))
+         && (! ISA_HAS_64BIT_REGS (mips_opts.isa) || sizeof (maxnum) > 4))
        goto do_true;
       if (imm_expr.X_op != O_constant)
-       as_bad ("Unsupported large constant");
+       as_bad (_("Unsupported large constant"));
       imm_expr.X_add_number++;
       /* FALLTHROUGH */
     case M_BLT_I:
@@ -3772,12 +3817,12 @@ macro (ip)
       likely = 1;
     case M_BLEU_I:
       if (sreg == 0
-         || (mips_opts.isa < 3
+         || (! ISA_HAS_64BIT_REGS (mips_opts.isa)
              && imm_expr.X_op == O_constant
              && imm_expr.X_add_number == 0xffffffff))
        goto do_true;
       if (imm_expr.X_op != O_constant)
-       as_bad ("Unsupported large constant");
+       as_bad (_("Unsupported large constant"));
       imm_expr.X_add_number++;
       /* FALLTHROUGH */
     case M_BLTU_I:
@@ -3853,11 +3898,11 @@ macro (ip)
     do_div3:
       if (treg == 0)
        {
-         as_warn ("Divide by zero.");
+         as_warn (_("Divide by zero."));
          if (mips_trap)
            macro_build ((char *) NULL, &icnt, NULL, "teq", "s,t", 0, 0);
          else
-           macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
+             macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
          return;
        }
 
@@ -3878,7 +3923,7 @@ macro (ip)
          macro_build ((char *) NULL, &icnt, NULL,
                       dbl ? "ddiv" : "div",
                       "z,s,t", sreg, treg);
-         macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
+           macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
        }
       expr1.X_add_number = -1;
       macro_build ((char *) NULL, &icnt, &expr1,
@@ -3901,15 +3946,24 @@ macro (ip)
                       (int) BFD_RELOC_HI16);
        }
       if (mips_trap)
-       macro_build ((char *) NULL, &icnt, NULL, "teq", "s,t", sreg, AT);
+       {
+         macro_build ((char *) NULL, &icnt, NULL, "teq", "s,t", sreg, AT);
+         /* We want to close the noreorder block as soon as possible, so
+            that later insns are available for delay slot filling.  */
+         --mips_opts.noreorder;
+       }
       else
        {
          expr1.X_add_number = 8;
          macro_build ((char *) NULL, &icnt, &expr1, "bne", "s,t,p", sreg, AT);
          macro_build ((char *) NULL, &icnt, NULL, "nop", "", 0);
-         macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
+
+         /* We want to close the noreorder block as soon as possible, so
+            that later insns are available for delay slot filling.  */
+         --mips_opts.noreorder;
+
+           macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
        }
-      --mips_opts.noreorder;
       macro_build ((char *) NULL, &icnt, NULL, s, "d", dreg);
       break;
 
@@ -3951,11 +4005,11 @@ macro (ip)
     do_divi:
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        {
-         as_warn ("Divide by zero.");
+         as_warn (_("Divide by zero."));
          if (mips_trap)
            macro_build ((char *) NULL, &icnt, NULL, "teq", "s,t", 0, 0);
          else
-           macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
+             macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
          return;
        }
       if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
@@ -4013,15 +4067,21 @@ macro (ip)
        {
          macro_build ((char *) NULL, &icnt, NULL, "teq", "s,t", treg, 0);
          macro_build ((char *) NULL, &icnt, NULL, s, "z,s,t", sreg, treg);
+         /* We want to close the noreorder block as soon as possible, so
+            that later insns are available for delay slot filling.  */
+         --mips_opts.noreorder;
        }
       else
        {
          expr1.X_add_number = 8;
          macro_build ((char *) NULL, &icnt, &expr1, "bne", "s,t,p", treg, 0);
          macro_build ((char *) NULL, &icnt, NULL, s, "z,s,t", sreg, treg);
-         macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
+
+         /* We want to close the noreorder block as soon as possible, so
+            that later insns are available for delay slot filling.  */
+         --mips_opts.noreorder;
+           macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
        }
-      --mips_opts.noreorder;
       macro_build ((char *) NULL, &icnt, NULL, s2, "d", dreg);
       return;
 
@@ -4042,11 +4102,12 @@ macro (ip)
       if (mips_pic == EMBEDDED_PIC
          && offset_expr.X_op == O_subtract
          && now_seg == text_section
-         && (offset_expr.X_op_symbol->sy_value.X_op == O_constant
+         && (symbol_constant_p (offset_expr.X_op_symbol)
              ? S_GET_SEGMENT (offset_expr.X_op_symbol) == text_section
-             : (offset_expr.X_op_symbol->sy_value.X_op == O_symbol
-                && (S_GET_SEGMENT (offset_expr.X_op_symbol
-                                   ->sy_value.X_add_symbol)
+             : (symbol_equated_p (offset_expr.X_op_symbol)
+                && (S_GET_SEGMENT
+                    (symbol_get_value_expression (offset_expr.X_op_symbol)
+                     ->X_add_symbol)
                     == text_section)))
          && breg == 0
          && offset_expr.X_add_number == 0)
@@ -4054,7 +4115,9 @@ macro (ip)
          macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u",
                       treg, (int) BFD_RELOC_PCREL_HI16_S);
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      mips_opts.isa < 3 ? "addiu" : "daddiu",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "addiu" : "daddiu"),
                       "t,r,j", treg, treg, (int) BFD_RELOC_PCREL_LO16);
          return;
        }
@@ -4062,7 +4125,7 @@ macro (ip)
       if (offset_expr.X_op != O_symbol
          && offset_expr.X_op != O_constant)
        {
-         as_bad ("expression too complex");
+         as_bad (_("expression too complex"));
          offset_expr.X_op = O_constant;
        }
 
@@ -4095,7 +4158,9 @@ macro (ip)
            {
              frag_grow (20);
              macro_build ((char *) NULL, &icnt, &offset_expr,
-                          mips_opts.isa < 3 ? "addiu" : "daddiu",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "addiu" : "daddiu"),
                           "t,r,j", tempreg, GP, (int) BFD_RELOC_MIPS_GPREL);
              p = frag_var (rs_machine_dependent, 8, 0,
                            RELAX_ENCODE (4, 8, 0, 4, 0,
@@ -4107,7 +4172,9 @@ macro (ip)
          if (p != NULL)
            p += 4;
          macro_build (p, &icnt, &offset_expr,
-                      mips_opts.isa < 3 ? "addiu" : "daddiu",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "addiu" : "daddiu"),
                       "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
        }
       else if (mips_pic == SVR4_PIC && ! mips_big_got)
@@ -4172,7 +4239,9 @@ macro (ip)
                  p += 4;
                }
              macro_build (p, &icnt, &expr1,
-                          mips_opts.isa < 3 ? "addiu" : "daddiu",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "addiu" : "daddiu"),
                           "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
              /* FIXME: If breg == 0, and the next instruction uses
                 $tempreg, then if this variant case is used an extra
@@ -4184,7 +4253,9 @@ macro (ip)
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                           "nop", "");
              macro_build ((char *) NULL, &icnt, &expr1,
-                          mips_opts.isa < 3 ? "addiu" : "daddiu",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "addiu" : "daddiu"),
                           "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
              (void) frag_var (rs_machine_dependent, 0, 0,
                               RELAX_ENCODE (0, 0, -12, -4, 0, 0),
@@ -4209,7 +4280,9 @@ macro (ip)
                  macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                               "nop", "");
                  macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                              mips_opts.isa < 3 ? "addu" : "daddu",
+                              ((bfd_arch_bits_per_address (stdoutput) == 32
+                                || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                               ? "addu" : "daddu"),
                               "d,v,t", treg, AT, breg);
                  breg = 0;
                  tempreg = treg;
@@ -4224,10 +4297,14 @@ macro (ip)
              mips_optimize = hold_mips_optimize;
 
              macro_build ((char *) NULL, &icnt, &expr1,
-                          mips_opts.isa < 3 ? "addiu" : "daddiu",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "addiu" : "daddiu"),
                           "t,r,j", AT, AT, (int) BFD_RELOC_LO16);
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                          mips_opts.isa < 3 ? "addu" : "daddu",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "addu" : "daddu"),
                           "d,v,t", tempreg, tempreg, AT);
              (void) frag_var (rs_machine_dependent, 0, 0,
                               RELAX_ENCODE (0, 0, -16 + off1, -8, 0, 0),
@@ -4286,7 +4363,9 @@ macro (ip)
          macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u",
                       tempreg, (int) BFD_RELOC_MIPS_GOT_HI16);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                      mips_opts.isa < 3 ? "addu" : "daddu",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "addu" : "daddu"),
                       "d,v,t", tempreg, tempreg, GP);
          macro_build ((char *) NULL, &icnt, &offset_expr,
                       dbl ? "ld" : "lw",
@@ -4323,7 +4402,9 @@ macro (ip)
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                           "nop", "");
              macro_build ((char *) NULL, &icnt, &expr1,
-                          mips_opts.isa < 3 ? "addiu" : "daddiu",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "addiu" : "daddiu"),
                           "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
 
              p = frag_var (rs_machine_dependent, 12 + gpdel, 0,
@@ -4356,7 +4437,9 @@ macro (ip)
                  macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                               "nop", "");
                  macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                              mips_opts.isa < 3 ? "addu" : "daddu",
+                              ((bfd_arch_bits_per_address (stdoutput) == 32
+                                || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                               ? "addu" : "daddu"),
                               "d,v,t", treg, AT, breg);
                  dreg = treg;
                  adj = 8;
@@ -4370,10 +4453,14 @@ macro (ip)
              mips_optimize = hold_mips_optimize;
 
              macro_build ((char *) NULL, &icnt, &expr1,
-                          mips_opts.isa < 3 ? "addiu" : "daddiu",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "addiu" : "daddiu"),
                           "t,r,j", AT, AT, (int) BFD_RELOC_LO16);
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                          mips_opts.isa < 3 ? "addu" : "daddu",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "addu" : "daddu"),
                           "d,v,t", dreg, dreg, AT);
 
              p = frag_var (rs_machine_dependent, 16 + gpdel + adj, 0,
@@ -4405,7 +4492,9 @@ macro (ip)
              macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
              p += 4;
              macro_build (p, &icnt, &expr1,
-                          mips_opts.isa < 3 ? "addiu" : "daddiu",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "addiu" : "daddiu"),
                           "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
              /* FIXME: If add_number is 0, and there was no base
                  register, the external symbol case ended with a load,
@@ -4423,7 +4512,9 @@ macro (ip)
                  macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
                  p += 4;
                  macro_build (p, &icnt, (expressionS *) NULL,
-                              mips_opts.isa < 3 ? "addu" : "daddu",
+                              ((bfd_arch_bits_per_address (stdoutput) == 32
+                                || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                               ? "addu" : "daddu"),
                               "d,v,t", treg, AT, breg);
                  p += 4;
                  tempreg = treg;
@@ -4435,11 +4526,15 @@ macro (ip)
              macro_build_lui (p, &icnt, &expr1, AT);
              p += 4;
              macro_build (p, &icnt, &expr1,
-                          mips_opts.isa < 3 ? "addiu" : "daddiu",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "addiu" : "daddiu"),
                           "t,r,j", AT, AT, (int) BFD_RELOC_LO16);
              p += 4;
              macro_build (p, &icnt, (expressionS *) NULL,
-                          mips_opts.isa < 3 ? "addu" : "daddu",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "addu" : "daddu"),
                           "d,v,t", tempreg, tempreg, AT);
              p += 4;
            }
@@ -4450,7 +4545,9 @@ macro (ip)
               addiu    $tempreg,$gp,<sym>      (BFD_RELOC_MIPS_GPREL)
             */
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      mips_opts.isa < 3 ? "addiu" : "daddiu",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "addiu" : "daddiu"),
                       "t,r,j", tempreg, GP, (int) BFD_RELOC_MIPS_GPREL);
        }
       else
@@ -4458,7 +4555,9 @@ macro (ip)
 
       if (breg != 0)
        macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                    mips_opts.isa < 3 ? "addu" : "daddu",
+                    ((bfd_arch_bits_per_address (stdoutput) == 32
+                      || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                     ? "addu" : "daddu"),
                     "d,v,t", treg, tempreg, breg);
 
       if (! used_at)
@@ -4490,17 +4589,19 @@ macro (ip)
       else if (mips_pic == SVR4_PIC)
        {
          if (sreg != PIC_CALL_REG)
-           as_warn ("MIPS PIC call to register other than $25");
+           as_warn (_("MIPS PIC call to register other than $25"));
       
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "jalr",
                       "d,s", dreg, sreg);
          if (mips_cprestore_offset < 0)
-           as_warn ("No .cprestore pseudo-op used in PIC code");
+           as_warn (_("No .cprestore pseudo-op used in PIC code"));
          else
            {
              expr1.X_add_number = mips_cprestore_offset;
              macro_build ((char *) NULL, &icnt, &expr1,
-                          mips_opts.isa < 3 ? "lw" : "ld",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "lw" : "ld"),
                           "t,o(b)", GP, (int) BFD_RELOC_LO16, mips_frame_reg);
            }
        }
@@ -4541,7 +4642,9 @@ macro (ip)
          if (! mips_big_got)
            {
              macro_build ((char *) NULL, &icnt, &offset_expr,
-                          mips_opts.isa < 3 ? "lw" : "ld",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "lw" : "ld"),
                           "t,o(b)", PIC_CALL_REG,
                           (int) BFD_RELOC_MIPS_CALL16, GP);
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
@@ -4562,10 +4665,14 @@ macro (ip)
              macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u",
                           PIC_CALL_REG, (int) BFD_RELOC_MIPS_CALL_HI16);
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                          mips_opts.isa < 3 ? "addu" : "daddu",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "addu" : "daddu"),
                           "d,v,t", PIC_CALL_REG, PIC_CALL_REG, GP);
              macro_build ((char *) NULL, &icnt, &offset_expr,
-                          mips_opts.isa < 3 ? "lw" : "ld",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "lw" : "ld"),
                           "t,o(b)", PIC_CALL_REG,
                           (int) BFD_RELOC_MIPS_CALL_LO16, PIC_CALL_REG);
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
@@ -4581,7 +4688,9 @@ macro (ip)
                  p += 4;
                }
              macro_build (p, &icnt, &offset_expr,
-                          mips_opts.isa < 3 ? "lw" : "ld",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "lw" : "ld"),
                           "t,o(b)", PIC_CALL_REG,
                           (int) BFD_RELOC_MIPS_GOT16, GP);
              p += 4;
@@ -4589,13 +4698,15 @@ macro (ip)
              p += 4;
            }                      
          macro_build (p, &icnt, &offset_expr,
-                      mips_opts.isa < 3 ? "addiu" : "daddiu",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "addiu" : "daddiu"),
                       "t,r,j", PIC_CALL_REG, PIC_CALL_REG,
                       (int) BFD_RELOC_LO16);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                       "jalr", "s", PIC_CALL_REG);
          if (mips_cprestore_offset < 0)
-           as_warn ("No .cprestore pseudo-op used in PIC code");
+           as_warn (_("No .cprestore pseudo-op used in PIC code"));
          else
            {
              if (mips_opts.noreorder)
@@ -4603,7 +4714,9 @@ macro (ip)
                             "nop", "");
              expr1.X_add_number = mips_cprestore_offset;
              macro_build ((char *) NULL, &icnt, &expr1,
-                          mips_opts.isa < 3 ? "lw" : "ld",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "lw" : "ld"),
                           "t,o(b)", GP, (int) BFD_RELOC_LO16,
                           mips_frame_reg);
            }
@@ -4664,9 +4777,9 @@ macro (ip)
       lr = 1;
       goto ld;
     case M_LDC1_AB:
-      if (mips_4650)
+      if (mips_cpu == 4650)
        {
-         as_bad ("opcode not supported on this processor");
+         as_bad (_("opcode not supported on this processor"));
          return;
        }
       s = "ldc1";
@@ -4753,9 +4866,9 @@ macro (ip)
       s = "scd";
       goto st;
     case M_SDC1_AB:
-      if (mips_4650)
+      if (mips_cpu == 4650)
        {
-         as_bad ("opcode not supported on this processor");
+         as_bad (_("opcode not supported on this processor"));
          return;
        }
       s = "sdc1";
@@ -4797,7 +4910,7 @@ macro (ip)
       if (offset_expr.X_op != O_constant
          && offset_expr.X_op != O_symbol)
        {
-         as_bad ("expression too complex");
+         as_bad (_("expression too complex"));
          offset_expr.X_op = O_constant;
        }
 
@@ -4858,7 +4971,9 @@ macro (ip)
                {
                  frag_grow (28);
                  macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                              mips_opts.isa < 3 ? "addu" : "daddu",
+                              ((bfd_arch_bits_per_address (stdoutput) == 32
+                                || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                               ? "addu" : "daddu"),
                               "d,v,t", tempreg, breg, GP);
                  macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
                               treg, (int) BFD_RELOC_MIPS_GPREL, tempreg);
@@ -4871,7 +4986,9 @@ macro (ip)
              if (p != NULL)
                p += 4;
              macro_build (p, &icnt, (expressionS *) NULL,
-                          mips_opts.isa < 3 ? "addu" : "daddu",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "addu" : "daddu"),
                           "d,v,t", tempreg, tempreg, breg);
              if (p != NULL)
                p += 4;
@@ -4901,10 +5018,12 @@ macro (ip)
          offset_expr.X_add_number = 0;
          if (expr1.X_add_number < -0x8000
              || expr1.X_add_number >= 0x8000)
-           as_bad ("PIC code offset overflow (max 16 signed bits)");
+           as_bad (_("PIC code offset overflow (max 16 signed bits)"));
          frag_grow (20);
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      mips_opts.isa < 3 ? "lw" : "ld",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "lw" : "ld"),
                       "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16, GP);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", "");
          p = frag_var (rs_machine_dependent, 4, 0, 
@@ -4912,11 +5031,15 @@ macro (ip)
                        offset_expr.X_add_symbol, (offsetT) 0,
                        (char *) NULL);
          macro_build (p, &icnt, &offset_expr,
-                      mips_opts.isa < 3 ? "addiu" : "daddiu",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "addiu" : "daddiu"),
                       "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
          if (breg != 0)
            macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                        mips_opts.isa < 3 ? "addu" : "daddu",
+                        ((bfd_arch_bits_per_address (stdoutput) == 32
+                          || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                         ? "addu" : "daddu"),
                         "d,v,t", tempreg, tempreg, breg);
          macro_build ((char *) NULL, &icnt, &expr1, s, fmt, treg,
                       (int) BFD_RELOC_LO16, tempreg);
@@ -4946,7 +5069,7 @@ macro (ip)
          offset_expr.X_add_number = 0;
          if (expr1.X_add_number < -0x8000
              || expr1.X_add_number >= 0x8000)
-           as_bad ("PIC code offset overflow (max 16 signed bits)");
+           as_bad (_("PIC code offset overflow (max 16 signed bits)"));
          if (reg_needs_delay (GP))
            gpdel = 4;
          else
@@ -4955,10 +5078,14 @@ macro (ip)
          macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u",
                       tempreg, (int) BFD_RELOC_MIPS_GOT_HI16);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                      mips_opts.isa < 3 ? "addu" : "daddu",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "addu" : "daddu"),
                       "d,v,t", tempreg, tempreg, GP);
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      mips_opts.isa < 3 ? "lw" : "ld",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "lw" : "ld"),
                       "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT_LO16,
                       tempreg);
          p = frag_var (rs_machine_dependent, 12 + gpdel, 0,
@@ -4970,17 +5097,23 @@ macro (ip)
              p += 4;
            }
          macro_build (p, &icnt, &offset_expr,
-                      mips_opts.isa < 3 ? "lw" : "ld",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "lw" : "ld"),
                       "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16, GP);
          p += 4;
          macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
          p += 4;
          macro_build (p, &icnt, &offset_expr,
-                      mips_opts.isa < 3 ? "addiu" : "daddiu",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "addiu" : "daddiu"),
                       "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
          if (breg != 0)
            macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                        mips_opts.isa < 3 ? "addu" : "daddu",
+                        ((bfd_arch_bits_per_address (stdoutput) == 32
+                          || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                         ? "addu" : "daddu"),
                         "d,v,t", tempreg, tempreg, breg);
          macro_build ((char *) NULL, &icnt, &expr1, s, fmt, treg,
                       (int) BFD_RELOC_LO16, tempreg);
@@ -5003,7 +5136,9 @@ macro (ip)
          else
            {
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                          mips_opts.isa < 3 ? "addu" : "daddu",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "addu" : "daddu"),
                           "d,v,t", tempreg, breg, GP);
              macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
                           treg, (int) BFD_RELOC_MIPS_GPREL, tempreg);
@@ -5053,7 +5188,7 @@ macro (ip)
          or in offset_expr.  */
       if (imm_expr.X_op == O_constant || imm_expr.X_op == O_big)
        {
-         if (mips_opts.isa >= 3)
+         if (ISA_HAS_64BIT_REGS (mips_opts.isa))
            load_register (&icnt, treg, &imm_expr, 1);
          else
            {
@@ -5097,7 +5232,9 @@ macro (ip)
       else if (mips_pic == SVR4_PIC)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      mips_opts.isa < 3 ? "lw" : "ld",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "lw" : "ld"),
                       "t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT16, GP);
        }
       else if (mips_pic == EMBEDDED_PIC)
@@ -5105,7 +5242,9 @@ macro (ip)
          /* For embedded PIC we pick up the entire address off $gp in
             a single instruction.  */
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      mips_opts.isa < 3 ? "addiu" : "daddiu",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "addiu" : "daddiu"),
                       "t,r,j", AT, GP, (int) BFD_RELOC_MIPS_GPREL);
          offset_expr.X_op = O_constant;
          offset_expr.X_add_number = 0;
@@ -5114,7 +5253,7 @@ macro (ip)
        abort ();
        
       /* Now we load the register(s).  */
-      if (mips_opts.isa >= 3)
+      if (ISA_HAS_64BIT_REGS (mips_opts.isa))
        macro_build ((char *) NULL, &icnt, &offset_expr, "ld", "t,o(b)",
                     treg, (int) BFD_RELOC_LO16, AT);
       else
@@ -5145,8 +5284,8 @@ macro (ip)
          or in offset_expr.  */
       if (imm_expr.X_op == O_constant || imm_expr.X_op == O_big)
        {
-         load_register (&icnt, AT, &imm_expr, mips_opts.isa >= 3);
-         if (mips_opts.isa >= 3)
+         load_register (&icnt, AT, &imm_expr, ISA_HAS_64BIT_REGS (mips_opts.isa));
+         if (ISA_HAS_64BIT_REGS (mips_opts.isa))
            macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                         "dmtc1", "t,S", AT, treg);
          else
@@ -5172,7 +5311,7 @@ macro (ip)
       s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
       if (strcmp (s, ".lit8") == 0)
        {
-         if (mips_opts.isa >= 2)
+         if (mips_opts.isa != 1)
            {
              macro_build ((char *) NULL, &icnt, &offset_expr, "ldc1",
                           "T,o(b)", treg, (int) BFD_RELOC_MIPS_LITERAL, GP);
@@ -5187,7 +5326,9 @@ macro (ip)
          assert (strcmp (s, RDATA_SECTION_NAME) == 0);
          if (mips_pic == SVR4_PIC)
            macro_build ((char *) NULL, &icnt, &offset_expr,
-                        mips_opts.isa < 3 ? "lw" : "ld",
+                        ((bfd_arch_bits_per_address (stdoutput) == 32
+                          || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                         ? "lw" : "ld"),
                         "t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT16, GP);
          else
            {
@@ -5195,7 +5336,7 @@ macro (ip)
              macro_build_lui ((char *) NULL, &icnt, &offset_expr, AT);
            }
              
-         if (mips_opts.isa >= 2)
+         if (mips_opts.isa != 1)
            {
              macro_build ((char *) NULL, &icnt, &offset_expr, "ldc1",
                           "T,o(b)", treg, (int) BFD_RELOC_LO16, AT);
@@ -5213,16 +5354,16 @@ macro (ip)
        }
 
     case M_L_DOB:
-      if (mips_4650)
+      if (mips_cpu == 4650)
        {
-         as_bad ("opcode not supported on this processor");
+         as_bad (_("opcode not supported on this processor"));
          return;
        }
       /* Even on a big endian machine $fn comes before $fn+1.  We have
         to adjust when loading from memory.  */
       r = BFD_RELOC_LO16;
     dob:
-      assert (mips_opts.isa < 2);
+      assert (mips_opts.isa == 1);
       macro_build ((char *) NULL, &icnt, &offset_expr, "lwc1", "T,o(b)",
                   target_big_endian ? treg + 1 : treg,
                   (int) r, breg);
@@ -5254,14 +5395,14 @@ macro (ip)
        * But, the resulting address is the same after relocation so why
        * generate the extra instruction?
        */
-      if (mips_4650)
+      if (mips_cpu == 4650)
        {
-         as_bad ("opcode not supported on this processor");
+         as_bad (_("opcode not supported on this processor"));
          return;
        }
       /* Itbl support may require additional care here. */
       coproc = 1;
-      if (mips_opts.isa >= 2)
+      if (mips_opts.isa != 1)
        {
          s = "ldc1";
          goto ld;
@@ -5272,13 +5413,13 @@ macro (ip)
       goto ldd_std;
 
     case M_S_DAB:
-      if (mips_4650)
+      if (mips_cpu == 4650)
        {
-         as_bad ("opcode not supported on this processor");
+         as_bad (_("opcode not supported on this processor"));
          return;
        }
 
-      if (mips_opts.isa >= 2)
+      if (mips_opts.isa != 1)
        {
          s = "sdc1";
          goto st;
@@ -5291,7 +5432,7 @@ macro (ip)
       goto ldd_std;
 
     case M_LD_AB:
-      if (mips_opts.isa >= 3)
+      if (ISA_HAS_64BIT_REGS (mips_opts.isa))
        {
          s = "ld";
          goto ld;
@@ -5302,7 +5443,7 @@ macro (ip)
       goto ldd_std;
 
     case M_SD_AB:
-      if (mips_opts.isa >= 3)
+      if (ISA_HAS_64BIT_REGS (mips_opts.isa))
        {
          s = "sd";
          goto st;
@@ -5315,7 +5456,7 @@ macro (ip)
       if (offset_expr.X_op != O_symbol
          && offset_expr.X_op != O_constant)
        {
-         as_bad ("expression too complex");
+         as_bad (_("expression too complex"));
          offset_expr.X_op = O_constant;
        }
 
@@ -5364,7 +5505,9 @@ macro (ip)
                {
                  frag_grow (36);
                  macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                              mips_opts.isa < 3 ? "addu" : "daddu",
+                              ((bfd_arch_bits_per_address (stdoutput) == 32
+                                || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                               ? "addu" : "daddu"),
                               "d,v,t", AT, breg, GP);
                  tempreg = AT;
                  off = 4;
@@ -5420,7 +5563,9 @@ macro (ip)
          if (breg != 0)
            {
              macro_build (p, &icnt, (expressionS *) NULL,
-                          mips_opts.isa < 3 ? "addu" : "daddu",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "addu" : "daddu"),
                           "d,v,t", AT, breg, AT);
              if (p != NULL)
                p += 4;
@@ -5460,19 +5605,23 @@ macro (ip)
          offset_expr.X_add_number = 0;
          if (expr1.X_add_number < -0x8000
              || expr1.X_add_number >= 0x8000 - 4)
-           as_bad ("PIC code offset overflow (max 16 signed bits)");
+           as_bad (_("PIC code offset overflow (max 16 signed bits)"));
          if (breg == 0)
            off = 0;
          else
            off = 4;
          frag_grow (24 + off);
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      mips_opts.isa < 3 ? "lw" : "ld",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "lw" : "ld"),
                       "t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT16, GP);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", "");
          if (breg != 0)
            macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                        mips_opts.isa < 3 ? "addu" : "daddu",
+                        ((bfd_arch_bits_per_address (stdoutput) == 32
+                          || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                         ? "addu" : "daddu"),
                         "d,v,t", AT, breg, AT);
           /* Itbl support may require additional care here. */
          macro_build ((char *) NULL, &icnt, &expr1, s, fmt,
@@ -5519,7 +5668,7 @@ macro (ip)
          offset_expr.X_add_number = 0;
          if (expr1.X_add_number < -0x8000
              || expr1.X_add_number >= 0x8000 - 4)
-           as_bad ("PIC code offset overflow (max 16 signed bits)");
+           as_bad (_("PIC code offset overflow (max 16 signed bits)"));
          if (reg_needs_delay (GP))
            gpdel = 4;
          else
@@ -5532,15 +5681,21 @@ macro (ip)
          macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u",
                       AT, (int) BFD_RELOC_MIPS_GOT_HI16);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                      mips_opts.isa < 3 ? "addu" : "daddu",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "addu" : "daddu"),
                       "d,v,t", AT, AT, GP);
          macro_build ((char *) NULL, &icnt, &offset_expr,
-                      mips_opts.isa < 3 ? "lw" : "ld",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "lw" : "ld"),
                       "t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT_LO16, AT);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", "");
          if (breg != 0)
            macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                        mips_opts.isa < 3 ? "addu" : "daddu",
+                        ((bfd_arch_bits_per_address (stdoutput) == 32
+                          || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                         ? "addu" : "daddu"),
                         "d,v,t", AT, breg, AT);
           /* Itbl support may require additional care here. */
          macro_build ((char *) NULL, &icnt, &expr1, s, fmt,
@@ -5570,7 +5725,9 @@ macro (ip)
              p += 4;
            }
          macro_build (p, &icnt, &offset_expr,
-                      mips_opts.isa < 3 ? "lw" : "ld",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "lw" : "ld"),
                       "t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT16, GP);
          p += 4;
          macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
@@ -5578,7 +5735,9 @@ macro (ip)
          if (breg != 0)
            {
              macro_build (p, &icnt, (expressionS *) NULL,
-                          mips_opts.isa < 3 ? "addu" : "daddu",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "addu" : "daddu"),
                           "d,v,t", AT, breg, AT);
              p += 4;
            }
@@ -5617,7 +5776,9 @@ macro (ip)
          else
            {
              macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                          mips_opts.isa < 3 ? "addu" : "daddu",
+                          ((bfd_arch_bits_per_address (stdoutput) == 32
+                            || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                           ? "addu" : "daddu"),
                           "d,v,t", AT, breg, GP);
              tempreg = AT;
              used_at = 1;
@@ -5647,7 +5808,8 @@ macro (ip)
     case M_SD_OB:
       s = "sw";
     sd_ob:
-      assert (mips_opts.isa < 3);
+      assert (bfd_arch_bits_per_address (stdoutput) == 32 
+             || ! ISA_HAS_64BIT_REGS (mips_opts.isa));
       macro_build ((char *) NULL, &icnt, &offset_expr, s, "t,o(b)", treg,
                   (int) BFD_RELOC_LO16, breg);
       offset_expr.X_add_number += 4;
@@ -5673,19 +5835,21 @@ macro (ip)
       this knowledge can be encoded in the itbl spec. */
 
     case M_COP0:
-      s = "cop0";
+      s = "c0";
       goto copz;
     case M_COP1:
-      s = "cop1";
+      s = "c1";
       goto copz;
     case M_COP2:
-      s = "cop2";
+      s = "c2";
       goto copz;
     case M_COP3:
-      s = "cop3";
+      s = "c3";
     copz:
-      /* For now we just do C (same as Cz). */
-      macro_build ((char *) NULL, &icnt, &offset_expr, s, "C");
+      /* For now we just do C (same as Cz).  The parameter will be
+         stored in insn_opcode by mips_ip.  */
+      macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s, "C",
+                  ip->insn_opcode);
       return;
 
 #ifdef LOSING_COMPILER
@@ -5711,7 +5875,7 @@ macro (ip)
       return;
     }
   if (mips_opts.noat)
-    as_warn ("Macro used $at after \".set noat\"");
+    as_warn (_("Macro used $at after \".set noat\""));
 }
           
 static void
@@ -5731,6 +5895,7 @@ macro2 (ip)
   int dbl = 0;
   int coproc = 0;
   int lr = 0;
+  int imm = 0;
   int off;
   offsetT maxnum;
   bfd_reloc_code_real_type r;
@@ -5772,15 +5937,24 @@ macro2 (ip)
       macro_build ((char *) NULL, &icnt, NULL, "mflo", "d", dreg);
       break;
 
+    case M_DMULO_I:
+      dbl = 1;
+    case M_MULO_I:
+      imm = 1;
+      goto do_mulo;
+
     case M_DMULO:
       dbl = 1;
     case M_MULO:
+    do_mulo:
       mips_emit_delays (true);
       ++mips_opts.noreorder;
       mips_any_noreorder = 1;
+      if (imm)
+       load_register (&icnt, AT, &imm_expr, dbl);
       macro_build ((char *) NULL, &icnt, NULL,
                   dbl ? "dmult" : "mult",
-                  "s,t", sreg, treg);
+                  "s,t", sreg, imm ? AT : treg);
       macro_build ((char *) NULL, &icnt, NULL, "mflo", "d", dreg);
       macro_build ((char *) NULL, &icnt, NULL,
                   dbl ? "dsra32" : "sra",
@@ -5793,21 +5967,30 @@ macro2 (ip)
          expr1.X_add_number = 8;
          macro_build ((char *) NULL, &icnt, &expr1, "beq", "s,t,p", dreg, AT);
          macro_build ((char *) NULL, &icnt, NULL, "nop", "", 0);
-         macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
+           macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
        }
       --mips_opts.noreorder;
       macro_build ((char *) NULL, &icnt, NULL, "mflo", "d", dreg);
       break;
 
+    case M_DMULOU_I:
+      dbl = 1;
+    case M_MULOU_I:
+      imm = 1;
+      goto do_mulou;
+
     case M_DMULOU:
       dbl = 1;
     case M_MULOU:
+    do_mulou:
       mips_emit_delays (true);
       ++mips_opts.noreorder;
       mips_any_noreorder = 1;
+      if (imm)
+       load_register (&icnt, AT, &imm_expr, dbl);
       macro_build ((char *) NULL, &icnt, NULL,
                   dbl ? "dmultu" : "multu",
-                  "s,t", sreg, treg);
+                  "s,t", sreg, imm ? AT : treg);
       macro_build ((char *) NULL, &icnt, NULL, "mfhi", "d", AT);
       macro_build ((char *) NULL, &icnt, NULL, "mflo", "d", dreg);
       if (mips_trap)
@@ -5817,7 +6000,7 @@ macro2 (ip)
          expr1.X_add_number = 8;
          macro_build ((char *) NULL, &icnt, &expr1, "beq", "s,t,p", AT, 0);
          macro_build ((char *) NULL, &icnt, NULL, "nop", "", 0);
-         macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
+           macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
        }
       --mips_opts.noreorder;
       break;
@@ -5832,7 +6015,7 @@ macro2 (ip)
 
     case M_ROL_I:
       if (imm_expr.X_op != O_constant)
-       as_bad ("rotate count too large");
+       as_bad (_("rotate count too large"));
       macro_build ((char *) NULL, &icnt, NULL, "sll", "d,w,<", AT, sreg,
                   (int) (imm_expr.X_add_number & 0x1f));
       macro_build ((char *) NULL, &icnt, NULL, "srl", "d,w,<", dreg, sreg,
@@ -5850,7 +6033,7 @@ macro2 (ip)
 
     case M_ROR_I:
       if (imm_expr.X_op != O_constant)
-       as_bad ("rotate count too large");
+       as_bad (_("rotate count too large"));
       macro_build ((char *) NULL, &icnt, NULL, "srl", "d,w,<", AT, sreg,
                   (int) (imm_expr.X_add_number & 0x1f));
       macro_build ((char *) NULL, &icnt, NULL, "sll", "d,w,<", dreg, sreg,
@@ -5859,12 +6042,12 @@ macro2 (ip)
       break;
 
     case M_S_DOB:
-      if (mips_4650)
+      if (mips_cpu == 4650)
        {
-         as_bad ("opcode not supported on this processor");
+         as_bad (_("opcode not supported on this processor"));
          return;
        }
-      assert (mips_opts.isa < 2);
+      assert (mips_opts.isa == 1);
       /* Even on a big endian machine $fn comes before $fn+1.  We have
         to adjust when storing to memory.  */
       macro_build ((char *) NULL, &icnt, &offset_expr, "swc1", "T,o(b)",
@@ -5901,7 +6084,7 @@ macro2 (ip)
        }
       if (sreg == 0)
        {
-         as_warn ("Instruction %s: result is always false",
+         as_warn (_("Instruction %s: result is always false"),
                   ip->insn_mo->name);
          macro_build ((char *) NULL, &icnt, NULL, "move", "d,s", dreg, 0);
          return;
@@ -5920,7 +6103,9 @@ macro2 (ip)
        {
          imm_expr.X_add_number = -imm_expr.X_add_number;
          macro_build ((char *) NULL, &icnt, &imm_expr,
-                      mips_opts.isa < 3 ? "addiu" : "daddiu",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "addiu" : "daddiu"),
                       "t,r,j", dreg, sreg,
                       (int) BFD_RELOC_LO16);
          used_at = 0;
@@ -5955,7 +6140,7 @@ macro2 (ip)
          && imm_expr.X_add_number >= -0x8000
          && imm_expr.X_add_number < 0x8000)
        {
-         macro_build ((char *) NULL, &icnt, &expr1,
+         macro_build ((char *) NULL, &icnt, &imm_expr,
                       mask == M_SGE_I ? "slti" : "sltiu",
                       "t,r,j", dreg, sreg, (int) BFD_RELOC_LO16);
          used_at = 0;
@@ -6068,10 +6253,12 @@ macro2 (ip)
        }
       if (sreg == 0)
        {
-         as_warn ("Instruction %s: result is always true",
+         as_warn (_("Instruction %s: result is always true"),
                   ip->insn_mo->name);
          macro_build ((char *) NULL, &icnt, &expr1,
-                      mips_opts.isa < 3 ? "addiu" : "daddiu",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "addiu" : "daddiu"),
                       "t,r,j", dreg, 0, (int) BFD_RELOC_LO16);
          return;
        }
@@ -6089,7 +6276,9 @@ macro2 (ip)
        {
          imm_expr.X_add_number = -imm_expr.X_add_number;
          macro_build ((char *) NULL, &icnt, &imm_expr,
-                      mips_opts.isa < 3 ? "addiu" : "daddiu",
+                      ((bfd_arch_bits_per_address (stdoutput) == 32
+                        || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                       ? "addiu" : "daddiu"),
                       "t,r,j", dreg, sreg, (int) BFD_RELOC_LO16);
          used_at = 0;
        }
@@ -6167,7 +6356,7 @@ macro2 (ip)
 
     case M_TRUNCWD:
     case M_TRUNCWS:
-      assert (mips_opts.isa < 2);
+      assert (mips_opts.isa == 1);
       sreg = (ip->insn_opcode >> 11) & 0x1f;   /* floating reg */
       dreg = (ip->insn_opcode >> 06) & 0x1f;   /* floating reg */
 
@@ -6203,7 +6392,7 @@ macro2 (ip)
       s = "lbu";
     ulh:
       if (offset_expr.X_add_number >= 0x7fff)
-       as_bad ("operand overflow");
+       as_bad (_("operand overflow"));
       /* avoid load delay */
       if (! target_big_endian)
        offset_expr.X_add_number += 1;
@@ -6230,7 +6419,7 @@ macro2 (ip)
       off = 3;
     ulw:
       if (offset_expr.X_add_number >= 0x8000 - off)
-       as_bad ("operand overflow");
+       as_bad (_("operand overflow"));
       if (! target_big_endian)
        offset_expr.X_add_number += off;
       macro_build ((char *) NULL, &icnt, &offset_expr, s, "t,o(b)", treg,
@@ -6256,7 +6445,9 @@ macro2 (ip)
       load_address (&icnt, AT, &offset_expr);
       if (breg != 0)
        macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                    mips_opts.isa < 3 ? "addu" : "daddu",
+                    ((bfd_arch_bits_per_address (stdoutput) == 32
+                      || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                     ? "addu" : "daddu"),
                     "d,v,t", AT, AT, breg);
       if (! target_big_endian)
        expr1.X_add_number = off;
@@ -6277,7 +6468,9 @@ macro2 (ip)
       load_address (&icnt, AT, &offset_expr);
       if (breg != 0)
        macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                    mips_opts.isa < 3 ? "addu" : "daddu",
+                    ((bfd_arch_bits_per_address (stdoutput) == 32
+                      || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                     ? "addu" : "daddu"),
                     "d,v,t", AT, AT, breg);
       if (target_big_endian)
        expr1.X_add_number = 0;
@@ -6298,7 +6491,7 @@ macro2 (ip)
 
     case M_USH:
       if (offset_expr.X_add_number >= 0x7fff)
-       as_bad ("operand overflow");
+       as_bad (_("operand overflow"));
       if (target_big_endian)
        offset_expr.X_add_number += 1;
       macro_build ((char *) NULL, &icnt, &offset_expr, "sb", "t,o(b)", treg,
@@ -6323,7 +6516,7 @@ macro2 (ip)
       off = 3;
     usw:
       if (offset_expr.X_add_number >= 0x8000 - off)
-       as_bad ("operand overflow");
+       as_bad (_("operand overflow"));
       if (! target_big_endian)
        offset_expr.X_add_number += off;
       macro_build ((char *) NULL, &icnt, &offset_expr, s, "t,o(b)", treg,
@@ -6349,7 +6542,9 @@ macro2 (ip)
       load_address (&icnt, AT, &offset_expr);
       if (breg != 0)
        macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                    mips_opts.isa < 3 ? "addu" : "daddu",
+                    ((bfd_arch_bits_per_address (stdoutput) == 32
+                      || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                     ? "addu" : "daddu"),
                     "d,v,t", AT, AT, breg);
       if (! target_big_endian)
        expr1.X_add_number = off;
@@ -6369,7 +6564,9 @@ macro2 (ip)
       load_address (&icnt, AT, &offset_expr);
       if (breg != 0)
        macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-                    mips_opts.isa < 3 ? "addu" : "daddu",
+                    ((bfd_arch_bits_per_address (stdoutput) == 32
+                      || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+                     ? "addu" : "daddu"),
                     "d,v,t", AT, AT, breg);
       if (! target_big_endian)
        expr1.X_add_number = 0;
@@ -6398,11 +6595,11 @@ macro2 (ip)
     default:
       /* FIXME: Check if this is one of the itbl macros, since they
         are added dynamically. */
-      as_bad ("Macro %s not implemented yet", ip->insn_mo->name);
+      as_bad (_("Macro %s not implemented yet"), ip->insn_mo->name);
       break;
     }
   if (mips_opts.noat)
-    as_warn ("Macro used $at after \".set noat\"");
+    as_warn (_("Macro used $at after \".set noat\""));
 }
 
 /* Implement macros in mips16 mode.  */
@@ -6456,7 +6653,8 @@ mips16_macro (ip)
                   "0,x,y", xreg, yreg);
       expr1.X_add_number = 2;
       macro_build ((char *) NULL, &icnt, &expr1, "bnez", "x,p", yreg);
-      macro_build ((char *) NULL, &icnt, NULL, "break", "6", 7);
+       macro_build ((char *) NULL, &icnt, NULL, "break", "6", 7);
+      
       /* FIXME: The normal code checks for of -1 / -0x80000000 here,
          since that causes an overflow.  We should do that as well,
          but I don't see how to do the comparisons without a temporary
@@ -6487,7 +6685,7 @@ mips16_macro (ip)
       macro_build ((char *) NULL, &icnt, NULL, s, "0,x,y", xreg, yreg);
       expr1.X_add_number = 2;
       macro_build ((char *) NULL, &icnt, &expr1, "bnez", "x,p", yreg);
-      macro_build ((char *) NULL, &icnt, NULL, "break", "6", 7);
+       macro_build ((char *) NULL, &icnt, NULL, "break", "6", 7);
       --mips_opts.noreorder;
       macro_build ((char *) NULL, &icnt, NULL, s2, "x", zreg);
       break;
@@ -6507,7 +6705,7 @@ mips16_macro (ip)
     case M_SUBU_I:
     do_subu:
       if (imm_expr.X_op != O_constant)
-       as_bad ("Unsupported large constant");
+       as_bad (_("Unsupported large constant"));
       imm_expr.X_add_number = -imm_expr.X_add_number;
       macro_build ((char *) NULL, &icnt, &imm_expr,
                   dbl ? "daddiu" : "addiu",
@@ -6516,7 +6714,7 @@ mips16_macro (ip)
 
     case M_SUBU_I_2:
       if (imm_expr.X_op != O_constant)
-       as_bad ("Unsupported large constant");
+       as_bad (_("Unsupported large constant"));
       imm_expr.X_add_number = -imm_expr.X_add_number;
       macro_build ((char *) NULL, &icnt, &imm_expr, "addiu",
                   "x,k", xreg);
@@ -6524,7 +6722,7 @@ mips16_macro (ip)
 
     case M_DSUBU_I_2:
       if (imm_expr.X_op != O_constant)
-       as_bad ("Unsupported large constant");
+       as_bad (_("Unsupported large constant"));
       imm_expr.X_add_number = -imm_expr.X_add_number;
       macro_build ((char *) NULL, &icnt, &imm_expr, "daddiu",
                   "y,j", yreg);
@@ -6633,7 +6831,7 @@ mips16_macro (ip)
 
     do_addone_branch_i:
       if (imm_expr.X_op != O_constant)
-       as_bad ("Unsupported large constant");
+       as_bad (_("Unsupported large constant"));
       ++imm_expr.X_add_number;
 
     do_branch_i:
@@ -6667,7 +6865,7 @@ validate_mips_insn (opc)
 
   if ((used_bits & opc->match) != opc->match)
     {
-      as_bad ("internal: bad mips opcode (mask error): %s %s",
+      as_bad (_("internal: bad mips opcode (mask error): %s %s"),
              opc->name, opc->args);
       return 0;
     }
@@ -6708,6 +6906,7 @@ validate_mips_insn (opc)
       case 'l': break;
       case 'o': USE_BITS (OP_MASK_DELTA,       OP_SH_DELTA);   break;
       case 'p':        USE_BITS (OP_MASK_DELTA,        OP_SH_DELTA);   break;
+      case 'q':        USE_BITS (OP_MASK_CODE2,        OP_SH_CODE2);   break;
       case 'r': USE_BITS (OP_MASK_RS,          OP_SH_RS);      break;
       case 's':        USE_BITS (OP_MASK_RS,           OP_SH_RS);      break;
       case 't':        USE_BITS (OP_MASK_RT,           OP_SH_RT);      break;
@@ -6717,38 +6916,15 @@ validate_mips_insn (opc)
       case 'x': break;
       case 'z': break;
       case 'P': USE_BITS (OP_MASK_PERFREG,     OP_SH_PERFREG); break;
-       /* start-sanitize-vr5400 */
-      case 'e': USE_BITS (OP_MASK_VECBYTE,     OP_SH_VECBYTE); break;
-      case '%': USE_BITS (OP_MASK_VECALIGN,    OP_SH_VECALIGN); break;
-      case '[': break;
-      case ']': break;
-       /* end-sanitize-vr5400 */
       default:
-       as_bad ("internal: bad mips opcode (unknown operand type `%c'): %s %s",
+       as_bad (_("internal: bad mips opcode (unknown operand type `%c'): %s %s"),
                c, opc->name, opc->args);
        return 0;
       }
 #undef USE_BITS
-  /* Some of the trapping instructions (break, t*, sdbbp) have "code"
-     fields that cannot currently be set by assembly code.  Ignore them
-     for now.  */
-  if (opc->pinfo & INSN_TRAP)
-    {
-      static const char *const trap_insns[] = {
-       "break", "sdbbp",
-       "teq", "tge", "tgeu", "tlt", "tltu", "tne",
-      };
-      int i;
-      for (i = sizeof(trap_insns)/sizeof(trap_insns[0]) - 1; i >= 0; i--)
-       if (!strcmp (trap_insns[i], opc->name))
-         {
-           used_bits |= 0xffc0;
-           break;
-         }
-    }
   if (used_bits != 0xffffffff)
     {
-      as_bad ("internal: bad mips opcode (bits 0x%lx undefined): %s %s",
+      as_bad (_("internal: bad mips opcode (bits 0x%lx undefined): %s %s"),
              ~used_bits & 0xffffffff, opc->name, opc->args);
       return 0;
     }
@@ -6773,67 +6949,75 @@ mips_ip (str, ip)
   unsigned int regno;
   unsigned int lastregno = 0;
   char *s_reset;
+  char save_c = 0;
+  int full_opcode_match = 1;
 
   insn_error = NULL;
 
-  for (s = str; *s != '\0' && !isspace(*s); ++s)
+  /* If the instruction contains a '.', we first try to match an instruction
+     including the '.'.  Then we try again without the '.'.  */
+  insn = NULL;
+  for (s = str; *s != '\0' && !isspace ((unsigned char) *s); ++s)
     continue;
-  if (isspace (*s))
-    *s++ = '\0';
 
-  if ((insn = (struct mips_opcode *) hash_find (op_hash, str)) == NULL)
+  /* If we stopped on whitespace, then replace the whitespace with null for
+     the call to hash_find.  Save the character we replaced just in case we
+     have to re-parse the instruction.  */
+  if (isspace ((unsigned char) *s))
     {
-      insn_error = "unrecognized opcode";
-      return;
+      save_c = *s;
+      *s++ = '\0';
+    }
+       
+  insn = (struct mips_opcode *) hash_find (op_hash, str);
+
+  /* If we didn't find the instruction in the opcode table, try again, but
+     this time with just the instruction up to, but not including the
+     first '.'.  */
+  if (insn == NULL)
+    {
+      /* Restore the character we overwrite above (if any).  */ 
+      if (save_c)
+       *(--s) = save_c;
+
+      /* Scan up to the first '.' or whitespace.  */
+      for (s = str; *s != '\0' && *s != '.' && !isspace ((unsigned char) *s); ++s)
+       continue;
+
+      /* If we did not find a '.', then we can quit now.  */
+      if (*s != '.')
+       {
+         insn_error = "unrecognized opcode";
+         return;
+       }
+
+      /* Lookup the instruction in the hash table.  */
+      *s++ = '\0';
+      if ((insn = (struct mips_opcode *) hash_find (op_hash, str)) == NULL)
+       {
+         insn_error = "unrecognized opcode";
+         return;
+       }
+
+      full_opcode_match = 0;
     }
+
   argsStart = s;
   for (;;)
     {
-      int insn_isa;
       boolean ok;
 
       assert (strcmp (insn->name, str) == 0);
 
-      if ((insn->membership & INSN_ISA) == INSN_ISA1)
-       insn_isa = 1;
-      else if ((insn->membership & INSN_ISA) == INSN_ISA2)
-       insn_isa = 2;
-      else if ((insn->membership & INSN_ISA) == INSN_ISA3)
-       insn_isa = 3;
-      else if ((insn->membership & INSN_ISA) == INSN_ISA4)
-       insn_isa = 4;
-      else
-       insn_isa = 15;
-
-      if (insn_isa <= mips_opts.isa)
-       ok = true;
-      else if (insn->pinfo == INSN_MACRO)
-       ok = false;
-      else if ((mips_4650 && (insn->membership & INSN_4650) != 0)
-              || (mips_4010 && (insn->membership & INSN_4010) != 0)
-              || (mips_4100 && (insn->membership & INSN_4100) != 0)
-              /* start-sanitize-tx49 */
-              || (mips_4900 && (insn->membership & INSN_4900) != 0)
-              /* end-sanitize-tx49 */
-              /* start-sanitize-r5900 */
-              || (mips_5900 && (insn->membership & INSN_5900) != 0)
-              /* end-sanitize-r5900 */
-              /* start-sanitize-vr5400 */
-              || (mips_5400 && (insn->membership & INSN_5400) != 0)
-              /* end-sanitize-vr5400 */
-              || (mips_3900 && (insn->membership & INSN_3900) != 0))
+      if (OPCODE_IS_MEMBER (insn, mips_opts.isa, mips_cpu))
        ok = true;
-      else
+      else 
        ok = false;
-
+      
       if (insn->pinfo != INSN_MACRO)
        {
-         if (mips_4650 && (insn->pinfo & FP_D) != 0)
+         if (mips_cpu == 4650 && (insn->pinfo & FP_D) != 0)
            ok = false;
-         /* start-sanitize-r5900 */
-         if (mips_5900 && (insn->pinfo & FP_D) != 0)
-           ok = false;
-         /* end-sanitize-r5900 */
        }
 
       if (! ok)
@@ -6844,17 +7028,16 @@ mips_ip (str, ip)
              ++insn;
              continue;
            }
-         if (insn_isa == 15 
-              || insn_isa <= mips_opts.isa)
-           insn_error = "opcode not supported on this processor";
          else
            {
              static char buf[100];
-
-             sprintf (buf, "opcode requires -mips%d or greater", insn_isa);
+             sprintf (buf, 
+                      _("opcode not supported on this processor: %d (MIPS%d)"),
+                      mips_cpu, mips_opts.isa);
+                      
              insn_error = buf;
+             return;
            }
-         return;
        }
 
       ip->insn_mo = insn;
@@ -6893,20 +7076,17 @@ mips_ip (str, ip)
              break;
 
            case '(':
-             /* handle optional base register.
+             /* Handle optional base register.
                 Either the base register is omitted or
                 we must have a left paren. */
-             /* this is dependent on the next operand specifier
-                is a 'b' for base register */
-             assert (args[1] == 'b');
+             /* This is dependent on the next operand specifier
+                is a base register specification.  */
+             assert (args[1] == 'b' || args[1] == '5'
+                     || args[1] == '-' || args[1] == '4');
              if (*s == '\0')
                return;
 
            case ')':           /* these must match exactly */
-             /* start-sanitize-vr5400 */
-           case '[':
-           case ']':
-             /* end-sanitize-vr5400 */
              if (*s++ == *args)
                continue;
              break;
@@ -6922,7 +7102,7 @@ mips_ip (str, ip)
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > 31)
                {
-                 as_warn ("Improper shift amount (%ld)",
+                 as_warn (_("Improper shift amount (%ld)"),
                           (long) imm_expr.X_add_number);
                  imm_expr.X_add_number = imm_expr.X_add_number & 0x1f;
                }
@@ -6942,13 +7122,14 @@ mips_ip (str, ip)
              s = expr_end;
              continue;
 
+
            case 'k':           /* cache code */
            case 'h':           /* prefx code */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > 31)
                {
-                 as_warn ("Invalid value for `%s' (%lu)",
+                 as_warn (_("Invalid value for `%s' (%lu)"),
                           ip->insn_mo->name,
                           (unsigned long) imm_expr.X_add_number);
                  imm_expr.X_add_number &= 0x1f;
@@ -6965,18 +7146,35 @@ mips_ip (str, ip)
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned) imm_expr.X_add_number > 1023)
-               as_warn ("Illegal break code (%ld)",
-                        (long) imm_expr.X_add_number);
+               {
+                 as_warn (_("Illegal break code (%ld)"),
+                          (long) imm_expr.X_add_number);
+                 imm_expr.X_add_number &= 0x3ff;
+               }
              ip->insn_opcode |= imm_expr.X_add_number << 16;
              imm_expr.X_op = O_absent;
              s = expr_end;
              continue;
 
+           case 'q':           /* lower break code */
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+             if ((unsigned) imm_expr.X_add_number > 1023)
+               {
+                 as_warn (_("Illegal lower break code (%ld)"),
+                          (long) imm_expr.X_add_number);
+                 imm_expr.X_add_number &= 0x3ff;
+               }
+             ip->insn_opcode |= imm_expr.X_add_number << 6;
+             imm_expr.X_op = O_absent;
+             s = expr_end;
+             continue;
+
            case 'B':           /* syscall code */
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned) imm_expr.X_add_number > 0xfffff)
-               as_warn ("Illegal syscall code (%ld)",
+               as_warn (_("Illegal syscall code (%ld)"),
                         (long) imm_expr.X_add_number);
              ip->insn_opcode |= imm_expr.X_add_number << 6;
              imm_expr.X_op = O_absent;
@@ -6988,7 +7186,7 @@ mips_ip (str, ip)
              check_absolute_expr (ip, &imm_expr);
               if ((unsigned long) imm_expr.X_add_number >= (1<<25))
                {
-                  as_warn ("Coproccesor code > 25 bits (%ld)",
+                  as_warn (_("Coproccesor code > 25 bits (%ld)"),
                           (long) imm_expr.X_add_number);
                   imm_expr.X_add_number &= ((1<<25) - 1);
                }
@@ -6997,6 +7195,20 @@ mips_ip (str, ip)
               s = expr_end;
               continue;
 
+           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)
+               {
+                  as_warn (_("Invalidate performance regster (%ld)"),
+                          (long) imm_expr.X_add_number);
+                  imm_expr.X_add_number &= 1;
+               }
+              ip->insn_opcode |= (imm_expr.X_add_number << 1);
+              imm_expr.X_op = O_absent;
+              s = expr_end;
+              continue;
+
            case 'b':           /* base register */
            case 'd':           /* destination register */
            case 's':           /* source register */
@@ -7008,11 +7220,11 @@ mips_ip (str, ip)
            case 'G':           /* coprocessor destination register */
            case 'x':           /* ignore register name */
            case 'z':           /* must be zero register */
-           case 'P':           /* performance register */
              s_reset = s;
              if (s[0] == '$')
                {
-                 if (isdigit (s[1]))
+
+                 if (isdigit ((unsigned char) s[1]))
                    {
                      ++s;
                      regno = 0;
@@ -7022,9 +7234,9 @@ mips_ip (str, ip)
                          regno += *s - '0';
                          ++s;
                        }
-                     while (isdigit (*s));
+                     while (isdigit ((unsigned char) *s));
                      if (regno > 31)
-                       as_bad ("Invalid register number (%d)", regno);
+                       as_bad (_("Invalid register number (%d)"), regno);
                    }
                  else if (*args == 'E' || *args == 'G')
                    goto notreg;
@@ -7063,23 +7275,22 @@ mips_ip (str, ip)
                      else if (itbl_have_entries)
                        {
                          char *p, *n;
-                         int r;
+                         unsigned long r;
 
-                         p = s+1;      /* advance past '$' */
+                         p = s + 1;    /* advance past '$' */
                          n = itbl_get_field (&p);  /* n is name */
 
-                         /* See if this is a register defined in an 
-                            itbl entry */
-                         r = itbl_get_reg_val (n);
-                         if (r)
+                         /* 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. */
+                                rack to the end of the last field.  */
                              if (p) 
                                s = p - 1;
                              else 
-                               s = strchr (s,'\0');
+                               s = strchr (s, '\0');
                              regno = r;
                            }
                          else
@@ -7091,9 +7302,8 @@ mips_ip (str, ip)
                  if (regno == AT
                      && ! mips_opts.noat
                      && *args != 'E'
-                     && *args != 'P'
                      && *args != 'G')
-                   as_warn ("Used $at without \".set noat\"");
+                   as_warn (_("Used $at without \".set noat\""));
                  c = *args;
                  if (*s == ' ')
                    s++;
@@ -7147,9 +7357,6 @@ mips_ip (str, ip)
                    case 'D':
                      /* Itbl operand; not yet implemented. FIXME ?? */
                      break;
-                   case 'P':
-                     ip->insn_opcode |= regno << 1;
-                     break;
                      /* What about all other operands like 'i', which
                         can be specified in the opcode table? */
                    }
@@ -7176,7 +7383,7 @@ mips_ip (str, ip)
            case 'V':
            case 'W':
              s_reset = s;
-             if (s[0] == '$' && s[1] == 'f' && isdigit (s[2]))
+             if (s[0] == '$' && s[1] == 'f' && isdigit ((unsigned char) s[2]))
                {
                  s += 2;
                  regno = 0;
@@ -7186,20 +7393,20 @@ mips_ip (str, ip)
                      regno += *s - '0';
                      ++s;
                    }
-                 while (isdigit (*s));
+                 while (isdigit ((unsigned char) *s));
 
                  if (regno > 31)
-                   as_bad ("Invalid float register number (%d)", regno);
+                   as_bad (_("Invalid float register number (%d)"), regno);
 
                  if ((regno & 1) != 0
-                     && mips_opts.isa < 3
+                     && ! ISA_HAS_64BIT_REGS (mips_opts.isa)
                      && ! (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))
-                   as_warn ("Float register should be even, was %d",
+                   as_warn (_("Float register should be even, was %d"),
                             regno);
 
                  c = *args;
@@ -7234,6 +7441,8 @@ mips_ip (str, ip)
                  lastregno = regno;
                  continue;
                }
+
+
              switch (*args++)
                {
                case 'V':
@@ -7249,7 +7458,7 @@ mips_ip (str, ip)
              my_getExpression (&imm_expr, s);
              if (imm_expr.X_op != O_big
                  && imm_expr.X_op != O_constant)
-               insn_error = "absolute expression required";
+               insn_error = _("absolute expression required");
              s = expr_end;
              continue;
 
@@ -7310,7 +7519,7 @@ mips_ip (str, ip)
                input_line_pointer = save_in;
                if (err != NULL && *err != '\0')
                  {
-                   as_bad ("Bad floating point constant: %s", err);
+                   as_bad (_("Bad floating point constant: %s"), err);
                    memset (temp, '\0', sizeof temp);
                    length = f64 ? 8 : 4;
                  }
@@ -7343,7 +7552,7 @@ mips_ip (str, ip)
                        offset_expr to the low order 32 bits.
                        Otherwise, set imm_expr to the entire 64 bit
                        constant.  */
-                   if (mips_opts.isa < 3)
+                   if (! ISA_HAS_64BIT_REGS (mips_opts.isa))
                      {
                        imm_expr.X_op = O_constant;
                        offset_expr.X_op = O_constant;
@@ -7427,7 +7636,7 @@ mips_ip (str, ip)
                    else
                      record_alignment (new_seg, *args == 'l' ? 2 : 3);
                    if (seg == now_seg)
-                     as_bad ("Can't use floating point insn in this section");
+                     as_bad (_("Can't use floating point insn in this section"));
 
                    /* Set the argument to the current address in the
                       section.  */
@@ -7466,6 +7675,8 @@ mips_ip (str, ip)
                      else
                        imm_reloc = BFD_RELOC_HI16;
                    }
+                 else if (imm_expr.X_op == O_constant)
+                   imm_expr.X_add_number &= 0xffff;
                }
              if (*args == 'i')
                {
@@ -7479,9 +7690,9 @@ mips_ip (str, ip)
                        break;
                      if (imm_expr.X_op != O_constant
                          && imm_expr.X_op != O_big)
-                       insn_error = "absolute expression required";
+                       insn_error = _("absolute expression required");
                      else
-                       as_bad ("16 bit expression not in range 0..65535");
+                       as_bad (_("16 bit expression not in range 0..65535"));
                    }
                }
              else
@@ -7510,7 +7721,7 @@ mips_ip (str, ip)
                           && imm_expr.X_op == O_constant)
                      || (more
                          && imm_expr.X_add_number < 0
-                         && mips_opts.isa >= 3
+                         && ISA_HAS_64BIT_REGS (mips_opts.isa)
                          && imm_expr.X_unsigned
                          && sizeof (imm_expr.X_add_number) <= 4))
                    {
@@ -7518,9 +7729,9 @@ mips_ip (str, ip)
                        break;
                      if (imm_expr.X_op != O_constant
                          && imm_expr.X_op != O_big)
-                       insn_error = "absolute expression required";
+                       insn_error = _("absolute expression required");
                      else
-                       as_bad ("16 bit expression not in range -32768..32767");
+                       as_bad (_("16 bit expression not in range -32768..32767"));
                    }
                }
              s = expr_end;
@@ -7551,13 +7762,14 @@ mips_ip (str, ip)
                          != text_section)))
                break;
 
-             offset_reloc = BFD_RELOC_LO16;
              if (c == 'h' || c == 'H')
                {
-                 assert (offset_expr.X_op == O_constant);
+                 if (offset_expr.X_op != O_constant)
+                   break;
                  offset_expr.X_add_number =
                    (offset_expr.X_add_number >> 16) & 0xffff;
                }
+             offset_reloc = BFD_RELOC_LO16;
              s = expr_end;
              continue;
 
@@ -7569,10 +7781,6 @@ mips_ip (str, ip)
 
            case 'u':           /* upper 16 bits */
              c = my_getSmallExpression (&imm_expr, s);
-             if (imm_expr.X_op == O_constant
-                 && (imm_expr.X_add_number < 0
-                     || imm_expr.X_add_number >= 0x10000))
-               as_bad ("lui expression not in range 0..65535");
              imm_reloc = BFD_RELOC_LO16;
              if (c)
                {
@@ -7589,7 +7797,13 @@ mips_ip (str, ip)
                      else
                        imm_reloc = BFD_RELOC_HI16;
                    }
+                 else if (imm_expr.X_op == O_constant)
+                   imm_expr.X_add_number &= 0xffff;
                }
+             if (imm_expr.X_op == O_constant
+                 && (imm_expr.X_add_number < 0
+                     || imm_expr.X_add_number >= 0x10000))
+               as_bad (_("lui expression not in range 0..65535"));
              s = expr_end;
              continue;
 
@@ -7611,47 +7825,17 @@ mips_ip (str, ip)
                  regno += *s - '0';
                  ++s;
                }
-             while (isdigit (*s));
+             while (isdigit ((unsigned char) *s));
              if (regno > 7)
-               as_bad ("invalid condition code register $fcc%d", regno);
+               as_bad (_("invalid condition code register $fcc%d"), regno);
              if (*args == 'N')
                ip->insn_opcode |= regno << OP_SH_BCC;
              else
                ip->insn_opcode |= regno << OP_SH_CCC;
               continue;
 
-             /* start-sanitize-vr5400 */
-           case 'e':           /* must be at least one digit */
-             my_getExpression (&imm_expr, s);
-             check_absolute_expr (ip, &imm_expr);
-             if ((unsigned long) imm_expr.X_add_number > (unsigned long) OP_MASK_VECBYTE)
-               {
-                 as_bad ("bad byte vector index (%ld)",
-                          (long) imm_expr.X_add_number);
-                 imm_expr.X_add_number = imm_expr.X_add_number;
-               }
-             ip->insn_opcode |= imm_expr.X_add_number << OP_SH_VECBYTE;
-             imm_expr.X_op = O_absent;
-             s = expr_end;
-             continue;
-
-           case '%':
-             my_getExpression (&imm_expr, s);
-             check_absolute_expr (ip, &imm_expr);
-             if ((unsigned long) imm_expr.X_add_number > (unsigned long) OP_MASK_VECALIGN)
-               {
-                 as_bad ("bad byte vector index (%ld)",
-                          (long) imm_expr.X_add_number);
-                 imm_expr.X_add_number = imm_expr.X_add_number;
-               }
-             ip->insn_opcode |= imm_expr.X_add_number << OP_SH_VECALIGN;
-             imm_expr.X_op = O_absent;
-             s = expr_end;
-             continue;
-
-             /* end-sanitize-vr5400 */
            default:
-             as_bad ("bad char = '%c'\n", *args);
+             as_bad (_("bad char = '%c'\n"), *args);
              internalError ();
            }
          break;
@@ -7664,7 +7848,7 @@ mips_ip (str, ip)
          s = argsStart;
          continue;
        }
-      insn_error = "illegal operands";
+      insn_error = _("illegal operands");
       return;
     }
 }
@@ -7694,7 +7878,7 @@ mips16_ip (str, ip)
   mips16_small = false;
   mips16_ext = false;
 
-  for (s = str; islower (*s); ++s)
+  for (s = str; islower ((unsigned char) *s); ++s)
     ;
   switch (*s)
     {
@@ -7722,7 +7906,7 @@ mips16_ip (str, ip)
        }
       /* Fall through.  */
     default:
-      insn_error = "unknown opcode";
+      insn_error = _("unknown opcode");
       return;
     }
 
@@ -7731,7 +7915,7 @@ mips16_ip (str, ip)
 
   if ((insn = (struct mips_opcode *) hash_find (mips16_op_hash, str)) == NULL)
     {
-      insn_error = "unrecognized opcode";
+      insn_error = _("unrecognized opcode");
       return;
     }
 
@@ -7827,7 +8011,7 @@ mips16_ip (str, ip)
              if (s[0] != '$')
                break;
              s_reset = s;
-             if (isdigit (s[1]))
+             if (isdigit ((unsigned char) s[1]))
                {
                  ++s;
                  regno = 0;
@@ -7837,10 +8021,10 @@ mips16_ip (str, ip)
                      regno += *s - '0';
                      ++s;
                    }
-                 while (isdigit (*s));
+                 while (isdigit ((unsigned char) *s));
                  if (regno > 31)
                    {
-                     as_bad ("invalid register number (%d)", regno);
+                     as_bad (_("invalid register number (%d)"), regno);
                      regno = 2;
                    }
                }
@@ -7921,7 +8105,7 @@ mips16_ip (str, ip)
                case 'X':
                case 'Y':
                  if (regno == AT && ! mips_opts.noat)
-                   as_warn ("used $at without \".set noat\"");
+                   as_warn (_("used $at without \".set noat\""));
                  break;
 
                default:
@@ -8062,7 +8246,7 @@ mips16_ip (str, ip)
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > 63)
                {
-                 as_warn ("Invalid value for `%s' (%lu)",
+                 as_warn (_("Invalid value for `%s' (%lu)"),
                           ip->insn_mo->name,
                           (unsigned long) imm_expr.X_add_number);
                  imm_expr.X_add_number &= 0x3f;
@@ -8096,7 +8280,7 @@ mips16_ip (str, ip)
                      ++s;
                    if (*s != '$')
                      {
-                       as_bad ("can't parse register list");
+                       as_bad (_("can't parse register list"));
                        break;
                      }
                    ++s;
@@ -8108,7 +8292,7 @@ mips16_ip (str, ip)
                        ++s;
                      }
                    reg1 = 0;
-                   while (isdigit (*s))
+                   while (isdigit ((unsigned char) *s))
                      {
                        reg1 *= 10;
                        reg1 += *s - '0';
@@ -8130,12 +8314,12 @@ mips16_ip (str, ip)
                              ++s;
                            else
                              {
-                               as_bad ("invalid register list");
+                               as_bad (_("invalid register list"));
                                break;
                              }
                          }
                        reg2 = 0;
-                       while (isdigit (*s))
+                       while (isdigit ((unsigned char) *s))
                          {
                            reg2 *= 10;
                            reg2 += *s - '0';
@@ -8160,7 +8344,7 @@ mips16_ip (str, ip)
                      mask |= 1;
                    else
                      {
-                       as_bad ("invalid register list");
+                       as_bad (_("invalid register list"));
                        break;
                      }
                  }
@@ -8177,7 +8361,7 @@ mips16_ip (str, ip)
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > 0x7ff)
                {
-                 as_warn ("Invalid value for `%s' (%lu)",
+                 as_warn (_("Invalid value for `%s' (%lu)"),
                           ip->insn_mo->name,
                           (unsigned long) imm_expr.X_add_number);
                  imm_expr.X_add_number &= 0x7ff;
@@ -8202,7 +8386,7 @@ mips16_ip (str, ip)
          continue;
        }
 
-      insn_error = "illegal operands";
+      insn_error = _("illegal operands");
 
       return;
     }
@@ -8327,9 +8511,9 @@ mips16_immed (file, line, type, val, warn, small, ext, insn, use_extend,
     needext = false;
 
   if (warn && ext && ! needext)
-    as_warn_where (file, line, "extended operand requested but not required");
+    as_warn_where (file, line, _("extended operand requested but not required"));
   if (small && needext)
-    as_bad_where (file, line, "invalid unextended operand value");
+    as_bad_where (file, line, _("invalid unextended operand value"));
 
   if (small || (! ext && ! needext))
     {
@@ -8357,7 +8541,7 @@ mips16_immed (file, line, type, val, warn, small, ext, insn, use_extend,
        }
       if (val < minext || val > maxext)
        as_bad_where (file, line,
-                     "operand value out of range for instruction");
+                     _("operand value out of range for instruction"));
 
       *use_extend = true;
       if (op->extbits == 16)
@@ -8419,9 +8603,9 @@ my_getSmallExpression (ep, str)
        ;
       if (sp - 4 >= str && sp[-1] == RP)
        {
-         if (isdigit (sp[-2]))
+         if (isdigit ((unsigned char) sp[-2]))
            {
-             for (sp -= 3; sp >= str && isdigit (*sp); sp--)
+             for (sp -= 3; sp >= str && isdigit ((unsigned char) *sp); sp--)
                ;
              if (*sp == '$' && sp > str && sp[-1] == LP)
                {
@@ -8492,10 +8676,10 @@ my_getExpression (ep, str)
       && ep->X_op == O_symbol
       && strcmp (S_GET_NAME (ep->X_add_symbol), FAKE_LABEL_NAME) == 0
       && S_GET_SEGMENT (ep->X_add_symbol) == now_seg
-      && ep->X_add_symbol->sy_frag == frag_now
-      && ep->X_add_symbol->sy_value.X_op == O_constant
-      && ep->X_add_symbol->sy_value.X_add_number == frag_now_fix ())
-    ++ep->X_add_symbol->sy_value.X_add_number;
+      && symbol_get_frag (ep->X_add_symbol) == frag_now
+      && symbol_constant_p (ep->X_add_symbol)
+      && S_GET_VALUE (ep->X_add_symbol) == frag_now_fix ())
+    S_SET_VALUE (ep->X_add_symbol, S_GET_VALUE (ep->X_add_symbol) + 1);
 }
 
 /* Turn a string in input_line_pointer into a floating point constant
@@ -8526,7 +8710,7 @@ md_atof (type, litP, sizeP)
 
     default:
       *sizeP = 0;
-      return "bad call to md_atof";
+      return _("bad call to md_atof");
     }
 
   t = atof_ieee (input_line_pointer, type, words);
@@ -8609,36 +8793,15 @@ struct option md_longopts[] = {
   {"mips16", no_argument, NULL, OPTION_MIPS16},
 #define OPTION_NO_MIPS16 (OPTION_MD_BASE + 23)
   {"no-mips16", no_argument, NULL, OPTION_NO_MIPS16},
-  /* start-sanitize-r5900 */
-#define OPTION_M5900 (OPTION_MD_BASE + 24)
-  {"m5900", no_argument, NULL, OPTION_M5900},
-#define OPTION_NO_M5900 (OPTION_MD_BASE + 25)
-  {"no-m5900", no_argument, NULL, OPTION_NO_M5900},
-  /* end-sanitize-r5900 */
 #define OPTION_M3900 (OPTION_MD_BASE + 26)
   {"m3900", no_argument, NULL, OPTION_M3900},
 #define OPTION_NO_M3900 (OPTION_MD_BASE + 27)
   {"no-m3900", no_argument, NULL, OPTION_NO_M3900},
 
-  /* start-sanitize-tx19 */
-  {"m1900", no_argument, NULL, OPTION_M3900},
-  {"no-m1900", no_argument, NULL, OPTION_NO_M3900},
-  /* end-sanitize-tx19 */
-
-  /* start-sanitize-vr5400 */
-#define OPTION_M5400 (OPTION_MD_BASE + 28)
-  {"m5400", no_argument, NULL, OPTION_M5400},
-#define OPTION_NO_M5400 (OPTION_MD_BASE + 29)
-  {"no-m5400", no_argument, NULL, OPTION_NO_M5400},
-
-  /* end-sanitize-vr5400 */
-  /* start-sanitize-tx49 */
-#define OPTION_M4900 (OPTION_MD_BASE + 30)
-  {"m4900", no_argument, NULL, OPTION_M4900},
-#define OPTION_NO_M4900 (OPTION_MD_BASE + 31)
-  {"no-m4900", no_argument, NULL, OPTION_NO_M4900},
-
-  /* end-sanitize-tx49 */
+
+#define OPTION_MABI (OPTION_MD_BASE + 38)
+  {"mabi", required_argument, NULL, OPTION_MABI},
+
 #define OPTION_CALL_SHARED (OPTION_MD_BASE + 7)
 #define OPTION_NON_SHARED (OPTION_MD_BASE + 8)
 #define OPTION_XGOT (OPTION_MD_BASE + 19)
@@ -8747,10 +8910,6 @@ md_parse_option (c, arg)
                    || strcmp (p, "10k") == 0
                    || strcmp (p, "10K") == 0)
                  mips_cpu = 10000;
-                /* start-sanitize-tx19 */
-                else if (strcmp (p, "1900") == 0)
-                  mips_cpu = 3900;
-                /* end-sanitize-tx19 */
                break;
 
              case '2':
@@ -8776,6 +8935,8 @@ md_parse_option (c, arg)
                  mips_cpu = 4000;
                else if (strcmp (p, "4100") == 0)
                     mips_cpu = 4100;
+               else if (strcmp (p, "4111") == 0)
+                    mips_cpu = 4111;
                else if (strcmp (p, "4300") == 0)
                  mips_cpu = 4300;
                else if (strcmp (p, "4400") == 0)
@@ -8784,10 +8945,6 @@ md_parse_option (c, arg)
                  mips_cpu = 4600;
                else if (strcmp (p, "4650") == 0)
                    mips_cpu = 4650;
-                /* start-sanitize-tx49 */
-               else if (strcmp (p, "4900") == 0)
-                 mips_cpu = 4900;
-                /* end-sanitize-tx49 */
                else if (strcmp (p, "4010") == 0)
                   mips_cpu = 4010;
                break;
@@ -8797,14 +8954,6 @@ md_parse_option (c, arg)
                    || strcmp (p, "5k") == 0
                    || strcmp (p, "5K") == 0)
                  mips_cpu = 5000;
-                /* start-sanitize-vr5400 */
-                else if (strcmp (p, "5400") == 0)
-                  mips_cpu = 5400;
-                /* end-sanitize-vr5400 */
-                /* start-sanitize-r5900 */
-                else if (strcmp (p, "5900") == 0)
-                  mips_cpu = 5900;
-                /* end-sanitize-r5900 */
                break;
 
              case '6':
@@ -8830,18 +8979,16 @@ md_parse_option (c, arg)
            if (sv
                && (mips_cpu != 4300
                    && mips_cpu != 4100
-                   /* start-sanitize-vr5400 */
-                   && mips_cpu != 5400
-                   /* end-sanitize-vr5400 */
+                   && mips_cpu != 4111
                    && mips_cpu != 5000))
              {
-               as_bad ("ignoring invalid leading 'v' in -mcpu=%s switch", arg);
+               as_bad (_("ignoring invalid leading 'v' in -mcpu=%s switch"), arg);
                return 0;
              }
 
            if (mips_cpu == -1)
              {
-               as_bad ("invalid architecture -mcpu=%s", arg);
+               as_bad (_("invalid architecture -mcpu=%s"), arg);
                return 0;
              }
          }
@@ -8849,67 +8996,34 @@ md_parse_option (c, arg)
       break;
 
     case OPTION_M4650:
-      mips_4650 = 1;
+      mips_cpu = 4650;
       break;
 
     case OPTION_NO_M4650:
-      mips_4650 = 0;
       break;
 
     case OPTION_M4010:
-      mips_4010 = 1;
+      mips_cpu = 4010;
       break;
 
     case OPTION_NO_M4010:
-      mips_4010 = 0;
       break;
 
     case OPTION_M4100:
-      mips_4100 = 1;
+      mips_cpu = 4100;
       break;
 
     case OPTION_NO_M4100:
-      mips_4100 = 0;
-      break;
-
-      /* start-sanitize-r5900 */
-    case OPTION_M5900:
-      mips_5900 = 1;
       break;
 
-    case OPTION_NO_M5900:
-      mips_5900 = 0;
-      break;
-      /* end-sanitize-r5900 */
-
-      /* start-sanitize-vr5400 */
-    case OPTION_M5400:
-      mips_5400 = 1;
-      break;
-
-    case OPTION_NO_M5400:
-      mips_5400 = 0;
-      break;
 
-      /* end-sanitize-vr5400 */
     case OPTION_M3900:
-      mips_3900 = 1;
+      mips_cpu = 3900;
       break;
       
     case OPTION_NO_M3900:
-      mips_3900 = 0;
       break;
 
-      /* start-sanitize-tx49 */
-    case OPTION_M4900:
-      mips_4900 = 1;
-      break;
-      
-    case OPTION_NO_M4900:
-      mips_4900 = 0;
-      break;
-
-      /* end-sanitize-tx49 */
     case OPTION_MIPS16:
       mips_opts.mips16 = 1;
       mips_no_prev_insn (false);
@@ -8924,7 +9038,7 @@ md_parse_option (c, arg)
       mips_pic = EMBEDDED_PIC;
       if (USE_GLOBAL_POINTER_OPT && g_switch_seen)
        {
-         as_bad ("-G may not be used with embedded PIC code");
+         as_bad (_("-G may not be used with embedded PIC code"));
          return 0;
        }
       g_switch_value = 0x7fffffff;
@@ -8936,13 +9050,13 @@ md_parse_option (c, arg)
     case OPTION_CALL_SHARED:
       if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
        {
-         as_bad ("-call_shared is supported only for ELF format");
+         as_bad (_("-call_shared is supported only for ELF format"));
          return 0;
        }
       mips_pic = SVR4_PIC;
       if (g_switch_seen && g_switch_value != 0)
        {
-         as_bad ("-G may not be used with SVR4 PIC code");
+         as_bad (_("-G may not be used with SVR4 PIC code"));
          return 0;
        }
       g_switch_value = 0;
@@ -8951,7 +9065,7 @@ md_parse_option (c, arg)
     case OPTION_NON_SHARED:
       if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
        {
-         as_bad ("-non_shared is supported only for ELF format");
+         as_bad (_("-non_shared is supported only for ELF format"));
          return 0;
        }
       mips_pic = NO_PIC;
@@ -8967,12 +9081,12 @@ md_parse_option (c, arg)
     case 'G':
       if (! USE_GLOBAL_POINTER_OPT)
        {
-         as_bad ("-G is not supported for this configuration");
+         as_bad (_("-G is not supported for this configuration"));
          return 0;
        }
       else if (mips_pic == SVR4_PIC || mips_pic == EMBEDDED_PIC)
        {
-         as_bad ("-G may not be used with SVR4 or embedded PIC code");
+         as_bad (_("-G may not be used with SVR4 or embedded PIC code"));
          return 0;
        }
       else
@@ -8996,12 +9110,22 @@ md_parse_option (c, arg)
              || strcmp (*l, "elf64-littlemips") == 0)
            break;
        if (*l == NULL)
-         as_fatal ("No compiled in support for 64 bit object file format");
+         as_fatal (_("No compiled in support for 64 bit object file format"));
        free (list);
        mips_64 = 1;
       }
       break;
 
+
+    case OPTION_MABI:
+      if (strcmp (arg,"32") == 0
+         || strcmp (arg,"n32") == 0
+         || strcmp (arg,"64") == 0
+         || strcmp (arg,"o64") == 0
+         || strcmp (arg,"eabi") == 0)
+       mips_abi_string = arg;
+      break;
+
     default:
       return 0;
     }
@@ -9009,46 +9133,106 @@ md_parse_option (c, arg)
   return 1;
 }
 
+
+static void
+show (stream, string, col_p, first_p)
+     FILE *stream;
+     char *string;
+     int *col_p;
+     int *first_p;
+{
+  if (*first_p)
+    {
+      fprintf (stream, "%24s", "");
+      *col_p = 24;
+    }
+  else
+    {
+      fprintf (stream, ", ");
+      *col_p += 2;
+    }
+
+  if (*col_p + strlen (string) > 72)
+    {
+      fprintf (stream, "\n%24s", "");
+      *col_p = 24;
+    }
+
+  fprintf (stream, "%s", string);
+  *col_p += strlen (string);
+
+  *first_p = 0;
+}
+
+
 void
 md_show_usage (stream)
      FILE *stream;
 {
-  fprintf(stream, "\
+  int column, first;
+
+  fprintf(stream, _("\
 MIPS options:\n\
 -membedded-pic         generate embedded position independent code\n\
 -EB                    generate big endian output\n\
 -EL                    generate little endian output\n\
 -g, -g2                        do not remove uneeded NOPs or swap branches\n\
 -G NUM                 allow referencing objects up to NUM bytes\n\
-                       implicitly with the gp register [default 8]\n");
-  fprintf(stream, "\
--mips1, -mcpu=r{2,3}000        generate code for r2000 and r3000\n\
--mips2, -mcpu=r6000    generate code for r6000\n\
--mips3, -mcpu=r4000    generate code for r4000\n\
--mips4, -mcpu=r8000    generate code for r8000\n\
--mcpu=vr4300           generate code for vr4300\n\
--mcpu=vr4100           generate code for vr4100\n\
--m4650                 permit R4650 instructions\n\
--no-m4650              do not permit R4650 instructions\n\
--m4010                 permit R4010 instructions\n\
--no-m4010              do not permit R4010 instructions\n\
--m4100                  permit VR4100 instructions\n\
--no-m4100              do not permit VR4100 instructions\n");
-  fprintf(stream, "\
+                       implicitly with the gp register [default 8]\n"));
+  fprintf(stream, _("\
+-mips1                 generate MIPS ISA I instructions\n\
+-mips2                 generate MIPS ISA II instructions\n\
+-mips3                 generate MIPS ISA III instructions\n\
+-mips4                 generate MIPS ISA IV instructions\n\
+-mcpu=CPU              generate code for CPU, where CPU is one of:\n"));
+
+  first = 1;
+
+  show (stream, "2000", &column, &first);
+  show (stream, "3000", &column, &first);
+  show (stream, "3900", &column, &first);
+  show (stream, "4000", &column, &first);
+  show (stream, "4010", &column, &first);
+  show (stream, "4100", &column, &first);
+  show (stream, "4111", &column, &first);
+  show (stream, "4300", &column, &first);
+  show (stream, "4400", &column, &first);
+  show (stream, "4600", &column, &first);
+  show (stream, "4650", &column, &first);
+  show (stream, "5000", &column, &first);
+  show (stream, "6000", &column, &first);
+  show (stream, "8000", &column, &first);
+  show (stream, "10000", &column, &first);
+  fputc ('\n', stream);
+
+  fprintf (stream, _("\
+-mCPU                  equivalent to -mcpu=CPU.\n\
+-no-mCPU               don't generate code specific to CPU.\n\
+                       For -mCPU and -no-mCPU, CPU must be one of:\n"));
+
+  first = 1;
+
+  show (stream, "3900", &column, &first);
+  show (stream, "4010", &column, &first);
+  show (stream, "4100", &column, &first);
+  show (stream, "4650", &column, &first);
+  fputc ('\n', stream);
+
+  fprintf(stream, _("\
 -mips16                        generate mips16 instructions\n\
--no-mips16             do not generate mips16 instructions\n");
-  fprintf(stream, "\
+-no-mips16             do not generate mips16 instructions\n"));
+  fprintf(stream, _("\
 -O0                    remove unneeded NOPs, do not swap branches\n\
 -O                     remove unneeded NOPs and swap branches\n\
 --trap, --no-break     trap exception on div by 0 and mult overflow\n\
---break, --no-trap     break exception on div by 0 and mult overflow\n");
+--break, --no-trap     break exception on div by 0 and mult overflow\n"));
 #ifdef OBJ_ELF
-  fprintf(stream, "\
+  fprintf(stream, _("\
 -KPIC, -call_shared    generate SVR4 position independent code\n\
 -non_shared            do not generate position independent code\n\
 -xgot                  assume a 32 bit GOT\n\
 -32                    create 32 bit object file (default)\n\
--64                    create 64 bit object file\n");
+-64                    create 64 bit object file\n"));
 #endif
 }
 \f
@@ -9100,7 +9284,7 @@ cons_fix_new_mips (frag, where, nbytes, exp)
 #endif
 
   if (nbytes != 2 && nbytes != 4 && nbytes != 8)
-    as_bad ("Unsupported reloc size %d", nbytes);
+    as_bad (_("Unsupported reloc size %d"), nbytes);
 
   fix_new_exp (frag_now, where, (int) nbytes, exp, 0,
               (nbytes == 2
@@ -9199,9 +9383,12 @@ mips_frob_file ()
          if (f != NULL)
            break;
 
+#if 0 /* GCC code motion plus incomplete dead code elimination
+        can leave a %hi without a %lo.  */
          if (pass == 1)
            as_warn_where (l->fixp->fx_file, l->fixp->fx_line,
-                          "Unmatched %%hi reloc");
+                          _("Unmatched %%hi reloc"));
+#endif
        }
     }
 }
@@ -9227,6 +9414,10 @@ int
 mips_force_relocation (fixp)
      fixS *fixp;
 {
+  if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+    return 1;
+
   return (mips_pic == EMBEDDED_PIC
          && (fixp->fx_pcrel
              || SWITCH_TABLE (fixp)
@@ -9246,28 +9437,39 @@ md_apply_fix (fixP, valueP)
 
   assert (fixP->fx_size == 4
          || fixP->fx_r_type == BFD_RELOC_16
-         || fixP->fx_r_type == BFD_RELOC_64);
+         || fixP->fx_r_type == BFD_RELOC_64
+         || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+         || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY);
 
   value = *valueP;
 
   /* If we aren't adjusting this fixup to be against the section
      symbol, we need to adjust the value.  */
 #ifdef OBJ_ELF
-  if (fixP->fx_addsy != NULL
-      && OUTPUT_FLAVOR == bfd_target_elf_flavour
-      && S_GET_OTHER (fixP->fx_addsy) == STO_MIPS16)
-    {
-      value -= S_GET_VALUE (fixP->fx_addsy);
-      if (value != 0 && ! fixP->fx_pcrel)
-       {
-         /* In this case, the bfd_install_relocation routine will
-             incorrectly add the symbol value back in.  We just want
-             the addend to appear in the object file.  */
-         value -= S_GET_VALUE (fixP->fx_addsy);
-       }
-    }
+  if (fixP->fx_addsy != NULL && OUTPUT_FLAVOR == bfd_target_elf_flavour)
+    if (S_GET_OTHER (fixP->fx_addsy) == STO_MIPS16 
+        || S_IS_WEAK (fixP->fx_addsy)
+        || (symbol_used_in_reloc_p (fixP->fx_addsy)
+            && (((bfd_get_section_flags (stdoutput,
+                                        S_GET_SEGMENT (fixP->fx_addsy))
+                 & SEC_LINK_ONCE) != 0)
+               || !strncmp (segment_name (S_GET_SEGMENT (fixP->fx_addsy)),
+                            ".gnu.linkonce",
+                            sizeof (".gnu.linkonce") - 1))))
+
+      {
+        value -= S_GET_VALUE (fixP->fx_addsy);
+        if (value != 0 && ! fixP->fx_pcrel)
+          {
+            /* In this case, the bfd_install_relocation routine will
+               incorrectly add the symbol value back in.  We just want
+               the addend to appear in the object file.  */
+            value -= S_GET_VALUE (fixP->fx_addsy);
+          }
+      }
 #endif
 
+
   fixP->fx_addnumber = value;  /* Remember value for tc_gen_reloc */
 
   if (fixP->fx_addsy == NULL && ! fixP->fx_pcrel)
@@ -9290,7 +9492,7 @@ md_apply_fix (fixP, valueP)
     case BFD_RELOC_MIPS16_GPREL:
       if (fixP->fx_pcrel)
        as_bad_where (fixP->fx_file, fixP->fx_line,
-                     "Invalid PC relative reloc");
+                     _("Invalid PC relative reloc"));
       /* Nothing needed to do. The value comes from the reloc entry */
       break;
 
@@ -9304,7 +9506,7 @@ md_apply_fix (fixP, valueP)
     case BFD_RELOC_PCREL_HI16_S:
       /* The addend for this is tricky if it is internal, so we just
         do everything here rather than in bfd_install_relocation.  */
-      if ((fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) == 0)
+      if ((symbol_get_bfdsym (fixP->fx_addsy)->flags & BSF_SECTION_SYM) == 0)
        {
          /* For an external symbol adjust by the address to make it
             pcrel_offset.  We use the address of the RELLO reloc
@@ -9324,7 +9526,7 @@ md_apply_fix (fixP, valueP)
     case BFD_RELOC_PCREL_LO16:
       /* The addend for this is tricky if it is internal, so we just
         do everything here rather than in bfd_install_relocation.  */
-      if ((fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) == 0)
+      if ((symbol_get_bfdsym (fixP->fx_addsy)->flags & BSF_SECTION_SYM) == 0)
        value += fixP->fx_frag->fr_address + fixP->fx_where;
       buf = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where;
       if (target_big_endian)
@@ -9389,7 +9591,7 @@ md_apply_fix (fixP, valueP)
        {
          if (value < -0x8000 || value > 0x7fff)
            as_bad_where (fixP->fx_file, fixP->fx_line,
-                         "relocation overflow");
+                         _("relocation overflow"));
          buf = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where;
          if (target_big_endian)
            buf += 2;
@@ -9405,7 +9607,7 @@ md_apply_fix (fixP, valueP)
        */
       if ((value & 0x3) != 0)
        as_bad_where (fixP->fx_file, fixP->fx_line,
-                     "Branch to odd address (%lx)", value);
+                     _("Branch to odd address (%lx)"), value);
       value >>= 2;
 
       /* update old instruction data */
@@ -9450,13 +9652,25 @@ md_apply_fix (fixP, valueP)
                  handle these cases, but it appears to do it
                  incorrectly.  */
              as_bad_where (fixP->fx_file, fixP->fx_line,
-                           "Branch out of range");
+                           _("Branch out of range"));
            }
        }
 
       md_number_to_chars ((char *) buf, (valueT) insn, 4);
       break;
 
+    case BFD_RELOC_VTABLE_INHERIT:
+      fixP->fx_done = 0;
+      if (fixP->fx_addsy
+          && !S_IS_DEFINED (fixP->fx_addsy)
+          && !S_IS_WEAK (fixP->fx_addsy))
+        S_SET_WEAK (fixP->fx_addsy);
+      break;
+
+    case BFD_RELOC_VTABLE_ENTRY:
+      fixP->fx_done = 0;
+      break;
+
     default:
       internalError ();
     }
@@ -9548,7 +9762,7 @@ printInsn (oc)
          return;
        }
     }
-  printf ("%08lx  UNDEFINED\n", oc);
+  printf (_("%08lx  UNDEFINED\n"), oc);
 }
 #endif
 
@@ -9581,7 +9795,7 @@ mips_align (to, fill, label)
   if (label != NULL)
     {
       assert (S_GET_SEGMENT (label) == now_seg);
-      label->sy_frag = frag_now;
+      symbol_set_frag (label, frag_now);
       S_SET_VALUE (label, (valueT) frag_now_fix ());
     }
 }
@@ -9611,10 +9825,10 @@ s_align (x)
 
   temp = get_absolute_expression ();
   if (temp > max_alignment)
-    as_bad ("Alignment too large: %d. assumed.", temp = max_alignment);
+    as_bad (_("Alignment too large: %d. assumed."), temp = max_alignment);
   else if (temp < 0)
     {
-      as_warn ("Alignment negative: 0 assumed.");
+      as_warn (_("Alignment negative: 0 assumed."));
       temp = 0;
     }
   if (*input_line_pointer == ',')
@@ -9702,7 +9916,7 @@ s_change_sec (sec)
        }
       else
        {
-         as_bad ("No read only data section in this object file format");
+         as_bad (_("No read only data section in this object file format"));
          demand_empty_rest_of_line ();
          return;
        }
@@ -9725,7 +9939,7 @@ s_change_sec (sec)
        }
       else
        {
-         as_bad ("Global pointers not supported; recompile -G 0");
+         as_bad (_("Global pointers not supported; recompile -G 0"));
          demand_empty_rest_of_line ();
          return;
        }
@@ -9765,10 +9979,12 @@ s_float_cons (type)
   mips_emit_delays (false);
 
   if (auto_align)
-    if (type == 'd')
-      mips_align (3, 0, label);
-    else
-      mips_align (2, 0, label);
+    {
+      if (type == 'd')
+       mips_align (3, 0, label);
+      else
+       mips_align (2, 0, label);
+    }
 
   mips_clear_insn_labels ();
 
@@ -9809,14 +10025,14 @@ s_mips_globl (x)
       c = get_symbol_end ();
       sec = bfd_get_section_by_name (stdoutput, secname);
       if (sec == NULL)
-       as_bad ("%s: no such section", secname);
+       as_bad (_("%s: no such section"), secname);
       *input_line_pointer = c;
 
       if (sec != NULL && (sec->flags & SEC_CODE) != 0)
        flag = BSF_FUNCTION;
     }
 
-  symbolP->bsym->flags |= flag;
+  symbol_get_bfdsym (symbolP)->flags |= flag;
 
   S_SET_EXTERNAL (symbolP);
   demand_empty_rest_of_line ();
@@ -9846,18 +10062,18 @@ s_option (x)
       else if (i == 2)
        mips_pic = SVR4_PIC;
       else
-       as_bad (".option pic%d not supported", i);
+       as_bad (_(".option pic%d not supported"), i);
 
       if (USE_GLOBAL_POINTER_OPT && mips_pic == SVR4_PIC)
        {
          if (g_switch_seen && g_switch_value != 0)
-           as_warn ("-G may not be used with SVR4 PIC code");
+           as_warn (_("-G may not be used with SVR4 PIC code"));
          g_switch_value = 0;
          bfd_set_gp_size (stdoutput, 0);
        }
     }
   else
-    as_warn ("Unrecognized option \"%s\"", opt);
+    as_warn (_("Unrecognized option \"%s\""), opt);
 
   *input_line_pointer = c;
   demand_empty_rest_of_line ();
@@ -9920,7 +10136,7 @@ s_mipsset (x)
   else if (strcmp (name, "nomacro") == 0)
     {
       if (mips_opts.noreorder == 0)
-       as_bad ("`noreorder' must be set before `nomacro'");
+       as_bad (_("`noreorder' must be set before `nomacro'"));
       mips_opts.warn_about_macros = 1;
     }
   else if (strcmp (name, "move") == 0 || strcmp (name, "novolatile") == 0)
@@ -9955,7 +10171,7 @@ s_mipsset (x)
       if (isa == 0)
        mips_opts.isa = file_mips_isa;
       else if (isa < 1 || isa > 4)
-       as_bad ("unknown ISA level");
+       as_bad (_("unknown ISA level"));
       else
        mips_opts.isa = isa;
     }
@@ -9978,7 +10194,7 @@ s_mipsset (x)
 
       s = mips_opts_stack;
       if (s == NULL)
-       as_bad (".set pop with no .set push");
+       as_bad (_(".set pop with no .set push"));
       else
        {
          /* If we're changing the reorder mode we need to handle
@@ -10002,7 +10218,7 @@ s_mipsset (x)
     }
   else
     {
-      as_warn ("Tried to set unrecognized symbol: %s\n", name);
+      as_warn (_("Tried to set unrecognized symbol: %s\n"), name);
     }
   *input_line_pointer = ch;
   demand_empty_rest_of_line ();
@@ -10019,7 +10235,7 @@ s_abicalls (ignore)
   if (USE_GLOBAL_POINTER_OPT)
     {
       if (g_switch_seen && g_switch_value != 0)
-       as_warn ("-G may not be used with SVR4 PIC code");
+       as_warn (_("-G may not be used with SVR4 PIC code"));
       g_switch_value = 0;
     }
   bfd_set_gp_size (stdoutput, 0);
@@ -10052,7 +10268,7 @@ s_cpload (ignore)
 
   /* .cpload should be a in .set noreorder section.  */
   if (mips_opts.noreorder == 0)
-    as_warn (".cpload not in noreorder section");
+    as_warn (_(".cpload not in noreorder section"));
 
   ex.X_op = O_symbol;
   ex.X_add_symbol = symbol_find_or_make ("_gp_disp");
@@ -10060,7 +10276,7 @@ s_cpload (ignore)
   ex.X_add_number = 0;
 
   /* In ELF, this symbol is implicitly an STT_OBJECT symbol.  */
-  ex.X_add_symbol->bsym->flags |= BSF_OBJECT;
+  symbol_get_bfdsym (ex.X_add_symbol)->flags |= BSF_OBJECT;
 
   macro_build_lui ((char *) NULL, &icnt, &ex, GP);
   macro_build ((char *) NULL, &icnt, &ex, "addiu", "t,r,j", GP, GP,
@@ -10098,7 +10314,9 @@ s_cprestore (ignore)
   ex.X_add_number = mips_cprestore_offset;
 
   macro_build ((char *) NULL, &icnt, &ex,
-              mips_opts.isa < 3 ? "sw" : "sd",
+              ((bfd_arch_bits_per_address (stdoutput) == 32
+                || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+               ? "sw" : "sd"),
               "t,o(b)", GP, (int) BFD_RELOC_LO16, SP);
 
   demand_empty_rest_of_line ();
@@ -10132,7 +10350,7 @@ s_gpword (ignore)
 
   if (ex.X_op != O_symbol || ex.X_add_number != 0)
     {
-      as_bad ("Unsupported use of .gpword");
+      as_bad (_("Unsupported use of .gpword"));
       ignore_rest_of_line ();
     }
 
@@ -10164,7 +10382,9 @@ s_cpadd (ignore)
   /* Add $gp to the register named as an argument.  */
   reg = tc_get_register (0);
   macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
-              mips_opts.isa < 3 ? "addu" : "daddu",
+              ((bfd_arch_bits_per_address (stdoutput) == 32
+                || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
+               ? "addu" : "daddu"),
               "d,v,t", reg, reg, GP);
 
   demand_empty_rest_of_line ();  
@@ -10205,6 +10425,55 @@ s_mips_stab (type)
   s_stab (type);
 }
 
+/* Handle the .weakext pseudo-op as defined in Kane and Heinrich.
+ */
+
+static void
+s_mips_weakext (ignore)
+     int ignore;
+{
+  char *name;
+  int c;
+  symbolS *symbolP;
+  expressionS exp;
+
+  name = input_line_pointer;
+  c = get_symbol_end ();
+  symbolP = symbol_find_or_make (name);
+  S_SET_WEAK (symbolP);
+  *input_line_pointer = c;
+
+  SKIP_WHITESPACE ();
+
+  if (! is_end_of_line[(unsigned char) *input_line_pointer])
+    {
+      if (S_IS_DEFINED (symbolP))
+       {
+         as_bad ("Ignoring attempt to redefine symbol `%s'.",
+                 S_GET_NAME (symbolP));
+         ignore_rest_of_line ();
+         return;
+       }
+      
+      if (*input_line_pointer == ',')
+       {
+         ++input_line_pointer;
+         SKIP_WHITESPACE ();
+       }
+      
+      expression (&exp);
+      if (exp.X_op != O_symbol)
+       {
+         as_bad ("bad .weakext directive");
+         ignore_rest_of_line();
+         return;
+       }
+      symbol_set_value_expression (symbolP, &exp);
+    }
+
+  demand_empty_rest_of_line ();
+}
+
 /* Parse a register string into a number.  Called from the ECOFF code
    to parse .frame.  The argument is non-zero if this is the frame
    register, so that we can record it in mips_frame_reg.  */
@@ -10218,7 +10487,7 @@ tc_get_register (frame)
   SKIP_WHITESPACE ();
   if (*input_line_pointer++ != '$')
     {
-      as_warn ("expected `$'");
+      as_warn (_("expected `$'"));
       reg = 0;
     }
   else if (isdigit ((unsigned char) *input_line_pointer))
@@ -10226,7 +10495,7 @@ tc_get_register (frame)
       reg = get_absolute_expression ();
       if (reg < 0 || reg >= 32)
        {
-         as_warn ("Bad register number");
+         as_warn (_("Bad register number"));
          reg = 0;
        }
     }
@@ -10242,7 +10511,7 @@ tc_get_register (frame)
        reg = AT;
       else
        {
-         as_warn ("Unrecognized register name");
+         as_warn (_("Unrecognized register name"));
          reg = 0;
        }
       input_line_pointer += 2;
@@ -10311,15 +10580,16 @@ nopic_need_relax (sym, before_relaxing)
       else if ((! S_IS_DEFINED (sym) || S_IS_COMMON (sym))
               && (0
 #ifndef NO_ECOFF_DEBUGGING
-                  || (sym->ecoff_extern_size != 0
-                      && sym->ecoff_extern_size <= g_switch_value)
+                  || (symbol_get_obj (sym)->ecoff_extern_size != 0
+                      && (symbol_get_obj (sym)->ecoff_extern_size
+                          <= g_switch_value))
 #endif
                   /* We must defer this decision until after the whole
                      file has been read, since there might be a .extern
                      after the first use of this symbol.  */
                   || (before_relaxing
 #ifndef NO_ECOFF_DEBUGGING
-                      && sym->ecoff_extern_size == 0
+                      && symbol_get_obj (sym)->ecoff_extern_size == 0
 #endif
                       && S_GET_VALUE (sym) == 0)
                   || (S_GET_VALUE (sym) != 0
@@ -10333,7 +10603,9 @@ nopic_need_relax (sym, before_relaxing)
          assert (strcmp (segname, ".lit8") != 0
                  && strcmp (segname, ".lit4") != 0);
          change = (strcmp (segname, ".sdata") != 0
-                   && strcmp (segname, ".sbss") != 0);
+                   && strcmp (segname, ".sbss") != 0
+                   && strncmp (segname, ".sdata.", 7) != 0
+                   && strncmp (segname, ".gnu.linkonce.s.", 16) != 0);
        }
       return change;
     }
@@ -10389,23 +10661,26 @@ mips16_extended_frag (fragp, sec, stretch)
       maxtiny = (1 << (op->nbits - 1)) - 1;
     }
 
-  /* We can't call S_GET_VALUE here, because we don't want to lock in
-     a particular frag address.  */
-  if (fragp->fr_symbol->sy_value.X_op == O_constant)
+  /* We can't always call S_GET_VALUE here, because we don't want to
+     lock in a particular frag address.  */
+  if (symbol_constant_p (fragp->fr_symbol))
     {
-      val = (fragp->fr_symbol->sy_value.X_add_number
-            + fragp->fr_symbol->sy_frag->fr_address);
+      val = (S_GET_VALUE (fragp->fr_symbol)
+            + symbol_get_frag (fragp->fr_symbol)->fr_address);
       symsec = S_GET_SEGMENT (fragp->fr_symbol);
     }
-  else if (fragp->fr_symbol->sy_value.X_op == O_symbol
-          && (fragp->fr_symbol->sy_value.X_add_symbol->sy_value.X_op
-              == O_constant))
+  else if (symbol_equated_p (fragp->fr_symbol)
+          && (symbol_constant_p
+              (symbol_get_value_expression (fragp->fr_symbol)->X_add_symbol)))
     {
-      val = (fragp->fr_symbol->sy_value.X_add_symbol->sy_value.X_add_number
-            + fragp->fr_symbol->sy_value.X_add_symbol->sy_frag->fr_address
-            + fragp->fr_symbol->sy_value.X_add_number
-            + fragp->fr_symbol->sy_frag->fr_address);
-      symsec = S_GET_SEGMENT (fragp->fr_symbol->sy_value.X_add_symbol);
+      symbolS *eqsym;
+
+      eqsym = symbol_get_value_expression (fragp->fr_symbol)->X_add_symbol;
+      val = (S_GET_VALUE (eqsym)
+            + symbol_get_frag (eqsym)->fr_address
+            + symbol_get_value_expression (fragp->fr_symbol)->X_add_number
+            + symbol_get_frag (fragp->fr_symbol)->fr_address);
+      symsec = S_GET_SEGMENT (eqsym);
     }
   else
     return 1;
@@ -10435,7 +10710,7 @@ mips16_extended_frag (fragp, sec, stretch)
              /* FIXME: We should support this, and let the linker
                  catch branches and loads that are out of range.  */
              as_bad_where (fragp->fr_file, fragp->fr_line,
-                           "unsupported PC relative reference to different section");
+                           _("unsupported PC relative reference to different section"));
 
              return 1;
            }
@@ -10447,7 +10722,8 @@ mips16_extended_frag (fragp, sec, stretch)
         in STRETCH in order to get a better estimate of the address.
         This particularly matters because of the shift bits.  */
       if (stretch != 0
-         && fragp->fr_symbol->sy_frag->fr_address >= fragp->fr_address)
+         && (symbol_get_frag (fragp->fr_symbol)->fr_address
+             >= fragp->fr_address))
        {
          fragS *f;
 
@@ -10458,7 +10734,7 @@ mips16_extended_frag (fragp, sec, stretch)
              a maximum number of bytes to skip when doing an
              alignment.  */
          for (f = fragp;
-              f != NULL && f != fragp->fr_symbol->sy_frag;
+              f != NULL && f != symbol_get_frag (fragp->fr_symbol);
               f = f->fr_next)
            {
              if (f->fr_type == rs_align || f->fr_type == rs_align_code)
@@ -10543,7 +10819,7 @@ mips16_extended_frag (fragp, sec, stretch)
        }
     }
   else if (symsec != absolute_section && sec != NULL)
-    as_bad_where (fragp->fr_file, fragp->fr_line, "unsupported relocation");
+    as_bad_where (fragp->fr_file, fragp->fr_line, _("unsupported relocation"));
 
   if ((val & ((1 << op->shift) - 1)) != 0
       || val < (mintiny << op->shift)
@@ -10592,14 +10868,14 @@ md_estimate_size_before_relax (fragp, segtype)
       sym = fragp->fr_symbol;
 
       /* Handle the case of a symbol equated to another symbol.  */
-      while (sym->sy_value.X_op == O_symbol
+      while (symbol_equated_p (sym)
             && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
        {
          symbolS *n;
 
          /* It's possible to get a loop here in a badly written
              program.  */
-         n = sym->sy_value.X_add_symbol;
+         n = symbol_get_value_expression (sym)->X_add_symbol;
          if (n == sym)
            break;
          sym = n;
@@ -10626,7 +10902,7 @@ md_estimate_size_before_relax (fragp, segtype)
                          + RELAX_RELOC1 (fragp->fr_subtype));
       /* FIXME: This really needs as_warn_where.  */
       if (RELAX_WARN (fragp->fr_subtype))
-       as_warn ("AT used after \".set noat\" or macro used after \".set nomacro\"");
+       as_warn (_("AT used after \".set noat\" or macro used after \".set nomacro\""));
     }
 
   if (! change)
@@ -10648,6 +10924,9 @@ mips_fix_adjustable (fixp)
 {
   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;
   if (fixp->fx_addsy == NULL)
     return 1;
 #ifdef OBJ_ELF
@@ -10674,7 +10953,8 @@ tc_gen_reloc (section, fixp)
   reloc = retval[0] = (arelent *) xmalloc (sizeof (arelent));
   retval[1] = NULL;
 
-  reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
   if (mips_pic == EMBEDDED_PIC
@@ -10685,13 +10965,13 @@ tc_gen_reloc (section, fixp)
         subtrahend.  */
       reloc->addend = reloc->address - S_GET_VALUE (fixp->fx_subsy);
       if (OUTPUT_FLAVOR != bfd_target_ecoff_flavour)
-       as_fatal ("Double check fx_r_type in tc-mips.c:tc_gen_reloc");
+       as_fatal (_("Double check fx_r_type in tc-mips.c:tc_gen_reloc"));
       fixp->fx_r_type = BFD_RELOC_GPREL32;
     }
   else if (fixp->fx_r_type == BFD_RELOC_PCREL_LO16)
     {
       /* We use a special addend for an internal RELLO reloc.  */
-      if (fixp->fx_addsy->bsym->flags & BSF_SECTION_SYM)
+      if (symbol_section_p (fixp->fx_addsy))
        reloc->addend = reloc->address - S_GET_VALUE (fixp->fx_subsy);
       else
        reloc->addend = fixp->fx_addnumber + reloc->address;
@@ -10703,7 +10983,7 @@ tc_gen_reloc (section, fixp)
       /* We use a special addend for an internal RELHI reloc.  The
         reloc is relative to the RELLO; adjust the addend
         accordingly.  */
-      if (fixp->fx_addsy->bsym->flags & BSF_SECTION_SYM)
+      if (symbol_section_p (fixp->fx_addsy))
        reloc->addend = (fixp->fx_next->fx_frag->fr_address
                         + fixp->fx_next->fx_where
                         - S_GET_VALUE (fixp->fx_subsy));
@@ -10762,7 +11042,8 @@ tc_gen_reloc (section, fixp)
       reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
       reloc2 = retval[1] = (arelent *) xmalloc (sizeof (arelent));
       retval[2] = NULL;
-      reloc2->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+      reloc2->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+      *reloc2->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
       reloc2->address = (reloc->address
                         + (RELAX_RELOC2 (fixp->fx_frag->fr_subtype)
                            - RELAX_RELOC1 (fixp->fx_frag->fr_subtype)));
@@ -10804,6 +11085,14 @@ tc_gen_reloc (section, fixp)
        abort ();
     }
 
+  /* Since MIPS ELF uses Rel instead of Rela, encode the vtable entry
+     to be used in the relocation's section offset.  */
+  if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+    {
+      reloc->address = reloc->addend;
+      reloc->addend = 0;
+    }
+
   /* Since DIFF_EXPR_OK is defined in tc-mips.h, it is possible that
      fixup_segment converted a non-PC relative reloc into a PC
      relative reloc.  In such a case, we need to convert the reloc
@@ -10835,7 +11124,7 @@ tc_gen_reloc (section, fixp)
          break;
        default:
          as_bad_where (fixp->fx_file, fixp->fx_line,
-                       "Cannot make %s relocation PC relative",
+                       _("Cannot make %s relocation PC relative"),
                        bfd_get_reloc_code_name (code));
        }
     }
@@ -10853,7 +11142,7 @@ tc_gen_reloc (section, fixp)
   if (reloc->howto == NULL)
     {
       as_bad_where (fixp->fx_file, fixp->fx_line,
-                   "Can not represent %s relocation in this object file format",
+                   _("Can not represent %s relocation in this object file format"),
                    bfd_get_reloc_code_name (code));
       retval[0] = NULL;
     }
@@ -10966,7 +11255,7 @@ md_convert_frag (abfd, asec, fragp)
          && (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype)
              || RELAX_MIPS16_DSLOT (fragp->fr_subtype)))
        as_warn_where (fragp->fr_file, fragp->fr_line,
-                      "extended instruction in delay slot");
+                      _("extended instruction in delay slot"));
 
       buf = (bfd_byte *) (fragp->fr_literal + fragp->fr_fix);
 
@@ -11108,77 +11397,86 @@ mips_elf_final_processing ()
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_NOREORDER;
   if (mips_pic != NO_PIC)
     elf_elfheader (stdoutput)->e_flags |= EF_MIPS_PIC;
+
+  /* Set the MIPS ELF ABI flags. */
+  if (mips_abi_string == 0)
+    ;
+  else if (strcmp (mips_abi_string,"32") == 0)
+    elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_O32;
+  else if (strcmp (mips_abi_string,"o64") == 0)
+    elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_O64;
+  else if (strcmp (mips_abi_string,"eabi") == 0)
+    {
+      if (mips_eabi64)
+       elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI64;
+      else
+       elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI32;
+    }
+
+  if (mips_32bitmode)
+    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_32BITMODE;
 }
 
 #endif /* OBJ_ELF || OBJ_MAYBE_ELF */
 \f
-/* These functions should really be defined by the object file format,
-   since they are related to debugging information.  However, this
-   code has to work for the a.out format, which does not define them,
-   so we provide simple versions here.  These don't actually generate
-   any debugging information, but they do simple checking and someday
-   somebody may make them useful.  */
-
-typedef struct loc
-{
-  struct loc *loc_next;
-  unsigned long loc_fileno;
-  unsigned long loc_lineno;
-  unsigned long loc_offset;
-  unsigned short loc_delta;
-  unsigned short loc_count;
-#if 0
-  fragS *loc_frag;
-#endif
-}
-locS;
-
 typedef struct proc
   {
-    struct proc *proc_next;
-    struct symbol *proc_isym;
-    struct symbol *proc_end;
-    unsigned long proc_reg_mask;
-    unsigned long proc_reg_offset;
-    unsigned long proc_fpreg_mask;
-    unsigned long proc_fpreg_offset;
-    unsigned long proc_frameoffset;
-    unsigned long proc_framereg;
-    unsigned long proc_pcreg;
-    locS *proc_iline;
-    struct file *proc_file;
-    int proc_index;
+    symbolS *isym;
+    unsigned long reg_mask;
+    unsigned long reg_offset;
+    unsigned long fpreg_mask;
+    unsigned long fpreg_offset;
+    unsigned long frame_offset;
+    unsigned long frame_reg;
+    unsigned long pc_reg;
   }
 procS;
 
-typedef struct file
-  {
-    struct file *file_next;
-    unsigned long file_fileno;
-    struct symbol *file_symbol;
-    struct symbol *file_end;
-    struct proc *file_proc;
-    int file_numprocs;
-  }
-fileS;
-
-static struct obstack proc_frags;
-static procS *proc_lastP;
-static procS *proc_rootP;
+static procS cur_proc;
+static procS *cur_proc_ptr;
 static int numprocs;
 
+/* When we align code in the .text section of mips16, use the correct two
+   byte nop pattern of 0x6500 (move $0,$0) */
+
+int
+mips_do_align (n, fill, len, max)
+     int n;
+     const char *fill;
+     int len;
+     int max;
+{
+  if (fill == NULL
+      && subseg_text_p (now_seg)
+      && n > 1
+      && mips_opts.mips16)
+    {
+      static const unsigned char be_nop[] = { 0x65, 0x00 };
+      static const unsigned char le_nop[] = { 0x00, 0x65 };
+
+      frag_align (1, 0, 0);
+
+      if (target_big_endian)
+       frag_align_pattern (n, be_nop, 2, max);      
+      else
+       frag_align_pattern (n, le_nop, 2, max);      
+      return 1;
+    }
+
+  return 0;
+}
+
 static void
 md_obj_begin ()
 {
-  obstack_begin (&proc_frags, 0x2000);
 }
 
 static void
 md_obj_end ()
 {
   /* check for premature end, nesting errors, etc */
-  if (proc_lastP && proc_lastP->proc_end == NULL)
-    as_warn ("missing `.end' at end of assembly");
+  if (cur_proc_ptr)
+    as_warn (_("missing `.end' at end of assembly"));
 }
 
 static long
@@ -11192,14 +11490,14 @@ get_number ()
       ++input_line_pointer;
       negative = 1;
     }
-  if (!isdigit (*input_line_pointer))
-    as_bad ("Expected simple number.");
+  if (!isdigit ((unsigned char) *input_line_pointer))
+    as_bad (_("Expected simple number."));
   if (input_line_pointer[0] == '0')
     {
       if (input_line_pointer[1] == 'x')
        {
          input_line_pointer += 2;
-         while (isxdigit (*input_line_pointer))
+         while (isxdigit ((unsigned char) *input_line_pointer))
            {
              val <<= 4;
              val |= hex_value (*input_line_pointer++);
@@ -11209,7 +11507,7 @@ get_number ()
       else
        {
          ++input_line_pointer;
-         while (isdigit (*input_line_pointer))
+         while (isdigit ((unsigned char) *input_line_pointer))
            {
              val <<= 3;
              val |= *input_line_pointer++ - '0';
@@ -11217,14 +11515,14 @@ get_number ()
          return negative ? -val : val;
        }
     }
-  if (!isdigit (*input_line_pointer))
+  if (!isdigit ((unsigned char) *input_line_pointer))
     {
-      printf (" *input_line_pointer == '%c' 0x%02x\n",
+      printf (_(" *input_line_pointer == '%c' 0x%02x\n"),
              *input_line_pointer, *input_line_pointer);
-      as_warn ("Invalid number");
+      as_warn (_("Invalid number"));
       return -1;
     }
-  while (isdigit (*input_line_pointer))
+  while (isdigit ((unsigned char) *input_line_pointer))
     {
       val *= 10;
       val += *input_line_pointer++ - '0';
@@ -11249,10 +11547,11 @@ s_file (x)
 /* The .end directive.  */
 
 static void
-s_mipsend (x)
+s_mips_end (x)
      int x;
 {
   symbolS *p;
+  int maybe_text;
 
   if (!is_end_of_line[(unsigned char) *input_line_pointer])
     {
@@ -11261,172 +11560,219 @@ s_mipsend (x)
     }
   else
     p = NULL;
-  if (now_seg != text_section)
-    as_warn (".end not in text section");
-  if (!proc_lastP)
+
+#ifdef BFD_ASSEMBLER
+  if ((bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
+    maybe_text = 1;
+  else
+    maybe_text = 0;
+#else
+  if (now_seg != data_section && now_seg != bss_section)
+    maybe_text = 1;
+  else
+    maybe_text = 0;
+#endif
+
+  if (!maybe_text)
+    as_warn (_(".end not in text section"));
+
+  if (!cur_proc_ptr)
     {
-      as_warn (".end and no .ent seen yet.");
+      as_warn (_(".end directive without a preceding .ent directive."));
+      demand_empty_rest_of_line ();
       return;
     }
 
   if (p != NULL)
     {
       assert (S_GET_NAME (p));
-      if (strcmp (S_GET_NAME (p), S_GET_NAME (proc_lastP->proc_isym)))
-       as_warn (".end symbol does not match .ent symbol.");
+      if (strcmp (S_GET_NAME (p), S_GET_NAME (cur_proc_ptr->isym)))
+       as_warn (_(".end symbol does not match .ent symbol."));
     }
+  else
+    as_warn (_(".end directive missing or unknown symbol"));
 
-  proc_lastP->proc_end = (symbolS *) 1;
+#ifdef MIPS_STABS_ELF
+  {
+    segT saved_seg = now_seg;
+    subsegT saved_subseg = now_subseg;
+    fragS *saved_frag = frag_now;
+    valueT dot;
+    segT seg;
+    expressionS exp;
+    char *fragp;
+
+    dot = frag_now_fix ();
+
+#ifdef md_flush_pending_output
+    md_flush_pending_output ();
+#endif
+
+    assert (pdr_seg);
+    subseg_set (pdr_seg, 0);
+
+    /* Write the symbol */
+    exp.X_op = O_symbol;
+    exp.X_add_symbol = p;
+    exp.X_add_number = 0;
+    emit_expr (&exp, 4);
+
+    fragp = frag_more (7*4);
+
+    md_number_to_chars (fragp,     (valueT) cur_proc_ptr->reg_mask, 4);
+    md_number_to_chars (fragp + 4, (valueT) cur_proc_ptr->reg_offset, 4);
+    md_number_to_chars (fragp + 8, (valueT) cur_proc_ptr->fpreg_mask, 4);
+    md_number_to_chars (fragp +12, (valueT) cur_proc_ptr->fpreg_offset, 4);
+    md_number_to_chars (fragp +16, (valueT) cur_proc_ptr->frame_offset, 4);
+    md_number_to_chars (fragp +20, (valueT) cur_proc_ptr->frame_reg, 4);
+    md_number_to_chars (fragp +24, (valueT) cur_proc_ptr->pc_reg, 4);
+
+    subseg_set (saved_seg, saved_subseg);
+  }
+#endif
+
+  cur_proc_ptr = NULL;
 }
 
 /* The .aent and .ent directives.  */
 
 static void
-s_ent (aent)
+s_mips_ent (aent)
      int aent;
 {
   int number = 0;
-  procS *procP;
   symbolS *symbolP;
+  int maybe_text;
 
   symbolP = get_symbol ();
   if (*input_line_pointer == ',')
     input_line_pointer++;
   SKIP_WHITESPACE ();
-  if (isdigit (*input_line_pointer) || *input_line_pointer == '-')
+  if (isdigit ((unsigned char) *input_line_pointer)
+      || *input_line_pointer == '-')
     number = get_number ();
-  if (now_seg != text_section)
-    as_warn (".ent or .aent not in text section.");
 
-  if (!aent && proc_lastP && proc_lastP->proc_end == NULL)
-    as_warn ("missing `.end'");
+#ifdef BFD_ASSEMBLER
+  if ((bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
+    maybe_text = 1;
+  else
+    maybe_text = 0;
+#else
+  if (now_seg != data_section && now_seg != bss_section)
+    maybe_text = 1;
+  else
+    maybe_text = 0;
+#endif
+
+  if (!maybe_text)
+    as_warn (_(".ent or .aent not in text section."));
+
+  if (!aent && cur_proc_ptr)
+    as_warn (_("missing `.end'"));
 
   if (!aent)
     {
-      procP = (procS *) obstack_alloc (&proc_frags, sizeof (*procP));
-      procP->proc_isym = symbolP;
-      procP->proc_reg_mask = 0;
-      procP->proc_reg_offset = 0;
-      procP->proc_fpreg_mask = 0;
-      procP->proc_fpreg_offset = 0;
-      procP->proc_frameoffset = 0;
-      procP->proc_framereg = 0;
-      procP->proc_pcreg = 0;
-      procP->proc_end = NULL;
-      procP->proc_next = NULL;
-      if (proc_lastP)
-       proc_lastP->proc_next = procP;
-      else
-       proc_rootP = procP;
-      proc_lastP = procP;
+      cur_proc_ptr = &cur_proc;
+      memset (cur_proc_ptr, '\0', sizeof (procS));
+
+      cur_proc_ptr->isym = symbolP;
+
+      symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
+
       numprocs++;
     }
+
   demand_empty_rest_of_line ();
 }
 
-/* The .frame directive.  */
+/* The .frame directive. If the mdebug section is present (IRIX 5 native)
+   then ecoff.c (ecoff_directive_frame) is used. For embedded targets, 
+   s_mips_frame is used so that we can set the PDR information correctly.
+   We can't use the ecoff routines because they make reference to the ecoff 
+   symbol table (in the mdebug section).  */
 
-#if 0
 static void
-s_frame (x)
-     int x;
+s_mips_frame (ignore)
+     int ignore;
 {
-  char str[100];
-  symbolS *symP;
-  int frame_reg;
-  int frame_off;
-  int pcreg;
+#ifdef MIPS_STABS_ELF
 
-  frame_reg = tc_get_register (1);
-  if (*input_line_pointer == ',')
-    input_line_pointer++;
-  frame_off = get_absolute_expression ();
-  if (*input_line_pointer == ',')
-    input_line_pointer++;
-  pcreg = tc_get_register (0);
-
-  /* bob third eye */
-  assert (proc_rootP);
-  proc_rootP->proc_framereg = frame_reg;
-  proc_rootP->proc_frameoffset = frame_off;
-  proc_rootP->proc_pcreg = pcreg;
-  /* bob macho .frame */
-
-  /* We don't have to write out a frame stab for unoptimized code. */
-  if (!(frame_reg == FP && frame_off == 0))
-    {
-      if (!proc_lastP)
-       as_warn ("No .ent for .frame to use.");
-      (void) sprintf (str, "R%d;%d", frame_reg, frame_off);
-      symP = symbol_new (str, N_VFP, 0, frag_now);
-      S_SET_TYPE (symP, N_RMASK);
-      S_SET_OTHER (symP, 0);
-      S_SET_DESC (symP, 0);
-      symP->sy_forward = proc_lastP->proc_isym;
-      /* bob perhaps I should have used pseudo set */
+  long val;
+
+  if (cur_proc_ptr ==  (procS *) NULL)
+    {
+      as_warn (_(".frame outside of .ent"));
+      demand_empty_rest_of_line ();
+      return;
     }
+
+  cur_proc_ptr->frame_reg = tc_get_register (1);
+
+  SKIP_WHITESPACE ();
+  if (*input_line_pointer++ != ','
+      || get_absolute_expression_and_terminator (&val) != ',')
+    {
+      as_warn (_("Bad .frame directive"));
+      --input_line_pointer;
+      demand_empty_rest_of_line ();
+      return;
+    }
+
+  cur_proc_ptr->frame_offset = val;
+  cur_proc_ptr->pc_reg = tc_get_register (0);
+
   demand_empty_rest_of_line ();
+#else
+  s_ignore (ignore);
+#endif /* MIPS_STABS_ELF */
 }
-#endif
 
-/* The .fmask and .mask directives.  */
+/* The .fmask and .mask directives. If the mdebug section is present 
+   (IRIX 5 native) then ecoff.c (ecoff_directive_mask) is used. For 
+   embedded targets, s_mips_mask is used so that we can set the PDR
+   information correctly. We can't use the ecoff routines because they 
+   make reference to the ecoff symbol table (in the mdebug section).  */
 
-#if 0
 static void
-s_mask (reg_type)
+s_mips_mask (reg_type)
      char reg_type;
 {
-  char str[100], *strP;
-  symbolS *symP;
-  int i;
-  unsigned int mask;
-  int off;
+#ifdef MIPS_STABS_ELF
+  long mask, off;
+  
+  if (cur_proc_ptr == (procS *) NULL)
+    {
+      as_warn (_(".mask/.fmask outside of .ent"));
+      demand_empty_rest_of_line ();
+      return;
+    }
+
+  if (get_absolute_expression_and_terminator (&mask) != ',')
+    {
+      as_warn (_("Bad .mask/.fmask directive"));
+      --input_line_pointer;
+      demand_empty_rest_of_line ();
+      return;
+    }
 
-  mask = get_number ();
-  if (*input_line_pointer == ',')
-    input_line_pointer++;
   off = get_absolute_expression ();
 
-  /* bob only for coff */
-  assert (proc_rootP);
   if (reg_type == 'F')
     {
-      proc_rootP->proc_fpreg_mask = mask;
-      proc_rootP->proc_fpreg_offset = off;
+      cur_proc_ptr->fpreg_mask = mask;
+      cur_proc_ptr->fpreg_offset = off;
     }
   else
     {
-      proc_rootP->proc_reg_mask = mask;
-      proc_rootP->proc_reg_offset = off;
+      cur_proc_ptr->reg_mask = mask;
+      cur_proc_ptr->reg_offset = off;
     }
 
-  /* bob macho .mask + .fmask */
-
-  /* We don't have to write out a mask stab if no saved regs. */
-  if (!(mask == 0))
-    {
-      if (!proc_lastP)
-       as_warn ("No .ent for .mask to use.");
-      strP = str;
-      for (i = 0; i < 32; i++)
-       {
-         if (mask % 2)
-           {
-             sprintf (strP, "%c%d,", reg_type, i);
-             strP += strlen (strP);
-           }
-         mask /= 2;
-       }
-      sprintf (strP, ";%d,", off);
-      symP = symbol_new (str, N_RMASK, 0, frag_now);
-      S_SET_TYPE (symP, N_RMASK);
-      S_SET_OTHER (symP, 0);
-      S_SET_DESC (symP, 0);
-      symP->sy_forward = proc_lastP->proc_isym;
-      /* bob perhaps I should have used pseudo set */
-    }
+  demand_empty_rest_of_line ();
+#else
+  s_ignore (reg_type);
+#endif /* MIPS_STABS_ELF */
 }
-#endif
 
 /* The .loc directive.  */
 
@@ -11451,3 +11797,6 @@ s_loc (x)
   symbolP->sy_segment = now_seg;
 }
 #endif
+
+
+  
This page took 0.097486 seconds and 4 git commands to generate.