Add r3900 support.
authorGavin Romig-Koch <gavin@redhat.com>
Mon, 2 Jun 1997 15:56:00 +0000 (15:56 +0000)
committerGavin Romig-Koch <gavin@redhat.com>
Mon, 2 Jun 1997 15:56:00 +0000 (15:56 +0000)
gas/ChangeLog
gas/config/tc-mips.c

index fe40435b8b97591cb868fbbbc79645b834d8ed07..0416606129dd3048894c04a802e67d77e04c2b66 100644 (file)
@@ -1,3 +1,7 @@
+Mon Jun  2 11:55:12 1997  Gavin Koch  <gavin@cygnus.com>
+
+       * config/tc-mips.c: Added r3900 support.
+
 Thu May 29 12:58:26 1997  Ben Pfaff  <pfaffben@pilot.msu.edu>
 
        * as.c: (parse_args) `-t' option requires an argument.
index 61623aed9ce237ed2dc3e3db41735a99dacd8ef2..5e92c7334bf22b90844ca6e6e39c2bcedcc97c97 100644 (file)
@@ -204,11 +204,20 @@ static int mips_4100 = -1;
 static int mips_5900 = -1;
 /* end-sanitize-r5900 */
 
-/* Whether the processor uses hardware interlocks, and thus does not
+/* Whether Toshiba r3900 instructions are permitted. */
+static int mips_3900 = -1;
+
+/* Whether the processor uses hardware interlocks to protect 
+   reads from the HI and LO registers, and thus does not
+   require nops to be inserted.  */
+static int hilo_interlocks = -1;
+
+/* Whether the processor uses hardware interlocks to protect 
+   reads from the GPRs, and thus does not
    require nops to be inserted.  */
-static int interlocks = -1;
+static int gpr_interlocks = -1;
 
-/* As with "interlocks" this is used by hardware that has FP
+/* As with other "interlocks" this is used by hardware that has FP
    (co-processor) interlocks.  */
 /* Itbl support may require additional care here. */
 static int cop_interlocks = -1;
@@ -787,6 +796,15 @@ md_begin ()
          if (mips_cpu == -1)
            mips_cpu = 3000;
        }
+      else if (strcmp (cpu, "r3900") == 0
+               || strcmp (cpu, "mipsr3900") == 0)
+       {
+         mips_opts.isa = 1;
+         if (mips_cpu == -1)
+           mips_cpu = 3900;
+          if (mips_3900 == -1)
+            mips_3900 = 1;
+       }
       else if (strcmp (cpu, "r6000") == 0
               || strcmp (cpu, "mips2") == 0)
        {
@@ -916,10 +934,23 @@ md_begin ()
     mips_5900 = 0;
   /* end-sanitize-r5900 */
 
-  if (mips_4010 || mips_cpu == 4300)
-    interlocks = 1;
+  if (mips_3900 < 0)
+    mips_3900 = 0;
+  
+  if (mips_4010 
+      || mips_cpu == 4300 
+      || mips_3900
+      )
+    hilo_interlocks = 1;
   else
-    interlocks = 0;
+    hilo_interlocks = 0;
+
+  if (mips_opts.isa >= 2 
+      || mips_3900
+      )
+    gpr_interlocks = 1;
+  else
+    gpr_interlocks = 0;
 
   /* Itbl support may require additional care here. */
   if (mips_cpu == 4300)
@@ -1273,7 +1304,7 @@ reg_needs_delay (reg)
   if (! mips_opts.noreorder
       && mips_opts.isa < 4
       && ((prev_pinfo & INSN_LOAD_COPROC_DELAY)
-         || (mips_opts.isa < 2
+         || (! gpr_interlocks
              && (prev_pinfo & INSN_LOAD_MEMORY_DELAY))))
     {
       /* A load from a coprocessor or from memory.  All load
@@ -1377,7 +1408,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
          && mips_opts.isa < 4
          && (((prev_pinfo & INSN_LOAD_COPROC_DELAY)
                && ! cop_interlocks)
-             || (mips_opts.isa < 2
+             || (! gpr_interlocks
                  && (prev_pinfo & INSN_LOAD_MEMORY_DELAY))))
        {
          /* A load from a coprocessor or from memory.  All load
@@ -1472,7 +1503,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
          /* The previous instruction reads the LO register; if the
             current instruction writes to the LO register, we must
             insert two NOPS.  Some newer processors have interlocks.  */
-         if (! interlocks
+         if (! hilo_interlocks
              && (mips_optimize == 0
                  || (pinfo & INSN_WRITE_LO)))
            nops += 2;
@@ -1482,7 +1513,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
          /* The previous instruction reads the HI register; if the
             current instruction writes to the HI register, we must
             insert a NOP.  Some newer processors have interlocks.  */
-         if (! interlocks
+         if (! hilo_interlocks
              && (mips_optimize == 0
                  || (pinfo & INSN_WRITE_HI)))
            nops += 2;
@@ -1510,10 +1541,10 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
           && ! cop_interlocks)
          || ((prev_prev_insn.insn_mo->pinfo & INSN_READ_LO)
              && (pinfo & INSN_WRITE_LO)
-             && ! interlocks)
+             && ! hilo_interlocks)
          || ((prev_prev_insn.insn_mo->pinfo & INSN_READ_HI)
              && (pinfo & INSN_WRITE_HI)
-             && ! interlocks))
+             && ! hilo_interlocks))
        prev_prev_nop = 1;
       else
        prev_prev_nop = 0;
@@ -1862,16 +1893,17 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                      & (INSN_LOAD_COPROC_DELAY
                         | INSN_COPROC_MOVE_DELAY
                         | INSN_WRITE_COND_CODE)))
-             || (! interlocks
+             || (! hilo_interlocks
                  && (prev_pinfo
                      & (INSN_READ_LO
                         | INSN_READ_HI)))
+             || (! mips_opts.mips16
+                 && ! gpr_interlocks
+                 && (prev_pinfo & INSN_LOAD_MEMORY_DELAY))
              || (! mips_opts.mips16
                  && mips_opts.isa < 2
-                 && (prev_pinfo
-                     & (INSN_LOAD_MEMORY_DELAY
-              /* Itbl support may require additional care here. */
-                        | INSN_COPROC_MEMORY_DELAY)))
+                  /* Itbl support may require additional care here. */
+                 && (prev_pinfo & INSN_COPROC_MEMORY_DELAY))
              /* We can not swap with a branch instruction.  */
              || (prev_pinfo
                  & (INSN_UNCOND_BRANCH_DELAY
@@ -1977,7 +2009,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
                  && mips_opts.isa < 4
               /* Itbl support may require additional care here. */
                  && ((prev_prev_insn.insn_mo->pinfo & INSN_LOAD_COPROC_DELAY)
-                     || (mips_opts.isa < 2
+                     || (! gpr_interlocks
                          && (prev_prev_insn.insn_mo->pinfo
                              & INSN_LOAD_MEMORY_DELAY)))
                  && insn_uses_reg (ip,
@@ -2183,15 +2215,18 @@ mips_emit_delays (insns)
                    & (INSN_LOAD_COPROC_DELAY
                       | INSN_COPROC_MOVE_DELAY
                       | INSN_WRITE_COND_CODE))))
-         || (! interlocks
+         || (! hilo_interlocks
              && (prev_insn.insn_mo->pinfo
                  & (INSN_READ_LO
                     | INSN_READ_HI)))
+         || (! mips_opts.mips16
+             && ! gpr_interlocks
+             && (prev_insn.insn_mo->pinfo 
+                  & INSN_LOAD_MEMORY_DELAY))
          || (! mips_opts.mips16
              && mips_opts.isa < 2
              && (prev_insn.insn_mo->pinfo
-                 & (INSN_LOAD_MEMORY_DELAY
-                    | INSN_COPROC_MEMORY_DELAY))))
+                 & INSN_COPROC_MEMORY_DELAY)))
        {
           /* Itbl support may require additional care here. */
          ++nops;
@@ -2199,7 +2234,7 @@ mips_emit_delays (insns)
               && mips_opts.isa < 4
               && (! cop_interlocks
                    && prev_insn.insn_mo->pinfo & INSN_WRITE_COND_CODE))
-             || (! interlocks
+             || (! hilo_interlocks
                  && ((prev_insn.insn_mo->pinfo & INSN_READ_HI)
                      || (prev_insn.insn_mo->pinfo & INSN_READ_LO))))
            ++nops;
@@ -2211,7 +2246,7 @@ mips_emit_delays (insns)
                && mips_opts.isa < 4
                && (! cop_interlocks
                     && prev_prev_insn.insn_mo->pinfo & INSN_WRITE_COND_CODE))
-              || (! interlocks
+              || (! hilo_interlocks
                   && ((prev_prev_insn.insn_mo->pinfo & INSN_READ_HI)
                       || (prev_prev_insn.insn_mo->pinfo & INSN_READ_LO))))
        {
@@ -2324,20 +2359,22 @@ macro_build (place, counter, ep, name, fmt, va_alist)
 
   while (strcmp (fmt, insn.insn_mo->args) != 0
         || insn.insn_mo->pinfo == INSN_MACRO
-        || ((insn.insn_mo->pinfo & INSN_ISA) == INSN_ISA2
+        || ((insn.insn_mo->membership & INSN_ISA) == INSN_ISA2
             && mips_opts.isa < 2)
-        || ((insn.insn_mo->pinfo & INSN_ISA) == INSN_ISA3
+        || ((insn.insn_mo->membership & INSN_ISA) == INSN_ISA3
             && mips_opts.isa < 3)
-        || ((insn.insn_mo->pinfo & INSN_ISA) == INSN_ISA4
+        || ((insn.insn_mo->membership & INSN_ISA) == INSN_ISA4
             && mips_opts.isa < 4)
-        || ((insn.insn_mo->pinfo & INSN_ISA) == INSN_4650
+         || ((insn.insn_mo->membership & INSN_ISA) == INSN_3900
+            && ! mips_3900)
+         || ((insn.insn_mo->membership & INSN_ISA) == INSN_4650
             && ! mips_4650)
-        || ((insn.insn_mo->pinfo & INSN_ISA) == INSN_4010
+        || ((insn.insn_mo->membership & INSN_ISA) == INSN_4010
             && ! mips_4010)
-        || ((insn.insn_mo->pinfo & INSN_ISA) == INSN_4100
+        || ((insn.insn_mo->membership & INSN_ISA) == INSN_4100
             && ! mips_4100)
         /* start-sanitize-r5900 */
-         || ((insn.insn_mo->pinfo & INSN_ISA) == INSN_5900
+         || ((insn.insn_mo->membership & INSN_ISA) == INSN_5900
             && ! mips_5900)
          /* end-sanitize-r5900 */
          )
@@ -2679,7 +2716,9 @@ set_at (counter, reg, unsignedp)
      int reg;
      int unsignedp;
 {
-  if (imm_expr.X_add_number >= -0x8000 && imm_expr.X_add_number < 0x8000)
+  if (imm_expr.X_op == O_constant
+      && imm_expr.X_add_number >= -0x8000
+      && imm_expr.X_add_number < 0x8000)
     macro_build ((char *) NULL, counter, &imm_expr,
                 unsignedp ? "sltiu" : "slti",
                 "t,r,j", AT, reg, (int) BFD_RELOC_LO16);
@@ -2699,7 +2738,9 @@ check_absolute_expr (ip, ex)
      struct mips_cl_insn *ip;
      expressionS *ex;
 {
-  if (ex->X_op != O_constant)
+  if (ex->X_op == O_big)
+    as_bad ("unsupported large constant");
+  else if (ex->X_op != O_constant)
     as_warn ("Instruction %s requires absolute expression", ip->insn_mo->name);
 }
 
@@ -3305,7 +3346,9 @@ macro (ip)
       s = "daddiu";
       s2 = "daddu";
     do_addi:
-      if (imm_expr.X_add_number >= -0x8000 && imm_expr.X_add_number < 0x8000)
+      if (imm_expr.X_op == O_constant
+         && imm_expr.X_add_number >= -0x8000
+         && imm_expr.X_add_number < 0x8000)
        {
          macro_build ((char *) NULL, &icnt, &imm_expr, s, "t,r,j", treg, sreg,
                       (int) BFD_RELOC_LO16);
@@ -3331,7 +3374,9 @@ macro (ip)
       s = "xori";
       s2 = "xor";
     do_bit:
-      if (imm_expr.X_add_number >= 0 && imm_expr.X_add_number < 0x10000)
+      if (imm_expr.X_op == O_constant
+         && imm_expr.X_add_number >= 0
+         && imm_expr.X_add_number < 0x10000)
        {
          if (mask != M_NOR_I)
            macro_build ((char *) NULL, &icnt, &imm_expr, s, "t,r,i", treg,
@@ -3364,7 +3409,7 @@ macro (ip)
       s = "bnel";
       likely = 1;
     beq_i:
-      if (imm_expr.X_add_number == 0)
+      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr, s, "s,t,p", sreg,
                       0);
@@ -3402,14 +3447,15 @@ macro (ip)
     case M_BGT_I:
       /* check for > max integer */
       maxnum = 0x7fffffff;
-      if (mips_opts.isa >= 3)
+      if (mips_opts.isa >= 3 && sizeof (maxnum) > 4)
        {
          maxnum <<= 16;
          maxnum |= 0xffff;
          maxnum <<= 16;
          maxnum |= 0xffff;
        }
-      if (imm_expr.X_add_number >= maxnum
+      if (imm_expr.X_op == O_constant
+         && imm_expr.X_add_number >= maxnum
          && (mips_opts.isa < 3 || sizeof (maxnum) > 4))
        {
        do_false:
@@ -3427,20 +3473,22 @@ macro (ip)
            }
          return;
        }
+      if (imm_expr.X_op != O_constant)
+       as_bad ("Unsupported large constant");
       imm_expr.X_add_number++;
       /* FALLTHROUGH */
     case M_BGE_I:
     case M_BGEL_I:
       if (mask == M_BGEL_I)
        likely = 1;
-      if (imm_expr.X_add_number == 0)
+      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
                       likely ? "bgezl" : "bgez",
                       "s,p", sreg);
          return;
        }
-      if (imm_expr.X_add_number == 1)
+      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
                       likely ? "bgtzl" : "bgtz",
@@ -3448,7 +3496,7 @@ macro (ip)
          return;
        }
       maxnum = 0x7fffffff;
-      if (mips_opts.isa >= 3)
+      if (mips_opts.isa >= 3 && sizeof (maxnum) > 4)
        {
          maxnum <<= 16;
          maxnum |= 0xffff;
@@ -3456,7 +3504,8 @@ macro (ip)
          maxnum |= 0xffff;
        }
       maxnum = - maxnum - 1;
-      if (imm_expr.X_add_number <= maxnum
+      if (imm_expr.X_op == O_constant
+         && imm_expr.X_add_number <= maxnum
          && (mips_opts.isa < 3 || sizeof (maxnum) > 4))
        {
        do_true:
@@ -3493,17 +3542,22 @@ macro (ip)
     case M_BGTUL_I:
       likely = 1;
     case M_BGTU_I:
-      if (sreg == 0 || imm_expr.X_add_number == -1)
+      if (sreg == 0
+         || (mips_opts.isa < 3
+             && imm_expr.X_op == O_constant
+             && imm_expr.X_add_number == 0xffffffff))
        goto do_false;
+      if (imm_expr.X_op != O_constant)
+       as_bad ("Unsupported large constant");
       imm_expr.X_add_number++;
       /* FALLTHROUGH */
     case M_BGEU_I:
     case M_BGEUL_I:
       if (mask == M_BGEUL_I)
        likely = 1;
-      if (imm_expr.X_add_number == 0)
+      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        goto do_true;
-      if (imm_expr.X_add_number == 1)
+      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
                       likely ? "bnel" : "bne",
@@ -3585,30 +3639,33 @@ macro (ip)
       likely = 1;
     case M_BLE_I:
       maxnum = 0x7fffffff;
-      if (mips_opts.isa >= 3)
+      if (mips_opts.isa >= 3 && sizeof (maxnum) > 4)
        {
          maxnum <<= 16;
          maxnum |= 0xffff;
          maxnum <<= 16;
          maxnum |= 0xffff;
        }
-      if (imm_expr.X_add_number >= maxnum
+      if (imm_expr.X_op == O_constant
+         && imm_expr.X_add_number >= maxnum
          && (mips_opts.isa < 3 || sizeof (maxnum) > 4))
        goto do_true;
+      if (imm_expr.X_op != O_constant)
+       as_bad ("Unsupported large constant");
       imm_expr.X_add_number++;
       /* FALLTHROUGH */
     case M_BLT_I:
     case M_BLTL_I:
       if (mask == M_BLTL_I)
        likely = 1;
-      if (imm_expr.X_add_number == 0)
+      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
                       likely ? "bltzl" : "bltz",
                       "s,p", sreg);
          return;
        }
-      if (imm_expr.X_add_number == 1)
+      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
                       likely ? "blezl" : "blez",
@@ -3643,17 +3700,22 @@ macro (ip)
     case M_BLEUL_I:
       likely = 1;
     case M_BLEU_I:
-      if (sreg == 0 || imm_expr.X_add_number == -1)
+      if (sreg == 0
+         || (mips_opts.isa < 3
+             && imm_expr.X_op == O_constant
+             && imm_expr.X_add_number == 0xffffffff))
        goto do_true;
+      if (imm_expr.X_op != O_constant)
+       as_bad ("Unsupported large constant");
       imm_expr.X_add_number++;
       /* FALLTHROUGH */
     case M_BLTU_I:
     case M_BLTUL_I:
       if (mask == M_BLTUL_I)
        likely = 1;
-      if (imm_expr.X_add_number == 0)
+      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        goto do_false;
-      if (imm_expr.X_add_number == 1)
+      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
        {
          macro_build ((char *) NULL, &icnt, &offset_expr,
                       likely ? "beql" : "beq",
@@ -3812,7 +3874,7 @@ macro (ip)
       s = "ddivu";
       s2 = "mfhi";
     do_divi:
-      if (imm_expr.X_add_number == 0)
+      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        {
          as_warn ("Divide by zero.");
          if (mips_trap)
@@ -3821,7 +3883,7 @@ macro (ip)
            macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7);
          return;
        }
-      if (imm_expr.X_add_number == 1)
+      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
        {
          if (strcmp (s2, "mflo") == 0)
            macro_build ((char *) NULL, &icnt, NULL, "move", "d,s", dreg,
@@ -3830,7 +3892,8 @@ macro (ip)
            macro_build ((char *) NULL, &icnt, NULL, "move", "d,s", dreg, 0);
          return;
        }
-      if (imm_expr.X_add_number == -1
+      if (imm_expr.X_op == O_constant
+         && imm_expr.X_add_number == -1
          && s[strlen (s) - 1] != 'u')
        {
          if (strcmp (s2, "mflo") == 0)
@@ -5636,6 +5699,8 @@ macro2 (ip)
       break;
 
     case M_ROL_I:
+      if (imm_expr.X_op != O_constant)
+       as_bad ("rotate count too large");
       macro_build ((char *) NULL, &icnt, NULL, "sll", "d,w,<", AT, sreg,
                   (int) (imm_expr.X_add_number & 0x1f));
       macro_build ((char *) NULL, &icnt, NULL, "srl", "d,w,<", dreg, sreg,
@@ -5652,6 +5717,8 @@ macro2 (ip)
       break;
 
     case M_ROR_I:
+      if (imm_expr.X_op != O_constant)
+       as_bad ("rotate count too large");
       macro_build ((char *) NULL, &icnt, NULL, "srl", "d,w,<", AT, sreg,
                   (int) (imm_expr.X_add_number & 0x1f));
       macro_build ((char *) NULL, &icnt, NULL, "sll", "d,w,<", dreg, sreg,
@@ -5689,7 +5756,7 @@ macro2 (ip)
       return;
 
     case M_SEQ_I:
-      if (imm_expr.X_add_number == 0)
+      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        {
          macro_build ((char *) NULL, &icnt, &expr1, "sltiu", "t,r,j", dreg,
                       sreg, (int) BFD_RELOC_LO16);
@@ -5702,13 +5769,17 @@ macro2 (ip)
          macro_build ((char *) NULL, &icnt, NULL, "move", "d,s", dreg, 0);
          return;
        }
-      if (imm_expr.X_add_number >= 0 && imm_expr.X_add_number < 0x10000)
+      if (imm_expr.X_op == O_constant
+         && imm_expr.X_add_number >= 0
+         && imm_expr.X_add_number < 0x10000)
        {
          macro_build ((char *) NULL, &icnt, &imm_expr, "xori", "t,r,i", dreg,
                       sreg, (int) BFD_RELOC_LO16);
          used_at = 0;
        }
-      else if (imm_expr.X_add_number > -0x8000 && imm_expr.X_add_number < 0)
+      else if (imm_expr.X_op == O_constant
+              && imm_expr.X_add_number > -0x8000
+              && imm_expr.X_add_number < 0)
        {
          imm_expr.X_add_number = -imm_expr.X_add_number;
          macro_build ((char *) NULL, &icnt, &imm_expr,
@@ -5743,7 +5814,9 @@ macro2 (ip)
 
     case M_SGE_I:              /* sreg >= I <==> not (sreg < I) */
     case M_SGEU_I:
-      if (imm_expr.X_add_number >= -0x8000 && imm_expr.X_add_number < 0x8000)
+      if (imm_expr.X_op == O_constant
+         && imm_expr.X_add_number >= -0x8000
+         && imm_expr.X_add_number < 0x8000)
        {
          macro_build ((char *) NULL, &icnt, &expr1,
                       mask == M_SGE_I ? "slti" : "sltiu",
@@ -5807,7 +5880,9 @@ macro2 (ip)
       break;
 
     case M_SLT_I:
-      if (imm_expr.X_add_number >= -0x8000 && imm_expr.X_add_number < 0x8000)
+      if (imm_expr.X_op == O_constant
+         && imm_expr.X_add_number >= -0x8000
+         && imm_expr.X_add_number < 0x8000)
        {
          macro_build ((char *) NULL, &icnt, &imm_expr, "slti", "t,r,j",
                       dreg, sreg, (int) BFD_RELOC_LO16);
@@ -5818,7 +5893,9 @@ macro2 (ip)
       break;
 
     case M_SLTU_I:
-      if (imm_expr.X_add_number >= -0x8000 && imm_expr.X_add_number < 0x8000)
+      if (imm_expr.X_op == O_constant
+         && imm_expr.X_add_number >= -0x8000
+         && imm_expr.X_add_number < 0x8000)
        {
          macro_build ((char *) NULL, &icnt, &imm_expr, "sltiu", "t,r,j",
                       dreg, sreg, (int) BFD_RELOC_LO16);
@@ -5846,7 +5923,7 @@ macro2 (ip)
       return;
 
     case M_SNE_I:
-      if (imm_expr.X_add_number == 0)
+      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        {
          macro_build ((char *) NULL, &icnt, NULL, "sltu", "d,v,t", dreg, 0,
                       sreg);
@@ -5861,13 +5938,17 @@ macro2 (ip)
                       "t,r,j", dreg, 0, (int) BFD_RELOC_LO16);
          return;
        }
-      if (imm_expr.X_add_number >= 0 && imm_expr.X_add_number < 0x10000)
+      if (imm_expr.X_op == O_constant
+         && imm_expr.X_add_number >= 0
+         && imm_expr.X_add_number < 0x10000)
        {
          macro_build ((char *) NULL, &icnt, &imm_expr, "xori", "t,r,i",
                       dreg, sreg, (int) BFD_RELOC_LO16);
          used_at = 0;
        }
-      else if (imm_expr.X_add_number > -0x8000 && imm_expr.X_add_number < 0)
+      else if (imm_expr.X_op == O_constant
+              && imm_expr.X_add_number > -0x8000
+              && imm_expr.X_add_number < 0)
        {
          imm_expr.X_add_number = -imm_expr.X_add_number;
          macro_build ((char *) NULL, &icnt, &imm_expr,
@@ -5890,7 +5971,9 @@ macro2 (ip)
     case M_DSUB_I:
       dbl = 1;
     case M_SUB_I:
-      if (imm_expr.X_add_number > -0x8000 && imm_expr.X_add_number <= 0x8000)
+      if (imm_expr.X_op == O_constant
+         && imm_expr.X_add_number > -0x8000
+         && imm_expr.X_add_number <= 0x8000)
        {
          imm_expr.X_add_number = -imm_expr.X_add_number;
          macro_build ((char *) NULL, &icnt, &imm_expr,
@@ -5907,7 +5990,9 @@ macro2 (ip)
     case M_DSUBU_I:
       dbl = 1;
     case M_SUBU_I:
-      if (imm_expr.X_add_number > -0x8000 && imm_expr.X_add_number <= 0x8000)
+      if (imm_expr.X_op == O_constant
+         && imm_expr.X_add_number > -0x8000
+         && imm_expr.X_add_number <= 0x8000)
        {
          imm_expr.X_add_number = -imm_expr.X_add_number;
          macro_build ((char *) NULL, &icnt, &imm_expr,
@@ -6284,6 +6369,8 @@ mips16_macro (ip)
       goto do_subu;
     case M_SUBU_I:
     do_subu:
+      if (imm_expr.X_op != O_constant)
+       as_bad ("Unsupported large constant");
       imm_expr.X_add_number = -imm_expr.X_add_number;
       macro_build ((char *) NULL, &icnt, &imm_expr,
                   dbl ? "daddiu" : "addiu",
@@ -6291,12 +6378,16 @@ mips16_macro (ip)
       break;
 
     case M_SUBU_I_2:
+      if (imm_expr.X_op != O_constant)
+       as_bad ("Unsupported large constant");
       imm_expr.X_add_number = -imm_expr.X_add_number;
       macro_build ((char *) NULL, &icnt, &imm_expr, "addiu",
                   "x,k", xreg);
       break;
 
     case M_DSUBU_I_2:
+      if (imm_expr.X_op != O_constant)
+       as_bad ("Unsupported large constant");
       imm_expr.X_add_number = -imm_expr.X_add_number;
       macro_build ((char *) NULL, &icnt, &imm_expr, "daddiu",
                   "y,j", yreg);
@@ -6404,6 +6495,8 @@ mips16_macro (ip)
       s3 = "x,8";
 
     do_addone_branch_i:
+      if (imm_expr.X_op != O_constant)
+       as_bad ("Unsupported large constant");
       ++imm_expr.X_add_number;
 
     do_branch_i:
@@ -6464,28 +6557,30 @@ mips_ip (str, ip)
 
       if (insn->pinfo == INSN_MACRO)
        insn_isa = insn->match;
-      else if ((insn->pinfo & INSN_ISA) == INSN_ISA2)
+      else if ((insn->membership & INSN_ISA) == INSN_ISA2)
        insn_isa = 2;
-      else if ((insn->pinfo & INSN_ISA) == INSN_ISA3)
+      else if ((insn->membership & INSN_ISA) == INSN_ISA3)
        insn_isa = 3;
-      else if ((insn->pinfo & INSN_ISA) == INSN_ISA4)
+      else if ((insn->membership & INSN_ISA) == INSN_ISA4)
        insn_isa = 4;
       else
        insn_isa = 1;
 
       if (insn_isa > mips_opts.isa
          || (insn->pinfo != INSN_MACRO
-             && (((insn->pinfo & INSN_ISA) == INSN_4650
-                  && ! mips_4650)
-                 || ((insn->pinfo & INSN_ISA) == INSN_4010
+             && (((insn->membership & INSN_ISA) == INSN_4650
+                   && ! mips_4650)
+                 || ((insn->membership & INSN_ISA) == INSN_4010
                      && ! mips_4010)
-                 || ((insn->pinfo & INSN_ISA) == INSN_4100
+                 || ((insn->membership & INSN_ISA) == INSN_4100
                      && ! mips_4100)
                  /* start-sanitize-r5900 */
-                 || ((insn->pinfo & INSN_ISA) == INSN_5900
+                 || ((insn->membership & INSN_ISA) == INSN_5900
                      && ! mips_5900)
                  /* end-sanitize-r5900 */
-                 )))
+                  || ((insn->membership & INSN_ISA) == INSN_3900
+                     && ! mips_3900)
+                  )))
        {
          if (insn + 1 < &mips_opcodes[NUMOPCODES]
              && strcmp (insn->name, insn[1].name) == 0)
@@ -8224,6 +8319,11 @@ struct option md_longopts[] = {
 #define OPTION_NO_M5900 (OPTION_MD_BASE + 25)
   {"no-m5900", no_argument, NULL, OPTION_NO_M5900},
   /* end-sanitize-r5900 */
+#define OPTION_M3900 (OPTION_MD_BASE + 26)
+  {"m3900", no_argument, NULL, OPTION_M3900},
+#define OPTION_NO_M3900 (OPTION_MD_BASE + 27)
+  {"no-m3900", no_argument, NULL, OPTION_NO_M3900},
+  
 
 #define OPTION_CALL_SHARED (OPTION_MD_BASE + 7)
 #define OPTION_NON_SHARED (OPTION_MD_BASE + 8)
@@ -8355,6 +8455,8 @@ md_parse_option (c, arg)
                    || strcmp (p, "3k") == 0
                    || strcmp (p, "3K") == 0)
                  mips_cpu = 3000;
+                else if (strcmp (p, "3900") == 0)
+                  mips_cpu = 3900;
                break;
 
              case '4':
@@ -8468,6 +8570,14 @@ md_parse_option (c, arg)
       break;
       /* end-sanitize-r5900 */
 
+    case OPTION_M3900:
+      mips_3900 = 1;
+      break;
+      
+    case OPTION_NO_M3900:
+      mips_3900 = 0;
+      break;
+
     case OPTION_MIPS16:
       mips_opts.mips16 = 1;
       mips_no_prev_insn (false);