Thu Mar 20 13:42:01 1997 H.J. Lu <hjl@lucon.org>
[binutils-gdb.git] / gas / config / tc-mips.c
index 1eb151ff64e4677ed56ed0751fa43ee8d5ad1ff4..5a92c2490adb266e233a5fb7b0e45ac24994465d 100644 (file)
 #endif
 
 #include "opcode/mips.h"
+#include "itbl-ops.h"
+
+#ifdef DEBUG
+#define DBG(x) printf x
+#else
+#define DBG(x)
+#endif
 
 #ifdef OBJ_MAYBE_ELF
 /* Clean up namespace so we can include obj-elf.h too.  */
+static int mips_output_flavor PARAMS ((void));
 static int mips_output_flavor () { return OUTPUT_FLAVOR; }
 #undef OBJ_PROCESS_STAB
 #undef OUTPUT_FLAVOR
@@ -86,6 +94,12 @@ static char *mips_regmask_frag;
 
 #define ILLEGAL_REG (32)
 
+/* Allow override of standard little-endian ECOFF format.  */
+
+#ifndef ECOFF_LITTLE_FORMAT
+#define ECOFF_LITTLE_FORMAT "ecoff-littlemips"
+#endif
+
 extern int target_big_endian;
 
 /* 1 is we should use the 64 bit MIPS ELF ABI, 0 if we should use the
@@ -101,7 +115,7 @@ mips_target_format ()
     case bfd_target_aout_flavour:
       return target_big_endian ? "a.out-mips-big" : "a.out-mips-little";
     case bfd_target_ecoff_flavour:
-      return target_big_endian ? "ecoff-bigmips" : "ecoff-littlemips";
+      return target_big_endian ? "ecoff-bigmips" : ECOFF_LITTLE_FORMAT;
     case bfd_target_elf_flavour:
       return (target_big_endian
              ? (mips_64 ? "elf64-bigmips" : "elf32-bigmips")
@@ -159,6 +173,7 @@ static int interlocks = -1;
 
 /* As with "interlocks" this is used by hardware that has FP
    (co-processor) interlocks.  */
+/* Itbl support may require additional care here. */
 static int cop_interlocks = -1;
 
 /* MIPS PIC level.  */
@@ -872,6 +887,7 @@ md_begin ()
   else
     interlocks = 0;
 
+  /* Itbl support may require additional care here. */
   if (mips_cpu == 4300)
     cop_interlocks = 1;
   else
@@ -1099,7 +1115,11 @@ md_assemble (str)
   if (mips16)
     mips16_ip (str, &insn);
   else
-    mips_ip (str, &insn);
+    {
+      mips_ip (str, &insn);
+      DBG(("returned from mips_ip(%s) insn_opcode = 0x%x\n", 
+               str, insn.insn_opcode));
+    }
 
   if (insn_error)
     {
@@ -1221,6 +1241,7 @@ reg_needs_delay (reg)
         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. */
       know (prev_pinfo & INSN_WRITE_GPR_T);
       if (reg == ((prev_insn.insn_opcode >> OP_SH_RT) & OP_MASK_RT))
        return 1;
@@ -1314,6 +1335,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. */
          know (prev_pinfo & INSN_WRITE_GPR_T);
          if (mips_optimize == 0
              || insn_uses_reg (ip,
@@ -1343,6 +1365,9 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
             knowledge of CP0 handling, and the coprocessors other
             than the floating point unit are not distinguished at
             all.  */
+          /* Itbl support may require additional care here. FIXME!
+             Need to modify this to include knowledge about 
+             user specified delays!  */
          if (prev_pinfo & INSN_WRITE_FPR_T)
            {
              if (mips_optimize == 0
@@ -1369,6 +1394,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                 instruction may set the condition codes, and the
                 current instruction uses them, we must insert two
                 NOPS.  */
+              /* Itbl support may require additional care here. */
              if (mips_optimize == 0
                  || ((prev_pinfo & INSN_WRITE_COND_CODE)
                      && (pinfo & INSN_READ_COND_CODE)))
@@ -1387,6 +1413,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. */
          if (mips_optimize == 0
              || (pinfo & INSN_READ_COND_CODE))
            ++nops;
@@ -1414,6 +1441,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
 
       /* If the previous instruction was in a noreorder section, then
          we don't want to insert the nop after all.  */
+      /* Itbl support may require additional care here. */
       if (prev_insn_unreordered)
        nops = 0;
 
@@ -1549,7 +1577,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                                          & INSN_UNCOND_BRANCH_DELAY),
                                         (prev_insn_reloc_type
                                          == BFD_RELOC_MIPS16_JMP)),
-                   make_expr_symbol (address_expr), (long) 0,
+                   make_expr_symbol (address_expr), (offsetT) 0,
                    (char *) NULL);
     }
   else if (place != NULL)
@@ -1675,7 +1703,10 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
        mips_cprmask[1] |= 1 << ((ip->insn_opcode >> OP_SH_FR) & OP_MASK_FR);
       if (pinfo & INSN_COP)
        {
-         /* We don't keep enough information to sort these cases out.  */
+         /* We don't keep enough information to sort these cases out. 
+            The itbl support does keep this information however, although 
+            we currently don't support itbl fprmats as part of the cop 
+            instruction.  May want to add this support in the future. */
        }
       /* Never set the bit for $0, which is always zero.  */
       mips_gprmask &=~ 1 << 0;
@@ -1776,6 +1807,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
              || (! mips16
                  && mips_isa < 4
                  && (prev_pinfo
+              /* Itbl support may require additional care here. */
                      & (INSN_LOAD_COPROC_DELAY
                         | INSN_COPROC_MOVE_DELAY
                         | INSN_WRITE_COND_CODE)))
@@ -1787,6 +1819,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                  && mips_isa < 2
                  && (prev_pinfo
                      & (INSN_LOAD_MEMORY_DELAY
+              /* Itbl support may require additional care here. */
                         | INSN_COPROC_MEMORY_DELAY)))
              /* We can not swap with a branch instruction.  */
              || (prev_pinfo
@@ -1891,6 +1924,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                 can not swap.  */
              || (! mips16
                  && mips_isa < 4
+              /* Itbl support may require additional care here. */
                  && ((prev_prev_insn.insn_mo->pinfo & INSN_LOAD_COPROC_DELAY)
                      || (mips_isa < 2
                          && (prev_prev_insn.insn_mo->pinfo
@@ -2108,6 +2142,7 @@ mips_emit_delays (insns)
                  & (INSN_LOAD_MEMORY_DELAY
                     | INSN_COPROC_MEMORY_DELAY))))
        {
+          /* Itbl support may require additional care here. */
          ++nops;
          if ((! mips16
               && mips_isa < 4
@@ -2129,6 +2164,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. */
          if (! prev_prev_insn_unreordered)
            ++nops;
        }
@@ -2756,8 +2792,12 @@ load_register (counter, reg, ep, dbl)
                    || ! ep->X_unsigned
                    || sizeof (ep->X_add_number) > 4
                    || (ep->X_add_number & 0x80000000) == 0))
-              || ((mips_isa < 3 || !dbl)
-                  && (ep->X_add_number &~ (offsetT) 0xffffffff) == 0))
+              || ((mips_isa < 3 || ! dbl)
+                  && (ep->X_add_number &~ (offsetT) 0xffffffff) == 0)
+              || (mips_isa < 3
+                  && ! dbl
+                  && ((ep->X_add_number &~ (offsetT) 0xffffffff)
+                      == ~ (offsetT) 0xffffffff)))
        {
          /* 32 bit values require an lui.  */
          macro_build ((char *) NULL, counter, ep, "lui", "t,u", reg,
@@ -3015,7 +3055,7 @@ load_address (counter, reg, ep)
                       "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, mips_warn_about_macros),
-                       ep->X_add_symbol, (long) 0, (char *) NULL);
+                       ep->X_add_symbol, (offsetT) 0, (char *) NULL);
        }
       macro_build_lui (p, counter, ep, reg);
       if (p != NULL)
@@ -3044,7 +3084,7 @@ load_address (counter, reg, ep)
       macro_build ((char *) NULL, counter, (expressionS *) NULL, "nop", "");
       p = frag_var (rs_machine_dependent, 4, 0,
                    RELAX_ENCODE (0, 4, -8, 0, 0, mips_warn_about_macros),
-                   ep->X_add_symbol, (long) 0, (char *) NULL);
+                   ep->X_add_symbol, (offsetT) 0, (char *) NULL);
       macro_build (p, counter, ep,
                   mips_isa < 3 ? "addiu" : "daddiu",
                   "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
@@ -3091,7 +3131,7 @@ load_address (counter, reg, ep)
       p = frag_var (rs_machine_dependent, 12 + off, 0,
                    RELAX_ENCODE (12, 12 + off, off, 8 + off, 0,
                                  mips_warn_about_macros),
-                   ep->X_add_symbol, (long) 0, (char *) NULL);
+                   ep->X_add_symbol, (offsetT) 0, (char *) NULL);
       if (off > 0)
        {
          /* We need a nop before loading from $gp.  This special
@@ -3886,7 +3926,7 @@ macro (ip)
              p = frag_var (rs_machine_dependent, 8, 0,
                            RELAX_ENCODE (4, 8, 0, 4, 0,
                                          mips_warn_about_macros),
-                           offset_expr.X_add_symbol, (long) 0,
+                           offset_expr.X_add_symbol, (offsetT) 0,
                            (char *) NULL);
            }
          macro_build_lui (p, &icnt, &offset_expr, tempreg);
@@ -3950,7 +3990,7 @@ macro (ip)
                                          (breg == 0
                                           ? mips_warn_about_macros
                                           : 0)),
-                           offset_expr.X_add_symbol, (long) 0,
+                           offset_expr.X_add_symbol, (offsetT) 0,
                            (char *) NULL);
              if (breg == 0)
                {
@@ -3974,7 +4014,7 @@ macro (ip)
                           "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),
-                              offset_expr.X_add_symbol, (long) 0,
+                              offset_expr.X_add_symbol, (offsetT) 0,
                               (char *) NULL);
            }
          else
@@ -4017,7 +4057,7 @@ macro (ip)
                           "d,v,t", tempreg, tempreg, AT);
              (void) frag_var (rs_machine_dependent, 0, 0,
                               RELAX_ENCODE (0, 0, -16 + off1, -8, 0, 0),
-                              offset_expr.X_add_symbol, (long) 0,
+                              offset_expr.X_add_symbol, (offsetT) 0,
                               (char *) NULL);
              used_at = 1;
            }
@@ -4100,7 +4140,7 @@ macro (ip)
                                          (breg == 0
                                           ? mips_warn_about_macros
                                           : 0)),
-                           offset_expr.X_add_symbol, (long) 0,
+                           offset_expr.X_add_symbol, (offsetT) 0,
                            (char *) NULL);
            }
          else if (expr1.X_add_number >= -0x8000
@@ -4117,7 +4157,7 @@ macro (ip)
                                          (breg == 0
                                           ? mips_warn_about_macros
                                           : 0)),
-                           offset_expr.X_add_symbol, (long) 0,
+                           offset_expr.X_add_symbol, (offsetT) 0,
                            (char *) NULL);
            }
          else
@@ -4168,7 +4208,7 @@ macro (ip)
                                          (breg == 0
                                           ? mips_warn_about_macros
                                           : 0)),
-                           offset_expr.X_add_symbol, (long) 0,
+                           offset_expr.X_add_symbol, (offsetT) 0,
                            (char *) NULL);
 
              used_at = 1;
@@ -4334,7 +4374,8 @@ macro (ip)
                           "nop", "");
              p = frag_var (rs_machine_dependent, 4, 0,
                            RELAX_ENCODE (0, 4, -8, 0, 0, 0),
-                           offset_expr.X_add_symbol, (long) 0, (char *) NULL);
+                           offset_expr.X_add_symbol, (offsetT) 0,
+                           (char *) NULL);
            }
          else
            {
@@ -4358,7 +4399,8 @@ macro (ip)
              p = frag_var (rs_machine_dependent, 12 + gpdel, 0,
                            RELAX_ENCODE (16, 12 + gpdel, gpdel, 8 + gpdel,
                                          0, 0),
-                           offset_expr.X_add_symbol, (long) 0, (char *) NULL);
+                           offset_expr.X_add_symbol, (offsetT) 0,
+                           (char *) NULL);
              if (gpdel > 0)
                {
                  macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
@@ -4421,18 +4463,22 @@ macro (ip)
       goto ld;
     case M_LWC0_AB:
       s = "lwc0";
+      /* Itbl support may require additional care here. */
       coproc = 1;
       goto ld;
     case M_LWC1_AB:
       s = "lwc1";
+      /* Itbl support may require additional care here. */
       coproc = 1;
       goto ld;
     case M_LWC2_AB:
       s = "lwc2";
+      /* Itbl support may require additional care here. */
       coproc = 1;
       goto ld;
     case M_LWC3_AB:
       s = "lwc3";
+      /* Itbl support may require additional care here. */
       coproc = 1;
       goto ld;
     case M_LWL_AB:
@@ -4445,14 +4491,17 @@ macro (ip)
       goto ld;
     case M_LDC1_AB:
       s = "ldc1";
+      /* Itbl support may require additional care here. */
       coproc = 1;
       goto ld;
     case M_LDC2_AB:
       s = "ldc2";
+      /* Itbl support may require additional care here. */
       coproc = 1;
       goto ld;
     case M_LDC3_AB:
       s = "ldc3";
+      /* Itbl support may require additional care here. */
       coproc = 1;
       goto ld;
     case M_LDL_AB:
@@ -4494,18 +4543,22 @@ macro (ip)
       goto st;
     case M_SWC0_AB:
       s = "swc0";
+      /* Itbl support may require additional care here. */
       coproc = 1;
       goto st;
     case M_SWC1_AB:
       s = "swc1";
+      /* Itbl support may require additional care here. */
       coproc = 1;
       goto st;
     case M_SWC2_AB:
       s = "swc2";
+      /* Itbl support may require additional care here. */
       coproc = 1;
       goto st;
     case M_SWC3_AB:
       s = "swc3";
+      /* Itbl support may require additional care here. */
       coproc = 1;
       goto st;
     case M_SWL_AB:
@@ -4523,13 +4576,16 @@ macro (ip)
     case M_SDC1_AB:
       s = "sdc1";
       coproc = 1;
+      /* Itbl support may require additional care here. */
       goto st;
     case M_SDC2_AB:
       s = "sdc2";
+      /* Itbl support may require additional care here. */
       coproc = 1;
       goto st;
     case M_SDC3_AB:
       s = "sdc3";
+      /* Itbl support may require additional care here. */
       coproc = 1;
       goto st;
     case M_SDL_AB:
@@ -4541,6 +4597,7 @@ macro (ip)
       tempreg = AT;
       used_at = 1;
     ld_st:
+      /* Itbl support may require additional care here. */
       if (mask == M_LWC1_AB
          || mask == M_SWC1_AB
          || mask == M_LDC1_AB
@@ -4597,7 +4654,7 @@ macro (ip)
                                RELAX_ENCODE (4, 8, 0, 4, 0,
                                              (mips_warn_about_macros
                                               || (used_at && mips_noat))),
-                               offset_expr.X_add_symbol, (long) 0,
+                               offset_expr.X_add_symbol, (offsetT) 0,
                                (char *) NULL);
                  used_at = 0;
                }
@@ -4622,7 +4679,7 @@ macro (ip)
                               treg, (int) BFD_RELOC_MIPS_GPREL, tempreg);
                  p = frag_var (rs_machine_dependent, 12, 0,
                                RELAX_ENCODE (8, 12, 0, 8, 0, 0),
-                               offset_expr.X_add_symbol, (long) 0,
+                               offset_expr.X_add_symbol, (offsetT) 0,
                                (char *) NULL);
                }
              macro_build_lui (p, &icnt, &offset_expr, tempreg);
@@ -4667,7 +4724,7 @@ macro (ip)
          macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", "");
          p = frag_var (rs_machine_dependent, 4, 0, 
                        RELAX_ENCODE (0, 4, -8, 0, 0, 0),
-                       offset_expr.X_add_symbol, (long) 0,
+                       offset_expr.X_add_symbol, (offsetT) 0,
                        (char *) NULL);
          macro_build (p, &icnt, &offset_expr,
                       mips_isa < 3 ? "addiu" : "daddiu",
@@ -4721,7 +4778,7 @@ macro (ip)
                       tempreg);
          p = frag_var (rs_machine_dependent, 12 + gpdel, 0,
                        RELAX_ENCODE (12, 12 + gpdel, gpdel, 8 + gpdel, 0, 0),
-                       offset_expr.X_add_symbol, (long) 0, (char *) NULL);
+                       offset_expr.X_add_symbol, (offsetT) 0, (char *) NULL);
          if (gpdel > 0)
            {
              macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
@@ -4939,6 +4996,7 @@ macro (ip)
        * But, the resulting address is the same after relocation so why
        * generate the extra instruction?
        */
+      /* Itbl support may require additional care here. */
       coproc = 1;
       if (mips_isa >= 2)
        {
@@ -4959,6 +5017,7 @@ macro (ip)
 
       s = "swc1";
       fmt = "T,o(b)";
+      /* Itbl support may require additional care here. */
       coproc = 1;
       goto ldd_std;
 
@@ -4994,6 +5053,7 @@ macro (ip)
       /* Even on a big endian machine $fn comes before $fn+1.  We have
         to adjust when loading from memory.  We set coproc if we must
         load $fn+1 first.  */
+      /* Itbl support may require additional care here. */
       if (! target_big_endian)
        coproc = 0;
 
@@ -5042,6 +5102,7 @@ macro (ip)
                  used_at = 1;
                }
 
+              /* 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);
@@ -5051,6 +5112,7 @@ macro (ip)
                  undesired nop.  */
              hold_mips_optimize = mips_optimize;
              mips_optimize = 2;
+              /* 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);
@@ -5059,7 +5121,7 @@ macro (ip)
              p = frag_var (rs_machine_dependent, 12 + off, 0,
                            RELAX_ENCODE (8 + off, 12 + off, 0, 4 + off, 1,
                                          used_at && mips_noat),
-                           offset_expr.X_add_symbol, (long) 0,
+                           offset_expr.X_add_symbol, (offsetT) 0,
                            (char *) NULL);
 
              /* We just generated two relocs.  When tc_gen_reloc
@@ -5084,6 +5146,7 @@ macro (ip)
              if (p != NULL)
                p += 4;
            }
+          /* Itbl support may require additional care here. */
          macro_build (p, &icnt, &offset_expr, s, fmt,
                       coproc ? treg + 1 : treg,
                       (int) BFD_RELOC_LO16, AT);
@@ -5091,6 +5154,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. */
          macro_build (p, &icnt, &offset_expr, s, fmt,
                       coproc ? treg : treg + 1,
                       (int) BFD_RELOC_LO16, AT);
@@ -5131,6 +5195,7 @@ macro (ip)
            macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                         mips_isa < 3 ? "addu" : "daddu",
                         "d,v,t", AT, breg, AT);
+          /* Itbl support may require additional care here. */
          macro_build ((char *) NULL, &icnt, &expr1, s, fmt,
                       coproc ? treg + 1 : treg,
                       (int) BFD_RELOC_LO16, AT);
@@ -5140,6 +5205,7 @@ macro (ip)
              nop.  */
          hold_mips_optimize = mips_optimize;
          mips_optimize = 2;
+          /* Itbl support may require additional care here. */
          macro_build ((char *) NULL, &icnt, &expr1, s, fmt,
                       coproc ? treg : treg + 1,
                       (int) BFD_RELOC_LO16, AT);
@@ -5147,7 +5213,7 @@ macro (ip)
 
          (void) frag_var (rs_machine_dependent, 0, 0,
                           RELAX_ENCODE (0, 0, -16 - off, -8, 1, 0),
-                          offset_expr.X_add_symbol, (long) 0,
+                          offset_expr.X_add_symbol, (offsetT) 0,
                           (char *) NULL);
        }
       else if (mips_pic == SVR4_PIC)
@@ -5197,6 +5263,7 @@ macro (ip)
            macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
                         mips_isa < 3 ? "addu" : "daddu",
                         "d,v,t", AT, breg, AT);
+          /* Itbl support may require additional care here. */
          macro_build ((char *) NULL, &icnt, &expr1, s, fmt,
                       coproc ? treg + 1 : treg,
                       (int) BFD_RELOC_LO16, AT);
@@ -5206,6 +5273,7 @@ macro (ip)
              nop.  */
          hold_mips_optimize = mips_optimize;
          mips_optimize = 2;
+          /* Itbl support may require additional care here. */
          macro_build ((char *) NULL, &icnt, &expr1, s, fmt,
                       coproc ? treg : treg + 1,
                       (int) BFD_RELOC_LO16, AT);
@@ -5215,7 +5283,7 @@ macro (ip)
          p = frag_var (rs_machine_dependent, 16 + gpdel + off, 0,
                        RELAX_ENCODE (24 + off, 16 + gpdel + off, gpdel,
                                      8 + gpdel + off, 1, 0),
-                       offset_expr.X_add_symbol, (long) 0,
+                       offset_expr.X_add_symbol, (offsetT) 0,
                        (char *) NULL);
          if (gpdel > 0)
            {
@@ -5235,6 +5303,7 @@ macro (ip)
                           "d,v,t", AT, breg, AT);
              p += 4;
            }
+          /* Itbl support may require additional care here. */
          macro_build (p, &icnt, &expr1, s, fmt,
                       coproc ? treg + 1 : treg,
                       (int) BFD_RELOC_LO16, AT);
@@ -5245,6 +5314,7 @@ macro (ip)
              nop.  */
          hold_mips_optimize = mips_optimize;
          mips_optimize = 2;
+          /* Itbl support may require additional care here. */
          macro_build (p, &icnt, &expr1, s, fmt,
                       coproc ? treg : treg + 1,
                       (int) BFD_RELOC_LO16, AT);
@@ -5274,10 +5344,12 @@ macro (ip)
              used_at = 1;
            }
 
+          /* 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. */
          macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
                       coproc ? treg : treg + 1,
                       (int) BFD_RELOC_MIPS_GPREL, tempreg);
@@ -5303,8 +5375,59 @@ macro (ip)
       macro_build ((char *) NULL, &icnt, &offset_expr, s, "t,o(b)", treg + 1,
                   (int) BFD_RELOC_LO16, breg);
       return;
+
+   /* New code added to support COPZ instructions.
+      This code builds table entries out of the macros in mip_opcodes.
+      R4000 uses interlocks to handle coproc delays.
+      Other chips (like the R3000) require nops to be inserted for delays.
+
+      FIXME: Currently, we require that the user handle delays.
+      In order to fill delay slots for non-interlocked chips,
+      we must have a way to specify delays based on the coprocessor.
+      Eg. 4 cycles if load coproc reg from memory, 1 if in cache, etc.
+      What are the side-effects of the cop instruction?
+      What cache support might we have and what are its effects?
+      Both coprocessor & memory require delays. how long???
+      What registers are read/set/modified? 
+
+      If an itbl is provided to interpret cop instructions,
+      this knowledge can be encoded in the itbl spec. */
+
+    case M_COP0:
+      s = "cop0";
+      goto copz;
+    case M_COP1:
+      s = "cop1";
+      goto copz;
+    case M_COP2:
+      s = "cop2";
+      goto copz;
+    case M_COP3:
+      s = "cop3";
+    copz:
+      /* For now we just do C (same as Cz). */
+      macro_build ((char *) NULL, &icnt, &offset_expr, s, "C");
+      return;
+
 #ifdef LOSING_COMPILER
     default:
+      /* Try and see if this is a new itbl instruction.
+         This code builds table entries out of the macros in mip_opcodes.
+         FIXME: For now we just assemble the expression and pass it's
+         value along as a 32-bit immediate.
+         We may want to have the assembler assemble this value, 
+         so that we gain the assembler's knowledge of delay slots,
+         symbols, etc.
+         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;
     }
@@ -5967,6 +6090,8 @@ macro2 (ip)
       break;
 
     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);
       break;
     }
@@ -6229,9 +6354,9 @@ mips_ip (str, ip)
 
   for (s = str; *s != '\0' && !isspace(*s); ++s)
     continue;
-  if ( isspace(*s) )
+  if (isspace (*s))
     *s++ = '\0';
-    
+
   if ((insn = (struct mips_opcode *) hash_find (op_hash, str)) == NULL)
     {
       insn_error = "unrecognized opcode";
@@ -6485,6 +6610,31 @@ mips_ip (str, ip)
                          s += 4;
                          regno = KT1;
                        }
+                     else if (itbl_have_entries)
+                       {
+                         char *p, *n;
+                         int r;
+
+                         p = s+1;      /* advance past '$' */
+                         n = itbl_get_field (&p);  /* n is name */
+
+                         /* See if this is a register defined in an 
+                            itbl entry */
+                         r = itbl_get_reg_val (n);
+                         if (r)
+                           {
+                             /* Get_field advances to the start of
+                                the next field, so we need to back
+                                rack to the end of the last field. */
+                             if (p) 
+                               s = p - 1;
+                             else 
+                               s = strchr (s,'\0');
+                             regno = r;
+                           }
+                         else
+                           goto notreg;
+                         }
                      else
                        goto notreg;
                    }
@@ -6508,6 +6658,9 @@ mips_ip (str, ip)
                  /* 'z' only matches $0.  */
                  if (c == 'z' && regno != 0)
                    break;
+
+       /* Now that we have assembled one operand, we use the args string 
+        * to figure out where it goes in the instruction. */
                  switch (c)
                    {
                    case 'r':
@@ -6540,6 +6693,11 @@ mips_ip (str, ip)
                         is $0.  This only matches $0, and is checked
                         outside the switch.  */
                      break;
+                   case 'D':
+                     /* Itbl operand; not yet implemented. FIXME ?? */
+                     break;
+                     /* What about all other operands like 'i', which
+                        can be specified in the opcode table? */
                    }
                  lastregno = regno;
                  continue;
@@ -7917,12 +8075,12 @@ 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-5900 */
+  /* 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-5900 */
+  /* end-sanitize-r5900 */
 
 #define OPTION_CALL_SHARED (OPTION_MD_BASE + 7)
 #define OPTION_NON_SHARED (OPTION_MD_BASE + 8)
@@ -8309,6 +8467,14 @@ MIPS options:\n\
 #endif
 }
 \f
+void
+mips_init_after_args ()
+{
+  /* initialize opcodes */
+  bfd_mips_num_opcodes = bfd_mips_num_builtin_opcodes;
+  mips_opcodes = (struct mips_opcode*) mips_builtin_opcodes;
+}
+
 long
 md_pcrel_from (fixP)
      fixS *fixP;
@@ -8357,6 +8523,24 @@ cons_fix_new_mips (frag, where, nbytes, exp)
                : (nbytes == 4 ? BFD_RELOC_32 : BFD_RELOC_64)));
 }
 
+/* This is called before the symbol table is processed.  In order to
+   work with gcc when using mips-tfile, we must keep all local labels.
+   However, in other cases, we want to discard them.  If we were
+   called with -g, but we didn't see any debugging information, it may
+   mean that gcc is smuggling debugging information through to
+   mips-tfile, in which case we must generate all local labels.  */
+
+void
+mips_frob_file_before_adjust ()
+{
+#ifndef NO_ECOFF_DEBUGGING
+  if (ECOFF_DEBUGGING
+      && mips_debug != 0
+      && ! ecoff_debugging_seen)
+    flag_keep_locals = 1;
+#endif
+}
+
 /* Sort any unmatched HI16_S relocs so that they immediately precede
    the corresponding LO reloc.  This is called before md_apply_fix and
    tc_gen_reloc.  Unmatched HI16_S relocs can only be generated by
@@ -8681,7 +8865,7 @@ md_apply_fix (fixP, valueP)
                  handle these cases, but it appears to do it
                  incorrectly.  */
              as_bad_where (fixP->fx_file, fixP->fx_line,
-                           "Relocation overflow");
+                           "Branch out of range");
            }
        }
 
@@ -9610,12 +9794,16 @@ mips16_extended_frag (fragp, sec, stretch)
        {
          fragS *f;
 
-         /* Adjust stretch for any alignment frag.  FIXME: This
-             doesn't handle the fr_subtype field, which specifies a
-             maximum number of bytes to skip when doing an alignment.  */
-         for (f = fragp; f != fragp->fr_symbol->sy_frag; f = f->fr_next)
+         /* Adjust stretch for any alignment frag.  Note that if have
+             been expanding the earlier code, the symbol may be
+             defined in what appears to be an earlier frag.  FIXME:
+             This doesn't handle the fr_subtype field, which specifies
+             a maximum number of bytes to skip when doing an
+             alignment.  */
+         for (f = fragp;
+              f != NULL && f != fragp->fr_symbol->sy_frag;
+              f = f->fr_next)
            {
-             assert (f != NULL);
              if (f->fr_type == rs_align || f->fr_type == rs_align_code)
                {
                  if (stretch < 0)
@@ -9627,7 +9815,8 @@ mips16_extended_frag (fragp, sec, stretch)
                    break;
                }
            }
-         val += stretch;
+         if (f != NULL)
+           val += stretch;
        }
 
       addr = fragp->fr_address + fragp->fr_fix;
@@ -9740,7 +9929,26 @@ md_estimate_size_before_relax (fragp, segtype)
     }
   else if (mips_pic == SVR4_PIC)
     {
-      asection *symsec = fragp->fr_symbol->bsym->section;
+      symbolS *sym;
+      asection *symsec;
+
+      sym = fragp->fr_symbol;
+
+      /* Handle the case of a symbol equated to another symbol.  */
+      while (sym->sy_value.X_op == O_symbol
+            && (! 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;
+         if (n == sym)
+           break;
+         sym = n;
+       }
+
+      symsec = S_GET_SEGMENT (sym);
 
       /* This must duplicate the test in adjust_reloc_syms.  */
       change = (symsec != &bfd_und_section
@@ -9787,7 +9995,8 @@ mips_fix_adjustable (fixp)
     return 1;
 #ifdef S_GET_OTHER
   if (OUTPUT_FLAVOR == bfd_target_elf_flavour
-      && S_GET_OTHER (fixp->fx_addsy) == STO_MIPS16)
+      && S_GET_OTHER (fixp->fx_addsy) == STO_MIPS16
+      && fixp->fx_subsy == NULL)
     return 0;
 #endif
   return 1;
@@ -10195,33 +10404,6 @@ mips_define_label (sym)
   l->next = insn_labels;
   insn_labels = l;
 }
-
-/* Decide whether a label is local.  This is called by LOCAL_LABEL.
-   In order to work with gcc when using mips-tfile, we must keep all
-   local labels.  However, in other cases, we want to discard them,
-   since they are useless.  */
-
-int
-mips_local_label (name)
-     const char *name;
-{
-#ifndef NO_ECOFF_DEBUGGING
-  if (ECOFF_DEBUGGING
-      && mips_debug != 0
-      && ! ecoff_debugging_seen)
-    {
-      /* We were called with -g, but we didn't see any debugging
-         information.  That may mean that gcc is smuggling debugging
-         information through to mips-tfile, in which case we must
-         generate all local labels.  */
-      return 0;
-    }
-#endif
-
-  /* Here it's OK to discard local labels.  */
-
-  return name[0] == '$';
-}
 \f
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)