Add MIPS r12k support
[deliverable/binutils-gdb.git] / gas / config / tc-mips.c
index ef6304dbb8e4dd5ca7b3137a3a39755b30324fbe..15c4f871303c474ee38793cdcf23d236a0700fd9 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-mips.c -- assemble code for a MIPS chip.
-   Copyright (C) 1993, 94, 95, 96, 97, 98, 1999, 2000
+   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
    Free Software Foundation, Inc.
    Contributed by the OSF and Ralph Campbell.
    Written by Keith Knowles and Ralph Campbell, working independently.
@@ -110,6 +110,7 @@ extern int target_big_endian;
 static int mips_64;
 
 /* The default target format to use.  */
+
 const char *
 mips_target_format ()
 {
@@ -125,7 +126,8 @@ mips_target_format ()
 #ifdef TE_TMIPS
       /* This is traditional mips */
       return (target_big_endian
-              ? "elf32-tradbigmips" : "elf32-tradlittlemips");
+             ? (mips_64 ? "elf64-tradbigmips" : "elf32-tradbigmips")
+             : (mips_64 ? "elf64-tradlittlemips" : "elf32-tradlittlemips"));
 #else
       return (target_big_endian
              ? (mips_64 ? "elf64-bigmips" : "elf32-bigmips")
@@ -187,10 +189,13 @@ struct mips_set_options
 };
 
 /* This is the struct we use to hold the current set of options.  Note
-   that we must set the isa and mips16 fields to -1 to indicate that
-   they have not been initialized.  */
+   that we must set the isa field to ISA_UNKNOWN and the mips16 field to
+   -1 to indicate that they have not been initialized.  */
 
-static struct mips_set_options mips_opts = { -1, -1, 0, 0, 0, 0, 0, 0 };
+static struct mips_set_options mips_opts =
+{
+  ISA_UNKNOWN, -1, 0, 0, 0, 0, 0, 0
+};
 
 /* These variables are filled in with the masks of registers used.
    The object format code reads them and puts them in the appropriate
@@ -199,13 +204,13 @@ unsigned long mips_gprmask;
 unsigned long mips_cprmask[4];
 
 /* MIPS ISA we are using for this output file.  */
-static int file_mips_isa;
+static int file_mips_isa = ISA_UNKNOWN;
 
-/* The CPU type as a number: 2000, 3000, 4000, 4400, etc.  */
-static int mips_cpu = -1;
+/* The CPU type we are using for this output file.  */
+static int mips_cpu = CPU_UNKNOWN;
 
 /* The argument of the -mabi= flag.  */
-static char* mips_abi_string = 0;
+static char * mips_abi_string = 0;
 
 /* Wether we should mark the file EABI64 or EABI32.  */
 static int mips_eabi64 = 0;
@@ -226,15 +231,17 @@ static int mips_gp32 = 0;
    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                            \
+   (ISA) == ISA_MIPS1                       \
+   || (ISA) == ISA_MIPS2                    \
+   || (ISA) == ISA_MIPS3                    \
    )
 
 /*  Return true if ISA supports 64 bit gp register instructions.  */
 #define ISA_HAS_64BIT_REGS(ISA) (    \
-   (ISA) == 3                        \
-   || (ISA) == 4                     \
+   (ISA) == ISA_MIPS3                \
+   || (ISA) == ISA_MIPS4             \
+   || (ISA) == ISA_MIPS5             \
+   || (ISA) == ISA_MIPS64            \
    )
 
 /* Whether the processor uses hardware interlocks to protect
@@ -270,7 +277,7 @@ static int mips_gp32 = 0;
 /* 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 != 1  \
+  (mips_opts.isa != ISA_MIPS1  \
    || mips_cpu == CPU_R3900)
 
 /* As with other "interlocks" this is used by hardware that has FP
@@ -584,8 +591,8 @@ static const unsigned int mips16_to_32_reg_map[] =
     | ((warn) ? 1 : 0)))
 #define RELAX_OLD(i) (((i) >> 23) & 0x7f)
 #define RELAX_NEW(i) (((i) >> 16) & 0x7f)
-#define RELAX_RELOC1(i) ((bfd_vma)(((i) >> 9) & 0x7f) - 64)
-#define RELAX_RELOC2(i) ((bfd_vma)(((i) >> 2) & 0x7f) - 64)
+#define RELAX_RELOC1(i) ((bfd_vma) (((i) >> 9) & 0x7f) - 64)
+#define RELAX_RELOC2(i) ((bfd_vma) (((i) >> 2) & 0x7f) - 64)
 #define RELAX_RELOC3(i) (((i) >> 1) & 1)
 #define RELAX_WARN(i) ((i) & 1)
 
@@ -706,9 +713,24 @@ 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 char *mips_cpu_to_str PARAMS ((int));
-
+static const char *mips_isa_to_str PARAMS ((int));
+static const char *mips_cpu_to_str PARAMS ((int));
 static int validate_mips_insn PARAMS ((const struct mips_opcode *));
+
+/* Table and functions used to map between CPU/ISA names, and
+   ISA levels, and CPU numbers.  */
+
+struct mips_cpu_info
+{
+  const char *name;           /* CPU or ISA name.  */
+  int is_isa;                 /* Is this an ISA?  (If 0, a CPU.) */
+  int isa;                    /* ISA level.  */
+  int cpu;                    /* CPU number (default CPU if ISA).  */
+};
+
+static const struct mips_cpu_info *mips_cpu_info_from_name PARAMS ((const char *));
+static const struct mips_cpu_info *mips_cpu_info_from_isa PARAMS ((int));
+static const struct mips_cpu_info *mips_cpu_info_from_cpu PARAMS ((int));
 \f
 /* Pseudo-op table.
 
@@ -730,7 +752,7 @@ static int validate_mips_insn PARAMS ((const struct mips_opcode *));
 
 static const pseudo_typeS mips_pseudo_table[] =
 {
- /* MIPS specific pseudo-ops.  */
 /* MIPS specific pseudo-ops.  */
   {"option", s_option, 0},
   {"set", s_mipsset, 0},
   {"rdata", s_change_sec, 'r'},
@@ -743,7 +765,7 @@ static const pseudo_typeS mips_pseudo_table[] =
   {"cpadd", s_cpadd, 0},
   {"insn", s_insn, 0},
 
- /* Relatively generic pseudo-ops that happen to be used on MIPS
 /* Relatively generic pseudo-ops that happen to be used on MIPS
      chips.  */
   {"asciiz", stringer, 1},
   {"bss", s_change_sec, 'b'},
@@ -752,7 +774,7 @@ static const pseudo_typeS mips_pseudo_table[] =
   {"dword", s_cons, 3},
   {"weakext", s_mips_weakext, 0},
 
- /* These pseudo-ops are defined in read.c, but must be overridden
 /* These pseudo-ops are defined in read.c, but must be overridden
      here for one reason or another.  */
   {"align", s_align, 0},
   {"byte", s_cons, 0},
@@ -774,9 +796,10 @@ static const pseudo_typeS mips_pseudo_table[] =
   { NULL, NULL, 0 },
 };
 
-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.  */
+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_mips_ent, 1},
   {"bgnb", s_ignore, 0},
   {"end", s_mips_end, 0},
@@ -852,33 +875,34 @@ static boolean mips16_small, mips16_ext;
 static segT pdr_seg;
 #endif
 
-static char *
+static const char *
+mips_isa_to_str (isa)
+     int isa;
+{
+  const struct mips_cpu_info *ci;
+  static char s[20];
+
+  ci = mips_cpu_info_from_isa (isa);
+  if (ci != NULL)
+    return (ci->name);
+
+  sprintf (s, "ISA#%d", isa);
+  return s;
+}
+
+static const char *
 mips_cpu_to_str (cpu)
      int cpu;
 {
+  const struct mips_cpu_info *ci;
   static char s[16];
-  switch (cpu)
-    {
-    case CPU_R2000: return "R2000";
-    case CPU_R3000: return "R3000";
-    case CPU_R3900: return "R3900";
-    case CPU_R4000: return "R4000";
-    case CPU_R4010: return "R4010";
-    case CPU_VR4100: return "VR4100";
-    case CPU_R4111: return "R4111";
-    case CPU_R4300: return "R4300";
-    case CPU_R4400: return "R4400";
-    case CPU_R4600: return "R4600";
-    case CPU_R4650: return "R4650";
-    case CPU_R5000: return "R5000";
-    case CPU_R6000: return "R6000";
-    case CPU_R8000: return "R8000";
-    case CPU_R10000: return "R10000";
-    case CPU_4K: return "4K";
-    default:
-      sprintf (s, "%d", cpu);
-      return s;
-    }
+
+  ci = mips_cpu_info_from_cpu (cpu);
+  if (ci != NULL)
+    return (ci->name);
+
+  sprintf (s, "CPU#%d", cpu);
+  return s;
 }
 
 /* This function is called once, at assembler startup time.  It should
@@ -887,13 +911,14 @@ mips_cpu_to_str (cpu)
 void
 md_begin ()
 {
-  boolean ok = false;
   register const char *retval = NULL;
   int i = 0;
   const char *cpu;
   char *a = NULL;
   int broken = 0;
   int mips_isa_from_cpu;
+  int target_cpu_had_mips16 = 0;
+  const struct mips_cpu_info *ci;
 
   /* GP relative stuff not working for PE */
   if (strncmp (TARGET_OS, "pe", 2) == 0
@@ -913,129 +938,51 @@ md_begin ()
       cpu = a;
     }
 
-  if (mips_cpu < 0)
+  if (strncmp (cpu, "mips16", sizeof "mips16" - 1) == 0)
     {
-      /* Set mips_cpu based on TARGET_CPU, unless TARGET_CPU is
-         just the generic 'mips', in which case set mips_cpu based
-         on the given ISA, if any.  */
-
-      if (strcmp (cpu, "mips") == 0)
-        {
-         if (mips_opts.isa < 0)
-           mips_cpu = CPU_R3000;
-
-         else if (mips_opts.isa == 2)
-            mips_cpu = CPU_R6000;
-
-          else if (mips_opts.isa == 3)
-            mips_cpu = CPU_R4000;
-
-          else if (mips_opts.isa == 4)
-            mips_cpu = CPU_R8000;
-
-          else
-            mips_cpu = CPU_R3000;
-        }
-
-      else if (strcmp (cpu, "r3900") == 0
-               || strcmp (cpu, "mipstx39") == 0
-               )
-        mips_cpu = CPU_R3900;
-
-      else if (strcmp (cpu, "r6000") == 0
-              || strcmp (cpu, "mips2") == 0)
-        mips_cpu = CPU_R6000;
-
-      else if (strcmp (cpu, "mips64") == 0
-              || strcmp (cpu, "r4000") == 0
-              || strcmp (cpu, "mips3") == 0)
-        mips_cpu = CPU_R4000;
-
-      else if (strcmp (cpu, "r4400") == 0)
-        mips_cpu = CPU_R4400;
-
-      else if (strcmp (cpu, "mips64orion") == 0
-              || strcmp (cpu, "r4600") == 0)
-        mips_cpu = CPU_R4600;
-
-      else if (strcmp (cpu, "r4650") == 0)
-        mips_cpu = CPU_R4650;
-
-      else if (strcmp (cpu, "mips64vr4300") == 0)
-        mips_cpu = CPU_R4300;
-
-      else if (strcmp (cpu, "mips64vr4111") == 0)
-        mips_cpu = CPU_R4111;
-
-      else if (strcmp (cpu, "mips64vr4100") == 0)
-        mips_cpu = CPU_VR4100;
-
-      else if (strcmp (cpu, "r4010") == 0)
-        mips_cpu = CPU_R4010;
-
-      else if (strcmp (cpu, "4Kc") == 0
-              || strcmp (cpu, "4Kp") == 0
-              || strcmp (cpu, "4Km") == 0)
-       mips_cpu = CPU_4K;
-
-      else if (strcmp (cpu, "r5000") == 0
-              || strcmp (cpu, "mips64vr5000") == 0)
-        mips_cpu = CPU_R5000;
-
-      else if (strcmp (cpu, "r8000") == 0
-              || strcmp (cpu, "mips4") == 0)
-        mips_cpu = CPU_R8000;
-
-      else if (strcmp (cpu, "r10000") == 0)
-        mips_cpu = CPU_R10000;
-
-      else if (strcmp (cpu, "mips16") == 0)
-        mips_cpu = 0; /* FIXME */
-
-      else
-        mips_cpu = CPU_R3000;
+      target_cpu_had_mips16 = 1;
+      cpu += sizeof "mips16" - 1;
     }
 
-  if (mips_cpu == CPU_R3000
-      || mips_cpu == CPU_R3900)
-    mips_isa_from_cpu = 1;
-
-  else if (mips_cpu == CPU_R6000
-          || mips_cpu == CPU_R4010)
-    mips_isa_from_cpu = 2;
-
-  else if (mips_cpu == CPU_R4000
-          || mips_cpu == CPU_VR4100
-          || mips_cpu == CPU_R4111
-          || mips_cpu == CPU_R4400
-          || mips_cpu == CPU_R4300
-          || mips_cpu == CPU_R4600
-          || mips_cpu == CPU_R4650)
-    mips_isa_from_cpu = 3;
-
-  else if (mips_cpu == CPU_R5000
-          || mips_cpu == CPU_R8000
-               || mips_cpu == CPU_R10000)
-    mips_isa_from_cpu = 4;
-
-  else
-    mips_isa_from_cpu = -1;
+  if (mips_opts.mips16 < 0)
+    mips_opts.mips16 = target_cpu_had_mips16;
 
-  if (mips_opts.isa == -1)
+  /* At this point, mips_cpu will either be CPU_UNKNOWN if no CPU was
+     specified on the command line, or some other value if one was.
+     Similarly, mips_opts.isa will be ISA_UNKNOWN if not specified on
+     the command line, or will be set otherwise if one was.  */
+  if (mips_cpu != CPU_UNKNOWN && mips_opts.isa != ISA_UNKNOWN)
     {
-      if (mips_isa_from_cpu != -1)
-       mips_opts.isa = mips_isa_from_cpu;
-      else
-       mips_opts.isa = 1;
+      /* We have it all.  There's nothing to do.  */
     }
-
-  if (mips_opts.mips16 < 0)
+  else if (mips_cpu != CPU_UNKNOWN && mips_opts.isa == ISA_UNKNOWN)
     {
-      if (strncmp (TARGET_CPU, "mips16", sizeof "mips16" - 1) == 0)
-       mips_opts.mips16 = 1;
-      else
-       mips_opts.mips16 = 0;
+      /* We have CPU, we need ISA.  */
+      ci = mips_cpu_info_from_cpu (mips_cpu);
+      assert (ci != NULL);
+      mips_opts.isa = ci->isa;
+    }
+  else if (mips_cpu == CPU_UNKNOWN && mips_opts.isa != ISA_UNKNOWN)
+    {
+      /* We have ISA, we need default CPU.  */
+      ci = mips_cpu_info_from_isa (mips_opts.isa);
+      assert (ci != NULL);
+      mips_cpu = ci->cpu;
     }
+  else
+    {
+      /* We need to set both ISA and CPU from target cpu.  */
+      ci = mips_cpu_info_from_name (cpu);
+      if (ci == NULL)
+       ci = mips_cpu_info_from_cpu (CPU_R3000);
+      assert (ci != NULL);
+      mips_opts.isa = ci->isa;
+      mips_cpu = ci->cpu;
+    }
+
+  ci = mips_cpu_info_from_cpu (mips_cpu);
+  assert (ci != NULL);
+  mips_isa_from_cpu = ci->isa;
 
   /* End of TARGET_CPU processing, get rid of malloced memory
      if necessary.  */
@@ -1046,7 +993,7 @@ md_begin ()
       a = NULL;
     }
 
-  if (mips_opts.isa == 1 && mips_trap)
+  if (mips_opts.isa == ISA_MIPS1 && mips_trap)
     as_bad (_("trap exception not supported at ISA 1"));
 
   /* Set the EABI kind based on the ISA before the user gets
@@ -1054,40 +1001,17 @@ md_begin ()
      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"))
+      && 0 == strcmp (mips_abi_string, "eabi"))
     mips_eabi64 = 1;
 
-  if (mips_cpu != 0 && mips_cpu != -1)
-    {
-      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 != ISA_UNKNOWN
+      && ! ISA_HAS_64BIT_REGS (mips_opts.isa)
+      && ISA_HAS_64BIT_REGS (mips_isa_from_cpu))
+    mips_32bitmode = 1;
 
-      /* 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, CPU_R3000);
-         break;
-       case 2:
-         ok = bfd_set_arch_mach (stdoutput, bfd_arch_mips, CPU_R6000);
-         break;
-       case 3:
-         ok = bfd_set_arch_mach (stdoutput, bfd_arch_mips, CPU_R4000);
-         break;
-       case 4:
-         ok = bfd_set_arch_mach (stdoutput, bfd_arch_mips, CPU_R8000);
-         break;
-       }
-    }
-
-  if (! ok)
+  if (! bfd_set_arch_mach (stdoutput, bfd_arch_mips, mips_cpu))
     as_warn (_("Could not set architecture and machine"));
 
   file_mips_isa = mips_opts.isa;
@@ -1303,8 +1227,8 @@ md_assemble (str)
   else
     {
       mips_ip (str, &insn);
-      DBG((_("returned from mips_ip(%s) insn_opcode = 0x%x\n"),
-               str, insn.insn_opcode));
+      DBG ((_("returned from mips_ip(%s) insn_opcode = 0x%x\n"),
+           str, insn.insn_opcode));
     }
 
   if (insn_error)
@@ -1536,7 +1460,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
             delays delay the use of general register rt for one
             instruction on the r3000.  The r6000 and r4000 use
             interlocks.  */
-          /* Itbl support may require additional care here.  */
+         /* Itbl support may require additional care here.  */
          know (prev_pinfo & INSN_WRITE_GPR_T);
          if (mips_optimize == 0
              || insn_uses_reg (ip,
@@ -1548,8 +1472,8 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
       else if (! mips_opts.mips16
               && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
               && (((prev_pinfo & INSN_COPROC_MOVE_DELAY)
-                    && ! cop_interlocks)
-                  || (mips_opts.isa == 1
+                   && ! cop_interlocks)
+                  || (mips_opts.isa == ISA_MIPS1
                       && (prev_pinfo & INSN_COPROC_MEMORY_DELAY))))
        {
          /* A generic coprocessor delay.  The previous instruction
@@ -1614,7 +1538,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
             (this means it is a floating point comparison
             instruction).  If this instruction uses the condition
             codes, we need to insert a single NOP.  */
-          /* Itbl support may require additional care here.  */
+         /* Itbl support may require additional care here.  */
          if (mips_optimize == 0
              || (pinfo & INSN_READ_COND_CODE))
            ++nops;
@@ -1628,9 +1552,8 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
       else if (mips_7000_hilo_fix
               && MF_HILO_INSN (prev_pinfo)
               && insn_uses_reg (ip, ((prev_insn.insn_opcode >> OP_SH_RD)
-                                       & OP_MASK_RD),
-                                    MIPS_GR_REG))
-
+                                     & OP_MASK_RD),
+                                MIPS_GR_REG))
        {
          nops += 2;
        }
@@ -1972,7 +1895,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
             instruction.  May want to add this support in the future.  */
        }
       /* Never set the bit for $0, which is always zero.  */
-      mips_gprmask &=1 << 0;
+      mips_gprmask &= ~1 << 0;
     }
   else
     {
@@ -2083,7 +2006,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 == 1
+                 && mips_opts.isa == ISA_MIPS1
                   /* Itbl support may require additional care here.  */
                  && (prev_pinfo & INSN_COPROC_MEMORY_DELAY))
              /* We can not swap with a branch instruction.  */
@@ -2419,11 +2342,11 @@ mips_emit_delays (insns)
              && (prev_insn.insn_mo->pinfo
                   & INSN_LOAD_MEMORY_DELAY))
          || (! mips_opts.mips16
-             && mips_opts.isa == 1
+             && mips_opts.isa == ISA_MIPS1
              && (prev_insn.insn_mo->pinfo
                  & INSN_COPROC_MEMORY_DELAY)))
        {
-          /* Itbl support may require additional care here.  */
+         /* Itbl support may require additional care here.  */
          ++nops;
          if ((! mips_opts.mips16
               && ISA_HAS_COPROC_DELAYS (mips_opts.isa)
@@ -2445,7 +2368,7 @@ mips_emit_delays (insns)
                   && ((prev_prev_insn.insn_mo->pinfo & INSN_READ_HI)
                       || (prev_prev_insn.insn_mo->pinfo & INSN_READ_LO))))
        {
-          /* Itbl support may require additional care here.  */
+         /* Itbl support may require additional care here.  */
          if (! prev_prev_insn_unreordered)
            ++nops;
        }
@@ -2597,6 +2520,15 @@ macro_build (place, counter, ep, name, fmt, va_alist)
          insn.insn_opcode |= va_arg (args, int) << 11;
          continue;
 
+       case 'U':
+         {
+           int tmp = va_arg (args, int);
+
+           insn.insn_opcode |= tmp << 16;
+           insn.insn_opcode |= tmp << 11;
+           continue;
+         }
+
        case 'V':
        case 'S':
          insn.insn_opcode |= va_arg (args, int) << 11;
@@ -2617,6 +2549,10 @@ macro_build (place, counter, ep, name, fmt, va_alist)
          insn.insn_opcode |= va_arg (args, int) << 6;
          continue;
 
+       case 'J':
+         insn.insn_opcode |= va_arg (args, int) << 6;
+         continue;
+
        case 'q':
          insn.insn_opcode |= va_arg (args, int) << 6;
          continue;
@@ -3113,63 +3049,65 @@ load_register (counter, reg, ep, dbl)
       unsigned long hi, lo;
 
       if (hi32.X_add_number == 0xffffffff)
-        {
-          if ((lo32.X_add_number & 0xffff8000) == 0xffff8000)
-            {
-              macro_build ((char *) NULL, counter, &lo32, "addiu", "t,r,j",
+       {
+         if ((lo32.X_add_number & 0xffff8000) == 0xffff8000)
+           {
+             macro_build ((char *) NULL, counter, &lo32, "addiu", "t,r,j",
                           reg, 0, (int) BFD_RELOC_LO16);
-              return;
-            }
-          if (lo32.X_add_number & 0x80000000)
-            {
-              macro_build ((char *) NULL, counter, &lo32, "lui", "t,u", reg,
-                           (int) BFD_RELOC_HI16);
+             return;
+           }
+         if (lo32.X_add_number & 0x80000000)
+           {
+             macro_build ((char *) NULL, counter, &lo32, "lui", "t,u", reg,
+                          (int) BFD_RELOC_HI16);
              if (lo32.X_add_number & 0xffff)
                macro_build ((char *) NULL, counter, &lo32, "ori", "t,r,i",
                             reg, reg, (int) BFD_RELOC_LO16);
-              return;
-            }
-        }
+             return;
+           }
+       }
 
       /* Check for 16bit shifted constant.  We know that hi32 is
          non-zero, so start the mask on the first bit of the hi32
          value.  */
       shift = 17;
       do
-       {
-        unsigned long himask, lomask;
-
-        if (shift < 32)
-          {
-            himask = 0xffff >> (32 - shift);
-            lomask = (0xffff << shift) & 0xffffffff;
-          }
-        else
-          {
-            himask = 0xffff << (shift - 32);
-            lomask = 0;
-          }
-        if ((hi32.X_add_number & ~ (offsetT) himask) == 0
-            && (lo32.X_add_number & ~ (offsetT) lomask) == 0)
-          {
-            expressionS tmp;
-
-            tmp.X_op = O_constant;
-            if (shift < 32)
-              tmp.X_add_number = ((hi32.X_add_number << (32 - shift))
-                                  | (lo32.X_add_number >> shift));
-            else
-              tmp.X_add_number = hi32.X_add_number >> (shift - 32);
-            macro_build ((char *) NULL, counter, &tmp, "ori", "t,r,i", reg, 0,
-                         (int) BFD_RELOC_LO16);
-            macro_build ((char *) NULL, counter, NULL,
-                         (shift >= 32) ? "dsll32" : "dsll",
-                         "d,w,<", reg, reg,
-                         (shift >= 32) ? shift - 32 : shift);
-            return;
-          }
-         shift++;
-       } while (shift <= (64 - 16));
+       {
+         unsigned long himask, lomask;
+
+         if (shift < 32)
+           {
+             himask = 0xffff >> (32 - shift);
+             lomask = (0xffff << shift) & 0xffffffff;
+           }
+         else
+           {
+             himask = 0xffff << (shift - 32);
+             lomask = 0;
+           }
+         if ((hi32.X_add_number & ~(offsetT) himask) == 0
+             && (lo32.X_add_number & ~(offsetT) lomask) == 0)
+           {
+             expressionS tmp;
+
+             tmp.X_op = O_constant;
+             if (shift < 32)
+               tmp.X_add_number = ((hi32.X_add_number << (32 - shift))
+                                   | (lo32.X_add_number >> shift));
+             else
+               tmp.X_add_number = hi32.X_add_number >> (shift - 32);
+             macro_build ((char *) NULL, counter, &tmp,
+                          "ori", "t,r,i", reg, 0,
+                          (int) BFD_RELOC_LO16);
+             macro_build ((char *) NULL, counter, NULL,
+                          (shift >= 32) ? "dsll32" : "dsll",
+                          "d,w,<", reg, reg,
+                          (shift >= 32) ? shift - 32 : shift);
+             return;
+           }
+         shift++;
+       }
+      while (shift <= (64 - 16));
 
       /* Find the bit number of the lowest one bit, and store the
          shifted value in hi/lo.  */
@@ -3201,38 +3139,38 @@ load_register (counter, reg, ep, dbl)
       /* Optimize if the shifted value is a (power of 2) - 1.  */
       if ((hi == 0 && ((lo + 1) & lo) == 0)
          || (lo == 0xffffffff && ((hi + 1) & hi) == 0))
-        {
-          shift = COUNT_TOP_ZEROES ((unsigned int) hi32.X_add_number);
+       {
+         shift = COUNT_TOP_ZEROES ((unsigned int) hi32.X_add_number);
          if (shift != 0)
-            {
+           {
              expressionS tmp;
 
              /* This instruction will set the register to be all
                  ones.  */
-              tmp.X_op = O_constant;
-              tmp.X_add_number = (offsetT) -1;
-              macro_build ((char *) NULL, counter, &tmp, "addiu", "t,r,j",
+             tmp.X_op = O_constant;
+             tmp.X_add_number = (offsetT) -1;
+             macro_build ((char *) NULL, counter, &tmp, "addiu", "t,r,j",
                           reg, 0, (int) BFD_RELOC_LO16);
-              if (bit != 0)
-                {
-                  bit += shift;
-                  macro_build ((char *) NULL, counter, NULL,
-                               (bit >= 32) ? "dsll32" : "dsll",
-                               "d,w,<", reg, reg,
-                               (bit >= 32) ? bit - 32 : bit);
-                }
-              macro_build ((char *) NULL, counter, NULL,
+             if (bit != 0)
+               {
+                 bit += shift;
+                 macro_build ((char *) NULL, counter, NULL,
+                              (bit >= 32) ? "dsll32" : "dsll",
+                              "d,w,<", reg, reg,
+                              (bit >= 32) ? bit - 32 : bit);
+               }
+             macro_build ((char *) NULL, counter, NULL,
                           (shift >= 32) ? "dsrl32" : "dsrl",
-                           "d,w,<", reg, reg,
+                          "d,w,<", reg, reg,
                           (shift >= 32) ? shift - 32 : shift);
-              return;
-            }
-        }
+             return;
+           }
+       }
 
       /* Sign extend hi32 before calling load_register, because we can
          generally get better code when we load a sign extended value.  */
       if ((hi32.X_add_number & 0x80000000) != 0)
-       hi32.X_add_number |= ~ (offsetT) 0xffffffff;
+       hi32.X_add_number |= ~(offsetT) 0xffffffff;
       load_register (counter, reg, &hi32, 0);
       freg = reg;
     }
@@ -3250,13 +3188,13 @@ load_register (counter, reg, ep, dbl)
       expressionS mid16;
 
       if ((freg == 0) && (lo32.X_add_number == 0xffffffff))
-        {
+       {
          macro_build ((char *) NULL, counter, &lo32, "lui", "t,u", reg,
                       (int) BFD_RELOC_HI16);
-          macro_build ((char *) NULL, counter, NULL, "dsrl32", "d,w,<", reg,
-                       reg, 0);
-          return;
-        }
+         macro_build ((char *) NULL, counter, NULL, "dsrl32", "d,w,<", reg,
+                      reg, 0);
+         return;
+       }
 
       if (freg != 0)
        {
@@ -3309,7 +3247,7 @@ load_address (counter, reg, ep)
           addiu        $reg,$reg,<sym>         (BFD_RELOC_LO16)
         If we have an addend, we always use the latter form.  */
       if ((valueT) ep->X_add_number >= MAX_GPREL_OFFSET
-          || nopic_need_relax (ep->X_add_symbol, 1))
+         || nopic_need_relax (ep->X_add_symbol, 1))
        p = NULL;
       else
        {
@@ -3999,7 +3937,7 @@ macro (ip)
          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;
        }
 
@@ -4020,7 +3958,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,
@@ -4059,7 +3997,7 @@ macro (ip)
             that later insns are available for delay slot filling.  */
          --mips_opts.noreorder;
 
-           macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
+         macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6);
        }
       macro_build ((char *) NULL, &icnt, NULL, s, "d", dreg);
       break;
@@ -4106,7 +4044,7 @@ macro (ip)
          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)
@@ -4177,7 +4115,7 @@ macro (ip)
          /* 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);
+         macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
        }
       macro_build ((char *) NULL, &icnt, NULL, s2, "d", dreg);
       return;
@@ -4276,9 +4214,13 @@ macro (ip)
        }
       else if (mips_pic == SVR4_PIC && ! mips_big_got)
        {
+         int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT16;
+
          /* If this is a reference to an external symbol, and there
             is no constant, we want
               lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT16)
+            or if tempreg is PIC_CALL_REG
+              lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_CALL16)
             For a local symbol, we want
               lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT16)
               nop
@@ -4305,9 +4247,11 @@ macro (ip)
          expr1.X_add_number = offset_expr.X_add_number;
          offset_expr.X_add_number = 0;
          frag_grow (32);
+         if (expr1.X_add_number == 0 && tempreg == PIC_CALL_REG)
+           lw_reloc_type = (int) BFD_RELOC_MIPS_CALL16;
          macro_build ((char *) NULL, &icnt, &offset_expr,
                       dbl ? "ld" : "lw",
-                      "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16, GP);
+                      "t,o(b)", tempreg, lw_reloc_type, GP);
          if (expr1.X_add_number == 0)
            {
              int off;
@@ -4413,12 +4357,18 @@ macro (ip)
       else if (mips_pic == SVR4_PIC)
        {
          int gpdel;
+         int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16;
+         int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16;
 
          /* This is the large GOT case.  If this is a reference to an
             external symbol, and there is no constant, we want
               lui      $tempreg,<sym>          (BFD_RELOC_MIPS_GOT_HI16)
               addu     $tempreg,$tempreg,$gp
               lw       $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
+            or if tempreg is PIC_CALL_REG
+              lui      $tempreg,<sym>          (BFD_RELOC_MIPS_CALL_HI16)
+              addu     $tempreg,$tempreg,$gp
+              lw       $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_CALL_LO16)
             For a local symbol, we want
               lw       $tempreg,<sym>($gp)     (BFD_RELOC_MIPS_GOT16)
               nop
@@ -4457,8 +4407,13 @@ macro (ip)
            gpdel = 4;
          else
            gpdel = 0;
+         if (expr1.X_add_number == 0 && tempreg == PIC_CALL_REG)
+           {
+             lui_reloc_type = (int) BFD_RELOC_MIPS_CALL_HI16;
+             lw_reloc_type = (int) BFD_RELOC_MIPS_CALL_LO16;
+           }
          macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u",
-                      tempreg, (int) BFD_RELOC_MIPS_GOT_HI16);
+                      tempreg, lui_reloc_type);
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                       ((bfd_arch_bits_per_address (stdoutput) == 32
                         || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
@@ -4466,8 +4421,7 @@ macro (ip)
                       "d,v,t", tempreg, tempreg, GP);
          macro_build ((char *) NULL, &icnt, &offset_expr,
                       dbl ? "ld" : "lw",
-                      "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT_LO16,
-                      tempreg);
+                      "t,o(b)", tempreg, lw_reloc_type, tempreg);
          if (expr1.X_add_number == 0)
            {
              int off;
@@ -5408,7 +5362,7 @@ macro (ip)
       s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
       if (strcmp (s, ".lit8") == 0)
        {
-         if (mips_opts.isa != 1)
+         if (mips_opts.isa != ISA_MIPS1)
            {
              macro_build ((char *) NULL, &icnt, &offset_expr, "ldc1",
                           "T,o(b)", treg, (int) BFD_RELOC_MIPS_LITERAL, GP);
@@ -5433,7 +5387,7 @@ macro (ip)
              macro_build_lui ((char *) NULL, &icnt, &offset_expr, AT);
            }
 
-         if (mips_opts.isa != 1)
+         if (mips_opts.isa != ISA_MIPS1)
            {
              macro_build ((char *) NULL, &icnt, &offset_expr, "ldc1",
                           "T,o(b)", treg, (int) BFD_RELOC_LO16, AT);
@@ -5460,7 +5414,7 @@ macro (ip)
         to adjust when loading from memory.  */
       r = BFD_RELOC_LO16;
     dob:
-      assert (mips_opts.isa == 1);
+      assert (mips_opts.isa == ISA_MIPS1);
       macro_build ((char *) NULL, &icnt, &offset_expr, "lwc1", "T,o(b)",
                   target_big_endian ? treg + 1 : treg,
                   (int) r, breg);
@@ -5499,7 +5453,7 @@ macro (ip)
        }
       /* Itbl support may require additional care here.  */
       coproc = 1;
-      if (mips_opts.isa != 1)
+      if (mips_opts.isa != ISA_MIPS1)
        {
          s = "ldc1";
          goto ld;
@@ -5516,7 +5470,7 @@ macro (ip)
          return;
        }
 
-      if (mips_opts.isa != 1)
+      if (mips_opts.isa != ISA_MIPS1)
        {
          s = "sdc1";
          goto st;
@@ -5611,7 +5565,7 @@ macro (ip)
                  used_at = 1;
                }
 
-              /* Itbl support may require additional care here.  */
+             /* Itbl support may require additional care here.  */
              macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
                           coproc ? treg + 1 : treg,
                           (int) BFD_RELOC_MIPS_GPREL, tempreg);
@@ -5621,7 +5575,7 @@ macro (ip)
                  undesired nop.  */
              hold_mips_optimize = mips_optimize;
              mips_optimize = 2;
-              /* Itbl support may require additional care here.  */
+             /* Itbl support may require additional care here.  */
              macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
                           coproc ? treg : treg + 1,
                           (int) BFD_RELOC_MIPS_GPREL, tempreg);
@@ -5667,7 +5621,7 @@ macro (ip)
              if (p != NULL)
                p += 4;
            }
-          /* Itbl support may require additional care here.  */
+         /* Itbl support may require additional care here.  */
          macro_build (p, &icnt, &offset_expr, s, fmt,
                       coproc ? treg + 1 : treg,
                       (int) BFD_RELOC_LO16, AT);
@@ -5675,7 +5629,7 @@ macro (ip)
            p += 4;
          /* FIXME: How do we handle overflow here?  */
          offset_expr.X_add_number += 4;
-          /* Itbl support may require additional care here.  */
+         /* Itbl support may require additional care here.  */
          macro_build (p, &icnt, &offset_expr, s, fmt,
                       coproc ? treg : treg + 1,
                       (int) BFD_RELOC_LO16, AT);
@@ -5720,7 +5674,7 @@ macro (ip)
                           || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
                          ? "addu" : "daddu"),
                         "d,v,t", AT, breg, AT);
-          /* Itbl support may require additional care here.  */
+         /* Itbl support may require additional care here.  */
          macro_build ((char *) NULL, &icnt, &expr1, s, fmt,
                       coproc ? treg + 1 : treg,
                       (int) BFD_RELOC_LO16, AT);
@@ -5730,7 +5684,7 @@ macro (ip)
              nop.  */
          hold_mips_optimize = mips_optimize;
          mips_optimize = 2;
-          /* Itbl support may require additional care here.  */
+         /* Itbl support may require additional care here.  */
          macro_build ((char *) NULL, &icnt, &expr1, s, fmt,
                       coproc ? treg : treg + 1,
                       (int) BFD_RELOC_LO16, AT);
@@ -5794,7 +5748,7 @@ macro (ip)
                           || ! ISA_HAS_64BIT_REGS (mips_opts.isa))
                          ? "addu" : "daddu"),
                         "d,v,t", AT, breg, AT);
-          /* Itbl support may require additional care here.  */
+         /* Itbl support may require additional care here.  */
          macro_build ((char *) NULL, &icnt, &expr1, s, fmt,
                       coproc ? treg + 1 : treg,
                       (int) BFD_RELOC_LO16, AT);
@@ -5804,7 +5758,7 @@ macro (ip)
              nop.  */
          hold_mips_optimize = mips_optimize;
          mips_optimize = 2;
-          /* Itbl support may require additional care here.  */
+         /* Itbl support may require additional care here.  */
          macro_build ((char *) NULL, &icnt, &expr1, s, fmt,
                       coproc ? treg : treg + 1,
                       (int) BFD_RELOC_LO16, AT);
@@ -5838,7 +5792,7 @@ macro (ip)
                           "d,v,t", AT, breg, AT);
              p += 4;
            }
-          /* Itbl support may require additional care here.  */
+         /* Itbl support may require additional care here.  */
          macro_build (p, &icnt, &expr1, s, fmt,
                       coproc ? treg + 1 : treg,
                       (int) BFD_RELOC_LO16, AT);
@@ -5849,7 +5803,7 @@ macro (ip)
              nop.  */
          hold_mips_optimize = mips_optimize;
          mips_optimize = 2;
-          /* Itbl support may require additional care here.  */
+         /* Itbl support may require additional care here.  */
          macro_build (p, &icnt, &expr1, s, fmt,
                       coproc ? treg : treg + 1,
                       (int) BFD_RELOC_LO16, AT);
@@ -5881,12 +5835,12 @@ macro (ip)
              used_at = 1;
            }
 
-          /* Itbl support may require additional care here.  */
+         /* Itbl support may require additional care here.  */
          macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
                       coproc ? treg + 1 : treg,
                       (int) BFD_RELOC_MIPS_GPREL, tempreg);
          offset_expr.X_add_number += 4;
-          /* Itbl support may require additional care here.  */
+         /* Itbl support may require additional care here.  */
          macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
                       coproc ? treg : treg + 1,
                       (int) BFD_RELOC_MIPS_GPREL, tempreg);
@@ -5961,13 +5915,13 @@ macro (ip)
          Would it be more efficient to use mask (id) here? */
       if (itbl_have_entries
          && (immed_expr = itbl_assemble (ip->insn_mo->name, "")))
-        {
+       {
          s = ip->insn_mo->name;
          s2 = "cop3";
          coproc = ITBL_DECODE_PNUM (immed_expr);;
          macro_build ((char *) NULL, &icnt, &immed_expr, s, "C");
          return;
-        }
+       }
       macro2 (ip);
       return;
     }
@@ -6064,7 +6018,7 @@ 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);
@@ -6097,7 +6051,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;
@@ -6144,7 +6098,7 @@ macro2 (ip)
          as_bad (_("opcode not supported on this processor"));
          return;
        }
-      assert (mips_opts.isa == 1);
+      assert (mips_opts.isa == ISA_MIPS1);
       /* 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)",
@@ -6453,7 +6407,7 @@ macro2 (ip)
 
     case M_TRUNCWS:
     case M_TRUNCWD:
-      assert (mips_opts.isa == 1);
+      assert (mips_opts.isa == ISA_MIPS1);
       sreg = (ip->insn_opcode >> 11) & 0x1f;   /* floating reg */
       dreg = (ip->insn_opcode >> 06) & 0x1f;   /* floating reg */
 
@@ -6750,7 +6704,7 @@ 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,
@@ -6976,7 +6930,7 @@ validate_mips_insn (opc)
       case '<': USE_BITS (OP_MASK_SHAMT,       OP_SH_SHAMT);   break;
       case '>':        USE_BITS (OP_MASK_SHAMT,        OP_SH_SHAMT);   break;
       case 'A': break;
-      case 'B':        USE_BITS (OP_MASK_SYSCALL,      OP_SH_SYSCALL); break;
+      case 'B': USE_BITS (OP_MASK_CODE20,       OP_SH_CODE20);  break;
       case 'C':        USE_BITS (OP_MASK_COPZ,         OP_SH_COPZ);    break;
       case 'D':        USE_BITS (OP_MASK_FD,           OP_SH_FD);      break;
       case 'E':        USE_BITS (OP_MASK_RT,           OP_SH_RT);      break;
@@ -6984,6 +6938,7 @@ validate_mips_insn (opc)
       case 'G':        USE_BITS (OP_MASK_RD,           OP_SH_RD);      break;
       case 'H': USE_BITS (OP_MASK_SEL,         OP_SH_SEL);     break;
       case 'I': break;
+      case 'J': USE_BITS (OP_MASK_CODE19,       OP_SH_CODE19);  break;
       case 'L': break;
       case 'M':        USE_BITS (OP_MASK_CCC,          OP_SH_CCC);     break;
       case 'N':        USE_BITS (OP_MASK_BCC,          OP_SH_BCC);     break;
@@ -7002,7 +6957,6 @@ validate_mips_insn (opc)
       case 'j':        USE_BITS (OP_MASK_DELTA,        OP_SH_DELTA);   break;
       case 'k':        USE_BITS (OP_MASK_CACHE,        OP_SH_CACHE);   break;
       case 'l': break;
-      case 'm': USE_BITS (OP_MASK_CODE20,      OP_SH_CODE20);  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;
@@ -7015,6 +6969,8 @@ validate_mips_insn (opc)
       case 'x': break;
       case 'z': break;
       case 'P': USE_BITS (OP_MASK_PERFREG,     OP_SH_PERFREG); break;
+      case 'U': USE_BITS (OP_MASK_RD,           OP_SH_RD);
+               USE_BITS (OP_MASK_RT,           OP_SH_RT);      break;
       default:
        as_bad (_("internal: bad mips opcode (unknown operand type `%c'): %s %s"),
                c, opc->name, opc->args);
@@ -7128,11 +7084,12 @@ mips_ip (str, ip)
              continue;
            }
          else
-           {
+           {
              static char buf[100];
              sprintf (buf,
-                      _("opcode not supported on this processor: %s (MIPS%d)"),
-                      mips_cpu_to_str (mips_cpu), mips_opts.isa);
+                      _("opcode not supported on this processor: %s (%s)"),
+                      mips_cpu_to_str (mips_cpu),
+                      mips_isa_to_str (mips_opts.isa));
 
              insn_error = buf;
              return;
@@ -7268,62 +7225,55 @@ mips_ip (str, ip)
              s = expr_end;
              continue;
 
-           case 'm':           /* Full 20 bit break code.  */
+           case 'B':           /* 20-bit syscall/break code.  */
              my_getExpression (&imm_expr, s);
-
              check_absolute_expr (ip, &imm_expr);
-
              if ((unsigned) imm_expr.X_add_number > 0xfffff)
+               as_warn (_("Illegal 20-bit code (%ld)"),
+                        (long) imm_expr.X_add_number);
+             ip->insn_opcode |= imm_expr.X_add_number << 6;
+             imm_expr.X_op = O_absent;
+             s = expr_end;
+             continue;
+
+            case 'C':           /* Coprocessor code */
+             my_getExpression (&imm_expr, s);
+             check_absolute_expr (ip, &imm_expr);
+             if ((unsigned long) imm_expr.X_add_number >= (1<<25))
                {
-                 as_warn (_("Illegal break code (%ld)"),
+                 as_warn (_("Coproccesor code > 25 bits (%ld)"),
                           (long) imm_expr.X_add_number);
-                 imm_expr.X_add_number &= 0xfffff;
+                 imm_expr.X_add_number &= ((1<<25) - 1);
                }
-
-             ip->insn_opcode |= imm_expr.X_add_number << 6;
+             ip->insn_opcode |= imm_expr.X_add_number;
              imm_expr.X_op = O_absent;
              s = expr_end;
-
              continue;
 
-           case 'B':           /* syscall code */
+           case 'J':           /* 19-bit wait 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)"),
+             if ((unsigned) imm_expr.X_add_number > 0x7ffff)
+               as_warn (_("Illegal 19-bit code (%ld)"),
                         (long) imm_expr.X_add_number);
              ip->insn_opcode |= imm_expr.X_add_number << 6;
              imm_expr.X_op = O_absent;
              s = expr_end;
              continue;
 
-            case 'C':           /* Coprocessor code */
-              my_getExpression (&imm_expr, s);
-             check_absolute_expr (ip, &imm_expr);
-              if ((unsigned long) imm_expr.X_add_number >= (1<<25))
-               {
-                  as_warn (_("Coproccesor code > 25 bits (%ld)"),
-                          (long) imm_expr.X_add_number);
-                  imm_expr.X_add_number &= ((1<<25) - 1);
-               }
-              ip->insn_opcode |= imm_expr.X_add_number;
-              imm_expr.X_op = O_absent;
-              s = expr_end;
-              continue;
-
            case 'P':           /* Performance register */
-              my_getExpression (&imm_expr, s);
+             my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
-              if (imm_expr.X_add_number != 0 && imm_expr.X_add_number != 1)
+             if (imm_expr.X_add_number != 0 && imm_expr.X_add_number != 1)
                {
-                  as_warn (_("Invalidate performance regster (%ld)"),
+                 as_warn (_("Invalidate performance regster (%ld)"),
                           (long) imm_expr.X_add_number);
-                  imm_expr.X_add_number &= 1;
+                 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;
+             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 */
@@ -7336,6 +7286,7 @@ mips_ip (str, ip)
            case 'G':           /* coprocessor destination register */
            case 'x':           /* ignore register name */
            case 'z':           /* must be zero register */
+           case 'U':           /* destination register (clo/clz).  */
              s_reset = s;
              if (s[0] == '$')
                {
@@ -7411,7 +7362,7 @@ mips_ip (str, ip)
                            }
                          else
                            goto notreg;
-                         }
+                       }
                      else
                        goto notreg;
                    }
@@ -7450,6 +7401,10 @@ mips_ip (str, ip)
                    case 'G':
                      ip->insn_opcode |= regno << 11;
                      break;
+                   case 'U':
+                     ip->insn_opcode |= regno << 11;
+                     ip->insn_opcode |= regno << 16;
+                     break;
                    case 'w':
                    case 't':
                    case 'E':
@@ -7802,8 +7757,8 @@ mips_ip (str, ip)
                {
                  if ((c == '\0' && imm_expr.X_op != O_constant)
                      || ((imm_expr.X_add_number < 0
-                           || imm_expr.X_add_number >= 0x10000)
-                          && imm_expr.X_op == O_constant))
+                          || imm_expr.X_add_number >= 0x10000)
+                         && imm_expr.X_op == O_constant))
                    {
                      if (insn + 1 < &mips_opcodes[NUMOPCODES] &&
                          !strcmp (insn->name, insn[1].name))
@@ -7835,8 +7790,8 @@ mips_ip (str, ip)
                    max = 0x10000;
                  if ((c == '\0' && imm_expr.X_op != O_constant)
                      || ((imm_expr.X_add_number < -0x8000
-                           || imm_expr.X_add_number >= max)
-                          && imm_expr.X_op == O_constant)
+                          || imm_expr.X_add_number >= max)
+                         && imm_expr.X_op == O_constant)
                      || (more
                          && imm_expr.X_add_number < 0
                          && ISA_HAS_64BIT_REGS (mips_opts.isa)
@@ -7947,7 +7902,7 @@ mips_ip (str, ip)
                ip->insn_opcode |= regno << OP_SH_BCC;
              else
                ip->insn_opcode |= regno << OP_SH_CCC;
-              continue;
+             continue;
 
            case 'H':
              if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
@@ -8648,7 +8603,8 @@ 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"));
 
@@ -8951,9 +8907,10 @@ struct option md_longopts[] =
   {"no-construct-floats", no_argument, NULL, OPTION_NO_CONSTRUCT_FLOATS},
 #define OPTION_MIPS32 (OPTION_MD_BASE + 28)
   {"mips32", no_argument, NULL, OPTION_MIPS32},
-#define OPTION_NO_MIPS32 (OPTION_MD_BASE + 29)
-  {"no-mips32", no_argument, NULL, OPTION_NO_MIPS32},
-
+#define OPTION_MIPS5 (OPTION_MD_BASE + 29)
+  {"mips5", no_argument, NULL, OPTION_MIPS5},
+#define OPTION_MIPS64 (OPTION_MD_BASE + 30)
+  {"mips64", no_argument, NULL, OPTION_MIPS64},
 #ifdef OBJ_ELF
 #define OPTION_ELF_BASE    (OPTION_MD_BASE + 35)
 #define OPTION_CALL_SHARED (OPTION_ELF_BASE + 0)
@@ -9024,154 +8981,47 @@ md_parse_option (c, arg)
       break;
 
     case OPTION_MIPS1:
-      mips_opts.isa = 1;
+      mips_opts.isa = ISA_MIPS1;
       break;
 
     case OPTION_MIPS2:
-      mips_opts.isa = 2;
+      mips_opts.isa = ISA_MIPS2;
       break;
 
     case OPTION_MIPS3:
-      mips_opts.isa = 3;
+      mips_opts.isa = ISA_MIPS3;
       break;
 
     case OPTION_MIPS4:
-      mips_opts.isa = 4;
+      mips_opts.isa = ISA_MIPS4;
+      break;
+
+    case OPTION_MIPS5:
+      mips_opts.isa = ISA_MIPS5;
+      break;
+
+    case OPTION_MIPS32:
+      mips_opts.isa = ISA_MIPS32;
+      break;
+
+    case OPTION_MIPS64:
+      mips_opts.isa = ISA_MIPS64;
       break;
 
     case OPTION_MCPU:
       {
-       char *p;
-
-       /* Identify the processor type */
-       p = arg;
-       if (strcmp (p, "default") == 0
-           || strcmp (p, "DEFAULT") == 0)
-         mips_cpu = -1;
+       /* Identify the processor type.  */
+       if (strcasecmp (arg, "default") == 0)
+         mips_cpu = CPU_UNKNOWN;
        else
          {
-           int sv = 0;
-
-           /* We need to cope with the various "vr" prefixes for the 4300
-              processor.  */
-           if (*p == 'v' || *p == 'V')
-             {
-               sv = 1;
-               p++;
-             }
+           const struct mips_cpu_info *ci;
 
-           if (*p == 'r' || *p == 'R')
-             p++;
-
-           mips_cpu = -1;
-           switch (*p)
-             {
-             case '1':
-               if (strcmp (p, "10000") == 0
-                   || strcmp (p, "10k") == 0
-                   || strcmp (p, "10K") == 0)
-                 mips_cpu = CPU_R10000;
-               break;
-
-             case '2':
-               if (strcmp (p, "2000") == 0
-                   || strcmp (p, "2k") == 0
-                   || strcmp (p, "2K") == 0)
-                 mips_cpu = CPU_R2000;
-               break;
-
-             case '3':
-               if (strcmp (p, "3000") == 0
-                   || strcmp (p, "3k") == 0
-                   || strcmp (p, "3K") == 0)
-                 mips_cpu = CPU_R3000;
-                else if (strcmp (p, "3900") == 0)
-                  mips_cpu = CPU_R3900;
-               break;
-
-             case '4':
-               if (strcmp (p, "4000") == 0
-                   || strcmp (p, "4k") == 0
-                   || strcmp (p, "4K") == 0)
-                 mips_cpu = CPU_R4000;
-               else if (strcmp (p, "4100") == 0)
-                    mips_cpu = CPU_VR4100;
-               else if (strcmp (p, "4111") == 0)
-                    mips_cpu = CPU_R4111;
-               else if (strcmp (p, "4300") == 0)
-                 mips_cpu = CPU_R4300;
-               else if (strcmp (p, "4400") == 0)
-                 mips_cpu = CPU_R4400;
-               else if (strcmp (p, "4600") == 0)
-                 mips_cpu = CPU_R4600;
-               else if (strcmp (p, "4650") == 0)
-                   mips_cpu = CPU_R4650;
-               else if (strcmp (p, "4010") == 0)
-                  mips_cpu = CPU_R4010;
-               else if (strcmp (p, "4Kc") == 0
-                        || strcmp (p, "4Kp") == 0
-                        || strcmp (p, "4Km") == 0)
-                 mips_cpu = CPU_MIPS32;
-               break;
-
-             case '5':
-               if (strcmp (p, "5000") == 0
-                   || strcmp (p, "5k") == 0
-                   || strcmp (p, "5K") == 0)
-                 mips_cpu = CPU_R5000;
-               break;
-
-             case '6':
-               if (strcmp (p, "6000") == 0
-                   || strcmp (p, "6k") == 0
-                   || strcmp (p, "6K") == 0)
-                 mips_cpu = CPU_R6000;
-               break;
-
-             case '8':
-               if (strcmp (p, "8000") == 0
-                   || strcmp (p, "8k") == 0
-                   || strcmp (p, "8K") == 0)
-                 mips_cpu = CPU_R8000;
-               break;
-
-             case 'o':
-               if (strcmp (p, "orion") == 0)
-                 mips_cpu = CPU_R4600;
-               break;
-
-             case 'm':
-             case 'M':
-               switch (atoi (p + 1))
-                 {
-                 case 5200:
-                 case 5230:
-                 case 5231:
-                 case 5261:
-                 case 5721:
-                 case 7000:
-                   mips_cpu = CPU_R5000;
-                   break;
-                 default:
-                   break;
-                 }
-             }
-
-           if (sv
-               && (mips_cpu != CPU_R4300
-                   && mips_cpu != CPU_VR4100
-                   && mips_cpu != CPU_R4111
-                   && mips_cpu != CPU_R5000))
-             {
-               as_bad (_("ignoring invalid leading 'v' in -mcpu=%s switch"), arg);
-               return 0;
-             }
-
-           if (mips_cpu == -1)
-             {
-               as_bad (_("invalid architecture -mcpu=%s"), arg);
-               return 0;
-             }
+           ci = mips_cpu_info_from_name (arg);
+           if (ci == NULL || ci->is_isa)
+             as_bad (_("invalid architecture -mcpu=%s"), arg);
+           else
+             mips_cpu = ci->cpu;
          }
       }
       break;
@@ -9197,13 +9047,6 @@ md_parse_option (c, arg)
     case OPTION_NO_M4100:
       break;
 
-    case OPTION_MIPS32:
-      mips_cpu = CPU_MIPS32;
-      break;
-
-    case OPTION_NO_MIPS32:
-      break;
-
     case OPTION_M3900:
       mips_cpu = CPU_R3900;
       break;
@@ -9231,6 +9074,7 @@ md_parse_option (c, arg)
       g_switch_value = 0x7fffffff;
       break;
 
+#ifdef OBJ_ELF
       /* When generating ELF code, we permit -KPIC and -call_shared to
         select SVR4_PIC, and -non_shared to select no PIC.  This is
         intended to be compatible with Irix 5.  */
@@ -9264,6 +9108,7 @@ md_parse_option (c, arg)
     case OPTION_XGOT:
       mips_big_got = 1;
       break;
+#endif /* OBJ_ELF */
 
     case 'G':
       if (! USE_GLOBAL_POINTER_OPT)
@@ -9281,6 +9126,7 @@ md_parse_option (c, arg)
       g_switch_seen = 1;
       break;
 
+#ifdef OBJ_ELF
       /* The -32 and -64 options tell the assembler to output the 32
          bit or the 64 bit MIPS ELF format.  */
     case OPTION_32:
@@ -9294,7 +9140,9 @@ md_parse_option (c, arg)
        list = bfd_target_list ();
        for (l = list; *l != NULL; l++)
          if (strcmp (*l, "elf64-bigmips") == 0
-             || strcmp (*l, "elf64-littlemips") == 0)
+             || strcmp (*l, "elf64-littlemips") == 0
+             || strcmp (*l, "elf64-tradbigmips") == 0
+             || strcmp (*l, "elf64-tradlittlemips") == 0)
            break;
        if (*l == NULL)
          as_fatal (_("No compiled in support for 64 bit object file format"));
@@ -9302,6 +9150,7 @@ md_parse_option (c, arg)
        mips_64 = 1;
       }
       break;
+#endif /* OBJ_ELF */
 
     case OPTION_GP32:
       mips_gp32 = 1;
@@ -9316,21 +9165,25 @@ md_parse_option (c, arg)
         gcc, but to set this flag before gcc is built with such
         multilibs will break too many systems.  */
 
-/*    mips_32bitmode = 1; */
+#if 0
+      mips_32bitmode = 1;
+#endif
       break;
 
     case OPTION_GP64:
       mips_gp32 = 0;
       mips_64 = 1;
-/*    mips_32bitmode = 0; */
+#if 0
+      mips_32bitmode = 0;
+#endif
       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)
+      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;
 
@@ -9385,7 +9238,7 @@ md_show_usage (stream)
 {
   int column, first;
 
-  fprintf(stream, _("\
+  fprintf (stream, _("\
 MIPS options:\n\
 -membedded-pic         generate embedded position independent code\n\
 -EB                    generate big endian output\n\
@@ -9393,11 +9246,14 @@ MIPS options:\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, _("\
+  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\
+-mips5                  generate MIPS ISA V instructions\n\
+-mips32                 generate MIPS32 ISA instructions\n\
+-mips64                 generate MIPS64 ISA instructions\n\
 -mcpu=CPU              generate code for CPU, where CPU is one of:\n"));
 
   first = 1;
@@ -9417,9 +9273,9 @@ MIPS options:\n\
   show (stream, "6000", &column, &first);
   show (stream, "8000", &column, &first);
   show (stream, "10000", &column, &first);
-  show (stream, "4Kc", &column, &first);
-  show (stream, "4Kp", &column, &first);
-  show (stream, "4Km", &column, &first);
+  show (stream, "12000", &column, &first);
+  show (stream, "mips32-4k", &column, &first);
+  show (stream, "sb-1", &column, &first);
   fputc ('\n', stream);
 
   fprintf (stream, _("\
@@ -9436,19 +9292,16 @@ MIPS options:\n\
   fputc ('\n', stream);
 
   fprintf (stream, _("\
--mips32                 generate MIPS32 instructions\n"));
-
-  fprintf(stream, _("\
 -mips16                        generate mips16 instructions\n\
 -no-mips16             do not generate mips16 instructions\n"));
-  fprintf(stream, _("\
+  fprintf (stream, _("\
 -O0                    remove unneeded NOPs, do not swap branches\n\
 -O                     remove unneeded NOPs and swap branches\n\
 --[no-]construct-floats [dis]allow floating point values to be constructed\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"));
 #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\
@@ -9462,7 +9315,7 @@ mips_init_after_args ()
 {
   /* initialize opcodes */
   bfd_mips_num_opcodes = bfd_mips_num_builtin_opcodes;
-  mips_opcodes = (struct mips_opcode*) mips_builtin_opcodes;
+  mips_opcodes = (struct mips_opcode *) mips_builtin_opcodes;
 }
 
 long
@@ -9631,7 +9484,6 @@ mips_frob_file ()
    relocations, in case the linker has to relax a call.  We also need
    to keep relocations for switch table entries.  */
 
-/*ARGSUSED*/
 int
 mips_force_relocation (fixp)
      fixS *fixp;
@@ -10428,12 +10280,18 @@ s_mipsset (x)
       /* Permit the user to change the ISA on the fly.  Needless to
         say, misuse can cause serious problems.  */
       isa = atoi (name + 4);
-      if (isa == 0)
-       mips_opts.isa = file_mips_isa;
-      else if (isa < 1 || isa > 4)
-       as_bad (_("unknown ISA level"));
-      else
-       mips_opts.isa = isa;
+      switch (isa)
+      {
+      case  0: mips_opts.isa = file_mips_isa;   break;
+      case  1: mips_opts.isa = ISA_MIPS1;       break;
+      case  2: mips_opts.isa = ISA_MIPS2;       break;
+      case  3: mips_opts.isa = ISA_MIPS3;       break;
+      case  5: mips_opts.isa = ISA_MIPS5;       break;
+      case  4: mips_opts.isa = ISA_MIPS4;       break;
+      case 32: mips_opts.isa = ISA_MIPS32;      break;
+      case 64: mips_opts.isa = ISA_MIPS64;      break;
+      default: as_bad (_("unknown ISA level")); break;
+      }
     }
   else if (strcmp (name, "autoextend") == 0)
     mips_opts.noautoextend = 0;
@@ -11094,7 +10952,6 @@ mips16_extended_frag (fragp, sec, stretch)
    encoded in the subtype information.  For the mips16, we have to
    decide whether we are using an extended opcode or not.  */
 
-/*ARGSUSED*/
 int
 md_estimate_size_before_relax (fragp, segtype)
      fragS *fragp;
@@ -11146,18 +11003,18 @@ md_estimate_size_before_relax (fragp, segtype)
 
       /* duplicate the test for LINK_ONCE sections as in adjust_reloc_syms */
       if (symsec != segtype && ! S_IS_LOCAL (sym))
-        {
-          if ((bfd_get_section_flags (stdoutput, symsec) & SEC_LINK_ONCE)
-              != 0)
-            linkonce = true;
-
-          /* The GNU toolchain uses an extension for ELF: a section
-             beginning with the magic string .gnu.linkonce is a linkonce
-             section.  */
-          if (strncmp (segment_name (symsec), ".gnu.linkonce",
-                       sizeof ".gnu.linkonce" - 1) == 0)
-            linkonce = true;
-        }
+       {
+         if ((bfd_get_section_flags (stdoutput, symsec) & SEC_LINK_ONCE)
+             != 0)
+           linkonce = true;
+
+         /* The GNU toolchain uses an extension for ELF: a section
+            beginning with the magic string .gnu.linkonce is a linkonce
+            section.  */
+         if (strncmp (segment_name (symsec), ".gnu.linkonce",
+                      sizeof ".gnu.linkonce" - 1) == 0)
+           linkonce = true;
+       }
 
       /* This must duplicate the test in adjust_reloc_syms.  */
       change = (symsec != &bfd_und_section
@@ -11500,7 +11357,7 @@ md_convert_frag (abfd, asec, fragp)
          ext = false;
        }
 
-      resolve_symbol_value (fragp->fr_symbol, 1);
+      resolve_symbol_value (fragp->fr_symbol);
       val = S_GET_VALUE (fragp->fr_symbol);
       if (op->pcrel)
        {
@@ -11684,11 +11541,11 @@ mips_elf_final_processing ()
   /* Set the MIPS ELF ABI flags.  */
   if (mips_abi_string == 0)
     ;
-  else if (strcmp (mips_abi_string,"32") == 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)
+  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)
+  else if (strcmp (mips_abi_string, "eabi") == 0)
     {
       if (mips_eabi64)
        elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI64;
@@ -11702,51 +11559,52 @@ mips_elf_final_processing ()
 
 #endif /* OBJ_ELF || OBJ_MAYBE_ELF */
 \f
-typedef struct proc
-  {
-    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 proc {
+  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;
 
 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) */
+/* Fill in an rs_align_code fragment.  */
 
-int
-mips_do_align (n, fill, len, max)
-     int n;
-     const char *fill;
-     int len ATTRIBUTE_UNUSED;
-     int max;
+void
+mips_handle_align (fragp)
+     fragS *fragp;
 {
-  if (fill == NULL
-      && subseg_text_p (now_seg)
-      && n > 1
-      && mips_opts.mips16)
+  if (fragp->fr_type != rs_align_code)
+    return;
+
+  if (mips_opts.mips16)
     {
       static const unsigned char be_nop[] = { 0x65, 0x00 };
       static const unsigned char le_nop[] = { 0x00, 0x65 };
 
-      frag_align (1, 0, 0);
+      int bytes;
+      char *p;
 
-      if (target_big_endian)
-       frag_align_pattern (n, be_nop, 2, max);
-      else
-       frag_align_pattern (n, le_nop, 2, max);
-      return 1;
+      bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
+      p = fragp->fr_literal + fragp->fr_fix;
+
+      if (bytes & 1)
+       {
+         *p++ = 0;
+         fragp->fr_fix += 1;
+       }
+
+      memcpy (p, (target_big_endian ? be_nop : le_nop), 2);
+      fragp->fr_var = 2;
     }
 
-  return 0;
+  /* For mips32, a nop is a zero, which we trivially get by doing nothing.  */
 }
 
 static void
@@ -11893,21 +11751,21 @@ s_mips_end (x)
     assert (pdr_seg);
     subseg_set (pdr_seg, 0);
 
-    /* Write the symbol */
+    /* 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);
+    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);
+    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);
   }
@@ -11981,7 +11839,7 @@ s_mips_frame (ignore)
 
   long val;
 
-  if (cur_proc_ptr ==  (procS *) NULL)
+  if (cur_proc_ptr == (procS *) NULL)
     {
       as_warn (_(".frame outside of .ent"));
       demand_empty_rest_of_line ();
@@ -12079,3 +11937,202 @@ s_loc (x)
   symbolP->sy_segment = now_seg;
 }
 #endif
+
+/* CPU name/ISA/number mapping table.
+
+   Entries are grouped by type.  The first matching CPU or ISA entry
+   gets chosen by CPU or ISA, so it should be the 'canonical' name
+   for that type.  Entries after that within the type are sorted
+   alphabetically.
+
+   Case is ignored in comparison, so put the canonical entry in the
+   appropriate case but everything else in lower case to ease eye pain.  */
+static const struct mips_cpu_info mips_cpu_info_table[] =
+{
+  /* MIPS1 ISA */
+  { "MIPS1",          1,      ISA_MIPS1,      CPU_R3000, },
+  { "mips",           1,      ISA_MIPS1,      CPU_R3000, },
+
+  /* MIPS2 ISA */
+  { "MIPS2",          1,      ISA_MIPS2,      CPU_R6000, },
+
+  /* MIPS3 ISA */
+  { "MIPS3",          1,      ISA_MIPS3,      CPU_R4000, },
+
+  /* MIPS4 ISA */
+  { "MIPS4",          1,      ISA_MIPS4,      CPU_R8000, },
+
+  /* MIPS5 ISA */
+  { "MIPS5",          1,      ISA_MIPS5,      CPU_MIPS5, },
+  { "Generic-MIPS5",  0,      ISA_MIPS5,      CPU_MIPS5, },
+
+  /* MIPS32 ISA */
+  { "MIPS32",         1,      ISA_MIPS32,     CPU_MIPS32, },
+  { "Generic-MIPS32", 0,      ISA_MIPS32,     CPU_MIPS32, },
+
+#if 1
+  /* XXX for now, MIPS64 -> MIPS3 because of history */
+  { "MIPS64",         1,      ISA_MIPS3,      CPU_R4000 }, /* XXX! */
+#else
+  /* MIPS64 ISA */
+  { "MIPS64",         1,      ISA_MIPS64,     CPU_MIPS64 },
+#endif
+  { "mips64isa",      1,      ISA_MIPS64,     CPU_MIPS64 },
+  { "Generic-MIPS64", 0,      ISA_MIPS64,     CPU_MIPS64, },
+
+  /* R2000 CPU */
+  { "R2000",          0,      ISA_MIPS1,      CPU_R2000, },
+  { "2000",           0,      ISA_MIPS1,      CPU_R2000, },
+  { "2k",             0,      ISA_MIPS1,      CPU_R2000, },
+  { "r2k",            0,      ISA_MIPS1,      CPU_R2000, },
+
+  /* R3000 CPU */
+  { "R3000",          0,      ISA_MIPS1,      CPU_R3000, },
+  { "3000",           0,      ISA_MIPS1,      CPU_R3000, },
+  { "3k",             0,      ISA_MIPS1,      CPU_R3000, },
+  { "r3k",            0,      ISA_MIPS1,      CPU_R3000, },
+
+  /* TX3900 CPU */
+  { "R3900",          0,      ISA_MIPS1,      CPU_R3900, },
+  { "3900",           0,      ISA_MIPS1,      CPU_R3900, },
+  { "mipstx39",       0,      ISA_MIPS1,      CPU_R3900, },
+
+  /* R4000 CPU */
+  { "R4000",          0,      ISA_MIPS3,      CPU_R4000, },
+  { "4000",           0,      ISA_MIPS3,      CPU_R4000, },
+  { "4k",             0,      ISA_MIPS3,      CPU_R4000, },   /* beware */
+  { "r4k",            0,      ISA_MIPS3,      CPU_R4000, },
+
+  /* R4010 CPU */
+  { "R4010",          0,      ISA_MIPS2,      CPU_R4010, },
+  { "4010",           0,      ISA_MIPS2,      CPU_R4010, },
+
+  /* R4400 CPU */
+  { "R4400",          0,      ISA_MIPS3,      CPU_R4400, },
+  { "4400",           0,      ISA_MIPS3,      CPU_R4400, },
+
+  /* R4600 CPU */
+  { "R4600",          0,      ISA_MIPS3,      CPU_R4600, },
+  { "4600",           0,      ISA_MIPS3,      CPU_R4600, },
+  { "mips64orion",    0,      ISA_MIPS3,      CPU_R4600, },
+  { "orion",          0,      ISA_MIPS3,      CPU_R4600, },
+
+  /* R4650 CPU */
+  { "R4650",          0,      ISA_MIPS3,      CPU_R4650, },
+  { "4650",           0,      ISA_MIPS3,      CPU_R4650, },
+
+  /* R6000 CPU */
+  { "R6000",          0,      ISA_MIPS2,      CPU_R6000, },
+  { "6000",           0,      ISA_MIPS2,      CPU_R6000, },
+  { "6k",             0,      ISA_MIPS2,      CPU_R6000, },
+  { "r6k",            0,      ISA_MIPS2,      CPU_R6000, },
+
+  /* R8000 CPU */
+  { "R8000",          0,      ISA_MIPS4,      CPU_R8000, },
+  { "8000",           0,      ISA_MIPS4,      CPU_R8000, },
+  { "8k",             0,      ISA_MIPS4,      CPU_R8000, },
+  { "r8k",            0,      ISA_MIPS4,      CPU_R8000, },
+
+  /* R10000 CPU */
+  { "R10000",         0,      ISA_MIPS4,      CPU_R10000, },
+  { "10000",          0,      ISA_MIPS4,      CPU_R10000, },
+  { "10k",            0,      ISA_MIPS4,      CPU_R10000, },
+  { "r10k",           0,      ISA_MIPS4,      CPU_R10000, },
+
+  /* R12000 CPU */
+  { "R12000",         0,      ISA_MIPS4,      CPU_R12000, },
+  { "12000",          0,      ISA_MIPS4,      CPU_R12000, },
+  { "12k",            0,      ISA_MIPS4,      CPU_R12000, },
+  { "r12k",           0,      ISA_MIPS4,      CPU_R12000, },
+
+  /* VR4100 CPU */
+  { "VR4100",         0,      ISA_MIPS3,      CPU_VR4100, },
+  { "4100",           0,      ISA_MIPS3,      CPU_VR4100, },
+  { "mips64vr4100",   0,      ISA_MIPS3,      CPU_VR4100, },
+  { "r4100",          0,      ISA_MIPS3,      CPU_VR4100, },
+
+  /* VR4111 CPU */
+  { "VR4111",         0,      ISA_MIPS3,      CPU_R4111, },
+  { "4111",           0,      ISA_MIPS3,      CPU_R4111, },
+  { "mips64vr4111",   0,      ISA_MIPS3,      CPU_R4111, },
+  { "r4111",          0,      ISA_MIPS3,      CPU_R4111, },
+
+  /* VR4300 CPU */
+  { "VR4300",         0,      ISA_MIPS3,      CPU_R4300, },
+  { "4300",           0,      ISA_MIPS3,      CPU_R4300, },
+  { "mips64vr4300",   0,      ISA_MIPS3,      CPU_R4300, },
+  { "r4300",          0,      ISA_MIPS3,      CPU_R4300, },
+
+  /* VR5000 CPU */
+  { "VR5000",         0,      ISA_MIPS4,      CPU_R5000, },
+  { "5000",           0,      ISA_MIPS4,      CPU_R5000, },
+  { "5k",             0,      ISA_MIPS4,      CPU_R5000, },
+  { "mips64vr5000",   0,      ISA_MIPS4,      CPU_R5000, },
+  { "r5000",          0,      ISA_MIPS4,      CPU_R5000, },
+  { "r5200",          0,      ISA_MIPS4,      CPU_R5000, },
+  { "r5230",          0,      ISA_MIPS4,      CPU_R5000, },
+  { "r5231",          0,      ISA_MIPS4,      CPU_R5000, },
+  { "r5261",          0,      ISA_MIPS4,      CPU_R5000, },
+  { "r5721",          0,      ISA_MIPS4,      CPU_R5000, },
+  { "r5k",            0,      ISA_MIPS4,      CPU_R5000, },
+  { "r7000",          0,      ISA_MIPS4,      CPU_R5000, },
+
+  /* MIPS32 4K CPU */
+  { "MIPS32-4K",      0,      ISA_MIPS32,     CPU_MIPS32_4K, },
+  { "4kc",            0,      ISA_MIPS32,     CPU_MIPS32_4K, },
+  { "4km",            0,      ISA_MIPS32,     CPU_MIPS32_4K, },
+  { "4kp",            0,      ISA_MIPS32,     CPU_MIPS32_4K, },
+  { "mips32-4kc",     0,      ISA_MIPS32,     CPU_MIPS32_4K, },
+  { "mips32-4km",     0,      ISA_MIPS32,     CPU_MIPS32_4K, },
+  { "mips32-4kp",     0,      ISA_MIPS32,     CPU_MIPS32_4K, },
+
+  /* SiByte SB-1 CPU */
+  { "SB-1",           0,      ISA_MIPS64,     CPU_SB1, },
+  { "sb-1250",        0,      ISA_MIPS64,     CPU_SB1, },
+  { "sb1",            0,      ISA_MIPS64,     CPU_SB1, },
+  { "sb1250",         0,      ISA_MIPS64,     CPU_SB1, },
+
+  /* End marker.  */
+  { NULL, 0, 0, 0, },
+};
+
+static const struct mips_cpu_info *
+mips_cpu_info_from_name (name)
+     const char *name;
+{
+  int i;
+
+  for (i = 0; mips_cpu_info_table[i].name != NULL; i++)
+    if (strcasecmp (name, mips_cpu_info_table[i].name) == 0)
+      return (&mips_cpu_info_table[i]);
+
+  return NULL;
+}
+
+static const struct mips_cpu_info *
+mips_cpu_info_from_isa (isa)
+     int isa;
+{
+  int i;
+
+  for (i = 0; mips_cpu_info_table[i].name != NULL; i++)
+    if (mips_cpu_info_table[i].is_isa
+      && isa == mips_cpu_info_table[i].isa)
+      return (&mips_cpu_info_table[i]);
+
+  return NULL;
+}
+
+static const struct mips_cpu_info *
+mips_cpu_info_from_cpu (cpu)
+     int cpu;
+{
+  int i;
+
+  for (i = 0; mips_cpu_info_table[i].name != NULL; i++)
+    if (!mips_cpu_info_table[i].is_isa
+      && cpu == mips_cpu_info_table[i].cpu)
+      return (&mips_cpu_info_table[i]);
+
+  return NULL;
+}
This page took 0.077996 seconds and 4 git commands to generate.