* config/tc-m68k.c (struct label_line): Define.
[deliverable/binutils-gdb.git] / gas / config / tc-m68k.c
index 6412a5da0fe90b915faafc96160593521d9f9f9e..1e82c90695b91ec73b6195972c34721fb045e01f 100644 (file)
@@ -1,5 +1,6 @@
 /* tc-m68k.c -- Assemble for the m68k family
-   Copyright (C) 1987, 91, 92, 93, 94, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1987, 91, 92, 93, 94, 95, 96, 1997
+   Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    02111-1307, USA.  */
 
 #include <ctype.h>
-#define  NO_RELOC 0
 #include "as.h"
 #include "obstack.h"
+#include "subsegs.h"
 
 #include "opcode/m68k.h"
 #include "m68k-parse.h"
 
-/* This array holds the chars that always start a comment.  If the
-   pre-processor is disabled, these aren't very useful */
-#ifdef OBJ_ELF
-CONST char comment_chars[] = "|#";
+/* This string holds the chars that always start a comment.  If the
+   pre-processor is disabled, these aren't very useful.  The macro
+   tc_comment_chars points to this.  We use this, rather than the
+   usual comment_chars, so that the --bitwise-or option will work.  */
+#if (defined (OBJ_ELF) && ! defined (TE_PSOS) && ! defined (TE_LINUX)) || defined (TE_DELTA)
+const char *m68k_comment_chars = "|#";
 #else
-CONST char comment_chars[] = "|";
+const char *m68k_comment_chars = "|";
 #endif
 
 /* This array holds the chars that only start a comment at the beginning of
@@ -41,9 +44,9 @@ CONST char comment_chars[] = "|";
    first line of the input file.  This is because the compiler outputs
    #NO_APP at the beginning of its output. */
 /* Also note that comments like this one will always work. */
-CONST char line_comment_chars[] = "#";
+const char line_comment_chars[] = "#";
 
-CONST char line_separator_chars[] = "";
+const char line_separator_chars[] = "";
 
 /* Chars that can be used to separate mant from exp in floating point nums */
 CONST char EXP_CHARS[] = "eE";
@@ -61,7 +64,8 @@ const int md_reloc_size = 8;  /* Size of relocation record */
 
 /* Are we trying to generate PIC code?  If so, absolute references
    ought to be made into linkage table references or pc-relative
-   references.  */
+   references.  Not implemented.  For ELF there are other means 
+   to denote pic relocations.  */
 int flag_want_pic;
 
 static int flag_short_refs;    /* -l option */
@@ -73,9 +77,53 @@ int flag_reg_prefix_optional = REGISTER_PREFIX_OPTIONAL;
 int flag_reg_prefix_optional;
 #endif
 
+/* Whether --register-prefix-optional was used on the command line.  */
+static int reg_prefix_optional_seen;
+
 /* The floating point coprocessor to use by default.  */
 static enum m68k_register m68k_float_copnum = COP1;
 
+/* If this is non-zero, then references to number(%pc) will be taken
+   to refer to number, rather than to %pc + number.  */
+static int m68k_abspcadd;
+
+/* If this is non-zero, then the quick forms of the move, add, and sub
+   instructions are used when possible.  */
+static int m68k_quick = 1;
+
+/* If this is non-zero, then if the size is not specified for a base
+   or outer displacement, the assembler assumes that the size should
+   be 32 bits.  */
+static int m68k_rel32 = 1;
+
+/* This is non-zero if m68k_rel32 was set from the command line.  */
+static int m68k_rel32_from_cmdline;
+
+/* The default width to use for an index register when using a base
+   displacement.  */
+static enum m68k_size m68k_index_width_default = SIZE_LONG;
+
+/* We want to warn if any text labels are misaligned.  In order to get
+   the right line number, we need to record the line number for each
+   label.  */
+
+struct label_line
+{
+  struct label_line *next;
+  symbolS *label;
+  char *file;
+  unsigned int line;
+  int text;
+};
+
+/* The list of labels.  */
+
+static struct label_line *labels;
+
+/* The current label.  */
+
+static struct label_line *current_label;
+
 /* Its an arbitrary name:  This means I don't approve of it */
 /* See flames below */
 static struct obstack robyn;
@@ -141,6 +189,11 @@ static const enum m68k_register m68060_control_regs[] = {
   USP, VBR, URP, SRP, PCR,
   0
 };
+static const enum m68k_register mcf5200_control_regs[] = {
+  CACR, TC, ITT0, ITT1, DTT0, DTT1, VBR, ROMBAR, 
+  RAMBAR0, RAMBAR1, MBAR,
+  0
+};
 #define cpu32_control_regs m68010_control_regs
 
 static const enum m68k_register *control_regs;
@@ -185,11 +238,16 @@ struct m68k_it
         significance of some values (in the branch instruction, for
         example).  */
       int pcrel_fix;
+#ifdef OBJ_ELF
+      /* Whether this expression needs special pic relocation, and if
+        so, which.  */
+      enum pic_relocation pic_reloc;
+#endif
     }
   reloc[5];                    /* Five is enough??? */
 };
 
-#define cpu_of_arch(x)         ((x) & m68000up)
+#define cpu_of_arch(x)         ((x) & (m68000up|mcf5200))
 #define float_of_arch(x)       ((x) & mfloat)
 #define mmu_of_arch(x)         ((x) & mmmu)
 
@@ -230,7 +288,7 @@ add_fix (width, exp, pc_rel, pc_fix)
      int pc_rel;
      int pc_fix;
 {
-  the_ins.reloc[the_ins.nrel].n = (((width)=='B')
+  the_ins.reloc[the_ins.nrel].n = ((width == 'B' || width == '3')
                                   ? (the_ins.numo*2-1)
                                   : (((width)=='b')
                                      ? (the_ins.numo*2+1)
@@ -238,6 +296,9 @@ add_fix (width, exp, pc_rel, pc_fix)
   the_ins.reloc[the_ins.nrel].exp = exp->exp;
   the_ins.reloc[the_ins.nrel].wid = width;
   the_ins.reloc[the_ins.nrel].pcrel_fix = pc_fix;
+#ifdef OBJ_ELF
+  the_ins.reloc[the_ins.nrel].pic_reloc = exp->pic_reloc;
+#endif
   the_ins.reloc[the_ins.nrel++].pcrel = pc_rel;
 }
 
@@ -280,42 +341,60 @@ static void s_proc PARAMS ((int));
 static void mri_chip PARAMS ((void));
 static void s_chip PARAMS ((int));
 static void s_fopt PARAMS ((int));
+static void s_opt PARAMS ((int));
+static void s_reg PARAMS ((int));
+static void s_restore PARAMS ((int));
+static void s_save PARAMS ((int));
+static void s_mri_if PARAMS ((int));
+static void s_mri_else PARAMS ((int));
+static void s_mri_endi PARAMS ((int));
+static void s_mri_break PARAMS ((int));
+static void s_mri_next PARAMS ((int));
+static void s_mri_for PARAMS ((int));
+static void s_mri_endf PARAMS ((int));
+static void s_mri_repeat PARAMS ((int));
+static void s_mri_until PARAMS ((int));
+static void s_mri_while PARAMS ((int));
+static void s_mri_endw PARAMS ((int));
 
 static int current_architecture;
 
 struct m68k_cpu {
   unsigned long arch;
   const char *name;
+  int alias;
 };
 
 static const struct m68k_cpu archs[] = {
-  { m68000, "68000" },
-  { m68010, "68010" },
-  { m68020, "68020" },
-  { m68030, "68030" },
-  { m68040, "68040" },
-  { m68060, "68060" },
-  { cpu32,  "cpu32" },
-  { m68881, "68881" },
-  { m68851, "68851" },
+  { m68000, "68000", 0 },
+  { m68010, "68010", 0 },
+  { m68020, "68020", 0 },
+  { m68030, "68030", 0 },
+  { m68040, "68040", 0 },
+  { m68060, "68060", 0 },
+  { cpu32,  "cpu32", 0 },
+  { m68881, "68881", 0 },
+  { m68851, "68851", 0 },
+  { mcf5200, "5200", 0 },
   /* Aliases (effectively, so far as gas is concerned) for the above
      cpus.  */
-  { m68020, "68k" },
-  { m68000, "68302" },
-  { m68000, "68008" },
-  { m68000, "68ec000" },
-  { m68000, "68hc000" },
-  { m68000, "68hc001" },
-  { m68020, "68ec020" },
-  { m68030, "68ec030" },
-  { m68040, "68ec040" },
-  { cpu32,  "68330" },
-  { cpu32,  "68331" },
-  { cpu32,  "68332" },
-  { cpu32,  "68333" },
-  { cpu32,  "68340" },
-  { cpu32,  "68360" },
-  { m68881, "68882" },
+  { m68020, "68k", 1 },
+  { m68000, "68302", 1 },
+  { m68000, "68008", 1 },
+  { m68000, "68ec000", 1 },
+  { m68000, "68hc000", 1 },
+  { m68000, "68hc001", 1 },
+  { m68020, "68ec020", 1 },
+  { m68030, "68ec030", 1 },
+  { m68040, "68ec040", 1 },
+  { m68060, "68ec060", 1 },
+  { cpu32,  "68330", 1 },
+  { cpu32,  "68331", 1 },
+  { cpu32,  "68332", 1 },
+  { cpu32,  "68333", 1 },
+  { cpu32,  "68340", 1 },
+  { cpu32,  "68360", 1 },
+  { m68881, "68882", 1 },
 };
 
 static const int n_archs = sizeof (archs) / sizeof (archs[0]);
@@ -390,7 +469,7 @@ relax_typeS md_relax_table[] =
    function to call to execute this pseudo-op
    Integer arg to pass to the function
    */
-CONST pseudo_typeS md_pseudo_table[] =
+const pseudo_typeS md_pseudo_table[] =
 {
   {"data1", s_data1, 0},
   {"data2", s_data2, 0},
@@ -398,18 +477,54 @@ CONST pseudo_typeS md_pseudo_table[] =
   {"even", s_even, 0},
   {"skip", s_space, 0},
   {"proc", s_proc, 0},
-#ifdef TE_SUN3
+#if defined (TE_SUN3) || defined (OBJ_ELF)
   {"align", s_align_bytes, 0},
 #endif
 #ifdef OBJ_ELF
   {"swbeg", s_ignore, 0},
 #endif
+  {"extend", float_cons, 'x'},
+  {"ldouble", float_cons, 'x'},
 
   /* The following pseudo-ops are supported for MRI compatibility.  */
   {"chip", s_chip, 0},
   {"comline", s_space, 1},
   {"fopt", s_fopt, 0},
   {"mask2", s_ignore, 0},
+  {"opt", s_opt, 0},
+  {"reg", s_reg, 0},
+  {"restore", s_restore, 0},
+  {"save", s_save, 0},
+
+  {"if", s_mri_if, 0},
+  {"if.b", s_mri_if, 'b'},
+  {"if.w", s_mri_if, 'w'},
+  {"if.l", s_mri_if, 'l'},
+  {"else", s_mri_else, 0},
+  {"else.s", s_mri_else, 's'},
+  {"else.l", s_mri_else, 'l'},
+  {"endi", s_mri_endi, 0},
+  {"break", s_mri_break, 0},
+  {"break.s", s_mri_break, 's'},
+  {"break.l", s_mri_break, 'l'},
+  {"next", s_mri_next, 0},
+  {"next.s", s_mri_next, 's'},
+  {"next.l", s_mri_next, 'l'},
+  {"for", s_mri_for, 0},
+  {"for.b", s_mri_for, 'b'},
+  {"for.w", s_mri_for, 'w'},
+  {"for.l", s_mri_for, 'l'},
+  {"endf", s_mri_endf, 0},
+  {"repeat", s_mri_repeat, 0},
+  {"until", s_mri_until, 0},
+  {"until.b", s_mri_until, 'b'},
+  {"until.w", s_mri_until, 'w'},
+  {"until.l", s_mri_until, 'l'},
+  {"while", s_mri_while, 0},
+  {"while.b", s_mri_while, 'b'},
+  {"while.w", s_mri_while, 'w'},
+  {"while.l", s_mri_while, 'l'},
+  {"endw", s_mri_endw, 0},
 
   {0, 0, 0}
 };
@@ -434,7 +549,11 @@ CONST pseudo_typeS mote_pseudo_table[] =
   {"dsb", s_space, 1},
 
   {"xdef", s_globl, 0},
+#ifdef OBJ_ELF
+  {"align", s_align_bytes, 0},
+#else
   {"align", s_align_ptwo, 0},
+#endif
 #ifdef M68KCOFF
   {"sect", obj_coff_section, 0},
   {"section", obj_coff_section, 0},
@@ -448,7 +567,7 @@ CONST pseudo_typeS mote_pseudo_table[] =
 #define isuword(x)     ((x)>=0 && (x)<=65535)
 
 #define isbyte(x)      ((x)>= -255 && (x)<=255)
-#define isword(x)      ((x)>=-32768 && (x)<=65535)
+#define isword(x)      ((x)>=-65536 && (x)<=65535)
 #define islong(x)      (1)
 
 extern char *input_line_pointer;
@@ -499,6 +618,8 @@ short
 tc_coff_fix2rtype (fixP)
      fixS *fixP;
 {
+  if (fixP->fx_tcbit && fixP->fx_size == 4)
+    return R_RELLONG_NEG;
 #ifdef NO_PCREL_RELOCS
   know (fixP->fx_pcrel == 0);
   return (fixP->fx_size == 1 ? R_RELBYTE
@@ -517,6 +638,145 @@ tc_coff_fix2rtype (fixP)
 
 #endif
 
+#ifdef OBJ_ELF
+
+/* Compute the relocation code for a fixup of SIZE bytes, using pc
+   relative relocation if PCREL is non-zero.  PIC says whether a special
+   pic relocation was requested.  */
+
+static bfd_reloc_code_real_type get_reloc_code
+  PARAMS ((int, int, enum pic_relocation));
+
+static bfd_reloc_code_real_type
+get_reloc_code (size, pcrel, pic)
+     int size;
+     int pcrel;
+     enum pic_relocation pic;
+{
+  switch (pic)
+    {
+    case pic_got_pcrel:
+      switch (size)
+       {
+       case 1:
+         return BFD_RELOC_8_GOT_PCREL;
+       case 2:
+         return BFD_RELOC_16_GOT_PCREL;
+       case 4:
+         return BFD_RELOC_32_GOT_PCREL;
+       }
+      break;
+
+    case pic_got_off:
+      switch (size)
+       {
+       case 1:
+         return BFD_RELOC_8_GOTOFF;
+       case 2:
+         return BFD_RELOC_16_GOTOFF;
+       case 4:
+         return BFD_RELOC_32_GOTOFF;
+       }
+      break;
+
+    case pic_plt_pcrel:
+      switch (size)
+       {
+       case 1:
+         return BFD_RELOC_8_PLT_PCREL;
+       case 2:
+         return BFD_RELOC_16_PLT_PCREL;
+       case 4:
+         return BFD_RELOC_32_PLT_PCREL;
+       }
+      break;
+
+    case pic_plt_off:
+      switch (size)
+       {
+       case 1:
+         return BFD_RELOC_8_PLTOFF;
+       case 2:
+         return BFD_RELOC_16_PLTOFF;
+       case 4:
+         return BFD_RELOC_32_PLTOFF;
+       }
+      break;
+
+    case pic_none:
+      if (pcrel)
+       {
+         switch (size)
+           {
+           case 1:
+             return BFD_RELOC_8_PCREL;
+           case 2:
+             return BFD_RELOC_16_PCREL;
+           case 4:
+             return BFD_RELOC_32_PCREL;
+           }
+       }
+      else
+       {
+         switch (size)
+           {
+           case 1:
+             return BFD_RELOC_8;
+           case 2:
+             return BFD_RELOC_16;
+           case 4:
+             return BFD_RELOC_32;
+           }
+       }
+    }
+
+  as_bad ("Can not do %d byte %s%srelocation", size,
+         pcrel ? "pc-relative " : "",
+         pic == pic_none ? "" : "pic ");
+  return BFD_RELOC_NONE;
+}
+
+/* Here we decide which fixups can be adjusted to make them relative
+   to the beginning of the section instead of the symbol.  Basically
+   we need to make sure that the dynamic relocations are done
+   correctly, so in some cases we force the original symbol to be
+   used.  */
+int
+tc_m68k_fix_adjustable (fixP)
+     fixS *fixP;
+{
+  /* Prevent all adjustments to global symbols. */
+  if (S_IS_EXTERNAL (fixP->fx_addsy))
+    return 0;
+
+  /* adjust_reloc_syms doesn't know about the GOT */
+  switch (fixP->fx_r_type)
+    {
+    case BFD_RELOC_8_GOT_PCREL:
+    case BFD_RELOC_16_GOT_PCREL:
+    case BFD_RELOC_32_GOT_PCREL:
+    case BFD_RELOC_8_GOTOFF:
+    case BFD_RELOC_16_GOTOFF:
+    case BFD_RELOC_32_GOTOFF:
+    case BFD_RELOC_8_PLT_PCREL:
+    case BFD_RELOC_16_PLT_PCREL:
+    case BFD_RELOC_32_PLT_PCREL:
+    case BFD_RELOC_8_PLTOFF:
+    case BFD_RELOC_16_PLTOFF:
+    case BFD_RELOC_32_PLTOFF:
+      return 0;
+
+    default:
+      return 1;
+    }
+}
+
+#else /* !OBJ_ELF */
+
+#define get_reloc_code(SIZE,PCREL,OTHER) NO_RELOC
+
+#endif /* OBJ_ELF */
+
 #ifdef BFD_ASSEMBLER
 
 arelent *
@@ -527,28 +787,91 @@ tc_gen_reloc (section, fixp)
   arelent *reloc;
   bfd_reloc_code_real_type code;
 
-#define F(SZ,PCREL)            (((SZ) << 1) + (PCREL))
-  switch (F (fixp->fx_size, fixp->fx_pcrel))
+  if (fixp->fx_tcbit)
+    abort ();
+
+  if (fixp->fx_r_type != BFD_RELOC_NONE)
+    {
+      code = fixp->fx_r_type;
+
+      /* Since DIFF_EXPR_OK is defined in tc-m68k.h, it is possible
+         that fixup_segment converted a non-PC relative reloc into a
+         PC relative reloc.  In such a case, we need to convert the
+         reloc code.  */
+      if (fixp->fx_pcrel)
+       {
+         switch (code)
+           {
+           case BFD_RELOC_8:
+             code = BFD_RELOC_8_PCREL;
+             break;
+           case BFD_RELOC_16:
+             code = BFD_RELOC_16_PCREL;
+             break;
+           case BFD_RELOC_32:
+             code = BFD_RELOC_32_PCREL;
+             break;
+           case BFD_RELOC_8_PCREL:
+           case BFD_RELOC_16_PCREL:
+           case BFD_RELOC_32_PCREL:
+           case BFD_RELOC_8_GOT_PCREL:
+           case BFD_RELOC_16_GOT_PCREL:
+           case BFD_RELOC_32_GOT_PCREL:
+           case BFD_RELOC_8_GOTOFF:
+           case BFD_RELOC_16_GOTOFF:
+           case BFD_RELOC_32_GOTOFF:
+           case BFD_RELOC_8_PLT_PCREL:
+           case BFD_RELOC_16_PLT_PCREL:
+           case BFD_RELOC_32_PLT_PCREL:
+           case BFD_RELOC_8_PLTOFF:
+           case BFD_RELOC_16_PLTOFF:
+           case BFD_RELOC_32_PLTOFF:
+             break;
+           default:
+             as_bad_where (fixp->fx_file, fixp->fx_line,
+                           "Cannot make %s relocation PC relative",
+                           bfd_get_reloc_code_name (code));
+           }
+       }
+    }
+  else
     {
+#define F(SZ,PCREL)            (((SZ) << 1) + (PCREL))
+      switch (F (fixp->fx_size, fixp->fx_pcrel))
+       {
 #define MAP(SZ,PCREL,TYPE)     case F(SZ,PCREL): code = (TYPE); break
-      MAP (1, 0, BFD_RELOC_8);
-      MAP (2, 0, BFD_RELOC_16);
-      MAP (4, 0, BFD_RELOC_32);
-      MAP (1, 1, BFD_RELOC_8_PCREL);
-      MAP (2, 1, BFD_RELOC_16_PCREL);
-      MAP (4, 1, BFD_RELOC_32_PCREL);
-    default:
-      abort ();
+         MAP (1, 0, BFD_RELOC_8);
+         MAP (2, 0, BFD_RELOC_16);
+         MAP (4, 0, BFD_RELOC_32);
+         MAP (1, 1, BFD_RELOC_8_PCREL);
+         MAP (2, 1, BFD_RELOC_16_PCREL);
+         MAP (4, 1, BFD_RELOC_32_PCREL);
+       default:
+         abort ();
+       }
     }
+#undef F
+#undef MAP
 
   reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
   assert (reloc != 0);
   reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+#ifndef OBJ_ELF
   if (fixp->fx_pcrel)
     reloc->addend = fixp->fx_addnumber;
   else
     reloc->addend = 0;
+#else
+  if (!fixp->fx_pcrel)
+    reloc->addend = fixp->fx_addnumber;
+  else
+    reloc->addend = (section->vma
+                    + (fixp->fx_pcrel_adjust == 64
+                       ? -1 : fixp->fx_pcrel_adjust)
+                    + fixp->fx_addnumber
+                    + md_pcrel_from (fixp));
+#endif
 
   reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
   assert (reloc->howto != 0);
@@ -651,6 +974,18 @@ m68k_ip (instring)
       return;
     }
 
+  if (flag_mri && opcode->m_opnum == 0)
+    {
+      /* In MRI mode, random garbage is allowed after an instruction
+         which accepts no operands.  */
+      the_ins.args = opcode->m_operands;
+      the_ins.numargs = opcode->m_opnum;
+      the_ins.numo = opcode->m_codenum;
+      the_ins.opcode[0] = getone (opcode);
+      the_ins.opcode[1] = gettwo (opcode);
+      return;
+    }
+
   for (opP = &the_ins.operands[0]; *p; opP++)
     {
       p = crack_operand (p, opP);
@@ -686,12 +1021,10 @@ m68k_ip (instring)
       /* If we didn't get the right number of ops, or we have no
         common model with this pattern then reject this pattern. */
 
+      ok_arch |= opcode->m_arch;
       if (opsfound != opcode->m_opnum
          || ((opcode->m_arch & current_architecture) == 0))
-       {
-         ++losing;
-         ok_arch |= opcode->m_arch;
-       }
+       ++losing;
       else
        {
          for (s = opcode->m_operands, opP = &the_ins.operands[0];
@@ -742,16 +1075,118 @@ m68k_ip (instring)
                    }
                  break;
 
+               case '<':
+                 switch (opP->mode)
+                   {
+                   case DREG:
+                   case AREG:
+                   case FPREG:
+                   case CONTROL:
+                   case IMMED:
+                   case ADEC:
+                   case REGLST:
+                     losing++;
+                     break;
+                   default:
+                     break;
+                   }
+                 break;
+
+               case '>':
+                 switch (opP->mode)
+                   {
+                   case DREG:
+                   case AREG:
+                   case FPREG:
+                   case CONTROL:
+                   case IMMED:
+                   case AINC:
+                   case REGLST:
+                     losing++;
+                     break;
+                   case ABSL:
+                     break;
+                   default:
+                     if (opP->reg == PC
+                         || opP->reg == ZPC)
+                       losing++;
+                     break;
+                   }
+                 break;
+
+               case 'm':
+                 switch (opP->mode)
+                   {
+                   case DREG:
+                   case AREG:
+                   case AINDR:
+                   case AINC:
+                   case ADEC:
+                     break;
+                   default:
+                     losing++;
+                   }
+                  break;
+
+               case 'n':
+                 switch (opP->mode)
+                   {
+                   case DISP:
+                     break;
+                   default:
+                     losing++;
+                   }
+                  break;
+
+               case 'o':
+                 switch (opP->mode)
+                   {
+                   case BASE:
+                   case ABSL:
+                   case IMMED:
+                     break;
+                   default:
+                     losing++;
+                   }
+                  break;
+
+               case 'p':
+                 switch (opP->mode)
+                   {
+                   case DREG:
+                   case AREG:
+                   case AINDR:
+                   case AINC:
+                   case ADEC:
+                   case DISP:
+                     break;
+                   default:
+                     losing++;
+                   }
+                  break;
+
                case '#':
                  if (opP->mode != IMMED)
                    losing++;
                  else if (s[1] == 'b'
                           && ! isvar (&opP->disp)
-                          && ! expr8 (&opP->disp))
+                          && (opP->disp.exp.X_op != O_constant
+                              || ! isbyte (opP->disp.exp.X_add_number)))
+                   losing++;
+                 else if (s[1] == 'B'
+                          && ! isvar (&opP->disp)
+                          && (opP->disp.exp.X_op != O_constant
+                              || ! issbyte (opP->disp.exp.X_add_number)))
                    losing++;
                  else if (s[1] == 'w'
                           && ! isvar (&opP->disp)
-                          && ! expr16 (&opP->disp))
+                          && (opP->disp.exp.X_op != O_constant
+                              || ! isword (opP->disp.exp.X_add_number)))
+                   losing++;
+                 else if (s[1] == 'W'
+                          && ! isvar (&opP->disp)
+                          && (opP->disp.exp.X_op != O_constant
+                              || ! issword (opP->disp.exp.X_add_number)))
                    losing++;
                  break;
 
@@ -777,8 +1212,8 @@ m68k_ip (instring)
                  if (opP->mode == CONTROL
                      || opP->mode == FPREG
                      || opP->mode == REGLST
+                     || opP->mode == IMMED
                      || (opP->mode != ABSL
-                         && opP->mode != IMMED
                          && (opP->reg == PC
                              || opP->reg == ZPC)))
                    losing++;
@@ -1036,6 +1471,14 @@ m68k_ip (instring)
                          opP->mode = REGLST;
                        }
                    }
+                 else if (opP->mode == ABSL
+                          && opP->disp.size == SIZE_UNSPEC
+                          && opP->disp.exp.X_op == O_constant)
+                   {
+                     /* This is what the MRI REG pseudo-op generates.  */
+                     opP->mode = REGLST;
+                     opP->mask = opP->disp.exp.X_add_number;
+                   }
                  else if (opP->mode != REGLST)
                    losing++;
                  else if (s[1] == '8' && (opP->mask & 0x0ffffff) != 0)
@@ -1047,22 +1490,34 @@ m68k_ip (instring)
                case 'M':
                  if (opP->mode != IMMED)
                    losing++;
-                 else if (! expr8 (&opP->disp))
+                 else if (opP->disp.exp.X_op != O_constant
+                          || ! issbyte (opP->disp.exp.X_add_number))
+                   losing++;
+                 else if (! m68k_quick
+                          && instring[3] != 'q'
+                          && instring[4] != 'q')
                    losing++;
                  break;
 
                case 'O':
-                 if (opP->mode != DREG && opP->mode != IMMED)
+                 if (opP->mode != DREG
+                     && opP->mode != IMMED
+                     && opP->mode != ABSL)
                    losing++;
                  break;
 
                case 'Q':
                  if (opP->mode != IMMED)
                    losing++;
-                 else if (! expr8 (&opP->disp)
+                 else if (opP->disp.exp.X_op != O_constant
                           || opP->disp.exp.X_add_number < 1
                           || opP->disp.exp.X_add_number > 8)
                    losing++;
+                 else if (! m68k_quick
+                          && (strncmp (instring, "add", 3) == 0
+                              || strncmp (instring, "sub", 3) == 0)
+                          && instring[3] != 'q')
+                   losing++;
                  break;
 
                case 'R':
@@ -1101,7 +1556,7 @@ m68k_ip (instring)
                case 't':
                  if (opP->mode != IMMED)
                    losing++;
-                 else if (! expr8 (&opP->disp)
+                 else if (opP->disp.exp.X_op != O_constant
                           || opP->disp.exp.X_add_number < 0
                           || opP->disp.exp.X_add_number > 7)
                    losing++;
@@ -1127,6 +1582,12 @@ m68k_ip (instring)
                      || opP->mode == AREG
                      || opP->mode == REGLST)
                    losing++;
+                 /* We should accept immediate operands, but they
+                     supposedly have to be quad word, and we don't
+                     handle that.  I would like to see what a Motorola
+                     assembler does before doing something here.  */
+                 if (opP->mode == IMMED)
+                   losing++;
                  break;
 
                case 'f':
@@ -1135,13 +1596,21 @@ m68k_ip (instring)
                    losing++;
                  break;
 
-               case 'P':
+               case '0':
+                 if (opP->mode != CONTROL || opP->reg != TC)
+                   losing++;
+                 break;
+
+               case '1':
+                 if (opP->mode != CONTROL || opP->reg != AC)
+                   losing++;
+                 break;
+
+               case '2':
                  if (opP->mode != CONTROL
-                     || (opP->reg != TC
-                         && opP->reg != CAL
+                     || (opP->reg != CAL
                          && opP->reg != VAL
-                         && opP->reg != SCC
-                         && opP->reg != AC))
+                         && opP->reg != SCC))
                    losing++;
                  break;
 
@@ -1214,7 +1683,7 @@ m68k_ip (instring)
              && !(ok_arch & current_architecture))
            {
              char buf[200], *cp;
-             int len;
+
              strcpy (buf,
                      "invalid instruction for this architecture; needs ");
              cp = buf + strlen (buf);
@@ -1241,7 +1710,8 @@ m68k_ip (instring)
                    for (idx = 0; idx < sizeof (archs) / sizeof (archs[0]);
                         idx++)
                      {
-                       if (archs[idx].arch & ok_arch)
+                       if ((archs[idx].arch & ok_arch)
+                           && ! archs[idx].alias)
                          {
                            if (got_one)
                              {
@@ -1255,8 +1725,7 @@ m68k_ip (instring)
                      }
                  }
                }
-             len = cp - buf + 1;
-             cp = malloc (len);
+             cp = xmalloc (strlen (buf) + 1);
              strcpy (cp, buf);
              the_ins.error = cp;
            }
@@ -1294,6 +1763,12 @@ m68k_ip (instring)
        case '?':
        case '/':
        case '`':
+       case '<':
+       case '>':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
 #ifndef NO_68851
        case '|':
 #endif
@@ -1321,6 +1796,12 @@ m68k_ip (instring)
                  addword (nextword);
                  baseo = 0;
                  break;
+               case 'W':
+                 if (!issword (nextword))
+                   opP->error = "operand out of range";
+                 addword (nextword);
+                 baseo = 0;
+                 break;
                case 'l':
                  addword (nextword >> 16);
                  addword (nextword);
@@ -1409,6 +1890,20 @@ m68k_ip (instring)
            case DISP:
 
              nextword = get_num (&opP->disp, 80);
+
+             if (opP->reg == PC
+                 && ! isvar (&opP->disp)
+                 && m68k_abspcadd)
+               {
+                 opP->disp.exp.X_op = O_symbol;
+#ifndef BFD_ASSEMBLER
+                 opP->disp.exp.X_add_symbol = &abs_symbol;
+#else
+                 opP->disp.exp.X_add_symbol =
+                   section_symbol (absolute_section);
+#endif
+               }
+
              /* Force into index mode.  Hope this works */
 
              /* We do the first bit for 32-bit displacements, and the
@@ -1424,6 +1919,9 @@ m68k_ip (instring)
                           && cpu_of_arch (current_architecture) >= m68020)
                          || opP->disp.size == SIZE_LONG)))
                {
+                 if (cpu_of_arch (current_architecture) < m68020)
+                   opP->error =
+                     "displacement too large for this architecture; needs 68020 or higher";
                  if (opP->reg == PC)
                    tmpreg = 0x3B;      /* 7.3 */
                  else
@@ -1432,16 +1930,24 @@ m68k_ip (instring)
                    {
                      if (opP->reg == PC)
                        {
-#if 0
-                         addword (0x0170);
-                         add_fix ('l', &opP->disp, 1, 2);
-                         addword (0), addword (0);
-#else
-                         add_frag (adds (&opP->disp),
-                                   offs (&opP->disp),
-                                   TAB (PCLEA, SZ_UNDEF));
+                         if (opP->disp.size == SIZE_LONG
+#ifdef OBJ_ELF
+                             /* If the displacement needs pic
+                                relocation it cannot be relaxed.  */
+                             || opP->disp.pic_reloc != pic_none
 #endif
-                         break;
+                             )
+                           {
+                             addword (0x0170);
+                             add_fix ('l', &opP->disp, 1, 2);
+                           }
+                         else
+                           {
+                             add_frag (adds (&opP->disp),
+                                       offs (&opP->disp),
+                                       TAB (PCLEA, SZ_UNDEF));
+                             break;
+                           }
                        }
                      else
                        {
@@ -1514,17 +2020,18 @@ m68k_ip (instring)
                {
                  nextword |= (opP->index.reg - DATA) << 12;
 
-                 if (opP->index.size == SIZE_UNSPEC
-                     || opP->index.size == SIZE_LONG)
+                 if (opP->index.size == SIZE_LONG
+                     || (opP->index.size == SIZE_UNSPEC
+                         && m68k_index_width_default == SIZE_LONG))
                    nextword |= 0x800;
 
-                 if (cpu_of_arch (current_architecture) < m68020)
+                 if ((opP->index.scale != 1 
+                      && cpu_of_arch (current_architecture) < m68020)
+                     || (opP->index.scale == 8 
+                         && current_architecture == mcf5200))
                    {
-                     if (opP->index.scale != 1)
-                       {
-                         opP->error =
-                           "scale factor invalid on this architecture; needs 68020 or higher";
-                       }
+                     opP->error =
+                       "scale factor invalid on this architecture; needs cpu32 or 68020 or higher";
                    }
 
                  switch (opP->index.scale)
@@ -1587,8 +2094,20 @@ m68k_ip (instring)
                      else if (siz1 == SIZE_UNSPEC
                               && opP->reg == PC
                               && isvar (&opP->disp)
-                              && subs (&opP->disp) == NULL)
+                              && subs (&opP->disp) == NULL
+#ifdef OBJ_ELF
+                              /* If the displacement needs pic
+                                 relocation it cannot be relaxed.  */
+                              && opP->disp.pic_reloc == pic_none
+#endif
+                              )
                        {
+                         /* The code in md_convert_frag_1 needs to be
+                             able to adjust nextword.  Call frag_grow
+                             to ensure that we have enough space in
+                             the frag obstack to make all the bytes
+                             contiguous.  */
+                         frag_grow (14);
                          nextword += baseo & 0xff;
                          addword (nextword);
                          add_frag (adds (&opP->disp), offs (&opP->disp),
@@ -1621,12 +2140,14 @@ m68k_ip (instring)
              switch (siz1)
                {
                case SIZE_UNSPEC:
-                 if (isvar (&opP->disp) || !issword (baseo))
+                 if (isvar (&opP->disp)
+                     ? m68k_rel32
+                     : ! issword (baseo))
                    {
                      siz1 = SIZE_LONG;
                      nextword |= 0x30;
                    }
-                 else if (baseo == 0)
+                 else if (! isvar (&opP->disp) && baseo == 0)
                    nextword |= 0x10;
                  else
                    {
@@ -1648,15 +2169,19 @@ m68k_ip (instring)
              /* Figure out innner displacement stuff */
              if (opP->mode == POST || opP->mode == PRE)
                {
+                 if (cpu_of_arch (current_architecture) & cpu32)
+                   opP->error = "invalid operand mode for this architecture; needs 68020 or higher";
                  switch (siz2)
                    {
                    case SIZE_UNSPEC:
-                     if (isvar (&opP->odisp) || !issword (outro))
+                     if (isvar (&opP->odisp)
+                         ? m68k_rel32
+                         : ! issword (outro))
                        {
                          siz2 = SIZE_LONG;
                          nextword |= 0x3;
                        }
-                     else if (outro == 0)
+                     else if (! isvar (&opP->odisp) && outro == 0)
                        nextword |= 0x1;
                      else
                        {
@@ -1674,7 +2199,8 @@ m68k_ip (instring)
                      nextword |= 0x3;
                      break;
                    }
-                 if (opP->mode == POST)
+                 if (opP->mode == POST
+                     && (nextword & 0x40) == 0)
                    nextword |= 0x04;
                }
              addword (nextword);
@@ -1718,8 +2244,12 @@ m68k_ip (instring)
                  if (isvar (&opP->disp)
                      && !subs (&opP->disp)
                      && adds (&opP->disp)
-                     && (S_GET_SEGMENT (adds (&opP->disp)) == text_section)
-                     && now_seg == text_section
+#ifdef OBJ_ELF
+                     /* If the displacement needs pic relocation it
+                        cannot be relaxed.  */
+                     && opP->disp.pic_reloc == pic_none
+#endif
+                     && S_GET_SEGMENT (adds (&opP->disp)) == now_seg
                      && cpu_of_arch (current_architecture) >= m68020
                      && !flag_long_jumps
                      && !strchr ("~%&$?", s[0]))
@@ -1788,7 +2318,15 @@ m68k_ip (instring)
                opP->error = "out of range";
              insop (tmpreg, opcode);
              if (isvar (&opP->disp))
-               the_ins.reloc[the_ins.nrel - 1].n = (opcode->m_codenum) * 2;
+               the_ins.reloc[the_ins.nrel - 1].n =
+                 (opcode->m_codenum) * 2 + 1;
+             break;
+           case 'B':
+             if (!issbyte (tmpreg))
+               opP->error = "out of range";
+             opcode->m_opcode |= tmpreg;
+             if (isvar (&opP->disp))
+               the_ins.reloc[the_ins.nrel - 1].n = opcode->m_codenum * 2 - 1;
              break;
            case 'w':
              if (!isword (tmpreg))
@@ -1797,6 +2335,13 @@ m68k_ip (instring)
              if (isvar (&opP->disp))
                the_ins.reloc[the_ins.nrel - 1].n = (opcode->m_codenum) * 2;
              break;
+           case 'W':
+             if (!issword (tmpreg))
+               opP->error = "out of range";
+             insop (tmpreg, opcode);
+             if (isvar (&opP->disp))
+               the_ins.reloc[the_ins.nrel - 1].n = (opcode->m_codenum) * 2;
+             break;
            case 'l':
              /* Because of the way insop works, we put these two out
                 backwards.  */
@@ -1828,7 +2373,11 @@ m68k_ip (instring)
          switch (s[1])
            {
            case 'B':
-             add_fix ('B', &opP->disp, 1, -1);
+             /* The pc_fix argument winds up in fx_pcrel_adjust,
+                 which is a char, and may therefore be unsigned.  We
+                 want to pass -1, but we pass 64 instead, and convert
+                 back in md_pcrel_from.  */
+             add_fix ('B', &opP->disp, 1, 64);
              break;
            case 'W':
              add_fix ('w', &opP->disp, 1, 0);
@@ -1847,6 +2396,13 @@ m68k_ip (instring)
              if (subs (&opP->disp))    /* We can't relax it */
                goto long_branch;
 
+#ifdef OBJ_ELF
+             /* If the displacement needs pic relocation it cannot be
+                relaxed.  */
+             if (opP->disp.pic_reloc != pic_none)
+               goto long_branch;
+#endif
+
              /* This could either be a symbol, or an absolute
                 address.  No matter, the frag hacking will finger it
                 out.  Not quite: it can't switch from BRANCH to
@@ -1995,6 +2551,18 @@ m68k_ip (instring)
            case PCR:
              tmpreg = 0x808;
              break;
+            case ROMBAR:
+             tmpreg = 0xC00;
+             break;
+           case RAMBAR0:
+             tmpreg = 0xC04;
+             break;
+           case RAMBAR1:
+             tmpreg = 0xC05;
+             break;
+           case MBAR:
+             tmpreg = 0xC0F;
+             break;
            default:
              abort ();
            }
@@ -2136,7 +2704,9 @@ m68k_ip (instring)
          install_operand (s[1], tmpreg);
          break;
 
-       case 'P':
+       case '0':
+       case '1':
+       case '2':
          switch (opP->reg)
            {
            case TC:
@@ -2372,6 +2942,7 @@ install_operand (mode, val)
       break;
     case 'b':
     case 'w':
+    case 'W':
     case 'l':
       break;
     case 'e':
@@ -2429,25 +3000,31 @@ crack_operand (str, opP)
   register int parens;
   register int c;
   register char *beg_str;
+  int inquote = 0;
 
   if (!str)
     {
       return str;
     }
   beg_str = str;
-  for (parens = 0; *str && (parens > 0 || notend (str)); str++)
+  for (parens = 0; *str && (parens > 0 || inquote || notend (str)); str++)
     {
-      if (*str == '(')
-       parens++;
-      else if (*str == ')')
+      if (! inquote)
        {
-         if (!parens)
-           {                   /* ERROR */
-             opP->error = "Extra )";
-             return str;
+         if (*str == '(')
+           parens++;
+         else if (*str == ')')
+           {
+             if (!parens)
+               {                       /* ERROR */
+                 opP->error = "Extra )";
+                 return str;
+               }
+             --parens;
            }
-         --parens;
        }
+      if (flag_mri && *str == '\'')
+       inquote = ! inquote;
     }
   if (!*str && parens)
     {                          /* ERROR */
@@ -2567,29 +3144,54 @@ static const struct init_entry init_table[] =
   { "ccr", CCR },
   { "cc", CCR },
 
-  { "usp", USP },
-  { "isp", ISP },
-  { "sfc", SFC },
+  /* control registers */
+  { "sfc", SFC },              /* Source Function Code */
   { "sfcr", SFC },
-  { "dfc", DFC },
+  { "dfc", DFC },              /* Destination Function Code */
   { "dfcr", DFC },
-  { "cacr", CACR },
-  { "caar", CAAR },
-
-  { "vbr", VBR },
-
-  { "msp", MSP },
-  { "itt0", ITT0 },
-  { "itt1", ITT1 },
-  { "dtt0", DTT0 },
-  { "dtt1", DTT1 },
-  { "mmusr", MMUSR },
-  { "tc", TC },
-  { "srp", SRP },
-  { "urp", URP },
+  { "cacr", CACR },            /* Cache Control Register */
+  { "caar", CAAR },            /* Cache Address Register */
+
+  { "usp", USP },              /* User Stack Pointer */
+  { "vbr", VBR },              /* Vector Base Register */
+  { "msp", MSP },              /* Master Stack Pointer */
+  { "isp", ISP },              /* Interrupt Stack Pointer */
+
+  { "itt0", ITT0 },            /* Instruction Transparent Translation Reg 0 */
+  { "itt1", ITT1 },            /* Instruction Transparent Translation Reg 1 */
+  { "dtt0", DTT0 },            /* Data Transparent Translation Register 0 */
+  { "dtt1", DTT1 },            /* Data Transparent Translation Register 1 */
+
+  /* 68ec040 versions of same */
+  { "iacr0", ITT0 },           /* Instruction Access Control Register 0 */
+  { "iacr1", ITT1 },           /* Instruction Access Control Register 0 */
+  { "dacr0", DTT0 },           /* Data Access Control Register 0 */
+  { "dacr1", DTT1 },           /* Data Access Control Register 0 */
+
+  /* mcf5200 versions of same.  The ColdFire programmer's reference
+     manual indicated that the order is 2,3,0,1, but Ken Rose
+     <rose@netcom.com> says that 0,1,2,3 is the correct order.  */
+  { "acr0", ITT0 },            /* Access Control Unit 0 */
+  { "acr1", ITT1 },            /* Access Control Unit 1 */
+  { "acr2", DTT0 },            /* Access Control Unit 2 */
+  { "acr3", DTT1 },            /* Access Control Unit 3 */
+
+  { "tc", TC },                        /* MMU Translation Control Register */
+  { "tcr", TC },
+
+  { "mmusr", MMUSR },          /* MMU Status Register */
+  { "srp", SRP },              /* User Root Pointer */
+  { "urp", URP },              /* Supervisor Root Pointer */
+
   { "buscr", BUSCR },
   { "pcr", PCR },
 
+  { "rombar", ROMBAR },                /* ROM Base Address Register */
+  { "rambar0", RAMBAR0 },      /* ROM Base Address Register */
+  { "rambar1", RAMBAR1 },      /* ROM Base Address Register */
+  { "mbar", MBAR },            /* Module Base Address Register */
+  /* end of control registers */
+
   { "ac", AC },
   { "bc", BC },
   { "cal", CAL },
@@ -2676,7 +3278,42 @@ md_assemble (str)
   int shorts_this_frag;
   fixS *fixP;
 
-  memset ((char *) (&the_ins), '\0', sizeof (the_ins));
+  /* In MRI mode, the instruction and operands are separated by a
+     space.  Anything following the operands is a comment.  The label
+     has already been removed.  */
+  if (flag_mri)
+    {
+      char *s;
+      int fields = 0;
+      int infield = 0;
+      int inquote = 0;
+
+      for (s = str; *s != '\0'; s++)
+       {
+         if ((*s == ' ' || *s == '\t') && ! inquote)
+           {
+             if (infield)
+               {
+                 ++fields;
+                 if (fields >= 2)
+                   {
+                     *s = '\0';
+                     break;
+                   }
+                 infield = 0;
+               }
+           }
+         else
+           {
+             if (! infield)
+               infield = 1;
+             if (*s == '\'')
+               inquote = ! inquote;
+           }
+       }
+    }
+
+  memset ((char *) (&the_ins), '\0', sizeof (the_ins));
   m68k_ip (str);
   er = the_ins.error;
   if (!er)
@@ -2694,6 +3331,13 @@ md_assemble (str)
       return;
     }
 
+  /* If there is a current label, record that it marks an instruction.  */
+  if (current_label != NULL)
+    {
+      current_label->text = 1;
+      current_label = NULL;
+    }
+
   if (the_ins.nfrag == 0)
     {
       /* No frag hacking involved; just put it out */
@@ -2717,7 +3361,7 @@ md_assemble (str)
              n = 1;
              break;
            case '3':
-             n = 2;
+             n = 1;
              break;
            case 'w':
              n = 2;
@@ -2736,8 +3380,11 @@ md_assemble (str)
                              n,
                              &the_ins.reloc[m].exp,
                              the_ins.reloc[m].pcrel,
-                             NO_RELOC);
+                             get_reloc_code (n, the_ins.reloc[m].pcrel,
+                                             the_ins.reloc[m].pic_reloc));
          fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix;
+         if (the_ins.reloc[m].wid == 'B')
+           fixP->fx_signed = 1;
        }
       return;
     }
@@ -2780,7 +3427,8 @@ md_assemble (str)
                              wid,
                              &the_ins.reloc[m].exp,
                              the_ins.reloc[m].pcrel,
-                             NO_RELOC);
+                             get_reloc_code (wid, the_ins.reloc[m].pcrel,
+                                             the_ins.reloc[m].pic_reloc));
          fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix;
        }
       (void) frag_var (rs_machine_dependent, 10, 0,
@@ -2816,7 +3464,8 @@ md_assemble (str)
                          wid,
                          &the_ins.reloc[m].exp,
                          the_ins.reloc[m].pcrel,
-                         NO_RELOC);
+                         get_reloc_code (wid, the_ins.reloc[m].pcrel,
+                                         the_ins.reloc[m].pic_reloc));
       fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix;
     }
 }
@@ -2842,7 +3491,12 @@ md_begin ()
   register char c;
 
   if (flag_mri)
-    flag_reg_prefix_optional = 1;
+    {
+      flag_reg_prefix_optional = 1;
+      m68k_abspcadd = 1;
+      if (! m68k_rel32_from_cmdline)
+       m68k_rel32 = 0;
+    }
 
   op_hash = hash_new ();
 
@@ -2890,6 +3544,43 @@ md_begin ()
        as_fatal ("Internal Error: Can't hash %s: %s", alias, retval);
     }
 
+  /* In MRI mode, all unsized branches are variable sized.  Normally,
+     they are word sized.  */
+  if (flag_mri)
+    {
+      static struct m68k_opcode_alias mri_aliases[] =
+       {
+         { "bhi",      "jhi", },
+         { "bls",      "jls", },
+         { "bcc",      "jcc", },
+         { "bcs",      "jcs", },
+         { "bne",      "jne", },
+         { "beq",      "jeq", },
+         { "bvc",      "jvc", },
+         { "bvs",      "jvs", },
+         { "bpl",      "jpl", },
+         { "bmi",      "jmi", },
+         { "bge",      "jge", },
+         { "blt",      "jlt", },
+         { "bgt",      "jgt", },
+         { "ble",      "jle", },
+         { "bra",      "jra", },
+         { "bsr",      "jbsr", },
+       };
+
+      for (i = 0; i < sizeof mri_aliases / sizeof mri_aliases[0]; i++)
+       {
+         const char *name = mri_aliases[i].primary;
+         const char *alias = mri_aliases[i].alias;
+         PTR val = hash_find (op_hash, name);
+         if (!val)
+           as_fatal ("Internal Error: Can't find %s in hash table", name);
+         retval = hash_jam (op_hash, alias, val);
+         if (retval)
+           as_fatal ("Internal Error: Can't hash %s: %s", alias, retval);
+       }
+    }
+
   for (i = 0; i < sizeof (mklower_table); i++)
     mklower_table[i] = (isupper (c = (char) i)) ? tolower (c) : c;
 
@@ -2923,6 +3614,20 @@ md_begin ()
      */
   alt_notend_table['@'] = 1;
 
+  /* We need to put digits in alt_notend_table to handle
+       bfextu %d0{24:1},%d0
+     */
+  alt_notend_table['0'] = 1;
+  alt_notend_table['1'] = 1;
+  alt_notend_table['2'] = 1;
+  alt_notend_table['3'] = 1;
+  alt_notend_table['4'] = 1;
+  alt_notend_table['5'] = 1;
+  alt_notend_table['6'] = 1;
+  alt_notend_table['7'] = 1;
+  alt_notend_table['8'] = 1;
+  alt_notend_table['9'] = 1;
+
 #ifndef MIT_SYNTAX_ONLY
   /* Insert pseudo ops, these have to go into the opcode table since
      gas expects pseudo ops to start with a dot */
@@ -2942,6 +3647,45 @@ md_begin ()
 #endif
 
   init_regtable ();
+
+#ifdef OBJ_ELF
+  record_alignment (text_section, 2);
+  record_alignment (data_section, 2);
+  record_alignment (bss_section, 2);
+#endif
+}
+
+static void
+select_control_regs ()
+{
+  /* Note which set of "movec" control registers is available.  */
+  switch (cpu_of_arch (current_architecture))
+    {
+    case m68000:
+      control_regs = m68000_control_regs;
+      break;
+    case m68010:
+      control_regs = m68010_control_regs;
+      break;
+    case m68020:
+    case m68030:
+      control_regs = m68020_control_regs;
+      break;
+    case m68040:
+      control_regs = m68040_control_regs;
+      break;
+    case m68060:
+      control_regs = m68060_control_regs;
+      break;
+    case cpu32:
+      control_regs = cpu32_control_regs;
+      break;
+    case mcf5200:
+      control_regs = mcf5200_control_regs;
+      break;
+    default:
+      abort ();
+    }
 }
 
 void
@@ -3008,34 +3752,100 @@ m68k_init_after_args ()
 #endif
 
   /* Note which set of "movec" control registers is available.  */
-  switch (cpu_of_arch (current_architecture))
-    {
-    case m68000:
-      control_regs = m68000_control_regs;
-      break;
-    case m68010:
-      control_regs = m68010_control_regs;
-      break;
-    case m68020:
-    case m68030:
-      control_regs = m68020_control_regs;
-      break;
-    case m68040:
-      control_regs = m68040_control_regs;
-      break;
-    case m68060:
-      control_regs = m68060_control_regs;
-      break;
-    case cpu32:
-      control_regs = cpu32_control_regs;
-      break;
-    default:
-      abort ();
-    }
+  select_control_regs ();
 
   if (cpu_of_arch (current_architecture) < m68020)
     md_relax_table[TAB (PCINDEX, BYTE)].rlx_more = 0;
 }
+\f
+/* This is called when a label is defined.  */
+
+void
+m68k_frob_label (sym)
+     symbolS *sym;
+{
+  struct label_line *n;
+
+  n = (struct label_line *) xmalloc (sizeof *n);
+  n->next = labels;
+  n->label = sym;
+  as_where (&n->file, &n->line);
+  labels = n;
+  current_label = n;
+}
+
+/* This is called when a value that is not an instruction is emitted.  */
+
+void
+m68k_flush_pending_output ()
+{
+  current_label = NULL;
+}
+
+/* This is called at the end of the assembly, when the final value of
+   the label is known.  We warn if this is a text symbol aligned at an
+   odd location.  */
+
+void
+m68k_frob_symbol (sym)
+     symbolS *sym;
+{
+  if ((S_GET_VALUE (sym) & 1) != 0)
+    {
+      struct label_line *l;
+
+      for (l = labels; l != NULL; l = l->next)
+       {
+         if (l->label == sym)
+           {
+             if (l->text)
+               as_warn_where (l->file, l->line,
+                              "text label `%s' aligned to odd boundary",
+                              S_GET_NAME (sym));
+             break;
+           }
+       }
+    }
+}
+\f
+/* This is called if we go in or out of MRI mode because of the .mri
+   pseudo-op.  */
+
+void
+m68k_mri_mode_change (on)
+     int on;
+{
+  if (on)
+    {
+      if (! flag_reg_prefix_optional)
+       {
+         flag_reg_prefix_optional = 1;
+#ifdef REGISTER_PREFIX
+         init_regtable ();
+#endif
+       }
+      m68k_abspcadd = 1;
+      if (! m68k_rel32_from_cmdline)
+       m68k_rel32 = 0;
+    }
+  else
+    {
+      if (! reg_prefix_optional_seen)
+       {
+#ifdef REGISTER_PREFIX_OPTIONAL
+         flag_reg_prefix_optional = REGISTER_PREFIX_OPTIONAL;
+#else
+         flag_reg_prefix_optional = 0;
+#endif
+#ifdef REGISTER_PREFIX
+         init_regtable ();
+#endif
+       }
+      m68k_abspcadd = 0;
+      if (! m68k_rel32_from_cmdline)
+       m68k_rel32 = 1;
+    }
+}
 
 /* Equal to MAX_PRECISION in atof-ieee.c */
 #define MAX_LITTLENUMS 6
@@ -3128,6 +3938,15 @@ md_apply_fix_2 (fixP, val)
   else
     val &= 0x7fffffff;
 
+#ifdef OBJ_ELF
+  if (fixP->fx_addsy)
+    {
+      memset (buf, 0, fixP->fx_size);
+      fixP->fx_addnumber = val;        /* Remember value for emit_reloc */
+      return;
+    }
+#endif
+
   switch (fixP->fx_size)
     {
       /* The cast to offsetT below are necessary to make code correct for
@@ -3155,11 +3974,19 @@ md_apply_fix_2 (fixP, val)
       BAD_CASE (fixP->fx_size);
     }
 
+  /* Fix up a negative reloc.  */
+  if (fixP->fx_addsy == NULL && fixP->fx_subsy != NULL)
+    {
+      fixP->fx_addsy = fixP->fx_subsy;
+      fixP->fx_subsy = NULL;
+      fixP->fx_tcbit = 1;
+    }
+
   /* For non-pc-relative values, it's conceivable we might get something
      like "0xff" for a byte field.  So extend the upper part of the range
      to accept such numbers.  We arbitrarily disallow "-0xff" or "0xff+0xff",
      so that we can do any range checking at all.  */
-  if (!fixP->fx_pcrel)
+  if (! fixP->fx_pcrel && ! fixP->fx_signed)
     upper_limit = upper_limit * 2 + 1;
 
   if ((addressT) val > upper_limit
@@ -3253,7 +4080,6 @@ md_convert_frag_1 (fragP)
            {
              fragP->fr_opcode[0] = 0x4E;
              fragP->fr_opcode[1] = (char) 0xB9; /* JBSR with ABSL LONG offset */
-             subseg_change (text_section, 0); /* @@ */
 
              fix_new (fragP,
                       fragP->fr_fix,
@@ -3271,7 +4097,6 @@ md_convert_frag_1 (fragP)
            {
              fragP->fr_opcode[0] = 0x4E;
              fragP->fr_opcode[1] = (char) 0xF9; /* JMP  with ABSL LONG offset */
-             subseg_change (text_section, 0); /* @@ */
              fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
                       fragP->fr_offset, 0, NO_RELOC);
              fragP->fr_fix += 4;
@@ -3300,7 +4125,6 @@ md_convert_frag_1 (fragP)
       *buffer_address++ = 0x4e;        /* put in jmp long (0x4ef9) */
       *buffer_address++ = (char) 0xf9;
       fragP->fr_fix += 2;      /* account for jmp instruction */
-      subseg_change (text_section, 0);
       fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
               fragP->fr_offset, 0, NO_RELOC);
       fragP->fr_fix += 4;
@@ -3318,7 +4142,6 @@ md_convert_frag_1 (fragP)
       *buffer_address++ = (char) 0xf9;
 
       fragP->fr_fix += 6;      /* account for bra/jmp instructions */
-      subseg_change (text_section, 0);
       fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
               fragP->fr_offset, 0, NO_RELOC);
       fragP->fr_fix += 4;
@@ -3339,7 +4162,6 @@ md_convert_frag_1 (fragP)
       /* The thing to do here is force it to ABSOLUTE LONG, since
        PCREL is really trying to shorten an ABSOLUTE address anyway */
       /* JF FOO This code has not been tested */
-      subseg_change (text_section, 0);
       fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
               0, NO_RELOC);
       if ((fragP->fr_opcode[1] & 0x3F) != 0x3A)
@@ -3352,7 +4174,6 @@ md_convert_frag_1 (fragP)
       ext = 0;
       break;
     case TAB (PCLEA, SHORT):
-      subseg_change (text_section, 0);
       fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol,
               fragP->fr_offset, 1, NO_RELOC);
       fragP->fr_opcode[1] &= ~0x3F;
@@ -3360,7 +4181,6 @@ md_convert_frag_1 (fragP)
       ext = 2;
       break;
     case TAB (PCLEA, LONG):
-      subseg_change (text_section, 0);
       fixP = fix_new (fragP, (int) (fragP->fr_fix) + 2, 4, fragP->fr_symbol,
                      fragP->fr_offset, 1, NO_RELOC);
       fixP->fx_pcrel_adjust = 2;
@@ -3385,7 +4205,6 @@ md_convert_frag_1 (fragP)
       ext = 0;
       break;
     case TAB (PCINDEX, SHORT):
-      subseg_change (text_section, 0);
       disp += 2;
       assert (issword (disp));
       assert (fragP->fr_fix >= 2);
@@ -3398,7 +4217,6 @@ md_convert_frag_1 (fragP)
       ext = 2;
       break;
     case TAB (PCINDEX, LONG):
-      subseg_change (text_section, 0);
       disp += 2;
       fixP = fix_new (fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol,
                      fragP->fr_offset, (fragP->fr_opcode[1] & 077) == 073,
@@ -3474,7 +4292,6 @@ md_estimate_size_before_relax (fragP, segment)
              {
                fragP->fr_opcode[0] = 0x4E;
                fragP->fr_opcode[1] = (char) 0xB9; /* JBSR with ABSL LONG offset */
-               subseg_change (text_section, 0);
                fix_new (fragP, fragP->fr_fix, 4,
                         fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC);
                fragP->fr_fix += 4;
@@ -3484,7 +4301,6 @@ md_estimate_size_before_relax (fragP, segment)
              {
                fragP->fr_opcode[0] = 0x4E;
                fragP->fr_opcode[1] = (char) 0xF9; /* JMP  with ABSL LONG offset */
-               subseg_change (text_section, 0);
                fix_new (fragP, fragP->fr_fix, 4,
                         fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC);
                fragP->fr_fix += 4;
@@ -3561,7 +4377,6 @@ md_estimate_size_before_relax (fragP, segment)
            buffer_address[0] = 0x4e;   /* put in jmp long (0x4ef9) */
            buffer_address[1] = (char) 0xf8;
            fragP->fr_fix += 2; /* account for jmp instruction */
-           subseg_change (text_section, 0);
            fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
                     fragP->fr_offset, 0, NO_RELOC);
            fragP->fr_fix += 2;
@@ -3573,7 +4388,6 @@ md_estimate_size_before_relax (fragP, segment)
            buffer_address[0] = 0x4e;   /* put in jmp long (0x4ef9) */
            buffer_address[1] = (char) 0xf9;
            fragP->fr_fix += 2; /* account for jmp instruction */
-           subseg_change (text_section, 0);
            fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
                     fragP->fr_offset, 0, NO_RELOC);
            fragP->fr_fix += 4;
@@ -3604,7 +4418,6 @@ md_estimate_size_before_relax (fragP, segment)
            buffer_address[4] = 0x4e;   /* Put in Jump Word */
            buffer_address[5] = (char) 0xf8;
            fragP->fr_fix += 6; /* account for bra/jmp instruction */
-           subseg_change (text_section, 0);
            fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
                     fragP->fr_offset, 0, NO_RELOC);
            fragP->fr_fix += 2;
@@ -3616,7 +4429,6 @@ md_estimate_size_before_relax (fragP, segment)
            buffer_address[4] = 0x4e;   /* put in jmp long (0x4ef9) */
            buffer_address[5] = (char) 0xf9;
            fragP->fr_fix += 6; /* account for bra/jmp instruction */
-           subseg_change (text_section, 0);
            fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
                     fragP->fr_offset, 0, NO_RELOC);
            fragP->fr_fix += 4;
@@ -3665,13 +4477,27 @@ md_estimate_size_before_relax (fragP, segment)
     {
     case TAB (BCC68000, BYTE):
     case TAB (ABRANCH, BYTE):
-      /* We can't do a short jump to the next instruction,
-          so we force word mode.  */
-      if (fragP->fr_symbol && S_GET_VALUE (fragP->fr_symbol) == 0 &&
-         fragP->fr_symbol->sy_frag == fragP->fr_next)
+      /* We can't do a short jump to the next instruction, so in that
+        case we force word mode.  At this point S_GET_VALUE should
+        return the offset of the symbol within its frag.  If the
+        symbol is at the start of a frag, and it is the next frag
+        with any data in it (usually this is just the next frag, but
+        assembler listings may introduce empty frags), we must use
+        word mode.  */
+      if (fragP->fr_symbol && S_GET_VALUE (fragP->fr_symbol) == 0)
        {
-         fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
-         fragP->fr_var += 2;
+         fragS *l;
+
+         for (l = fragP->fr_next;
+              l != fragP->fr_symbol->sy_frag;
+              l = l->fr_next)
+           if (l->fr_fix + l->fr_var != 0)
+             break;
+         if (l == fragP->fr_symbol->sy_frag)
+           {
+             fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
+             fragP->fr_var += 2;
+           }
        }
       break;
     default:
@@ -3976,6 +4802,7 @@ s_even (ignore)
   if (!need_pass_2)            /* Never make frag if expect extra pass. */
     frag_align (temp, (int) temp_fill);
   demand_empty_rest_of_line ();
+  record_alignment (now_seg, temp);
 }
 
 static void
@@ -3987,6 +4814,18 @@ s_proc (ignore)
 \f
 /* Pseudo-ops handled for MRI compatibility.  */
 
+/* This function returns non-zero if the argument is a conditional
+   pseudo-op.  This is called when checking whether a pending
+   alignment is needed.  */
+
+int
+m68k_conditional_pseudoop (pop)
+     pseudo_typeS *pop;
+{
+  return (pop->poc_handler == s_mri_if
+         || pop->poc_handler == s_mri_else);
+}
+
 /* Handle an MRI style chip specification.  */
 
 static void
@@ -4027,6 +4866,9 @@ mri_chip ()
        current_architecture |= m68851;
       *input_line_pointer = c;
     }
+
+  /* Update info about available control registers.  */
+  select_control_regs ();
 }
 
 /* The MRI CHIP pseudo-op.  */
@@ -4035,7 +4877,14 @@ static void
 s_chip (ignore)
      int ignore;
 {
+  char *stop = NULL;
+  char stopc;
+
+  if (flag_mri)
+    stop = mri_comment_field (&stopc);
   mri_chip ();
+  if (flag_mri)
+    mri_comment_end (stop, stopc);
   demand_empty_rest_of_line ();
 }
 
@@ -4067,88 +4916,1624 @@ s_fopt (ignore)
 
   demand_empty_rest_of_line ();
 }
-\f
-/*
- * md_parse_option
- *     Invocation line includes a switch not recognized by the base assembler.
- *     See if it's a processor-specific option.  These are:
- *
- *     -[A]m[c]68000, -[A]m[c]68008, -[A]m[c]68010, -[A]m[c]68020, -[A]m[c]68030, -[A]m[c]68040
- *     -[A]m[c]68881, -[A]m[c]68882, -[A]m[c]68851
- *             Select the architecture.  Instructions or features not
- *             supported by the selected architecture cause fatal
- *             errors.  More than one may be specified.  The default is
- *             -m68020 -m68851 -m68881.  Note that -m68008 is a synonym
- *             for -m68000, and -m68882 is a synonym for -m68881.
- *     -[A]m[c]no-68851, -[A]m[c]no-68881
- *             Don't accept 688?1 instructions.  (The "c" is kind of silly,
- *             so don't use or document it, but that's the way the parsing
- *             works).
- *
- *     -pic    Indicates PIC.
- *     -k      Indicates PIC.  (Sun 3 only.)
- *
- */
 
-#ifdef OBJ_ELF
-CONST char *md_shortopts = "lSA:m:kQ:V";
-#else
-CONST char *md_shortopts = "lSA:m:k";
-#endif
+/* The structure used to handle the MRI OPT pseudo-op.  */
 
-struct option md_longopts[] = {
-#define OPTION_PIC (OPTION_MD_BASE)
-  {"pic", no_argument, NULL, OPTION_PIC},
-#define OPTION_REGISTER_PREFIX_OPTIONAL (OPTION_MD_BASE + 1)
-  {"register-prefix-optional", no_argument, NULL,
-     OPTION_REGISTER_PREFIX_OPTIONAL},
-  {NULL, no_argument, NULL, 0}
+struct opt_action
+{
+  /* The name of the option.  */
+  const char *name;
+
+  /* If this is not NULL, just call this function.  The first argument
+     is the ARG field of this structure, the second argument is
+     whether the option was negated.  */
+  void (*pfn) PARAMS ((int arg, int on));
+
+  /* If this is not NULL, and the PFN field is NULL, set the variable
+     this points to.  Set it to the ARG field if the option was not
+     negated, and the NOTARG field otherwise.  */
+  int *pvar;
+
+  /* The value to pass to PFN or to assign to *PVAR.  */
+  int arg;
+
+  /* The value to assign to *PVAR if the option is negated.  If PFN is
+     NULL, and PVAR is not NULL, and ARG and NOTARG are the same, then
+     the option may not be negated.  */
+  int notarg;
 };
-size_t md_longopts_size = sizeof(md_longopts);
 
-int
-md_parse_option (c, arg)
-     int c;
-     char *arg;
+/* The table used to handle the MRI OPT pseudo-op.  */
+
+static void skip_to_comma PARAMS ((int, int));
+static void opt_nest PARAMS ((int, int));
+static void opt_chip PARAMS ((int, int));
+static void opt_list PARAMS ((int, int));
+static void opt_list_symbols PARAMS ((int, int));
+
+static const struct opt_action opt_table[] =
 {
-  switch (c)
-    {
-    case 'l':                  /* -l means keep external to 2 bit offset
-                                  rather than 16 bit one */
-      flag_short_refs = 1;
-      break;
+  { "abspcadd", 0, &m68k_abspcadd, 1, 0 },
+
+  /* We do relaxing, so there is little use for these options.  */
+  { "b", 0, 0, 0, 0 },
+  { "brs", 0, 0, 0, 0 },
+  { "brb", 0, 0, 0, 0 },
+  { "brl", 0, 0, 0, 0 },
+  { "brw", 0, 0, 0, 0 },
+
+  { "c", 0, 0, 0, 0 },
+  { "cex", 0, 0, 0, 0 },
+  { "case", 0, &symbols_case_sensitive, 1, 0 },
+  { "cl", 0, 0, 0, 0 },
+  { "cre", 0, 0, 0, 0 },
+  { "d", 0, &flag_keep_locals, 1, 0 },
+  { "e", 0, 0, 0, 0 },
+  { "f", 0, &flag_short_refs, 1, 0 },
+  { "frs", 0, &flag_short_refs, 1, 0 },
+  { "frl", 0, &flag_short_refs, 0, 1 },
+  { "g", 0, 0, 0, 0 },
+  { "i", 0, 0, 0, 0 },
+  { "m", 0, 0, 0, 0 },
+  { "mex", 0, 0, 0, 0 },
+  { "mc", 0, 0, 0, 0 },
+  { "md", 0, 0, 0, 0 },
+  { "nest", opt_nest, 0, 0, 0 },
+  { "next", skip_to_comma, 0, 0, 0 },
+  { "o", 0, 0, 0, 0 },
+  { "old", 0, 0, 0, 0 },
+  { "op", skip_to_comma, 0, 0, 0 },
+  { "pco", 0, 0, 0, 0 },
+  { "p", opt_chip, 0, 0, 0 },
+  { "pcr", 0, 0, 0, 0 },
+  { "pcs", 0, 0, 0, 0 },
+  { "r", 0, 0, 0, 0 },
+  { "quick", 0, &m68k_quick, 1, 0 },
+  { "rel32", 0, &m68k_rel32, 1, 0 },
+  { "s", opt_list, 0, 0, 0 },
+  { "t", opt_list_symbols, 0, 0, 0 },
+  { "w", 0, &flag_no_warnings, 0, 1 },
+  { "x", 0, 0, 0, 0 }
+};
 
-    case 'S':                  /* -S means that jbsr's always turn into
-                                  jsr's.  */
-      flag_long_jumps = 1;
-      break;
+#define OPTCOUNT (sizeof opt_table / sizeof opt_table[0])
 
-    case 'A':
-      if (*arg == 'm')
-       arg++;
-      /* intentional fall-through */
-    case 'm':
+/* The MRI OPT pseudo-op.  */
 
-      if (arg[0] == 'n' && arg[1] == 'o' && arg[2] == '-')
+static void
+s_opt (ignore)
+     int ignore;
+{
+  do
+    {
+      int t;
+      char *s;
+      char c;
+      int i;
+      const struct opt_action *o;
+
+      SKIP_WHITESPACE ();
+
+      t = 1;
+      if (*input_line_pointer == '-')
        {
-         int i;
-         unsigned long arch;
-         const char *oarg = arg;
+         ++input_line_pointer;
+         t = 0;
+       }
+      else if (strncasecmp (input_line_pointer, "NO", 2) == 0)
+       {
+         input_line_pointer += 2;
+         t = 0;
+       }
 
-         arg += 3;
-         if (*arg == 'm')
+      s = input_line_pointer;
+      c = get_symbol_end ();
+
+      for (i = 0, o = opt_table; i < OPTCOUNT; i++, o++)
+       {
+         if (strcasecmp (s, o->name) == 0)
            {
-             arg++;
-             if (arg[0] == 'c' && arg[1] == '6')
-               arg++;
-           }
-         for (i = 0; i < n_archs; i++)
-           if (!strcmp (arg, archs[i].name))
+             if (o->pfn)
+               {
+                 /* Restore input_line_pointer now in case the option
+                    takes arguments.  */
+                 *input_line_pointer = c;
+                 (*o->pfn) (o->arg, t);
+               }
+             else if (o->pvar != NULL)
+               {
+                 if (! t && o->arg == o->notarg)
+                   as_bad ("option `%s' may not be negated", s);
+                 *input_line_pointer = c;
+                 *o->pvar = t ? o->arg : o->notarg;
+               }
+             else
+               *input_line_pointer = c;
              break;
-         if (i == n_archs)
-           {
-           unknown:
-             as_bad ("unrecognized option `%s'", oarg);
+           }
+       }
+      if (i >= OPTCOUNT)
+       {
+         as_bad ("option `%s' not recognized", s);
+         *input_line_pointer = c;
+       }
+    }
+  while (*input_line_pointer++ == ',');
+
+  /* Move back to terminating character.  */
+  --input_line_pointer;
+  demand_empty_rest_of_line ();
+}
+
+/* Skip ahead to a comma.  This is used for OPT options which we do
+   not suppor tand which take arguments.  */
+
+static void
+skip_to_comma (arg, on)
+     int arg;
+     int on;
+{
+  while (*input_line_pointer != ','
+        && ! is_end_of_line[(unsigned char) *input_line_pointer])
+    ++input_line_pointer;
+}
+
+/* Handle the OPT NEST=depth option.  */
+
+static void
+opt_nest (arg, on)
+     int arg;
+     int on;
+{
+  if (*input_line_pointer != '=')
+    {
+      as_bad ("bad format of OPT NEST=depth");
+      return;
+    }
+
+  ++input_line_pointer;
+  max_macro_nest = get_absolute_expression ();
+}
+
+/* Handle the OPT P=chip option.  */
+
+static void
+opt_chip (arg, on)
+     int arg;
+     int on;
+{
+  if (*input_line_pointer != '=')
+    {
+      /* This is just OPT P, which we do not support.  */
+      return;
+    }
+
+  ++input_line_pointer;
+  mri_chip ();
+}
+
+/* Handle the OPT S option.  */
+
+static void
+opt_list (arg, on)
+     int arg;
+     int on;
+{
+  listing_list (on);
+}
+
+/* Handle the OPT T option.  */
+
+static void
+opt_list_symbols (arg, on)
+     int arg;
+     int on;
+{
+  if (on)
+    listing |= LISTING_SYMBOLS;
+  else
+    listing &=~ LISTING_SYMBOLS;
+}
+
+/* Handle the MRI REG pseudo-op.  */
+
+static void
+s_reg (ignore)
+     int ignore;
+{
+  char *s;
+  int c;
+  struct m68k_op rop;
+  unsigned long mask;
+  char *stop = NULL;
+  char stopc;
+
+  if (line_label == NULL)
+    {
+      as_bad ("missing label");
+      ignore_rest_of_line ();
+      return;
+    }
+
+  if (flag_mri)
+    stop = mri_comment_field (&stopc);
+
+  SKIP_WHITESPACE ();
+
+  s = input_line_pointer;
+  while (isalnum ((unsigned char) *input_line_pointer)
+#ifdef REGISTER_PREFIX
+        || *input_line_pointer == REGISTER_PREFIX
+#endif
+        || *input_line_pointer == '/'
+        || *input_line_pointer == '-')
+    ++input_line_pointer;
+  c = *input_line_pointer;
+  *input_line_pointer = '\0';
+
+  if (m68k_ip_op (s, &rop) != 0)
+    {
+      if (rop.error == NULL)
+       as_bad ("bad register list");
+      else
+       as_bad ("bad register list: %s", rop.error);
+      *input_line_pointer = c;
+      ignore_rest_of_line ();
+      return;
+    }
+
+  *input_line_pointer = c;
+
+  if (rop.mode == REGLST)
+    mask = rop.mask;
+  else if (rop.mode == DREG)
+    mask = 1 << (rop.reg - DATA0);
+  else if (rop.mode == AREG)
+    mask = 1 << (rop.reg - ADDR0 + 8);
+  else if (rop.mode == FPREG)
+    mask = 1 << (rop.reg - FP0 + 16);
+  else if (rop.mode == CONTROL
+          && rop.reg == FPI)
+    mask = 1 << 24;
+  else if (rop.mode == CONTROL
+          && rop.reg == FPS)
+    mask = 1 << 25;
+  else if (rop.mode == CONTROL
+          && rop.reg == FPC)
+    mask = 1 << 26;
+  else
+    {
+      as_bad ("bad register list");
+      ignore_rest_of_line ();
+      return;
+    }
+
+  S_SET_SEGMENT (line_label, absolute_section);
+  S_SET_VALUE (line_label, mask);
+  line_label->sy_frag = &zero_address_frag;
+
+  if (flag_mri)
+    mri_comment_end (stop, stopc);
+
+  demand_empty_rest_of_line ();
+}
+
+/* This structure is used for the MRI SAVE and RESTORE pseudo-ops.  */
+
+struct save_opts
+{
+  struct save_opts *next;
+  int abspcadd;
+  int symbols_case_sensitive;
+  int keep_locals;
+  int short_refs;
+  int architecture;
+  int quick;
+  int rel32;
+  int listing;
+  int no_warnings;
+  /* FIXME: We don't save OPT S.  */
+};
+
+/* This variable holds the stack of saved options.  */
+
+static struct save_opts *save_stack;
+
+/* The MRI SAVE pseudo-op.  */
+
+static void
+s_save (ignore)
+     int ignore;
+{
+  struct save_opts *s;
+
+  s = (struct save_opts *) xmalloc (sizeof (struct save_opts));
+  s->abspcadd = m68k_abspcadd;
+  s->symbols_case_sensitive = symbols_case_sensitive;
+  s->keep_locals = flag_keep_locals;
+  s->short_refs = flag_short_refs;
+  s->architecture = current_architecture;
+  s->quick = m68k_quick;
+  s->rel32 = m68k_rel32;
+  s->listing = listing;
+  s->no_warnings = flag_no_warnings;
+
+  s->next = save_stack;
+  save_stack = s;
+
+  demand_empty_rest_of_line ();
+}
+
+/* The MRI RESTORE pseudo-op.  */
+
+static void
+s_restore (ignore)
+     int ignore;
+{
+  struct save_opts *s;
+
+  if (save_stack == NULL)
+    {
+      as_bad ("restore without save");
+      ignore_rest_of_line ();
+      return;
+    }
+
+  s = save_stack;
+  save_stack = s->next;
+
+  m68k_abspcadd = s->abspcadd;
+  symbols_case_sensitive = s->symbols_case_sensitive;
+  flag_keep_locals = s->keep_locals;
+  flag_short_refs = s->short_refs;
+  current_architecture = s->architecture;
+  m68k_quick = s->quick;
+  m68k_rel32 = s->rel32;
+  listing = s->listing;
+  flag_no_warnings = s->no_warnings;
+
+  free (s);
+
+  demand_empty_rest_of_line ();
+}
+
+/* Types of MRI structured control directives.  */
+
+enum mri_control_type
+{
+  mri_for,
+  mri_if,
+  mri_repeat,
+  mri_while
+};
+
+/* This structure is used to stack the MRI structured control
+   directives.  */
+
+struct mri_control_info
+{
+  /* The directive within which this one is enclosed.  */
+  struct mri_control_info *outer;
+
+  /* The type of directive.  */
+  enum mri_control_type type;
+
+  /* Whether an ELSE has been in an IF.  */
+  int else_seen;
+
+  /* The add or sub statement at the end of a FOR.  */
+  char *incr;
+
+  /* The label of the top of a FOR or REPEAT loop.  */
+  char *top;
+
+  /* The label to jump to for the next iteration, or the else
+     expression of a conditional.  */
+  char *next;
+
+  /* The label to jump to to break out of the loop, or the label past
+     the end of a conditional.  */
+  char *bottom;
+};
+
+/* The stack of MRI structured control directives.  */
+
+static struct mri_control_info *mri_control_stack;
+
+/* The current MRI structured control directive index number, used to
+   generate label names.  */
+
+static int mri_control_index;
+
+/* Some function prototypes.  */
+
+static char *mri_control_label PARAMS ((void));
+static struct mri_control_info *push_mri_control
+  PARAMS ((enum mri_control_type));
+static void pop_mri_control PARAMS ((void));
+static int parse_mri_condition PARAMS ((int *));
+static int parse_mri_control_operand
+  PARAMS ((int *, char **, char **, char **, char **));
+static int swap_mri_condition PARAMS ((int));
+static int reverse_mri_condition PARAMS ((int));
+static void build_mri_control_operand
+  PARAMS ((int, int, char *, char *, char *, char *, const char *,
+          const char *, int));
+static void parse_mri_control_expression
+  PARAMS ((char *, int, const char *, const char *, int));
+
+/* Generate a new MRI label structured control directive label name.  */
+
+static char *
+mri_control_label ()
+{
+  char *n;
+
+  n = (char *) xmalloc (20);
+  sprintf (n, "%smc%d", FAKE_LABEL_NAME, mri_control_index);
+  ++mri_control_index;
+  return n;
+}
+
+/* Create a new MRI structured control directive.  */
+
+static struct mri_control_info *
+push_mri_control (type)
+     enum mri_control_type type;
+{
+  struct mri_control_info *n;
+
+  n = (struct mri_control_info *) xmalloc (sizeof (struct mri_control_info));
+
+  n->type = type;
+  n->else_seen = 0;
+  if (type == mri_if || type == mri_while)
+    n->top = NULL;
+  else
+    n->top = mri_control_label ();
+  n->next = mri_control_label ();
+  n->bottom = mri_control_label ();
+
+  n->outer = mri_control_stack;
+  mri_control_stack = n;
+
+  return n;
+}
+
+/* Pop off the stack of MRI structured control directives.  */
+
+static void
+pop_mri_control ()
+{
+  struct mri_control_info *n;
+
+  n = mri_control_stack;
+  mri_control_stack = n->outer;
+  if (n->top != NULL)
+    free (n->top);
+  free (n->next);
+  free (n->bottom);
+  free (n);
+}
+
+/* Recognize a condition code in an MRI structured control expression.  */
+
+static int
+parse_mri_condition (pcc)
+     int *pcc;
+{
+  char c1, c2;
+
+  know (*input_line_pointer == '<');
+
+  ++input_line_pointer;
+  c1 = *input_line_pointer++;
+  c2 = *input_line_pointer++;
+
+  if (*input_line_pointer != '>')
+    {
+      as_bad ("syntax error in structured control directive");
+      return 0;
+    }
+
+  ++input_line_pointer;
+  SKIP_WHITESPACE ();
+
+  if (isupper (c1))
+    c1 = tolower (c1);
+  if (isupper (c2))
+    c2 = tolower (c2);
+
+  *pcc = (c1 << 8) | c2;
+
+  return 1;
+}
+
+/* Parse a single operand in an MRI structured control expression.  */
+
+static int
+parse_mri_control_operand (pcc, leftstart, leftstop, rightstart, rightstop)
+     int *pcc;
+     char **leftstart;
+     char **leftstop;
+     char **rightstart;
+     char **rightstop;
+{
+  char *s;
+
+  SKIP_WHITESPACE ();
+
+  *pcc = -1;
+  *leftstart = NULL;
+  *leftstop = NULL;
+  *rightstart = NULL;
+  *rightstop = NULL;
+
+  if (*input_line_pointer == '<')
+    {
+      /* It's just a condition code.  */
+      return parse_mri_condition (pcc);
+    }
+
+  /* Look ahead for the condition code.  */
+  for (s = input_line_pointer; *s != '\0'; ++s)
+    {
+      if (*s == '<' && s[1] != '\0' && s[2] != '\0' && s[3] == '>')
+       break;
+    }
+  if (*s == '\0')
+    {
+      as_bad ("missing condition code in structured control directive");
+      return 0;
+    }
+
+  *leftstart = input_line_pointer;
+  *leftstop = s;
+  if (*leftstop > *leftstart
+      && ((*leftstop)[-1] == ' ' || (*leftstop)[-1] == '\t'))
+    --*leftstop;
+
+  input_line_pointer = s;
+  if (! parse_mri_condition (pcc))
+    return 0;
+
+  /* Look ahead for AND or OR or end of line.  */
+  for (s = input_line_pointer; *s != '\0'; ++s)
+    {
+      if ((strncasecmp (s, "AND", 3) == 0
+          && (s[3] == '.' || ! is_part_of_name (s[3])))
+         || (strncasecmp (s, "OR", 2) == 0
+             && (s[2] == '.' || ! is_part_of_name (s[2]))))
+       break;
+    }
+
+  *rightstart = input_line_pointer;
+  *rightstop = s;
+  if (*rightstop > *rightstart
+      && ((*rightstop)[-1] == ' ' || (*rightstop)[-1] == '\t'))
+    --*rightstop;
+
+  input_line_pointer = s;
+
+  return 1;
+}
+
+#define MCC(b1, b2) (((b1) << 8) | (b2))
+
+/* Swap the sense of a condition.  This changes the condition so that
+   it generates the same result when the operands are swapped.  */
+
+static int
+swap_mri_condition (cc)
+     int cc;
+{
+  switch (cc)
+    {
+    case MCC ('h', 'i'): return MCC ('c', 's');
+    case MCC ('l', 's'): return MCC ('c', 'c');
+    case MCC ('c', 'c'): return MCC ('l', 's');
+    case MCC ('c', 's'): return MCC ('h', 'i');
+    case MCC ('p', 'l'): return MCC ('m', 'i');
+    case MCC ('m', 'i'): return MCC ('p', 'l');
+    case MCC ('g', 'e'): return MCC ('l', 'e');
+    case MCC ('l', 't'): return MCC ('g', 't');
+    case MCC ('g', 't'): return MCC ('l', 't');
+    case MCC ('l', 'e'): return MCC ('g', 'e');
+    }
+  return cc;
+}
+
+/* Reverse the sense of a condition.  */
+
+static int
+reverse_mri_condition (cc)
+     int cc;
+{
+  switch (cc)
+    {
+    case MCC ('h', 'i'): return MCC ('l', 's');
+    case MCC ('l', 's'): return MCC ('h', 'i');
+    case MCC ('c', 'c'): return MCC ('c', 's');
+    case MCC ('c', 's'): return MCC ('c', 'c');
+    case MCC ('n', 'e'): return MCC ('e', 'q');
+    case MCC ('e', 'q'): return MCC ('n', 'e');
+    case MCC ('v', 'c'): return MCC ('v', 's');
+    case MCC ('v', 's'): return MCC ('v', 'c');
+    case MCC ('p', 'l'): return MCC ('m', 'i');
+    case MCC ('m', 'i'): return MCC ('p', 'l');
+    case MCC ('g', 'e'): return MCC ('l', 't');
+    case MCC ('l', 't'): return MCC ('g', 'e');
+    case MCC ('g', 't'): return MCC ('l', 'e');
+    case MCC ('l', 'e'): return MCC ('g', 't');
+    }
+  return cc;
+}
+
+/* Build an MRI structured control expression.  This generates test
+   and branch instructions.  It goes to TRUELAB if the condition is
+   true, and to FALSELAB if the condition is false.  Exactly one of
+   TRUELAB and FALSELAB will be NULL, meaning to fall through.  QUAL
+   is the size qualifier for the expression.  EXTENT is the size to
+   use for the branch.  */
+
+static void
+build_mri_control_operand (qual, cc, leftstart, leftstop, rightstart,
+                          rightstop, truelab, falselab, extent)
+     int qual;
+     int cc;
+     char *leftstart;
+     char *leftstop;
+     char *rightstart;
+     char *rightstop;
+     const char *truelab;
+     const char *falselab;
+     int extent;
+{
+  char *buf;
+  char *s;
+
+  if (leftstart != NULL)
+    {
+      struct m68k_op leftop, rightop;
+      char c;
+
+      /* Swap the compare operands, if necessary, to produce a legal
+        m68k compare instruction.  Comparing a register operand with
+        a non-register operand requires the register to be on the
+        right (cmp, cmpa).  Comparing an immediate value with
+        anything requires the immediate value to be on the left
+        (cmpi).  */
+
+      c = *leftstop;
+      *leftstop = '\0';
+      (void) m68k_ip_op (leftstart, &leftop);
+      *leftstop = c;
+
+      c = *rightstop;
+      *rightstop = '\0';
+      (void) m68k_ip_op (rightstart, &rightop);
+      *rightstop = c;
+
+      if (rightop.mode == IMMED
+         || ((leftop.mode == DREG || leftop.mode == AREG)
+             && (rightop.mode != DREG && rightop.mode != AREG)))
+       {
+         char *temp;
+
+         cc = swap_mri_condition (cc);
+         temp = leftstart;
+         leftstart = rightstart;
+         rightstart = temp;
+         temp = leftstop;
+         leftstop = rightstop;
+         rightstop = temp;
+       }
+    }
+
+  if (truelab == NULL)
+    {
+      cc = reverse_mri_condition (cc);
+      truelab = falselab;
+    }
+      
+  if (leftstart != NULL)
+    {
+      buf = (char *) xmalloc (20
+                             + (leftstop - leftstart)
+                             + (rightstop - rightstart));
+      s = buf;
+      *s++ = 'c';
+      *s++ = 'm';
+      *s++ = 'p';
+      if (qual != '\0')
+       *s++ = qual;
+      *s++ = ' ';
+      memcpy (s, leftstart, leftstop - leftstart);
+      s += leftstop - leftstart;
+      *s++ = ',';
+      memcpy (s, rightstart, rightstop - rightstart);
+      s += rightstop - rightstart;
+      *s = '\0';
+      md_assemble (buf);
+      free (buf);
+    }
+      
+  buf = (char *) xmalloc (20 + strlen (truelab));
+  s = buf;
+  *s++ = 'b';
+  *s++ = cc >> 8;
+  *s++ = cc & 0xff;
+  if (extent != '\0')
+    *s++ = extent;
+  *s++ = ' ';
+  strcpy (s, truelab);
+  md_assemble (buf);
+  free (buf);
+}
+
+/* Parse an MRI structured control expression.  This generates test
+   and branch instructions.  STOP is where the expression ends.  It
+   goes to TRUELAB if the condition is true, and to FALSELAB if the
+   condition is false.  Exactly one of TRUELAB and FALSELAB will be
+   NULL, meaning to fall through.  QUAL is the size qualifier for the
+   expression.  EXTENT is the size to use for the branch.  */
+
+static void
+parse_mri_control_expression (stop, qual, truelab, falselab, extent)
+     char *stop;
+     int qual;
+     const char *truelab;
+     const char *falselab;
+     int extent;
+{
+  int c;
+  int cc;
+  char *leftstart;
+  char *leftstop;
+  char *rightstart;
+  char *rightstop;
+
+  c = *stop;
+  *stop = '\0';
+
+  if (! parse_mri_control_operand (&cc, &leftstart, &leftstop,
+                                  &rightstart, &rightstop))
+    {
+      *stop = c;
+      return;
+    }
+
+  if (strncasecmp (input_line_pointer, "AND", 3) == 0)
+    {
+      const char *flab;
+
+      if (falselab != NULL)
+       flab = falselab;
+      else
+       flab = mri_control_label ();
+
+      build_mri_control_operand (qual, cc, leftstart, leftstop, rightstart,
+                                rightstop, (const char *) NULL, flab, extent);
+
+      input_line_pointer += 3;
+      if (*input_line_pointer != '.'
+         || input_line_pointer[1] == '\0')
+       qual = '\0';
+      else
+       {
+         qual = input_line_pointer[1];
+         input_line_pointer += 2;
+       }
+
+      if (! parse_mri_control_operand (&cc, &leftstart, &leftstop,
+                                      &rightstart, &rightstop))
+       {
+         *stop = c;
+         return;
+       }
+
+      build_mri_control_operand (qual, cc, leftstart, leftstop, rightstart,
+                                rightstop, truelab, falselab, extent);
+
+      if (falselab == NULL)
+       colon (flab);
+    }
+  else if (strncasecmp (input_line_pointer, "OR", 2) == 0)
+    {
+      const char *tlab;
+
+      if (truelab != NULL)
+       tlab = truelab;
+      else
+       tlab = mri_control_label ();
+
+      build_mri_control_operand (qual, cc, leftstart, leftstop, rightstart,
+                                rightstop, tlab, (const char *) NULL, extent);
+
+      input_line_pointer += 2;
+      if (*input_line_pointer != '.'
+         || input_line_pointer[1] == '\0')
+       qual = '\0';
+      else
+       {
+         qual = input_line_pointer[1];
+         input_line_pointer += 2;
+       }
+
+      if (! parse_mri_control_operand (&cc, &leftstart, &leftstop,
+                                      &rightstart, &rightstop))
+       {
+         *stop = c;
+         return;
+       }
+
+      build_mri_control_operand (qual, cc, leftstart, leftstop, rightstart,
+                                rightstop, truelab, falselab, extent);
+
+      if (truelab == NULL)
+       colon (tlab);
+    }
+  else
+    {
+      build_mri_control_operand (qual, cc, leftstart, leftstop, rightstart,
+                                rightstop, truelab, falselab, extent);
+    }
+
+  *stop = c;
+  if (input_line_pointer != stop)
+    as_bad ("syntax error in structured control directive");
+}
+
+/* Handle the MRI IF pseudo-op.  This may be a structured control
+   directive, or it may be a regular assembler conditional, depending
+   on its operands.  */
+
+static void
+s_mri_if (qual)
+     int qual;
+{
+  char *s;
+  int c;
+  struct mri_control_info *n;
+
+  /* A structured control directive must end with THEN with an
+     optional qualifier.  */
+  s = input_line_pointer;
+  while (! is_end_of_line[(unsigned char) *s]
+        && (! flag_mri || *s != '*'))
+    ++s;
+  --s;
+  while (s > input_line_pointer && (*s == ' ' || *s == '\t'))
+    --s;
+
+  if (s - input_line_pointer > 1
+      && s[-1] == '.')
+    s -= 2;
+
+  if (s - input_line_pointer < 3
+      || strncasecmp (s - 3, "THEN", 4) != 0)
+    {
+      if (qual != '\0')
+       {
+         as_bad ("missing then");
+         ignore_rest_of_line ();
+         return;
+       }
+
+      /* It's a conditional.  */
+      s_if (O_ne);
+      return;
+    }
+
+  /* Since this might be a conditional if, this pseudo-op will be
+     called even if we are supported to be ignoring input.  Double
+     check now.  Clobber *input_line_pointer so that ignore_input
+     thinks that this is not a special pseudo-op.  */
+  c = *input_line_pointer;
+  *input_line_pointer = 0;
+  if (ignore_input ())
+    {
+      *input_line_pointer = c;
+      while (! is_end_of_line[(unsigned char) *input_line_pointer])
+       ++input_line_pointer;
+      demand_empty_rest_of_line ();
+      return;
+    }
+  *input_line_pointer = c;
+
+  n = push_mri_control (mri_if);
+
+  parse_mri_control_expression (s - 3, qual, (const char *) NULL,
+                               n->next, s[1] == '.' ? s[2] : '\0');
+
+  if (s[1] == '.')
+    input_line_pointer = s + 3;
+  else
+    input_line_pointer = s + 1;
+
+  if (flag_mri)
+    {
+      while (! is_end_of_line[(unsigned char) *input_line_pointer])
+       ++input_line_pointer;
+    }
+
+  demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI else pseudo-op.  If we are currently doing an MRI
+   structured IF, associate the ELSE with the IF.  Otherwise, assume
+   it is a conditional else.  */
+
+static void
+s_mri_else (qual)
+     int qual;
+{
+  int c;
+  char *buf;
+  char q[2];
+
+  if (qual == '\0'
+      && (mri_control_stack == NULL
+         || mri_control_stack->type != mri_if
+         || mri_control_stack->else_seen))
+    {
+      s_else (0);
+      return;
+    }
+
+  c = *input_line_pointer;
+  *input_line_pointer = 0;
+  if (ignore_input ())
+    {
+      *input_line_pointer = c;
+      while (! is_end_of_line[(unsigned char) *input_line_pointer])
+       ++input_line_pointer;
+      demand_empty_rest_of_line ();
+      return;
+    }
+  *input_line_pointer = c;
+
+  if (mri_control_stack == NULL
+      || mri_control_stack->type != mri_if
+      || mri_control_stack->else_seen)
+    {
+      as_bad ("else without matching if");
+      ignore_rest_of_line ();
+      return;
+    }
+
+  mri_control_stack->else_seen = 1;
+
+  buf = (char *) xmalloc (20 + strlen (mri_control_stack->bottom));
+  q[0] = qual;
+  q[1] = '\0';
+  sprintf (buf, "bra%s %s", q, mri_control_stack->bottom);
+  md_assemble (buf);
+  free (buf);
+
+  colon (mri_control_stack->next);
+
+  if (flag_mri)
+    {
+      while (! is_end_of_line[(unsigned char) *input_line_pointer])
+       ++input_line_pointer;
+    }
+
+  demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI ENDI pseudo-op.  */
+
+static void
+s_mri_endi (ignore)
+     int ignore;
+{
+  if (mri_control_stack == NULL
+      || mri_control_stack->type != mri_if)
+    {
+      as_bad ("endi without matching if");
+      ignore_rest_of_line ();
+      return;
+    }
+
+  /* ignore_input will not return true for ENDI, so we don't need to
+     worry about checking it again here.  */
+
+  if (! mri_control_stack->else_seen)
+    colon (mri_control_stack->next);
+  colon (mri_control_stack->bottom);
+
+  pop_mri_control ();
+
+  if (flag_mri)
+    {
+      while (! is_end_of_line[(unsigned char) *input_line_pointer])
+       ++input_line_pointer;
+    }
+
+  demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI BREAK pseudo-op.  */
+
+static void
+s_mri_break (extent)
+     int extent;
+{
+  struct mri_control_info *n;
+  char *buf;
+  char ex[2];
+
+  n = mri_control_stack;
+  while (n != NULL
+        && n->type != mri_for
+        && n->type != mri_repeat
+        && n->type != mri_while)
+    n = n->outer;
+  if (n == NULL)
+    {
+      as_bad ("break outside of structured loop");
+      ignore_rest_of_line ();
+      return;
+    }
+
+  buf = (char *) xmalloc (20 + strlen (n->bottom));
+  ex[0] = extent;
+  ex[1] = '\0';
+  sprintf (buf, "bra%s %s", ex, n->bottom);
+  md_assemble (buf);
+  free (buf);
+
+  if (flag_mri)
+    {
+      while (! is_end_of_line[(unsigned char) *input_line_pointer])
+       ++input_line_pointer;
+    }
+
+  demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI NEXT pseudo-op.  */
+
+static void
+s_mri_next (extent)
+     int extent;
+{
+  struct mri_control_info *n;
+  char *buf;
+  char ex[2];
+
+  n = mri_control_stack;
+  while (n != NULL
+        && n->type != mri_for
+        && n->type != mri_repeat
+        && n->type != mri_while)
+    n = n->outer;
+  if (n == NULL)
+    {
+      as_bad ("next outside of structured loop");
+      ignore_rest_of_line ();
+      return;
+    }
+
+  buf = (char *) xmalloc (20 + strlen (n->next));
+  ex[0] = extent;
+  ex[1] = '\0';
+  sprintf (buf, "bra%s %s", ex, n->next);
+  md_assemble (buf);
+  free (buf);
+
+  if (flag_mri)
+    {
+      while (! is_end_of_line[(unsigned char) *input_line_pointer])
+       ++input_line_pointer;
+    }
+
+  demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI FOR pseudo-op.  */
+
+static void
+s_mri_for (qual)
+     int qual;
+{
+  const char *varstart, *varstop;
+  const char *initstart, *initstop;
+  const char *endstart, *endstop;
+  const char *bystart, *bystop;
+  int up;
+  int by;
+  int extent;
+  struct mri_control_info *n;
+  char *buf;
+  char *s;
+  char ex[2];
+
+  /* The syntax is
+       FOR.q var = init { TO | DOWNTO } end [ BY by ] DO.e
+     */
+
+  SKIP_WHITESPACE ();
+  varstart = input_line_pointer;
+
+  /* Look for the '='.  */
+  while (! is_end_of_line[(unsigned char) *input_line_pointer]
+        && *input_line_pointer != '=')
+    ++input_line_pointer;
+  if (*input_line_pointer != '=')
+    {
+      as_bad ("missing =");
+      ignore_rest_of_line ();
+      return;
+    }
+
+  varstop = input_line_pointer;
+  if (varstop > varstart
+      && (varstop[-1] == ' ' || varstop[-1] == '\t'))
+    --varstop;
+
+  ++input_line_pointer;
+
+  initstart = input_line_pointer;
+
+  /* Look for TO or DOWNTO.  */
+  up = 1;
+  initstop = NULL;
+  while (! is_end_of_line[(unsigned char) *input_line_pointer])
+    {
+      if (strncasecmp (input_line_pointer, "TO", 2) == 0
+         && ! is_part_of_name (input_line_pointer[2]))
+       {
+         initstop = input_line_pointer;
+         input_line_pointer += 2;
+         break;
+       }
+      if (strncasecmp (input_line_pointer, "DOWNTO", 6) == 0
+         && ! is_part_of_name (input_line_pointer[6]))
+       {
+         initstop = input_line_pointer;
+         up = 0;
+         input_line_pointer += 6;
+         break;
+       }
+      ++input_line_pointer;
+    }
+  if (initstop == NULL)
+    {
+      as_bad ("missing to or downto");
+      ignore_rest_of_line ();
+      return;
+    }
+  if (initstop > initstart
+      && (initstop[-1] == ' ' || initstop[-1] == '\t'))
+    --initstop;
+
+  SKIP_WHITESPACE ();
+  endstart = input_line_pointer;
+
+  /* Look for BY or DO.  */
+  by = 0;
+  endstop = NULL;
+  while (! is_end_of_line[(unsigned char) *input_line_pointer])
+    {
+      if (strncasecmp (input_line_pointer, "BY", 2) == 0
+         && ! is_part_of_name (input_line_pointer[2]))
+       {
+         endstop = input_line_pointer;
+         by = 1;
+         input_line_pointer += 2;
+         break;
+       }
+      if (strncasecmp (input_line_pointer, "DO", 2) == 0
+         && (input_line_pointer[2] == '.'
+             || ! is_part_of_name (input_line_pointer[2])))
+       {
+         endstop = input_line_pointer;
+         input_line_pointer += 2;
+         break;
+       }
+      ++input_line_pointer;
+    }
+  if (endstop == NULL)
+    {
+      as_bad ("missing do");
+      ignore_rest_of_line ();
+      return;
+    }
+  if (endstop > endstart
+      && (endstop[-1] == ' ' || endstop[-1] == '\t'))
+    --endstop;
+
+  if (! by)
+    {
+      bystart = "#1";
+      bystop = bystart + 2;
+    }
+  else
+    {
+      SKIP_WHITESPACE ();
+      bystart = input_line_pointer;
+
+      /* Look for DO.  */
+      bystop = NULL;
+      while (! is_end_of_line[(unsigned char) *input_line_pointer])
+       {
+         if (strncasecmp (input_line_pointer, "DO", 2) == 0
+             && (input_line_pointer[2] == '.'
+                 || ! is_part_of_name (input_line_pointer[2])))
+           {
+             bystop = input_line_pointer;
+             input_line_pointer += 2;
+             break;
+           }
+         ++input_line_pointer;
+       }
+      if (bystop == NULL)
+       {
+         as_bad ("missing do");
+         ignore_rest_of_line ();
+         return;
+       }
+      if (bystop > bystart
+         && (bystop[-1] == ' ' || bystop[-1] == '\t'))
+       --bystop;
+    }
+
+  if (*input_line_pointer != '.')
+    extent = '\0';
+  else
+    {
+      extent = input_line_pointer[1];
+      input_line_pointer += 2;
+    }
+
+  /* We have fully parsed the FOR operands.  Now build the loop.  */
+
+  n = push_mri_control (mri_for);
+
+  buf = (char *) xmalloc (50 + (input_line_pointer - varstart));
+
+  /* move init,var */
+  s = buf;
+  *s++ = 'm';
+  *s++ = 'o';
+  *s++ = 'v';
+  *s++ = 'e';
+  if (qual != '\0')
+    *s++ = qual;
+  *s++ = ' ';
+  memcpy (s, initstart, initstop - initstart);
+  s += initstop - initstart;
+  *s++ = ',';
+  memcpy (s, varstart, varstop - varstart);
+  s += varstop - varstart;
+  *s = '\0';
+  md_assemble (buf);
+
+  colon (n->top);
+
+  /* cmp end,var */
+  s = buf;
+  *s++ = 'c';
+  *s++ = 'm';
+  *s++ = 'p';
+  if (qual != '\0')
+    *s++ = qual;
+  *s++ = ' ';
+  memcpy (s, endstart, endstop - endstart);
+  s += endstop - endstart;
+  *s++ = ',';
+  memcpy (s, varstart, varstop - varstart);
+  s += varstop - varstart;
+  *s = '\0';
+  md_assemble (buf);
+
+  /* bcc bottom */
+  ex[0] = extent;
+  ex[1] = '\0';
+  if (up)
+    sprintf (buf, "blt%s %s", ex, n->bottom);
+  else
+    sprintf (buf, "bgt%s %s", ex, n->bottom);
+  md_assemble (buf);
+
+  /* Put together the add or sub instruction used by ENDF.  */
+  s = buf;
+  if (up)
+    strcpy (s, "add");
+  else
+    strcpy (s, "sub");
+  s += 3;
+  if (qual != '\0')
+    *s++ = qual;
+  *s++ = ' ';
+  memcpy (s, bystart, bystop - bystart);
+  s += bystop - bystart;
+  *s++ = ',';
+  memcpy (s, varstart, varstop - varstart);
+  s += varstop - varstart;
+  *s = '\0';
+  n->incr = buf;
+
+  if (flag_mri)
+    {
+      while (! is_end_of_line[(unsigned char) *input_line_pointer])
+       ++input_line_pointer;
+    }
+
+  demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI ENDF pseudo-op.  */
+
+static void
+s_mri_endf (ignore)
+     int ignore;
+{
+  if (mri_control_stack == NULL
+      || mri_control_stack->type != mri_for)
+    {
+      as_bad ("endf without for");
+      ignore_rest_of_line ();
+      return;
+    }
+
+  colon (mri_control_stack->next);
+
+  md_assemble (mri_control_stack->incr);
+
+  sprintf (mri_control_stack->incr, "bra %s", mri_control_stack->top);
+  md_assemble (mri_control_stack->incr);
+
+  free (mri_control_stack->incr);
+
+  colon (mri_control_stack->bottom);
+
+  pop_mri_control ();
+
+  if (flag_mri)
+    {
+      while (! is_end_of_line[(unsigned char) *input_line_pointer])
+       ++input_line_pointer;
+    }
+
+  demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI REPEAT pseudo-op.  */
+
+static void
+s_mri_repeat (ignore)
+     int ignore;
+{
+  struct mri_control_info *n;
+
+  n = push_mri_control (mri_repeat);
+  colon (n->top);
+  if (flag_mri)
+    {
+      while (! is_end_of_line[(unsigned char) *input_line_pointer])
+       ++input_line_pointer;
+    }
+  demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI UNTIL pseudo-op.  */
+
+static void
+s_mri_until (qual)
+     int qual;
+{
+  char *s;
+
+  if (mri_control_stack == NULL
+      || mri_control_stack->type != mri_repeat)
+    {
+      as_bad ("until without repeat");
+      ignore_rest_of_line ();
+      return;
+    }
+
+  colon (mri_control_stack->next);
+
+  for (s = input_line_pointer; ! is_end_of_line[(unsigned char) *s]; s++)
+    ;
+
+  parse_mri_control_expression (s, qual, (const char *) NULL,
+                               mri_control_stack->top, '\0');
+
+  colon (mri_control_stack->bottom);
+
+  input_line_pointer = s;
+
+  pop_mri_control ();
+
+  if (flag_mri)
+    {
+      while (! is_end_of_line[(unsigned char) *input_line_pointer])
+       ++input_line_pointer;
+    }
+
+  demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI WHILE pseudo-op.  */
+
+static void
+s_mri_while (qual)
+     int qual;
+{
+  char *s;
+
+  struct mri_control_info *n;
+
+  s = input_line_pointer;
+  while (! is_end_of_line[(unsigned char) *s]
+        && (! flag_mri || *s != '*'))
+    s++;
+  --s;
+  while (*s == ' ' || *s == '\t')
+    --s;
+  if (s - input_line_pointer > 1
+      && s[-1] == '.')
+    s -= 2;
+  if (s - input_line_pointer < 2
+      || strncasecmp (s - 1, "DO", 2) != 0)
+    {
+      as_bad ("missing do");
+      ignore_rest_of_line ();
+      return;
+    }
+
+  n = push_mri_control (mri_while);
+
+  colon (n->next);
+
+  parse_mri_control_expression (s - 1, qual, (const char *) NULL, n->bottom,
+                               s[1] == '.' ? s[2] : '\0');
+
+  input_line_pointer = s + 1;
+  if (*input_line_pointer == '.')
+    input_line_pointer += 2;
+
+  if (flag_mri)
+    {
+      while (! is_end_of_line[(unsigned char) *input_line_pointer])
+       ++input_line_pointer;
+    }
+
+  demand_empty_rest_of_line ();
+}
+
+/* Handle the MRI ENDW pseudo-op.  */
+
+static void
+s_mri_endw (ignore)
+     int ignore;
+{
+  char *buf;
+
+  if (mri_control_stack == NULL
+      || mri_control_stack->type != mri_while)
+    {
+      as_bad ("endw without while");
+      ignore_rest_of_line ();
+      return;
+    }
+
+  buf = (char *) xmalloc (20 + strlen (mri_control_stack->next));
+  sprintf (buf, "bra %s", mri_control_stack->next);
+  md_assemble (buf);
+  free (buf);
+
+  colon (mri_control_stack->bottom);
+
+  pop_mri_control ();
+
+  if (flag_mri)
+    {
+      while (! is_end_of_line[(unsigned char) *input_line_pointer])
+       ++input_line_pointer;
+    }
+
+  demand_empty_rest_of_line ();
+}
+\f
+/*
+ * md_parse_option
+ *     Invocation line includes a switch not recognized by the base assembler.
+ *     See if it's a processor-specific option.  These are:
+ *
+ *     -[A]m[c]68000, -[A]m[c]68008, -[A]m[c]68010, -[A]m[c]68020, -[A]m[c]68030, -[A]m[c]68040
+ *     -[A]m[c]68881, -[A]m[c]68882, -[A]m[c]68851
+ *             Select the architecture.  Instructions or features not
+ *             supported by the selected architecture cause fatal
+ *             errors.  More than one may be specified.  The default is
+ *             -m68020 -m68851 -m68881.  Note that -m68008 is a synonym
+ *             for -m68000, and -m68882 is a synonym for -m68881.
+ *     -[A]m[c]no-68851, -[A]m[c]no-68881
+ *             Don't accept 688?1 instructions.  (The "c" is kind of silly,
+ *             so don't use or document it, but that's the way the parsing
+ *             works).
+ *
+ *     -pic    Indicates PIC.
+ *     -k      Indicates PIC.  (Sun 3 only.)
+ *
+ *     --bitwise-or
+ *             Permit `|' to be used in expressions.
+ *
+ */
+
+#ifdef OBJ_ELF
+CONST char *md_shortopts = "lSA:m:kQ:V";
+#else
+CONST char *md_shortopts = "lSA:m:k";
+#endif
+
+struct option md_longopts[] = {
+#define OPTION_PIC (OPTION_MD_BASE)
+  {"pic", no_argument, NULL, OPTION_PIC},
+#define OPTION_REGISTER_PREFIX_OPTIONAL (OPTION_MD_BASE + 1)
+  {"register-prefix-optional", no_argument, NULL,
+     OPTION_REGISTER_PREFIX_OPTIONAL},
+#define OPTION_BITWISE_OR (OPTION_MD_BASE + 2)
+  {"bitwise-or", no_argument, NULL, OPTION_BITWISE_OR},
+#define OPTION_BASE_SIZE_DEFAULT_16 (OPTION_MD_BASE + 3)
+  {"base-size-default-16", no_argument, NULL, OPTION_BASE_SIZE_DEFAULT_16},
+#define OPTION_BASE_SIZE_DEFAULT_32 (OPTION_MD_BASE + 4)
+  {"base-size-default-32", no_argument, NULL, OPTION_BASE_SIZE_DEFAULT_32},
+#define OPTION_DISP_SIZE_DEFAULT_16 (OPTION_MD_BASE + 5)
+  {"disp-size-default-16", no_argument, NULL, OPTION_DISP_SIZE_DEFAULT_16},
+#define OPTION_DISP_SIZE_DEFAULT_32 (OPTION_MD_BASE + 6)
+  {"disp-size-default-32", no_argument, NULL, OPTION_DISP_SIZE_DEFAULT_32},
+  {NULL, no_argument, NULL, 0}
+};
+size_t md_longopts_size = sizeof(md_longopts);
+
+int
+md_parse_option (c, arg)
+     int c;
+     char *arg;
+{
+  switch (c)
+    {
+    case 'l':                  /* -l means keep external to 2 bit offset
+                                  rather than 16 bit one */
+      flag_short_refs = 1;
+      break;
+
+    case 'S':                  /* -S means that jbsr's always turn into
+                                  jsr's.  */
+      flag_long_jumps = 1;
+      break;
+
+    case 'A':
+      if (*arg == 'm')
+       arg++;
+      /* intentional fall-through */
+    case 'm':
+
+      if (arg[0] == 'n' && arg[1] == 'o' && arg[2] == '-')
+       {
+         int i;
+         unsigned long arch;
+         const char *oarg = arg;
+
+         arg += 3;
+         if (*arg == 'm')
+           {
+             arg++;
+             if (arg[0] == 'c' && arg[1] == '6')
+               arg++;
+           }
+         for (i = 0; i < n_archs; i++)
+           if (!strcmp (arg, archs[i].name))
+             break;
+         if (i == n_archs)
+           {
+           unknown:
+             as_bad ("unrecognized option `%s'", oarg);
              return 0;
            }
          arch = archs[i].arch;
@@ -4206,10 +6591,50 @@ md_parse_option (c, arg)
 
     case OPTION_REGISTER_PREFIX_OPTIONAL:
       flag_reg_prefix_optional = 1;
+      reg_prefix_optional_seen = 1;
       break;
 
-    case 'Q':
+      /* -V: SVR4 argument to print version ID.  */
     case 'V':
+      print_version_id ();
+      break;
+
+      /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section
+        should be emitted or not.  FIXME: Not implemented.  */
+    case 'Q':
+      break;
+
+    case OPTION_BITWISE_OR:
+      {
+       char *n, *t;
+       const char *s;
+
+       n = (char *) xmalloc (strlen (m68k_comment_chars) + 1);
+       t = n;
+       for (s = m68k_comment_chars; *s != '\0'; s++)
+         if (*s != '|')
+           *t++ = *s;
+       *t = '\0';
+       m68k_comment_chars = n;
+      }
+      break;
+
+    case OPTION_BASE_SIZE_DEFAULT_16:
+      m68k_index_width_default = SIZE_WORD;
+      break;
+
+    case OPTION_BASE_SIZE_DEFAULT_32:
+      m68k_index_width_default = SIZE_LONG;
+      break;
+
+    case OPTION_DISP_SIZE_DEFAULT_16:
+      m68k_rel32 = 0;
+      m68k_rel32_from_cmdline = 1;
+      break;
+
+    case OPTION_DISP_SIZE_DEFAULT_32:
+      m68k_rel32 = 1;
+      m68k_rel32_from_cmdline = 1;
       break;
 
     default:
@@ -4228,18 +6653,25 @@ md_show_usage (stream)
 -l                     use 1 word for refs to undefined symbols [default 2]\n\
 -m68000 | -m68008 | -m68010 | -m68020 | -m68030 | -m68040 | -m68060\n\
  | -m68302 | -m68331 | -m68332 | -m68333 | -m68340 | -m68360\n\
- | -mcpu32\n\
+ | -mcpu32 | -m5200\n\
                        specify variant of 680X0 architecture [default 68020]\n\
 -m68881 | -m68882 | -mno-68881 | -mno-68882\n\
                        target has/lacks floating-point coprocessor\n\
-                       [default yes for 68020, 68030, and cpu32]\n\
+                       [default yes for 68020, 68030, and cpu32]\n");
+  fprintf(stream, "\
 -m68851 | -mno-68851\n\
                        target has/lacks memory-management unit coprocessor\n\
                        [default yes for 68020 and up]\n\
 -pic, -k               generate position independent code\n\
 -S                     turn jbsr into jsr\n\
 --register-prefix-optional\n\
-                       recognize register names without prefix character\n");
+                       recognize register names without prefix character\n\
+--bitwise-or           do not treat `|' as a comment character\n");
+  fprintf (stream, "\
+--base-size-default-16 base reg without size is 16 bits\n\
+--base-size-default-32 base reg without size is 32 bits (default)\n\
+--disp-size-default-16 displacement with unknown size is 16 bits\n\
+--disp-size-default-32 displacement with unknown size is 32 bits (default)\n");
 }
 \f
 #ifdef TEST2
@@ -4359,7 +6791,14 @@ long
 md_pcrel_from (fixP)
      fixS *fixP;
 {
-  return (fixP->fx_where + fixP->fx_frag->fr_address - fixP->fx_pcrel_adjust);
+  int adjust;
+
+  /* Because fx_pcrel_adjust is a char, and may be unsigned, we store
+     -1 as 64.  */
+  adjust = fixP->fx_pcrel_adjust;
+  if (adjust == 64)
+    adjust = -1;
+  return fixP->fx_where + fixP->fx_frag->fr_address - adjust;
 }
 
 #ifndef BFD_ASSEMBLER
This page took 0.062176 seconds and 4 git commands to generate.