]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gas/config/tc-mn10200.c
* config/sh/tm-sh.h (BELIEVE_PCC_PROMOTION): Define, so that
[thirdparty/binutils-gdb.git] / gas / config / tc-mn10200.c
index dbca3befc57693704c14216325437a54180284e9..7bbc5725710e0bd538470bbe4ec5f61d93bda607 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-mn10200.c -- Assembler code for the Matsushita 10200
 
-   Copyright (C) 1996 Free Software Foundation.
+   Copyright (C) 1996, 1997 Free Software Foundation.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -53,6 +53,24 @@ const char EXP_CHARS[] = "eE";
 const char FLT_CHARS[] = "dD";
 \f
 
+const relax_typeS md_relax_table[] = {
+  /* bCC relaxing */
+  {0x7f, -0x80, 2, 1},
+  {0x7fff, -0x8000, 5, 2},
+  {0x7fffff, -0x8000000, 7, 0},
+  /* bCCx relaxing */
+  {0x7f, -0x80, 3, 4},
+  {0x7fff, -0x8000, 6, 5},
+  {0x7fffff, -0x8000000, 8, 0},
+  /* jsr relaxing */
+  {0x7fff, -0x8000, 3, 7},
+  {0x7fffff, -0x8000000, 5, 0},
+  /* jmp relaxing */
+  {0x7f, -0x80, 2, 9},
+  {0x7fff, -0x8000, 3, 10},
+  {0x7fffff, -0x8000000, 5, 0},
+
+};
 /* local functions */
 static void mn10200_insert_operand PARAMS ((unsigned long *, unsigned long *,
                                            const struct mn10200_operand *,
@@ -360,8 +378,338 @@ md_convert_frag (abfd, sec, fragP)
   asection *sec;
   fragS *fragP;
 {
-  /* printf ("call to md_convert_frag \n"); */
-  abort ();
+  subseg_change (sec, 0);
+  if (fragP->fr_subtype == 0)
+    {
+      fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol,
+              fragP->fr_offset + 1, 1, BFD_RELOC_8_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 2;
+    }
+  else if (fragP->fr_subtype == 1)
+    {
+      /* Reverse the condition of the first branch.  */
+      int offset = fragP->fr_fix;
+      int opcode = fragP->fr_literal[offset] & 0xff;
+
+      switch (opcode)
+       {
+       case 0xe8:
+         opcode = 0xe9;
+         break;
+       case 0xe9:
+         opcode = 0xe8;
+         break;
+       case 0xe0:
+         opcode = 0xe2;
+         break;
+       case 0xe2:
+         opcode = 0xe0;
+         break;
+       case 0xe3:
+         opcode = 0xe1;
+         break;
+       case 0xe1:
+         opcode = 0xe3;
+         break;
+       case 0xe4:
+         opcode = 0xe6;
+         break;
+       case 0xe6:
+         opcode = 0xe4;
+         break;
+       case 0xe7:
+         opcode = 0xe5;
+         break;
+       case 0xe5:
+         opcode = 0xe7;
+         break;
+       default:
+         abort ();
+       }
+      fragP->fr_literal[offset] = opcode;
+
+      /* Set the displacement bits so that we branch around
+        the unconditional branch.  */
+      fragP->fr_literal[offset + 1] = 0x5;
+
+      /* Now create the unconditional branch + fixup to the
+        final target.  */
+      fragP->fr_literal[offset + 2] = 0xfc;
+      fix_new (fragP, fragP->fr_fix + 3, 2, fragP->fr_symbol,
+              fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 5;
+    }
+  else if (fragP->fr_subtype == 2)
+    {
+      /* Reverse the condition of the first branch.  */
+      int offset = fragP->fr_fix;
+      int opcode = fragP->fr_literal[offset] & 0xff;
+
+      switch (opcode)
+       {
+       case 0xe8:
+         opcode = 0xe9;
+         break;
+       case 0xe9:
+         opcode = 0xe8;
+         break;
+       case 0xe0:
+         opcode = 0xe2;
+         break;
+       case 0xe2:
+         opcode = 0xe0;
+         break;
+       case 0xe3:
+         opcode = 0xe1;
+         break;
+       case 0xe1:
+         opcode = 0xe3;
+         break;
+       case 0xe4:
+         opcode = 0xe6;
+         break;
+       case 0xe6:
+         opcode = 0xe4;
+         break;
+       case 0xe7:
+         opcode = 0xe5;
+         break;
+       case 0xe5:
+         opcode = 0xe7;
+         break;
+       default:
+         abort ();
+       }
+      fragP->fr_literal[offset] = opcode;
+
+      /* Set the displacement bits so that we branch around
+        the unconditional branch.  */
+      fragP->fr_literal[offset + 1] = 0x7;
+
+      /* Now create the unconditional branch + fixup to the
+        final target.  */
+      fragP->fr_literal[offset + 2] = 0xf4;
+      fragP->fr_literal[offset + 3] = 0xe0;
+      fix_new (fragP, fragP->fr_fix + 4, 4, fragP->fr_symbol,
+              fragP->fr_offset + 2, 1, BFD_RELOC_24_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 7;
+    }
+  else if (fragP->fr_subtype == 3)
+    {
+      fix_new (fragP, fragP->fr_fix + 2, 1, fragP->fr_symbol,
+              fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 3;
+    }
+  else if (fragP->fr_subtype == 4)
+    {
+      /* Reverse the condition of the first branch.  */
+      int offset = fragP->fr_fix;
+      int opcode = fragP->fr_literal[offset + 1] & 0xff;
+
+      switch (opcode)
+       {
+       case 0xfc:
+         opcode = 0xfd;
+         break;
+       case 0xfd:
+         opcode = 0xfc;
+         break;
+       case 0xfe:
+         opcode = 0xff;
+         break;
+       case 0xff:
+         opcode = 0xfe;
+       case 0xe8:
+         opcode = 0xe9;
+         break;
+       case 0xe9:
+         opcode = 0xe8;
+         break;
+       case 0xe0:
+         opcode = 0xe2;
+         break;
+       case 0xe2:
+         opcode = 0xe0;
+         break;
+       case 0xe3:
+         opcode = 0xe1;
+         break;
+       case 0xe1:
+         opcode = 0xe3;
+         break;
+       case 0xe4:
+         opcode = 0xe6;
+         break;
+       case 0xe6:
+         opcode = 0xe4;
+         break;
+       case 0xe7:
+         opcode = 0xe5;
+         break;
+       case 0xe5:
+         opcode = 0xe7;
+         break;
+       case 0xec:
+         opcode = 0xed;
+         break;
+       case 0xed:
+         opcode = 0xec;
+         break;
+       case 0xee:
+         opcode = 0xef;
+         break;
+       case 0xef:
+         opcode = 0xee;
+         break;
+       default:
+         abort ();
+       }
+      fragP->fr_literal[offset + 1] = opcode;
+
+      /* Set the displacement bits so that we branch around
+        the unconditional branch.  */
+      fragP->fr_literal[offset + 2] = 0x6;
+
+      /* Now create the unconditional branch + fixup to the
+        final target.  */
+      fragP->fr_literal[offset + 3] = 0xfc;
+      fix_new (fragP, fragP->fr_fix + 4, 2, fragP->fr_symbol,
+              fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 6;
+    }
+  else if (fragP->fr_subtype == 5)
+    {
+      /* Reverse the condition of the first branch.  */
+      int offset = fragP->fr_fix;
+      int opcode = fragP->fr_literal[offset + 1] & 0xff;
+
+      switch (opcode)
+       {
+       case 0xfc:
+         opcode = 0xfd;
+         break;
+       case 0xfd:
+         opcode = 0xfc;
+         break;
+       case 0xfe:
+         opcode = 0xff;
+         break;
+       case 0xff:
+         opcode = 0xfe;
+       case 0xe8:
+         opcode = 0xe9;
+         break;
+       case 0xe9:
+         opcode = 0xe8;
+         break;
+       case 0xe0:
+         opcode = 0xe2;
+         break;
+       case 0xe2:
+         opcode = 0xe0;
+         break;
+       case 0xe3:
+         opcode = 0xe1;
+         break;
+       case 0xe1:
+         opcode = 0xe3;
+         break;
+       case 0xe4:
+         opcode = 0xe6;
+         break;
+       case 0xe6:
+         opcode = 0xe4;
+         break;
+       case 0xe7:
+         opcode = 0xe5;
+         break;
+       case 0xe5:
+         opcode = 0xe7;
+         break;
+       case 0xec:
+         opcode = 0xed;
+         break;
+       case 0xed:
+         opcode = 0xec;
+         break;
+       case 0xee:
+         opcode = 0xef;
+         break;
+       case 0xef:
+         opcode = 0xee;
+         break;
+       default:
+         abort ();
+       }
+      fragP->fr_literal[offset + 1] = opcode;
+
+      /* Set the displacement bits so that we branch around
+        the unconditional branch.  */
+      fragP->fr_literal[offset + 2] = 0x8;
+
+      /* Now create the unconditional branch + fixup to the
+        final target.  */
+      fragP->fr_literal[offset + 3] = 0xf4;
+      fragP->fr_literal[offset + 4] = 0xe0;
+      fix_new (fragP, fragP->fr_fix + 5, 4, fragP->fr_symbol,
+              fragP->fr_offset + 2, 1, BFD_RELOC_24_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 8;
+    }
+  else if (fragP->fr_subtype == 6)
+    {
+      fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol,
+              fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 3;
+    }
+  else if (fragP->fr_subtype == 7)
+    {
+      int offset = fragP->fr_fix;
+      fragP->fr_literal[offset] = 0xf4;
+      fragP->fr_literal[offset + 1] = 0xe1;
+
+      fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol,
+              fragP->fr_offset + 2, 1, BFD_RELOC_24_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 5;
+    }
+  else if (fragP->fr_subtype == 8)
+    {
+      fragP->fr_literal[fragP->fr_fix] = 0xea;
+      fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol,
+              fragP->fr_offset + 1, 1, BFD_RELOC_8_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 2;
+    }
+  else if (fragP->fr_subtype == 9)
+    {
+      int offset = fragP->fr_fix;
+      fragP->fr_literal[offset] = 0xfc;
+
+      fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
+              fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 3;
+    }
+  else if (fragP->fr_subtype == 10)
+    {
+      int offset = fragP->fr_fix;
+      fragP->fr_literal[offset] = 0xf4;
+      fragP->fr_literal[offset + 1] = 0xe0;
+
+      fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol,
+              fragP->fr_offset + 2, 1, BFD_RELOC_24_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 5;
+    }
+  else
+    abort ();
 }
 
 valueT
@@ -411,7 +759,7 @@ md_assemble (str)
   struct mn10200_opcode *opcode;
   struct mn10200_opcode *next_opcode;
   const unsigned char *opindex_ptr;
-  int next_opindex;
+  int next_opindex, relaxable;
   unsigned long insn, extension, size = 0;
   char *f;
   int i;
@@ -444,6 +792,7 @@ md_assemble (str)
       char *hold;
       int extra_shift = 0;
 
+      relaxable = 0;
       fc = 0;
       match = 0;
       next_opindex = 0;
@@ -471,6 +820,9 @@ md_assemble (str)
          while (*str == ' ' || *str == ',')
            ++str;
 
+         if (operand->flags & MN10200_OPERAND_RELAX)
+           relaxable = 1;
+
          /* Gather the operand. */
          hold = input_line_pointer;
          input_line_pointer = str;
@@ -649,7 +1001,7 @@ keep_going:
       if (match == 0)
         {
          next_opcode = opcode + 1;
-         if (next_opcode->opcode != 0 && !strcmp(next_opcode->name, opcode->name))
+         if (!strcmp(next_opcode->name, opcode->name))
            {
              opcode = next_opcode;
              continue;
@@ -684,135 +1036,151 @@ keep_going:
          
   /* Write out the instruction.  */
 
-  f = frag_more (size);
-
-  /* Oh, what a mess.  The instruction is in big endian format, but
-     16 and 24bit immediates are little endian!  */
-  if (opcode->format == FMT_3)
+  if (relaxable && fc > 0)
     {
-      number_to_chars_bigendian (f, (insn >> 16) & 0xff, 1);
-      number_to_chars_littleendian (f + 1, insn & 0xffff, 2);
-    }
-  else if (opcode->format == FMT_6)
-    {
-      number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
-      number_to_chars_littleendian (f + 2, insn & 0xffff, 2);
-    }
-  else if (opcode->format == FMT_7)
-    {
-      number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
-      number_to_chars_littleendian (f + 2, insn & 0xffff, 2);
-      number_to_chars_littleendian (f + 4, extension & 0xff, 1);
+      int type;
+
+      /* bCC */
+      if (size == 2 && opcode->opcode != 0xfc0000)
+       type = 0;
+      /* jsr */
+      else if (size == 3 && opcode->opcode == 0xfd0000)
+       type = 6;
+      /* jmp */
+      else if (size == 3 && opcode->opcode == 0xfc0000)
+       type = 8;
+      /* bCCx */
+      else
+       type = 3;
+
+      f = frag_var (rs_machine_dependent, 8, 8 - size, type,
+                   fixups[0].exp.X_add_symbol,
+                   fixups[0].exp.X_add_number,
+                   (char *)fixups[0].opindex);
+      number_to_chars_bigendian (f, insn, size);
+      if (8 - size > 4)
+       {
+         number_to_chars_bigendian (f + size, 0, 4);
+         number_to_chars_bigendian (f + size + 4, 0, 8 - size - 4);
+       }
+      else
+       number_to_chars_bigendian (f + size, 0, 8 - size);
     }
+
   else
     {
-      number_to_chars_bigendian (f, insn, size > 4 ? 4 : size);
-    }
+      f = frag_more (size);
 
-#if 0
-  /* Create any fixups.  */
-  for (i = 0; i < fc; i++)
-    {
-      const struct mn10200_operand *operand;
+      /* Oh, what a mess.  The instruction is in big endian format, but
+        16 and 24bit immediates are little endian!  */
+      if (opcode->format == FMT_3)
+       {
+         number_to_chars_bigendian (f, (insn >> 16) & 0xff, 1);
+         number_to_chars_littleendian (f + 1, insn & 0xffff, 2);
+       }
+      else if (opcode->format == FMT_6)
+       {
+         number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
+         number_to_chars_littleendian (f + 2, insn & 0xffff, 2);
+       }
+      else if (opcode->format == FMT_7)
+       {
+         number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
+         number_to_chars_littleendian (f + 2, insn & 0xffff, 2);
+         number_to_chars_littleendian (f + 4, extension & 0xff, 1);
+       }
+      else
+       {
+         number_to_chars_bigendian (f, insn, size > 4 ? 4 : size);
+       }
 
-      operand = &mn10200_operands[fixups[i].opindex];
-      if (fixups[i].reloc != BFD_RELOC_UNUSED)
+      /* Create any fixups.  */
+      for (i = 0; i < fc; i++)
        {
-         reloc_howto_type *reloc_howto;
-         int size;
-         int offset;
-         fixS *fixP;
+         const struct mn10200_operand *operand;
 
-         reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc);
+         operand = &mn10200_operands[fixups[i].opindex];
+         if (fixups[i].reloc != BFD_RELOC_UNUSED)
+           {
+             reloc_howto_type *reloc_howto;
+             int size;
+             int offset;
+             fixS *fixP;
+
+             reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc);
 
-         if (!reloc_howto)
-           abort();
+             if (!reloc_howto)
+               abort();
          
-         size = bfd_get_reloc_size (reloc_howto);
+             size = bfd_get_reloc_size (reloc_howto);
 
-         if (size < 1 || size > 4)
-           abort();
+             if (size < 1 || size > 4)
+               abort();
 
-         offset = 4 - size;
-         fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset, size,
-                             &fixups[i].exp, 
-                             reloc_howto->pc_relative,
-                             fixups[i].reloc);
-       }
-      else
-       {
-         int reloc, pcrel, reloc_size, offset;
-
-         reloc = BFD_RELOC_NONE;
-         /* How big is the reloc?  Remember SPLIT relocs are
-            implicitly 32bits.  */
-         reloc_size = operand->bits;
-
-         /* Is the reloc pc-relative?  */
-         pcrel = (operand->flags & MN10200_OPERAND_PCREL) != 0;
-
-         /* Gross.  This disgusting hack is to make sure we
-            get the right offset for the 16/32 bit reloc in 
-            "call" instructions.  Basically they're a pain
-            because the reloc isn't at the end of the instruction.  */
-         if ((size == 5 || size == 7)
-             && (((insn >> 24) & 0xff) == 0xcd
-                 || ((insn >> 24) & 0xff) == 0xdd))
-           size -= 2;
-
-         /* Similarly for certain bit instructions which don't
-            hav their 32bit reloc at the tail of the instruction.  */
-         if (size == 7
-             && (((insn >> 16) & 0xffff) == 0xfe00
-                 || ((insn >> 16) & 0xffff) == 0xfe01
-                 || ((insn >> 16) & 0xffff) == 0xfe02))
-           size -= 1;
-       
-         offset = size - reloc_size / 8;
-
-         /* Choose a proper BFD relocation type.  */
-         if (pcrel)
-           {
-             if (size == 6)
-               reloc = BFD_RELOC_MN10200_32_PCREL;
-             else if (size == 4)
-               reloc = BFD_RELOC_MN10200_16_PCREL;
-             else if (reloc_size == 32)
-               reloc = BFD_RELOC_32_PCREL;
-             else if (reloc_size == 16)
-               reloc = BFD_RELOC_16_PCREL;
-             else if (reloc_size == 8)
-               reloc = BFD_RELOC_8_PCREL;
-             else
-               abort ();
+             offset = 4 - size;
+             fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
+                                 size,
+                                 &fixups[i].exp, 
+                                 reloc_howto->pc_relative,
+                                 fixups[i].reloc);
            }
          else
            {
-             if (reloc_size == 32)
-               reloc = BFD_RELOC_MN10200_32B;
-             else if (reloc_size == 16)
-               reloc = BFD_RELOC_MN10200_16B;
-             else if (reloc_size == 8)
-               reloc = BFD_RELOC_8;
+             int reloc, pcrel, reloc_size, offset;
+             fixS *fixP;
+
+             reloc = BFD_RELOC_NONE;
+             /* How big is the reloc?  Remember SPLIT relocs are
+                implicitly 32bits.  */
+             reloc_size = operand->bits;
+
+             offset = size - reloc_size / 8;
+
+             /* Is the reloc pc-relative?  */
+             pcrel = (operand->flags & MN10200_OPERAND_PCREL) != 0;
+
+
+             /* Choose a proper BFD relocation type.  */
+             if (pcrel)
+               {
+                 if (reloc_size == 8)
+                   reloc = BFD_RELOC_8_PCREL;
+                 else if (reloc_size == 24)
+                   reloc = BFD_RELOC_24_PCREL;
+                 else
+                   abort ();
+               }
              else
-               abort ();
-           }
+               {
+                 if (reloc_size == 32)
+                   reloc = BFD_RELOC_32;
+                 else if (reloc_size == 16)
+                   reloc = BFD_RELOC_16;
+                 else if (reloc_size == 8)
+                   reloc = BFD_RELOC_8;
+                 else if (reloc_size == 24)
+                   reloc = BFD_RELOC_24;
+                 else
+                   abort ();
+               }
 
-         /* Convert the size of the reloc into what fix_new_exp wants.  */
-         reloc_size = reloc_size / 8;
-         if (reloc_size == 8)
-           reloc_size = 0;
-         else if (reloc_size == 16)
-           reloc_size = 1;
-         else if (reloc_size == 32)
-           reloc_size = 2;
-
-         fix_new_exp (frag_now, f - frag_now->fr_literal + offset, reloc_size,
-                      &fixups[i].exp, pcrel,
-                      ((bfd_reloc_code_real_type) reloc));
+             /* Convert the size of the reloc into what fix_new_exp wants.  */
+             reloc_size = reloc_size / 8;
+             if (reloc_size == 8)
+               reloc_size = 0;
+             else if (reloc_size == 16)
+               reloc_size = 1;
+             else if (reloc_size == 32 || reloc_size == 24)
+               reloc_size = 2;
+
+             fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
+                                 reloc_size, &fixups[i].exp, pcrel,
+                                 ((bfd_reloc_code_real_type) reloc));
+             if (pcrel)
+               fixP->fx_offset += offset;
+           }
        }
     }
-#endif
 }
 
 
@@ -826,17 +1194,28 @@ tc_gen_reloc (seg, fixp)
 {
   arelent *reloc;
   reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
-  reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
-  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
   if (reloc->howto == (reloc_howto_type *) NULL)
     {
       as_bad_where (fixp->fx_file, fixp->fx_line,
-                    "reloc %d not supported by object file format", (int)fixp->fx_r_type);
+                    "reloc %d not supported by object file format",
+                   (int)fixp->fx_r_type);
       return NULL;
     }
-  reloc->addend = fixp->fx_offset;
-  /*  printf("tc_gen_reloc: addr=%x  addend=%x\n", reloc->address, reloc->addend); */
+  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
+  if (fixp->fx_addsy && fixp->fx_subsy)
+    {
+      reloc->sym_ptr_ptr = &bfd_abs_symbol;
+      reloc->addend = (S_GET_VALUE (fixp->fx_addsy)
+                      - S_GET_VALUE (fixp->fx_subsy) + fixp->fx_offset);
+    }
+  else 
+    {
+      reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+      reloc->addend = fixp->fx_offset;
+    }
   return reloc;
 }
 
@@ -845,7 +1224,29 @@ md_estimate_size_before_relax (fragp, seg)
      fragS *fragp;
      asection *seg;
 {
-  return 0;
+  if (fragp->fr_subtype == 0)
+    return 2;
+  if (fragp->fr_subtype == 3)
+    return 3;
+  if (fragp->fr_subtype == 6)
+    {
+      if (!S_IS_DEFINED (fragp->fr_symbol)
+         || seg != S_GET_SEGMENT (fragp->fr_symbol))
+       {
+         fragp->fr_subtype = 7;
+         return 5;
+       }
+      return 3;
+    }
+  if (fragp->fr_subtype == 8)
+    {
+      if (!S_IS_DEFINED (fragp->fr_symbol))
+       {
+         fragp->fr_subtype = 10;
+         return 5;
+       }
+      return 2;
+    }
 } 
 
 long
@@ -887,8 +1288,9 @@ mn10200_insert_operand (insnp, extensionp, operand, val, file, line, shift)
      unsigned int line;
      unsigned int shift;
 {
-  /* No need to check 32bit operands for a bit.  */
-  if (operand->bits != 32)
+  /* No need to check 24 or 32bit operands for a bit.  */
+  if (operand->bits < 24
+      && (operand->flags & MN10200_OPERAND_NOCHECK) == 0)
     {
       long min, max;
       offsetT test;
@@ -943,8 +1345,9 @@ check_operand (insn, operand, val)
      const struct mn10200_operand *operand;
      offsetT val;
 {
-  /* No need to check 32bit operands for a bit.  */
-  if (operand->bits != 32)
+  /* No need to check 24bit or 32bit operands for a bit.  */
+  if (operand->bits < 24
+      && (operand->flags & MN10200_OPERAND_NOCHECK) == 0)
     {
       long min, max;
       offsetT test;