* config/tc-m68k.c (struct label_line): Define.
[deliverable/binutils-gdb.git] / gas / config / tc-m68k.c
index f0d419b57063f5c3547b11ed32116ccd678721ec..1e82c90695b91ec73b6195972c34721fb045e01f 100644 (file)
@@ -1,7 +1,6 @@
-/* tc-m68k.c  All the m68020 specific stuff in one convenient, huge,
-   slow to compile, easy to find file.
-
-   Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc.
+/* tc-m68k.c -- Assemble for the m68k family
+   Copyright (C) 1987, 91, 92, 93, 94, 95, 96, 1997
+   Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GAS; see the file COPYING.  If not, write to
-   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   along with GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
 
 #include <ctype.h>
-#define  NO_RELOC 0
 #include "as.h"
-
-/* need TARGET_CPU */
-#include "config.h"
-
 #include "obstack.h"
+#include "subsegs.h"
 
-/* The opcode table is too big for gcc, which (currently) requires
-   exponential space at compile time for initialized arrays.  */
-#ifdef __GNUC__
-#define DO_BREAK_UP_BIG_DECL
-#define BREAK_UP_BIG_DECL      }; struct m68k_opcode m68k_opcodes_2[] = {
-#define AND_OTHER_PART         sizeof (m68k_opcodes_2)
-#endif
-
-/* Note that this file includes real declarations and thus can only be
-   included by one source file per executable.  */
 #include "opcode/m68k.h"
-
-#ifndef BFD_ASSEMBLER
-#ifdef TE_SUN
-/* This variable contains the value to write out at the beginning of
-   the a.out file.  The 2<<16 means that this is a 68020 file instead
-   of an old-style 68000 file */
-
-long omagic = 2 << 16 | OMAGIC;        /* Magic byte for header file */
+#include "m68k-parse.h"
+
+/* 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
-long omagic = OMAGIC;
+const char *m68k_comment_chars = "|";
 #endif
-#endif
-
-/* This array holds the chars that always start a comment.  If the
-   pre-processor is disabled, these aren't very useful */
-CONST char comment_chars[] = "|";
 
 /* This array holds the chars that only start a comment at the beginning of
    a line.  If the line seems to have the form '# 123 filename'
@@ -63,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";
@@ -81,6 +62,68 @@ CONST char FLT_CHARS[] = "rRsSfFdDxXeEpP";
 
 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.  Not implemented.  For ELF there are other means 
+   to denote pic relocations.  */
+int flag_want_pic;
+
+static int flag_short_refs;    /* -l option */
+static int flag_long_jumps;    /* -S option */
+
+#ifdef REGISTER_PREFIX_OPTIONAL
+int flag_reg_prefix_optional = REGISTER_PREFIX_OPTIONAL;
+#else
+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;
@@ -92,310 +135,183 @@ static struct obstack robyn;
 #define LONG           2
 #define SZ_UNDEF       3
 #undef BRANCH
+/* Case `g' except when BCC68000 is applicable.  */
 #define ABRANCH                1
+/* Coprocessor branches.  */
 #define FBRANCH                2
+/* Mode 7.2 -- program counter indirect with (16-bit) displacement,
+   supported on all cpus.  Widens to 32-bit absolute.  */
 #define PCREL          3
+/* For inserting an extra jmp instruction with long offset on 68000,
+   for expanding conditional branches.  (Not bsr or bra.)  Since the
+   68000 doesn't support 32-bit displacements for conditional
+   branches, we fake it by reversing the condition and branching
+   around a jmp with an absolute long operand.  */
 #define BCC68000        4
+/* For the DBcc "instructions".  If the displacement requires 32 bits,
+   the branch-around-a-jump game is played here too.  */
 #define DBCC            5
+/* Not currently used?  */
 #define PCLEA          6
+/* Mode AINDX (apc-relative) using PC, with variable target, might fit
+   in 16 or 8 bits.  */
+#define PCINDEX                7
 
-/* Operands we can parse:  (And associated modes)
-
-   numb:       8 bit num
-   numw:       16 bit num
-   numl:       32 bit num
-   dreg:       data reg 0-7
-   reg:        address or data register
-   areg:       address register
-   apc:        address register, PC, ZPC or empty string
-   num:        16 or 32 bit num
-   num2:       like num
-   sz: w or l          if omitted, l assumed
-   scale:      1 2 4 or 8      if omitted, 1 assumed
-
-   7.4 IMMED #num                              --> NUM
-   0.? DREG  dreg                              --> dreg
-   1.? AREG  areg                              --> areg
-   2.? AINDR areg@                             --> *(areg)
-   3.? AINC  areg@+                    --> *(areg++)
-   4.? ADEC  areg@-                    --> *(--areg)
-   5.? AOFF  apc@(numw)                        --> *(apc+numw) -- empty string and ZPC not allowed here
-   6.? AINDX apc@(num,reg:sz:scale)    --> *(apc+num+reg*scale)
-   6.? AINDX apc@(reg:sz:scale)                --> same, with num=0
-   6.? APODX apc@(num)@(num2,reg:sz:scale)     --> *(*(apc+num)+num2+reg*scale)
-   6.? APODX apc@(num)@(reg:sz:scale)  --> same, with num2=0
-   6.? AMIND apc@(num)@(num2)          --> *(*(apc+num)+num2) (previous mode without an index reg)
-   6.? APRDX apc@(num,reg:sz:scale)@(num2)     --> *(*(apc+num+reg*scale)+num2)
-   6.? APRDX apc@(reg:sz:scale)@(num2) --> same, with num=0
-   7.0 ABSL  num:sz                    --> *(num)
-   num                         --> *(num) (sz L assumed)
-   *** MSCR  otherreg                  --> Magic
-   With -l option
-   5.? AOFF  apc@(num)                 --> *(apc+num) -- empty string and ZPC not allowed here still
-   ?.? DINDR dreg@                     --> (dreg) -- cas2 only
-
-   examples:
-   #foo        #0x35   #12
-   d2
-   a4
-   a3@
-   a5@+
-   a6@-
-   a2@(12)     pc@(14)
-   a1@(5,d2:w:1)       @(45,d6:l:4)
-   pc@(a2)             @(d4)
-   etc . . .
-
-
-   #name@(numw)        -->turn into PC rel mode
-   apc@(num8,reg:sz:scale)             --> *(apc+num8+reg*scale)
-
-   */
-
-enum operand_type
-  {
-    IMMED = 1,
-    DREG,
-    AREG,
-    AINDR,
-    ADEC,
-    AINC,
-    AOFF,
-    AINDX,
-    APODX,
-    AMIND,
-    APRDX,
-    ABSL,
-    MSCR,
-    REGLST,
-    DINDR
-  };
-
-
-struct m68k_exp
+struct m68k_incant
   {
-    char *e_beg;
-    char *e_end;
-    expressionS e_exp;
-    short e_siz;               /* 0== default 1==short/byte 2==word 3==long */
+    const char *m_operands;
+    unsigned long m_opcode;
+    short m_opnum;
+    short m_codenum;
+    int m_arch;
+    struct m68k_incant *m_next;
   };
 
-/* DATA and ADDR have to be contiguous, so that reg-DATA gives 0-7==data reg,
-   8-15==addr reg for operands that take both types */
+#define getone(x)      ((((x)->m_opcode)>>16)&0xffff)
+#define gettwo(x)      (((x)->m_opcode)&0xffff)
 
-enum _register
-  {
-    DATA = 1,                  /*   1- 8 == data registers 0-7 */
-    DATA0 = DATA,
-    DATA1,
-    DATA2,
-    DATA3,
-    DATA4,
-    DATA5,
-    DATA6,
-    DATA7,
-
-    ADDR,
-    ADDR0 = ADDR,
-    ADDR1,
-    ADDR2,
-    ADDR3,
-    ADDR4,
-    ADDR5,
-    ADDR6,
-    ADDR7,
-
-    /* Note that COPNUM==processor #1 -- COPNUM+7==#8, which stores as 000 */
-    /* I think. . .  */
-
-    SP = ADDR7,
-
-    FPREG,                     /* Eight FP registers */
-    FP0 = FPREG,
-    FP1,
-    FP2,
-    FP3,
-    FP4,
-    FP5,
-    FP6,
-    FP7,
-    COPNUM = (FPREG + 8),      /* Co-processor #1-#8 */
-    COP0 = COPNUM,
-    COP1,
-    COP2,
-    COP3,
-    COP4,
-    COP5,
-    COP6,
-    COP7,
-    PC,                                /* Program counter */
-    ZPC,                       /* Hack for Program space, but 0 addressing */
-    SR,                                /* Status Reg */
-    CCR,                       /* Condition code Reg */
-
-    /* These have to be in order for the movec instruction to work. */
-    USP,                       /*  User Stack Pointer */
-    ISP,                       /*  Interrupt stack pointer */
-    SFC,
-    DFC,
-    CACR,
-    VBR,
-    CAAR,
-    MSP,
-    ITT0,
-    ITT1,
-    DTT0,
-    DTT1,
-    MMUSR,
-    TC,
-    SRP,
-    URP,
-    /* end of movec ordering constraints */
-
-    FPI,
-    FPS,
-    FPC,
-
-    DRP,                       /* 68851 or 68030 MMU regs */
-    CRP,
-    CAL,
-    VAL,
-    SCC,
-    AC,
-    BAD,
-    BAD0 = BAD,
-    BAD1,
-    BAD2,
-    BAD3,
-    BAD4,
-    BAD5,
-    BAD6,
-    BAD7,
-    BAC,
-    BAC0 = BAC,
-    BAC1,
-    BAC2,
-    BAC3,
-    BAC4,
-    BAC5,
-    BAC6,
-    BAC7,
-    PSR,                       /* aka MMUSR on 68030 (but not MMUSR on 68040)
-                                  and ACUSR on 68ec030 */
-    PCSR,
-
-    IC,                                /* instruction cache token */
-    DC,                                /* data cache token */
-    NC,                                /* no cache token */
-    BC,                                /* both caches token */
-
-    TT0,                       /* 68030 access control unit regs */
-    TT1,
-  };
+static const enum m68k_register m68000_control_regs[] = { 0 };
+static const enum m68k_register m68010_control_regs[] = {
+  SFC, DFC, USP, VBR,
+  0
+};
+static const enum m68k_register m68020_control_regs[] = {
+  SFC, DFC, USP, VBR, CACR, CAAR, MSP, ISP,
+  0
+};
+static const enum m68k_register m68040_control_regs[] = {
+  SFC, DFC, CACR, TC, ITT0, ITT1, DTT0, DTT1,
+  USP, VBR, MSP, ISP, MMUSR, URP, SRP,
+  0
+};
+static const enum m68k_register m68060_control_regs[] = {
+  SFC, DFC, CACR, TC, ITT0, ITT1, DTT0, DTT1, BUSCR,
+  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
 
-/* Internal form of an operand.  */
-struct m68k_op
-  {
-    char *error;               /* Couldn't parse it */
-    enum operand_type mode;    /* What mode this instruction is in.  */
-    enum _register reg;                /* Base register */
-    struct m68k_exp *con1;
-    int ireg;                  /* Index register */
-    int isiz;                  /* 0==unspec  1==byte(?)  2==short  3==long  */
-    int imul;                  /* Multipy ireg by this (1,2,4,or 8) */
-    struct m68k_exp *con2;
-  };
+static const enum m68k_register *control_regs;
 
 /* internal form of a 68020 instruction */
 struct m68k_it
-  {
-    char *error;
-    char *args;                        /* list of opcode info */
-    int numargs;
+{
+  const char *error;
+  const char *args;            /* list of opcode info */
+  int numargs;
 
-    int numo;                  /* Number of shorts in opcode */
-    short opcode[11];
+  int numo;                    /* Number of shorts in opcode */
+  short opcode[11];
 
-    struct m68k_op operands[6];
+  struct m68k_op operands[6];
 
-    int nexp;                  /* number of exprs in use */
-    struct m68k_exp exprs[4];
+  int nexp;                    /* number of exprs in use */
+  struct m68k_exp exprs[4];
 
-    int nfrag;                 /* Number of frags we have to produce */
-    struct
-      {
-       int fragoff;            /* Where in the current opcode[] the frag ends */
-       symbolS *fadd;
-       long foff;
-       int fragty;
-      }
-    fragb[4];
+  int nfrag;                   /* Number of frags we have to produce */
+  struct
+    {
+      int fragoff;             /* Where in the current opcode the frag ends */
+      symbolS *fadd;
+      long foff;
+      int fragty;
+    }
+  fragb[4];
 
-    int nrel;                  /* Num of reloc strucs in use */
-    struct
-      {
-       int n;
-       symbolS *add, *sub;
-       long off;
-       char wid;
-       char pcrel;
-      }
-    reloc[5];                  /* Five is enough??? */
-  };
+  int nrel;                    /* Num of reloc strucs in use */
+  struct
+    {
+      int n;
+      expressionS exp;
+      char wid;
+      char pcrel;
+      /* In a pc relative address the difference between the address
+        of the offset and the address that the offset is relative
+        to.  This depends on the addressing mode.  Basically this
+        is the value to put in the offset field to address the
+        first byte of the offset, without regarding the special
+        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)
 
 static struct m68k_it the_ins; /* the instruction being assembled */
 
-#define seg(exp)       ((exp)->e_exp.X_seg)
-#define adds(exp)      ((exp)->e_exp.X_add_symbol)
-#define subs(exp)      ((exp)->e_exp.X_subtract_symbol)
-#define offs(exp)      ((exp)->e_exp.X_add_number)
+#define op(ex)         ((ex)->exp.X_op)
+#define adds(ex)       ((ex)->exp.X_add_symbol)
+#define subs(ex)       ((ex)->exp.X_op_symbol)
+#define offs(ex)       ((ex)->exp.X_add_number)
 
 /* Macros for adding things to the m68k_it struct */
 
 #define addword(w)     the_ins.opcode[the_ins.numo++]=(w)
 
 /* Like addword, but goes BEFORE general operands */
-#define insop(w)       {int z;\
-                            for(z=the_ins.numo;z>opcode->m_codenum;--z)\
-                                the_ins.opcode[z]=the_ins.opcode[z-1];\
-                                    for(z=0;z<the_ins.nrel;z++)\
-                                        the_ins.reloc[z].n+=2;\
-                                            the_ins.opcode[opcode->m_codenum]=w;\
-                                                the_ins.numo++;\
-                                            }
-
-
-#define add_exp(beg,end) (\
-                         the_ins.exprs[the_ins.nexp].e_beg=beg,\
-                         the_ins.exprs[the_ins.nexp].e_end=end,\
-                         &the_ins.exprs[the_ins.nexp++]\
-                         )
-
+static void
+insop (w, opcode)
+     int w;
+     struct m68k_incant *opcode;
+{
+  int z;
+  for(z=the_ins.numo;z>opcode->m_codenum;--z)
+    the_ins.opcode[z]=the_ins.opcode[z-1];
+  for(z=0;z<the_ins.nrel;z++)
+    the_ins.reloc[z].n+=2;
+  for (z = 0; z < the_ins.nfrag; z++)
+    the_ins.fragb[z].fragoff++;
+  the_ins.opcode[opcode->m_codenum]=w;
+  the_ins.numo++;
+}
 
 /* The numo+1 kludge is so we can hit the low order byte of the prev word.
    Blecch.  */
 static void
-add_fix (width, exp, pc_rel)
+add_fix (width, exp, pc_rel, pc_fix)
      char width;
      struct m68k_exp *exp;
      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-1)*2)
+                                     ? (the_ins.numo*2+1)
                                      : (the_ins.numo*2)));
-  the_ins.reloc[the_ins.nrel].add = adds((exp));
-  the_ins.reloc[the_ins.nrel].sub = subs((exp));
-  the_ins.reloc[the_ins.nrel].off = offs((exp));
+  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;
 }
 
+/* Cause an extra frag to be generated here, inserting up to 10 bytes
+   (that value is chosen in the frag_var call in md_assemble).  TYPE
+   is the subtype of the frag to be generated; its primary type is
+   rs_machine_dependent.
+
+   The TYPE parameter is also used by md_convert_frag_1 and
+   md_estimate_size_before_relax.  The appropriate type of fixup will
+   be emitted by md_convert_frag_1.
+
+   ADD becomes the FR_SYMBOL field of the frag, and OFF the FR_OFFSET.  */
 static void
 add_frag(add,off,type)
      symbolS *add;
@@ -408,40 +324,81 @@ add_frag(add,off,type)
   the_ins.fragb[the_ins.nfrag++].fragty=type;
 }
 
-#define isvar(exp)     ((exp) && (adds(exp) || subs(exp)))
-
-struct m68k_incant
-  {
-    char *m_operands;
-    unsigned long m_opcode;
-    short m_opnum;
-    short m_codenum;
-    int m_arch;
-    struct m68k_incant *m_next;
-  };
-
-
-
-#define getone(x)      ((((x)->m_opcode)>>16)&0xffff)
-#define gettwo(x)      (((x)->m_opcode)&0xffff)
-
+#define isvar(ex) \
+  (op (ex) != O_constant && op (ex) != O_big)
 
 static char *crack_operand PARAMS ((char *str, struct m68k_op *opP));
 static int get_num PARAMS ((struct m68k_exp *exp, int ok));
-static int get_regs PARAMS ((int i, char *str, struct m68k_op *opP));
 static int reverse_16_bits PARAMS ((int in));
 static int reverse_8_bits PARAMS ((int in));
-static int try_index PARAMS ((char **s, struct m68k_op *opP));
 static void install_gen_operand PARAMS ((int mode, int val));
 static void install_operand PARAMS ((int mode, int val));
-static void s_bss PARAMS ((void));
-static void s_data1 PARAMS ((void));
-static void s_data2 PARAMS ((void));
-static void s_even PARAMS ((void));
-static void s_proc PARAMS ((void));
+static void s_bss PARAMS ((int));
+static void s_data1 PARAMS ((int));
+static void s_data2 PARAMS ((int));
+static void s_even PARAMS ((int));
+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", 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", 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]);
+
 /* BCC68000 is for patching in an extra jmp instruction for long offsets
    on the 68000.  The 68000 doesn't support long branches with branchs */
 
@@ -457,7 +414,7 @@ static int current_architecture;
    How many bytes this mode will add to the size of the frag
    Which mode to go to if the offset won't fit in this one
    */
-CONST relax_typeS md_relax_table[] =
+relax_typeS md_relax_table[] =
 {
   {1, 1, 0, 0},                        /* First entries aren't used */
   {1, 1, 0, 0},                        /* For no good reason except */
@@ -494,6 +451,11 @@ CONST relax_typeS md_relax_table[] =
   {0, 0, 6, 0},
   {1, 1, 0, 0},
 
+  /* For, e.g., jmp pcrel indexed.  */
+  {125, -130, 0, TAB (PCINDEX, SHORT)},
+  {32765, -32770, 2, TAB (PCINDEX, LONG)},
+  {0, 0, 4, 0},
+  {1, 1, 0, 0},
 };
 
 /* These are the machine dependent pseudo-ops.  These are included so
@@ -507,7 +469,7 @@ CONST 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},
@@ -515,9 +477,55 @@ 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}
 };
 
@@ -530,23 +538,27 @@ extern void obj_coff_section ();
 CONST pseudo_typeS mote_pseudo_table[] =
 {
 
-  {"dc.l", cons, 4},
+  {"dcl", cons, 4},
   {"dc", cons, 2},
-  {"dc.w", cons, 2},
-  {"dc.b", cons, 1},
+  {"dcw", cons, 2},
+  {"dcb", cons, 1},
 
-  {"ds.l", s_space, 4},
+  {"dsl", s_space, 4},
   {"ds", s_space, 2},
-  {"ds.w", s_space, 2},
-  {"ds.b", s_space, 1},
+  {"dsw", s_space, 2},
+  {"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},
 #endif
-  0,
+  {0, 0, 0}
 };
 
 #define issbyte(x)     ((x)>=-128 && (x)<=127)
@@ -555,901 +567,311 @@ 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;
 
-enum
-  {
-    FAIL = 0,
-    OK = 1,
-  };
-
-/* JF these tables here are for speed at the expense of size */
-/* You can replace them with the #if 0 versions if you really
-   need space and don't mind it running a bit slower */
-
 static char mklower_table[256];
 #define mklower(c) (mklower_table[(unsigned char)(c)])
 static char notend_table[256];
 static char alt_notend_table[256];
-#define notend(s) ( !(notend_table[(unsigned char)(*s)] || (*s==':' &&\
-                                                           alt_notend_table[(unsigned char)(s[1])])))
-
-#if 0
-#define mklower(c)     (isupper(c) ? tolower(c) : c)
-#endif
-
+#define notend(s)                                              \
+  (! (notend_table[(unsigned char) *s]                         \
+      || (*s == ':'                                            \
+         && alt_notend_table[(unsigned char) s[1]])))
 
-/* JF modified this to handle cases where the first part of a symbol name
-   looks like a register */
+#if defined (M68KCOFF) && !defined (BFD_ASSEMBLER)
 
-/*
- * m68k_reg_parse() := if it looks like a register, return it's token &
- * advance the pointer.
- */
+#ifdef NO_PCREL_RELOCS
 
-enum _register
-m68k_reg_parse (ccp)
-     register char **ccp;
+int
+make_pcrel_absolute(fixP, add_number)
+    fixS *fixP;
+    long *add_number;
 {
-  char *start = *ccp;
-  char c;
-  char *p;
-  symbolS *symbolP;
-
-#ifdef REGISTER_PREFIX
-  if (*start != REGISTER_PREFIX)
-    return FAIL;
-  p = start + 1;
-#else
-  p = start;
-  if (*p == OPTIONAL_REGISTER_PREFIX)
-    p++, start++;
-#endif
-  if (!isalpha (*p) || !is_name_beginner (*p))
-    return FAIL;
+  register unsigned char *opcode = fixP->fx_frag->fr_opcode;
 
-  c = *p++;
-  while (isalpha (c) || isdigit (c) || c == '_')
+  /* rewrite the PC relative instructions to absolute address ones.
+   * these are rumoured to be faster, and the apollo linker refuses
+   * to deal with the PC relative relocations.
+   */
+  if (opcode[0] == 0x60 && opcode[1] == 0xff) /* BRA -> JMP */
     {
-      c = *p++;
+      opcode[0] = 0x4e;
+      opcode[1] = 0xf9;
     }
-
-  *--p = 0;
-  symbolP = symbol_find (start);
-  *p = c;
-
-  if (symbolP && S_GET_SEGMENT (symbolP) == reg_section)
+  else if (opcode[0] == 0x61 && opcode[1] == 0xff) /* BSR -> JSR */
     {
-      *ccp = p;
-      return S_GET_VALUE (symbolP);
+      opcode[0] = 0x4e;
+      opcode[1] = 0xb9;
     }
+  else
+    as_fatal ("Unknown PC relative instruction");
+  *add_number -= 4;
+  return 0;
+}
 
-  return FAIL;
+#endif /* NO_PCREL_RELOCS */
+
+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
+         : fixP->fx_size == 2 ? R_DIR16
+         : R_DIR32);
+#else
+  return (fixP->fx_pcrel ?
+         (fixP->fx_size == 1 ? R_PCRBYTE :
+          fixP->fx_size == 2 ? R_PCRWORD :
+          R_PCRLONG) :
+         (fixP->fx_size == 1 ? R_RELBYTE :
+          fixP->fx_size == 2 ? R_RELWORD :
+          R_RELLONG));
+#endif
 }
 
-#define SKIP_WHITE()   { str++; if(*str==' ') str++;}
-#define SKIP_W()       { ss++; if(*ss==' ') ss++;}
+#endif
 
-/* Parse an index specification using Motorola syntax.  */
+#ifdef OBJ_ELF
 
-static int
-try_moto_index (s, opP)
-     char **s;
-     struct m68k_op *opP;
+/* 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;
 {
-  register int i;
-  char *ss;
-
-  ss = *s;
-  /* SKIP_W(); */
-  if (*ss == ' ')
-    ss++;
-  i = m68k_reg_parse (&ss);
-  if (!(i >= DATA + 0 && i <= ADDR + 7))
-    {                          /* if i is not DATA or ADDR reg */
-      opP->error = "Invalid index register";
-      *s = ss;
-      return FAIL;
-    }
-  opP->ireg = i;
-  /* SKIP_W(); */
-  if (*ss == ')')
-    {
-      opP->isiz = 0;
-      opP->imul = 1;
-      SKIP_W ();
-      *s = ss;
-      return OK;
-    }
-  if (*ss != '.')
-    {
-      opP->error = "Missing . in index register";
-      *s = ss;
-      return FAIL;
-    }
-  SKIP_W ();
-  if (mklower (*ss) == 'w')
-    opP->isiz = 2;
-  else if (mklower (*ss) == 'l')
-    opP->isiz = 3;
-  else
+  switch (pic)
     {
-      opP->error = "Size spec not .W or .L";
-      *s = ss;
-      return FAIL;
-    }
-  SKIP_W ();
-  if (*ss == '.' || *ss == '*')
-    {
-      SKIP_W ();
-      switch (*ss)
+    case pic_got_pcrel:
+      switch (size)
        {
-       case '1':
-       case '2':
-       case '4':
-       case '8':
-         opP->imul = *ss - '0';
-         break;
-       default:
-         opP->error = "index multiplier not 1, 2, 4 or 8";
-         *s = ss;
-         return FAIL;
+       case 1:
+         return BFD_RELOC_8_GOT_PCREL;
+       case 2:
+         return BFD_RELOC_16_GOT_PCREL;
+       case 4:
+         return BFD_RELOC_32_GOT_PCREL;
        }
-      SKIP_W ();
-    }
-  else
-    opP->imul = 1;
-  if (*ss != ')')
-    {
-      opP->error = "Missing )";
-      *s = ss;
-      return FAIL;
-    }
-  SKIP_W ();
-  *s = ss;
-  return OK;
-}
+      break;
 
-/*
- *
- * try_index := data_or_address_register + ')' + SKIP_W
- *     | data_or_address_register + ':' + SKIP_W + size_spec + SKIP_W + multiplier + ')' + SKIP_W
- *
- * multiplier := <empty>
- *     | ':' + multiplier_number
- *     ;
- *
- * multiplier_number := '1' | '2' | '4' | '8' ;
- *
- * size_spec := 'l' | 'L' | 'w' | 'W' ;
- *
- * SKIP_W := <empty> | ' ' ;
- *
- */
+    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;
 
-static int
-try_index (s, opP)
-     char **s;
-     struct m68k_op *opP;
-{
-  register int i;
-  char *ss;
-
-  ss = *s;
-  /* SKIP_W(); */
-  i = m68k_reg_parse (&ss);
-  if (!(i >= DATA + 0 && i <= ADDR + 7))
-    {                          /* if i is not DATA or ADDR reg */
-      *s = ss;
-      return FAIL;
-    }
-  opP->ireg = i;
-  /* SKIP_W(); */
-  if (*ss == ')')
-    {
-      opP->isiz = 0;
-      opP->imul = 1;
-      SKIP_W ();
-      *s = ss;
-      return OK;
-    }
-  if (*ss != ':')
-    {
-      opP->error = "Missing : in index register";
-      *s = ss;
-      return FAIL;
-    }
-  SKIP_W ();
-  switch (*ss)
-    {
-    case 'w':
-    case 'W':
-      opP->isiz = 2;
+    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 'l':
-    case 'L':
-      opP->isiz = 3;
+
+    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;
-    default:
-      opP->error = "Index register size spec not :w or :l";
-      *s = ss;
-      return FAIL;
-    }
-  SKIP_W ();
-  if (*ss == ':')
-    {
-      SKIP_W ();
-      switch (*ss)
+
+    case pic_none:
+      if (pcrel)
        {
-       case '1':
-       case '2':
-       case '4':
-       case '8':
-         if (cpu_of_arch (current_architecture) < m68020)
+         switch (size)
            {
-             opP->error = "no index scaling in pre-68020's";
-             *s = ss;
-             return FAIL;
+           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;
            }
-         opP->imul = *ss - '0';
-         break;
-       default:
-         opP->error = "index multiplier not 1, 2, 4 or 8";
-         *s = ss;
-         return FAIL;
        }
-      SKIP_W ();
-    }
-  else
-    opP->imul = 1;
-  if (*ss != ')')
-    {
-      opP->error = "Missing )";
-      *s = ss;
-      return FAIL;
     }
-  SKIP_W ();
-  *s = ss;
-  return OK;
-}                              /* try_index() */
-
-/* Ian Taylor expanded this function to accept both MIT and Motorola
-   syntax.  I removed the old comment, since it was wrong.  The syntax
-   this accepted even before my changes was complex and undocumented.
-   I mainly added a large case when the operand string does not
-   contain an '@', since the Motorola syntax does not use the '@'
-   character.  */
 
+  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
-m68k_ip_op (str, opP)
-     char *str;
-     register struct m68k_op *opP;
+tc_m68k_fix_adjustable (fixP)
+     fixS *fixP;
 {
-  char *strend;
-  long i;
-  char *parse_index ();
-  int needp;
+  /* Prevent all adjustments to global symbols. */
+  if (S_IS_EXTERNAL (fixP->fx_addsy))
+    return 0;
 
-  if (*str == ' ')
+  /* adjust_reloc_syms doesn't know about the GOT */
+  switch (fixP->fx_r_type)
     {
-      str++;
-    }                          /* Find the beginning of the string */
+    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;
 
-  if (!*str)
-    {
-      opP->error = "Missing operand";
-      return FAIL;
-    }                          /* Out of gas */
+    default:
+      return 1;
+    }
+}
 
-  for (strend = str; *strend; strend++)
-    ;
-  --strend;
+#else /* !OBJ_ELF */
 
-  if (*str == '#')
-    {
-      str++;
-      opP->con1 = add_exp (str, strend);
-      opP->mode = IMMED;
-      return OK;
-    }                          /* Guess what:  A constant.  Shar and enjoy */
+#define get_reloc_code(SIZE,PCREL,OTHER) NO_RELOC
 
-  i = m68k_reg_parse (&str);
+#endif /* OBJ_ELF */
 
-  if (i != FAIL)
-    {
-      if (*str == '/' || *str == '-')
-       {
-         /* "Rm-Rn/Ro-Rp"  Register list for MOVEM instruction */
-         opP->mode = REGLST;
-         return get_regs (i, str, opP);
-       }
-      if (*str == '\0')
-       {
-         opP->reg = i;
-         /* "Rn"  Register Direct mode */
-         if (i >= DATA + 0 && i <= DATA + 7)
-           opP->mode = DREG;
-         else if (i >= ADDR + 0 && i <= ADDR + 7)
-           opP->mode = AREG;
-         else
-           opP->mode = MSCR;
-         return OK;
-       }
-    }
+#ifdef BFD_ASSEMBLER
 
-  if (*str != '@')
+arelent *
+tc_gen_reloc (section, fixp)
+     asection *section;
+     fixS *fixp;
+{
+  arelent *reloc;
+  bfd_reloc_code_real_type code;
+
+  if (fixp->fx_tcbit)
+    abort ();
+
+  if (fixp->fx_r_type != BFD_RELOC_NONE)
     {
-      char *stmp;
+      code = fixp->fx_r_type;
 
-      if ((stmp = strchr (str, '@')) != 0)
+      /* 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)
        {
-         opP->con1 = add_exp (str, stmp - 1);
-         if (stmp == strend)
+         switch (code)
            {
-             opP->mode = AINDX;
-             return (OK);
+           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));
            }
-
-         if ((current_architecture & m68020up) == 0)
-           {
-             return (FAIL);
-           }                   /* if target is not a '20 or better */
-
-         stmp++;
-         if (*stmp++ != '(' || *strend-- != ')')
-           {
-             opP->error = "Malformed operand";
-             return (FAIL);
-           }
-         i = try_index (&stmp, opP);
-         opP->con2 = add_exp (stmp, strend);
-
-         if (i == FAIL)
-           {
-             opP->mode = AMIND;
-           }
-         else
-           {
-             opP->mode = APODX;
-           }
-         return (OK);
-       }                       /* if there's an '@' */
-
-#ifndef MIT_SYNTAX_ONLY
-      /* The operand has no '@'.  Try to parse it using
-        Motorola syntax.  */
-      /* Logic of the parsing switch(*str):
-                  case                 opP->mode =
-                  ----                 -----------
-                  #anything            IMMED   1
-                  REG                  AREG or DREG or MSCR    3 or 2 or 13
-                  REG- or REG/         REGLST  14
-                  (REG)                AINDR   4
-                  (REG)+               AINC    6
-                  (REG,INDX)           AINDX   8
-                  (EXPR,REG)           AOFF    7
-                  (EXPR,REG,INDX)      AINDX   8
-                  -(REG)               ADEC    5
-                  EXP2(REG)            AOFF    7
-                  EXP2(REG,INDX)       AINDX   8
-                  EXP2                 ABSL    12
-
-                  REG  means truth(m68k_reg_parse(&str))
-                  INDX means truth(try_moto_index(&str,opP))
-                  EXPR means not REG
-                  EXP2 means not REG and not '(' and not '-('
-                  */
-
-      if (*str == '(')
-       {
-         str++;
-         i = m68k_reg_parse (&str);
-         if ((i < ADDR + 0 || i > ADDR + 7)
-             && (i < DATA + 0 || i > DATA + 7
-                 || *str != ')' || str[1] != '0')
-             && i != PC && i != ZPC && i != FAIL)
-           {
-             /* Can't indirect off non address regs */
-             opP->error = "Invalid indirect register";
-             return FAIL;
-           }
-         if (i != FAIL)
-           {
-             opP->reg = i;
-             if (*str == ')')
-               {
-                 str++;
-                 if (*str == '\0')
-                   {
-                     /* "(An)"  Address Register Indirect mode
-                                        or "(Dn)" for cas2.  */
-                     if (i >= DATA + 0 && i <= DATA + 7)
-                       opP->mode = DINDR;
-                     else
-                       opP->mode = AINDR;
-                     return OK;
-                   }
-                 if (*str == '+')
-                   {
-                     if (str[1] == '\0')
-                       {
-                         /* "(An)+" Register Indirect w Postincrement */
-                         opP->mode = AINC;
-                         return OK;
-                       }
-                   }
-                 opP->error = "Junk after indirect";
-                 return FAIL;
-               }
-             if (*str == ',')
-               {
-                 str++;
-                 i = try_moto_index (&str, opP);
-                 if (i == FAIL)
-                   return FAIL;
-                 /* "(An,Rn)"  Register Indirect with Index mode*/
-                 opP->mode = AINDX;
-                 return OK;
-               }
-             else
-               {
-                 opP->error = "Bad indirect syntax";
-                 return FAIL;
-               }
-           }
-         else
-           {
-             /* "(EXPR,..." , a displacement */
-             char *stmp;
-             char *index ();
-
-             if (stmp = index (str, ','))
-               {
-                 opP->con1 = add_exp (str, stmp - 1);
-                 str = stmp;
-                 SKIP_WHITE ();
-                 i = m68k_reg_parse (&str);
-                 if ((i < ADDR + 0 || i > ADDR + 7) && i != PC && i != ZPC)
-                   {
-                     /* Can't indirect off non address regs */
-                     opP->error = "Invalid indirect register";
-                     return FAIL;
-                   }
-                 if (i != FAIL)
-                   {
-                     opP->reg = i;
-                     if (*str == ')')
-                       {
-                         /* "(d,An)"  Register Indirect w Displacement */
-                         opP->mode = AOFF;
-                         return OK;
-                       }
-                     if (*str == ',')
-                       {
-                         str++;
-                         i = try_moto_index (&str, opP);
-                         if (i == FAIL)
-                           return FAIL;
-                         /* "(d,An,Rn)"  Register Indirect with Index */
-                         opP->mode = AINDX;
-                         return OK;
-                       }
-                     else
-                       {
-                         opP->error = "Bad indirect syntax";
-                         return FAIL;
-                       }
-                   }
-                 else
-                   {
-                     opP->error = "Invalid register";
-                     return FAIL;
-                   }
-               }
-             else
-               {
-                 opP->mode = ABSL;
-                 opP->con1 = add_exp (str - 1, strend);
-                 return OK;
-               }
-           }
-       }
-
-      if (*str == '-')
-       {
-         if (str[1] == '(')
-           {
-             str = str + 2;
-             i = m68k_reg_parse (&str);
-             if ((i < ADDR + 0 || i > ADDR + 7) && i != PC && i != ZPC && i != FAIL)
-               {
-                 /* Can't indirect off non address regs */
-                 opP->error = "Invalid indirect register";
-                 return FAIL;
-               }
-             if (i != FAIL)
-               {
-                 opP->reg = i;
-                 if (*str == ')')
-                   {
-                     str++;
-                     if (*str == '\0')
-                       {
-                         /* "-(An)" Register Indirect with Predecrement */
-                         opP->mode = ADEC;
-                         return OK;
-                       }
-                     opP->error = "Junk after indirect";
-                     return FAIL;
-                   }
-                 opP->error = "Bad indirect syntax";
-                 return FAIL;
-               }
-             opP->mode = ABSL;
-             opP->con1 = add_exp (str - 2, strend);
-             return OK;
-           }
-         /* if '-' but not "-(', do nothing */
-       }
-
-      /* whether *str=='-' or not */
-      {
-       /* "EXP2" or "EXP2(REG..." */
-       char *stmp;
-       char *index ();
-       if (stmp = index (str, '('))
-         {
-           char *ostr = str;
-
-           opP->con1 = add_exp (str, stmp - 1);
-           str = stmp + 1;
-           i = m68k_reg_parse (&str);
-           if ((i < ADDR + 0 || i > ADDR + 7) && i != PC
-               && i != ZPC && i != FAIL)
-             {
-               /* Can't indirect off non address regs */
-               opP->error = "Invalid indirect register";
-               return FAIL;
-             }
-           if (i != FAIL)
-             {
-               opP->reg = i;
-               if (*str == ')')
-                 {
-                   /* "d(An)"  Register Indirect w Displacement */
-                   opP->mode = AOFF;
-                   return OK;
-                 }
-               if (*str == ',')
-                 {
-                   str++;
-                   i = try_moto_index (&str, opP);
-                   if (i == FAIL)
-                     return FAIL;
-                   /* "d(An,Rn)"  Register Indirect with Index */
-                   opP->mode = AINDX;
-                   return OK;
-                 }
-               else
-                 {
-                   opP->error = "Bad indirect syntax";
-                   return FAIL;
-                 }
-             }
-           else
-             {
-               opP->mode = ABSL;
-               opP->con1 = add_exp (ostr, strend);
-               return OK;
-             }
-         }
-       else
-         {
-           /* "EXP2"  Absolute */
-           opP->mode = ABSL;
-           opP->isiz = 0;
-           if (strend[-1] == '.' || strend[-1] == ':')
-             {
-               /* mode ==foo.[wl] */
-               switch (*strend)
-                 {
-                 case 'w':
-                 case 'W':
-                   opP->isiz = 2;
-                   strend -= 2;
-                   break;
-                 case 'l':
-                 case 'L':
-                   opP->isiz = 3;
-                   strend -= 2;
-                   break;
-                 }
-             }
-           opP->con1 = add_exp (str, strend);
-           return OK;
-         }
-      }
-      /*NOTREACHED*/
-#else /* defined (MIT_SYNTAX_ONLY) */
-      opP->mode = ABSL;
-      opP->con1 = add_exp (str, strend);
-      return OK;
-#endif /* defined (MIT_SYNTAX_ONLY) */
-    }
-
-  opP->reg = i;
-
-  /* Can't indirect off non address regs, but Dx@ is OK for cas2 */
-  if ((i < ADDR + 0 || i > ADDR + 7) && i != PC && i != ZPC && i != FAIL
-      && (str[1] != '\0' || i < DATA + 0 || i > DATA + 7))
-    {
-      opP->error = "Invalid indirect register";
-      return FAIL;
-    }
-  know (*str == '@');
-
-  str++;
-  switch (*str)
-    {
-    case '\0':
-      if (i < DATA + 0 || i > DATA + 7)
-       opP->mode = AINDR;
-      else
-       opP->mode = DINDR;
-      return OK;
-    case '-':
-      opP->mode = ADEC;
-      return OK;
-    case '+':
-      opP->mode = AINC;
-      return OK;
-    case '(':
-      str++;
-      break;
-    default:
-      opP->error = "Junk after indirect";
-      return FAIL;
-    }
-  /* Some kind of indexing involved.  Lets find out how bad it is */
-  i = try_index (&str, opP);
-  /* Didn't start with an index reg, maybe its offset or offset,reg */
-  if (i == FAIL)
-    {
-      char *beg_str;
-
-      beg_str = str;
-      for (i = 1; i;)
-       {
-         switch (*str++)
-           {
-           case '\0':
-             opP->error = "Missing )";
-             return FAIL;
-           case ',':
-             i = 0;
-             break;
-           case '(':
-             i++;
-             break;
-           case ')':
-             --i;
-             break;
-           }
-       }
-#if 0
-      if (str[-3]==':')
-       {
-         int siz;
-
-         switch (str[-2])
-           {
-           case 'b':
-           case 'B':
-             siz=1;
-             break;
-           case 'w':
-           case 'W':
-             siz=2;
-             break;
-           case 'l':
-           case 'L':
-             siz=3;
-             break;
-           default:
-             opP->error="Specified size isn't :w or :l";
-             return FAIL;
-           }
-         opP->con1=add_exp(beg_str,str-4);
-         opP->con1->e_siz=siz;
-       }
-      else
-#endif
-       opP->con1 = add_exp (beg_str, str - 2);
-      /* Should be offset,reg */
-      if (str[-1] == ',')
-       {
-         i = try_index (&str, opP);
-         if (i == FAIL)
-           {
-             opP->error = "Malformed index reg";
-             return FAIL;
-           }
-       }
-    }
-  /* We've now got offset)   offset,reg)   or    reg) */
-
-  if (*str == '\0')
-    {
-      /* Th-the-thats all folks */
-      if (opP->reg == FAIL)
-       opP->mode = AINDX;      /* Other form of indirect */
-      else if (opP->ireg == FAIL)
-       opP->mode = AOFF;
-      else
-       opP->mode = AINDX;
-      return (OK);
-    }
-  /* Next thing had better be another @ */
-  if (*str == '@')
-    {
-      if (str[1] == '(')
-       {
-         needp = 1;
-         str += 2;
-       }
-      else
-       {
-         needp = 0;
-         str++;
-       }
-    }
-
-  if ((current_architecture & m68020up) == 0)
-    {
-      return (FAIL);
-    }                          /* if target is not a '20 or better */
-
-
-  if (opP->ireg != FAIL)
-    {
-      opP->mode = APRDX;
-
-      i = try_index (&str, opP);
-      if (i != FAIL)
-       {
-         opP->error = "Two index registers!  not allowed!";
-         return (FAIL);
-       }
-    }
-  else
-    {
-      i = try_index (&str, opP);
-    }
-
-  if (i == FAIL)
-    {
-      char *beg_str;
-
-      beg_str = str;
-
-      for (i = 1; i;)
-       {
-         switch (*str++)
-           {
-           case '\0':
-             if (needp)
-               opP->error = "Missing )";
-             return (FAIL);
-             break;
-           case ',':
-             i = 0;
-             break;
-           case '(':
-             i++;
-             break;
-           case ')':
-             --i;
-             break;
-           }
-       }
-
-      opP->con2 = add_exp (beg_str, str - 2);
-
-      if (str[-1] == ',')
-       {
-         if (opP->ireg != FAIL)
-           {
-             opP->error = "Can't have two index regs";
-             return (FAIL);
-           }
-
-         i = try_index (&str, opP);
-
-         if (i == FAIL)
-           {
-             opP->error = "malformed index reg";
-             return (FAIL);
-           }
-
-         opP->mode = APODX;
-       }
-      else if (opP->ireg != FAIL)
-       {
-         opP->mode = APRDX;
-       }
-      else
-       {
-         opP->mode = AMIND;
        }
     }
   else
     {
-      opP->mode = APODX;
-    }
-
-  if (*str != '\0')
-    {
-      opP->error = "Junk after indirect";
-      return FAIL;
-    }
-  return (OK);
-}                              /* m68k_ip_op() */
-
-
-#if defined (M68KCOFF) && !defined (BFD_ASSEMBLER)
-
-short
-tc_coff_fix2rtype (fixP)
-     fixS *fixP;
-{
-  return (fixP->fx_pcrel ?
-         (fixP->fx_size == 1 ? R_PCRBYTE :
-          fixP->fx_size == 2 ? R_PCRWORD :
-          R_PCRLONG) :
-         (fixP->fx_size == 1 ? R_RELBYTE :
-          fixP->fx_size == 2 ? R_RELWORD :
-          R_RELLONG));
-
-
-}
-
-#endif
-
-#ifdef BFD_ASSEMBLER
-
-arelent *
-tc_gen_reloc (section, fixp)
-     asection *section;
-     fixS *fixp;
-{
-  arelent *reloc;
-  bfd_reloc_code_real_type code;
-
 #define F(SZ,PCREL)            (((SZ) << 1) + (PCREL))
-  switch (F (fixp->fx_size, fixp->fx_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);
@@ -1459,65 +881,12 @@ tc_gen_reloc (section, fixp)
 
 #endif /* BFD_ASSEMBLER */
 
-#ifdef TEST1                   /* TEST1 tests m68k_ip_op(), which parses operands */
-main ()
-{
-  char buf[128];
-  struct m68k_op thark;
-
-  for (;;)
-    {
-      if (!gets (buf))
-       break;
-      memset (&thark, '\0', sizeof (thark));
-      if (!m68k_ip_op (buf, &thark))
-       printf ("FAIL:");
-      if (thark.error)
-       printf ("op1 error %s in %s\n", thark.error, buf);
-      printf ("mode %d, reg %d, ", thark.mode, thark.reg);
-      if (thark.b_const)
-       printf ("Constant: '%.*s',", 1 + thark.e_const - thark.b_const, thark.b_const);
-      printf ("ireg %d, isiz %d, imul %d ", thark.ireg, thark.isiz, thark.imul);
-      if (thark.b_iadd)
-       printf ("Iadd: '%.*s'", 1 + thark.e_iadd - thark.b_iadd, thark.b_iadd);
-      printf ("\n");
-    }
-  exit (0);
-}
-
-#endif
-
-
 /* Handle of the OPCODE hash table.  NULL means any use before
    m68k_ip_begin() will crash.  */
 static struct hash_control *op_hash;
 \f
+/* Assemble an m68k instruction.  */
 
-/*
- *             m 6 8 k _ i p ( )
- *
- * This converts a string into a 68k instruction.
- * The string must be a bare single instruction in sun format
- * with RMS-style 68020 indirects
- *  (example:  )
- *
- * It provides some error messages: at most one fatal error message (which
- * stops the scan) and at most one warning message for each operand.
- * The 68k instruction is returned in exploded form, since we have no
- * knowledge of how you parse (or evaluate) your expressions.
- * We do however strip off and decode addressing modes and operation
- * mnemonic.
- *
- * This function's value is a string. If it is not "" then an internal
- * logic error was found: read this code to assign meaning to the string.
- * No argument string should generate such an error string:
- * it means a bug in our code, not in the user's text.
- *
- * You MUST have called m68k_ip_begin() once and m86_ip_end() never before using
- * this function.
- */
-
-/* JF this function no longer returns a useful value.  Sorry */
 void
 m68k_ip (instring)
      char *instring;
@@ -1525,10 +894,10 @@ m68k_ip (instring)
   register char *p;
   register struct m68k_op *opP;
   register struct m68k_incant *opcode;
-  register char *s;
+  register const char *s;
   register int tmpreg = 0, baseo = 0, outro = 0, nextword;
   char *pdot, *pdotmove;
-  int siz1, siz2;
+  enum m68k_size siz1, siz2;
   char c;
   int losing;
   int opsfound;
@@ -1554,14 +923,12 @@ m68k_ip (instring)
   if (p == instring)
     {
       the_ins.error = "No operator";
-      the_ins.opcode[0] = NULL;
-      /* the_ins.numo=1; */
       return;
     }
 
   /* p now points to the end of the opcode name, probably whitespace.
-     make sure the name is null terminated by clobbering the whitespace,
-     look it up in the hash table, then fix it back.
+     Make sure the name is null terminated by clobbering the
+     whitespace, look it up in the hash table, then fix it back.
      Remove a dot, first, since the opcode tables have none.  */
   if (pdot != NULL)
     {
@@ -1586,8 +953,6 @@ m68k_ip (instring)
   if (opcode == NULL)
     {
       the_ins.error = "Unknown operator";
-      the_ins.opcode[0] = NULL;
-      /* the_ins.numo=1; */
       return;
     }
 
@@ -1595,7 +960,6 @@ m68k_ip (instring)
   while (*p == ' ')
     ++p;
 
-
   if (opcode->m_operands == 0)
     {
       char *old = input_line_pointer;
@@ -1610,9 +974,20 @@ m68k_ip (instring)
       return;
     }
 
-  for (opP = &the_ins.operands[0]; *p; opP++)
+  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);
 
       if (opP->error)
@@ -1624,8 +999,8 @@ m68k_ip (instring)
 
   opsfound = opP - &the_ins.operands[0];
 
-  /* This ugly hack is to support the floating pt opcodes in their standard form */
-  /* Essentially, we fake a first enty of type COP#1 */
+  /* This ugly hack is to support the floating pt opcodes in their
+     standard form.  Essentially, we fake a first enty of type COP#1 */
   if (opcode->m_operands[0] == 'I')
     {
       int n;
@@ -1633,9 +1008,10 @@ m68k_ip (instring)
       for (n = opsfound; n > 0; --n)
        the_ins.operands[n] = the_ins.operands[n - 1];
 
-      memset ((char *) (&the_ins.operands[0]), '\0', sizeof (the_ins.operands[0]));
-      the_ins.operands[0].mode = MSCR;
-      the_ins.operands[0].reg = COPNUM;        /* COP #1 */
+      memset ((char *) (&the_ins.operands[0]), '\0',
+             sizeof (the_ins.operands[0]));
+      the_ins.operands[0].mode = CONTROL;
+      the_ins.operands[0].reg = m68k_float_copnum;
       opsfound++;
     }
 
@@ -1645,15 +1021,15 @@ 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]; *s && !losing; s += 2, opP++)
+         for (s = opcode->m_operands, opP = &the_ins.operands[0];
+              *s && !losing;
+              s += 2, opP++)
            {
              /* Warning: this switch is huge! */
              /* I've tried to organize the cases into this order:
@@ -1664,40 +1040,154 @@ m68k_ip (instring)
              switch (*s)
                {
                case '!':
-                 if (opP->mode == MSCR || opP->mode == IMMED
-                     || opP->mode == DREG || opP->mode == AREG
-                     || opP->mode == AINC || opP->mode == ADEC
-                     || opP->mode == REGLST)
-                   losing++;
+                 switch (opP->mode)
+                   {
+                   case IMMED:
+                   case DREG:
+                   case AREG:
+                   case FPREG:
+                   case CONTROL:
+                   case AINC:
+                   case ADEC:
+                   case REGLST:
+                     losing++;
+                     break;
+                   default:
+                     break;
+                   }
                  break;
 
                case '`':
                  switch (opP->mode)
                    {
-                   case MSCR:
                    case IMMED:
                    case DREG:
                    case AREG:
+                   case FPREG:
+                   case CONTROL:
                    case AINC:
                    case REGLST:
                    case AINDR:
                      losing++;
+                     break;
+                   default:
+                     break;
                    }
                  break;
 
-               case '#':
-                 if (opP->mode != IMMED)
-                   losing++;
-                 else
+               case '<':
+                 switch (opP->mode)
                    {
-                     long t;
+                   case DREG:
+                   case AREG:
+                   case FPREG:
+                   case CONTROL:
+                   case IMMED:
+                   case ADEC:
+                   case REGLST:
+                     losing++;
+                     break;
+                   default:
+                     break;
+                   }
+                 break;
 
-                     t = get_num (opP->con1, 80);
-                     if (s[1] == 'b' && !isbyte (t))
-                       losing++;
-                     else if (s[1] == 'w' && !isword (t))
+               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)
+                          && (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)
+                          && (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;
 
                case '^':
@@ -1707,27 +1197,55 @@ m68k_ip (instring)
                  break;
 
                case '$':
-                 if (opP->mode == MSCR || opP->mode == AREG ||
-                     opP->mode == IMMED || opP->reg == PC || opP->reg == ZPC || opP->mode == REGLST)
+                 if (opP->mode == AREG
+                     || opP->mode == CONTROL
+                     || opP->mode == FPREG
+                     || opP->mode == IMMED
+                     || opP->mode == REGLST
+                     || (opP->mode != ABSL
+                         && (opP->reg == PC
+                             || opP->reg == ZPC)))
                    losing++;
                  break;
 
                case '%':
-                 if (opP->mode == MSCR || opP->reg == PC ||
-                     opP->reg == ZPC || opP->mode == REGLST)
+                 if (opP->mode == CONTROL
+                     || opP->mode == FPREG
+                     || opP->mode == REGLST
+                     || opP->mode == IMMED
+                     || (opP->mode != ABSL
+                         && (opP->reg == PC
+                             || opP->reg == ZPC)))
                    losing++;
                  break;
 
-
                case '&':
-                 if (opP->mode == MSCR || opP->mode == DREG ||
-                     opP->mode == AREG || opP->mode == IMMED || opP->reg == PC || opP->reg == ZPC ||
-                     opP->mode == AINC || opP->mode == ADEC || opP->mode == REGLST)
-                   losing++;
+                 switch (opP->mode)
+                   {
+                   case DREG:
+                   case AREG:
+                   case FPREG:
+                   case CONTROL:
+                   case IMMED:
+                   case AINC:
+                   case ADEC:
+                   case REGLST:
+                     losing++;
+                     break;
+                   case ABSL:
+                     break;
+                   default:
+                     if (opP->reg == PC
+                         || opP->reg == ZPC)
+                       losing++;
+                     break;
+                   }
                  break;
 
                case '*':
-                 if (opP->mode == MSCR || opP->mode == REGLST)
+                 if (opP->mode == CONTROL
+                     || opP->mode == FPREG
+                     || opP->mode == REGLST)
                    losing++;
                  break;
 
@@ -1742,37 +1260,96 @@ m68k_ip (instring)
                  break;
 
                case '/':
-                 if (opP->mode == MSCR || opP->mode == AREG ||
-                     opP->mode == AINC || opP->mode == ADEC || opP->mode == IMMED || opP->mode == REGLST)
-                   losing++;
+                 switch (opP->mode)
+                   {
+                   case AREG:
+                   case CONTROL:
+                   case FPREG:
+                   case AINC:
+                   case ADEC:
+                   case IMMED:
+                   case REGLST:
+                     losing++;
+                     break;
+                   default:
+                     break;
+                   }
                  break;
 
                case ';':
-                 if (opP->mode == MSCR || opP->mode == AREG || opP->mode == REGLST)
-                   losing++;
+                 switch (opP->mode)
+                   {
+                   case AREG:
+                   case CONTROL:
+                   case FPREG:
+                   case REGLST:
+                     losing++;
+                     break;
+                   default:
+                     break;
+                   }
                  break;
 
                case '?':
-                 if (opP->mode == MSCR || opP->mode == AREG ||
-                     opP->mode == AINC || opP->mode == ADEC || opP->mode == IMMED || opP->reg == PC ||
-                     opP->reg == ZPC || opP->mode == REGLST)
-                   losing++;
+                 switch (opP->mode)
+                   {
+                   case AREG:
+                   case CONTROL:
+                   case FPREG:
+                   case AINC:
+                   case ADEC:
+                   case IMMED:
+                   case REGLST:
+                     losing++;
+                     break;
+                   case ABSL:
+                     break;
+                   default:
+                     if (opP->reg == PC || opP->reg == ZPC)
+                       losing++;
+                     break;
+                   }
                  break;
 
                case '@':
-                 if (opP->mode == MSCR || opP->mode == AREG ||
-                     opP->mode == IMMED || opP->mode == REGLST)
-                   losing++;
+                 switch (opP->mode)
+                   {
+                   case AREG:
+                   case CONTROL:
+                   case FPREG:
+                   case IMMED:
+                   case REGLST:
+                     losing++;
+                     break;
+                   default:
+                     break;
+                   }
                  break;
 
                case '~':       /* For now! (JF FOO is this right?) */
-                 if (opP->mode == MSCR || opP->mode == DREG ||
-                     opP->mode == AREG || opP->mode == IMMED || opP->reg == PC || opP->reg == ZPC || opP->mode == REGLST)
-                   losing++;
+                 switch (opP->mode)
+                   {
+                   case DREG:
+                   case AREG:
+                   case CONTROL:
+                   case FPREG:
+                   case IMMED:
+                   case REGLST:
+                     losing++;
+                     break;
+                   case ABSL:
+                     break;
+                   default:
+                     if (opP->reg == PC
+                         || opP->reg == ZPC)
+                       losing++;
+                     break;
+                   }
                  break;
 
                case '3':
-                 if (opP->mode != MSCR || (opP->reg != TT0 && opP->reg != TT1))
+                 if (opP->mode != CONTROL
+                     || (opP->reg != TT0 && opP->reg != TT1))
                    losing++;
                  break;
 
@@ -1780,28 +1357,28 @@ m68k_ip (instring)
                  if (opP->mode != AREG)
                    losing++;
                  break;
+
                case 'a':
                  if (opP->mode != AINDR)
-                   {
-                     ++losing;
-                   }           /* if not address register indirect */
+                   ++losing;
                  break;
+
                case 'B':       /* FOO */
-                 if (opP->mode != ABSL || (flagseen['S'] && instring[0] == 'j'
-                                           && instring[1] == 'b'
-                                           && instring[2] == 's'
-                                           && instring[3] == 'r'))
+                 if (opP->mode != ABSL
+                     || (flag_long_jumps
+                         && strncmp (instring, "jbsr", 4) == 0))
                    losing++;
                  break;
 
                case 'C':
-                 if (opP->mode != MSCR || opP->reg != CCR)
+                 if (opP->mode != CONTROL || opP->reg != CCR)
                    losing++;
                  break;
 
-               case 'd':       /* FOO This mode is a KLUDGE!! */
-                 if (opP->mode != AOFF && (opP->mode != ABSL ||
-                 opP->con1->e_beg[0] != '(' || opP->con1->e_end[0] != ')'))
+               case 'd':
+                 if (opP->mode != DISP
+                     || opP->reg < ADDR0
+                     || opP->reg > ADDR7)
                    losing++;
                  break;
 
@@ -1811,40 +1388,31 @@ m68k_ip (instring)
                  break;
 
                case 'F':
-                 if (opP->mode != MSCR || opP->reg < (FPREG + 0) || opP->reg > (FPREG + 7))
+                 if (opP->mode != FPREG)
                    losing++;
                  break;
 
                case 'I':
-                 if (opP->mode != MSCR || opP->reg < COPNUM ||
-                     opP->reg >= COPNUM + 7)
+                 if (opP->mode != CONTROL
+                     || opP->reg < COP0
+                     || opP->reg > COP7)
                    losing++;
                  break;
 
                case 'J':
-                 if (opP->mode != MSCR
+                 if (opP->mode != CONTROL
                      || opP->reg < USP
-                     || opP->reg > URP
-                     || cpu_of_arch (current_architecture) < m68010    /* before 68010 had none */
-                     || (cpu_of_arch (current_architecture) < m68020
-                         && opP->reg != SFC
-                         && opP->reg != DFC
-                         && opP->reg != USP
-                         && opP->reg != VBR)   /* 68010's had only these */
-                     || (cpu_of_arch (current_architecture) < m68040
-                         && opP->reg != SFC
-                         && opP->reg != DFC
-                         && opP->reg != USP
-                         && opP->reg != VBR
-                         && opP->reg != CACR
-                         && opP->reg != CAAR
-                         && opP->reg != MSP
-                         && opP->reg != ISP)   /* 680[23]0's have only these */
-                     || (cpu_of_arch (current_architecture) == m68040  /* 68040 has all but this */
-                         && opP->reg == CAAR))
+                     || opP->reg > last_movec_reg)
+                   losing++;
+                 else
                    {
-                     losing++;
-                   }           /* doesn't cut it */
+                     const enum m68k_register *rp;
+                     for (rp = control_regs; *rp; rp++)
+                       if (*rp == opP->reg)
+                         break;
+                     if (*rp == 0)
+                       losing++;
+                   }
                  break;
 
                case 'k':
@@ -1854,57 +1422,102 @@ m68k_ip (instring)
 
                case 'l':
                case 'L':
-                 if (opP->mode == DREG || opP->mode == AREG || opP->mode == FPREG)
+                 if (opP->mode == DREG
+                     || opP->mode == AREG
+                     || opP->mode == FPREG)
                    {
                      if (s[1] == '8')
                        losing++;
                      else
                        {
+                         switch (opP->mode)
+                           {
+                           case DREG:
+                             opP->mask = 1 << (opP->reg - DATA0);
+                             break;
+                           case AREG:
+                             opP->mask = 1 << (opP->reg - ADDR0 + 8);
+                             break;
+                           case FPREG:
+                             opP->mask = 1 << (opP->reg - FP0 + 16);
+                             break;
+                           default:
+                             abort ();
+                           }
                          opP->mode = REGLST;
-                         opP->reg = 1 << (opP->reg - DATA);
                        }
                    }
-                 else if (opP->mode != REGLST)
+                 else if (opP->mode == CONTROL)
                    {
-                     losing++;
+                     if (s[1] != '8')
+                       losing++;
+                     else
+                       {
+                         switch (opP->reg)
+                           {
+                           case FPI:
+                             opP->mask = 1 << 24;
+                             break;
+                           case FPS:
+                             opP->mask = 1 << 25;
+                             break;
+                           case FPC:
+                             opP->mask = 1 << 26;
+                             break;
+                           default:
+                             losing++;
+                             break;
+                           }
+                         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 (s[1] == '8' && opP->reg & 0x0FFffFF)
+                 else if (opP->mode != REGLST)
+                   losing++;
+                 else if (s[1] == '8' && (opP->mask & 0x0ffffff) != 0)
                    losing++;
-                 else if (s[1] == '3' && opP->reg & 0x7000000)
+                 else if (s[1] == '3' && (opP->mask & 0x7000000) != 0)
                    losing++;
                  break;
 
                case 'M':
                  if (opP->mode != IMMED)
                    losing++;
-                 else
-                   {
-                     long t;
-
-                     t = get_num (opP->con1, 0);
-                     if (!issbyte (t)
-                         || isvar (opP->con1)
-                         || seg (opP->con1) != absolute_section)
-                       losing++;
-                   }
+                 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
-                   {
-                     long t;
-
-                     t = get_num (opP->con1, 80);
-                     if (t < 1 || t > 8 || isvar (opP->con1))
-                       losing++;
-                   }
+                 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':
@@ -1913,33 +1526,44 @@ m68k_ip (instring)
                  break;
 
                case 'r':
-                 if (opP->mode != AINDR && opP->mode != DINDR)
+                 if (opP->mode != AINDR
+                     && (opP->mode != BASE
+                         || (opP->reg != 0
+                             && opP->reg != ZADDR0)
+                         || opP->disp.exp.X_op != O_absent
+                         || ((opP->index.reg < DATA0
+                              || opP->index.reg > DATA7)
+                             && (opP->index.reg < ADDR0
+                                 || opP->index.reg > ADDR7))
+                         || opP->index.size != SIZE_UNSPEC
+                         || opP->index.scale != 1))
                    losing++;
                  break;
 
                case 's':
-                 if (opP->mode != MSCR || !(opP->reg == FPI || opP->reg == FPS || opP->reg == FPC))
+                 if (opP->mode != CONTROL
+                     || ! (opP->reg == FPI
+                           || opP->reg == FPS
+                           || opP->reg == FPC))
                    losing++;
                  break;
 
                case 'S':
-                 if (opP->mode != MSCR || opP->reg != SR)
+                 if (opP->mode != CONTROL || opP->reg != SR)
                    losing++;
                  break;
 
                case 't':
                  if (opP->mode != IMMED)
                    losing++;
-                 else
-                   {
-                     long t = get_num (opP->con1, 80);
-                     if (t < 0 || t > 7 || isvar (opP->con1))
-                       losing++;
-                   }
+                 else if (opP->disp.exp.X_op != O_constant
+                          || opP->disp.exp.X_add_number < 0
+                          || opP->disp.exp.X_add_number > 7)
+                   losing++;
                  break;
 
                case 'U':
-                 if (opP->mode != MSCR || opP->reg != USP)
+                 if (opP->mode != CONTROL || opP->reg != USP)
                    losing++;
                  break;
 
@@ -1952,57 +1576,81 @@ m68k_ip (instring)
 #ifndef NO_68851
                  /* Memory addressing mode used by pflushr */
                case '|':
-                 if (opP->mode == MSCR || opP->mode == DREG ||
-                     opP->mode == AREG || opP->mode == REGLST)
+                 if (opP->mode == CONTROL
+                     || opP->mode == FPREG
+                     || opP->mode == DREG
+                     || 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':
-                 if (opP->mode != MSCR || (opP->reg != SFC && opP->reg != DFC))
+                 if (opP->mode != CONTROL
+                     || (opP->reg != SFC && opP->reg != DFC))
+                   losing++;
+                 break;
+
+               case '0':
+                 if (opP->mode != CONTROL || opP->reg != TC)
+                   losing++;
+                 break;
+
+               case '1':
+                 if (opP->mode != CONTROL || opP->reg != AC)
                    losing++;
                  break;
 
-               case 'P':
-                 if (opP->mode != MSCR
-                     || (opP->reg != TC && opP->reg != CAL
-                  && opP->reg != VAL && opP->reg != SCC && opP->reg != AC))
+               case '2':
+                 if (opP->mode != CONTROL
+                     || (opP->reg != CAL
+                         && opP->reg != VAL
+                         && opP->reg != SCC))
                    losing++;
                  break;
 
                case 'V':
-                 if (opP->reg != VAL)
+                 if (opP->mode != CONTROL
+                     || opP->reg != VAL)
                    losing++;
                  break;
 
                case 'W':
-                 if (opP->mode != MSCR
-                     || (opP->reg != DRP && opP->reg != SRP
+                 if (opP->mode != CONTROL
+                     || (opP->reg != DRP
+                         && opP->reg != SRP
                          && opP->reg != CRP))
                    losing++;
                  break;
 
                case 'X':
-                 if (opP->mode != MSCR ||
-                     (!(opP->reg >= BAD && opP->reg <= BAD + 7) &&
-                      !(opP->reg >= BAC && opP->reg <= BAC + 7)))
+                 if (opP->mode != CONTROL
+                     || (!(opP->reg >= BAD && opP->reg <= BAD + 7)
+                         && !(opP->reg >= BAC && opP->reg <= BAC + 7)))
                    losing++;
                  break;
 
                case 'Y':
-                 if (opP->reg != PSR)
+                 if (opP->mode != CONTROL || opP->reg != PSR)
                    losing++;
                  break;
 
                case 'Z':
-                 if (opP->reg != PCSR)
+                 if (opP->mode != CONTROL || opP->reg != PCSR)
                    losing++;
                  break;
 #endif
                case 'c':
-                 if (opP->reg != NC
-                     && opP->reg != IC
-                     && opP->reg != DC
-                     && opP->reg != BC)
+                 if (opP->mode != CONTROL
+                     || (opP->reg != NC
+                         && opP->reg != IC
+                         && opP->reg != DC
+                         && opP->reg != BC))
                    {
                      losing++;
                    }           /* not a cache specifier. */
@@ -2010,14 +1658,11 @@ m68k_ip (instring)
 
                case '_':
                  if (opP->mode != ABSL)
-                   {
-                     ++losing;
-                   }           /* not absolute */
+                   ++losing;
                  break;
 
                default:
-                 as_fatal ("Internal error:  Operand mode %c unknown in line %d of file \"%s\"",
-                           *s, __LINE__, __FILE__);
+                 abort ();
                }               /* switch on type of operand */
 
              if (losing)
@@ -2038,13 +1683,14 @@ m68k_ip (instring)
              && !(ok_arch & current_architecture))
            {
              char buf[200], *cp;
-             int len;
-             strcpy (buf, "invalid instruction for this architecture; needs ");
+
+             strcpy (buf,
+                     "invalid instruction for this architecture; needs ");
              cp = buf + strlen (buf);
              switch (ok_arch)
                {
                case mfloat:
-                 strcpy (cp, "fpu (68040 or 68881/68882)");
+                 strcpy (cp, "fpu (68040, 68060 or 68881/68882)");
                  break;
                case mmmu:
                  strcpy (cp, "mmu (68030 or 68851)");
@@ -2061,25 +1707,11 @@ m68k_ip (instring)
                default:
                  {
                    int got_one = 0, idx;
-                   CONST static struct
+                   for (idx = 0; idx < sizeof (archs) / sizeof (archs[0]);
+                        idx++)
                      {
-                       int arch;
-                       CONST char *name;
-                     }
-                   archs[] =
-                   {
-                     m68000, "68000",
-                     m68010, "68010",
-                     m68020, "68020",
-                     m68030, "68030",
-                     m68040, "68040",
-                     cpu32,  "cpu32",
-                     m68881, "68881",
-                     m68851, "68851",
-                   };
-                   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)
                              {
@@ -2093,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;
            }
@@ -2132,6 +1763,12 @@ m68k_ip (instring)
        case '?':
        case '/':
        case '`':
+       case '<':
+       case '>':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
 #ifndef NO_68851
        case '|':
 #endif
@@ -2140,11 +1777,11 @@ m68k_ip (instring)
            case IMMED:
              tmpreg = 0x3c;    /* 7.4 */
              if (strchr ("bwl", s[1]))
-               nextword = get_num (opP->con1, 80);
+               nextword = get_num (&opP->disp, 80);
              else
-               nextword = get_num (opP->con1, 0);
-             if (isvar (opP->con1))
-               add_fix (s[1], opP->con1, 0);
+               nextword = get_num (&opP->disp, 0);
+             if (isvar (&opP->disp))
+               add_fix (s[1], &opP->disp, 0, 0);
              switch (s[1])
                {
                case 'b':
@@ -2159,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);
@@ -2182,40 +1825,47 @@ m68k_ip (instring)
                  outro = -1;
                  break;
                default:
-                 as_fatal ("Internal error:  Can't decode %c%c in line %s of file \"%s\"",
-                           *s, s[1], __LINE__, __FILE__);
+                 abort ();
                }
              if (!baseo)
                break;
 
              /* We gotta put out some float */
-#if 0
-             if (seg (opP->con1) != SEG_BIG)
-               {
-                 int_to_gen (nextword);
-                 gen_to_words (words, baseo, (long int) outro);
-                 for (wordp = words; baseo--; wordp++)
-                   addword (*wordp);
-                 break;
-               }               /* Its BIG */
-#else
-             if (seg (opP->con1) != big_section)
+             if (op (&opP->disp) != O_big)
                {
-                 abort ();
+                 valueT val;
+                 int gencnt;
+
+                 /* Can other cases happen here?  */
+                 if (op (&opP->disp) != O_constant)
+                   abort ();
+
+                 val = (valueT) offs (&opP->disp);
+                 gencnt = 0;
+                 do
+                   {
+                     generic_bignum[gencnt] = (LITTLENUM_TYPE) val;
+                     val >>= LITTLENUM_NUMBER_OF_BITS;
+                     ++gencnt;
+                   }
+                 while (val != 0);
+                 offs (&opP->disp) = gencnt;
                }
-#endif
-             if (offs (opP->con1) > 0)
+             if (offs (&opP->disp) > 0)
                {
-                 if (offs (opP->con1) > baseo)
+                 if (offs (&opP->disp) > baseo)
                    {
-                     as_warn ("Bignum too big for %c format; truncated", s[1]);
-                     offs (opP->con1) = baseo;
+                     as_warn ("Bignum too big for %c format; truncated",
+                              s[1]);
+                     offs (&opP->disp) = baseo;
                    }
-                 baseo -= offs (opP->con1);
-                 for (wordp = generic_bignum + offs (opP->con1) - 1; offs (opP->con1)--; --wordp)
-                   addword (*wordp);
+                 baseo -= offs (&opP->disp);
                  while (baseo--)
                    addword (0);
+                 for (wordp = generic_bignum + offs (&opP->disp) - 1;
+                      offs (&opP->disp)--;
+                      --wordp)
+                   addword (*wordp);
                  break;
                }
              gen_to_words (words, baseo, (long) outro);
@@ -2237,9 +1887,23 @@ m68k_ip (instring)
            case AINC:
              tmpreg = 0x18 + opP->reg - ADDR;  /* 3.areg */
              break;
-           case AOFF:
+           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
+               }
 
-             nextword = get_num (opP->con1, 80);
              /* Force into index mode.  Hope this works */
 
              /* We do the first bit for 32-bit displacements, and the
@@ -2249,29 +1913,46 @@ m68k_ip (instring)
                 inefficiency for the sake of working output.  */
 
              if (!issword (nextword)
-                 || (isvar (opP->con1)
-                     && ((opP->con1->e_siz == 0
-                          && flagseen['l'] == 0)
-                         || opP->con1->e_siz == 3)))
+                 || (isvar (&opP->disp)
+                     && ((opP->disp.size == SIZE_UNSPEC
+                          && flag_short_refs == 0
+                          && 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
                    tmpreg = 0x30 + opP->reg - ADDR;    /* 6.areg */
-                 if (isvar (opP->con1))
+                 if (isvar (&opP->disp))
                    {
                      if (opP->reg == PC)
                        {
-                         add_frag (adds (opP->con1),
-                                   offs (opP->con1) + 2,
-                                   TAB (PCLEA, SZ_UNDEF));
-                         break;
+                         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
+                             )
+                           {
+                             addword (0x0170);
+                             add_fix ('l', &opP->disp, 1, 2);
+                           }
+                         else
+                           {
+                             add_frag (adds (&opP->disp),
+                                       offs (&opP->disp),
+                                       TAB (PCLEA, SZ_UNDEF));
+                             break;
+                           }
                        }
                      else
                        {
                          addword (0x0170);
-                         add_fix ('l', opP->con1, 0);
+                         add_fix ('l', &opP->disp, 0, 0);
                        }
                    }
                  else
@@ -2285,55 +1966,75 @@ m68k_ip (instring)
                  else
                    tmpreg = 0x28 + opP->reg - ADDR;    /* 5.areg */
 
-                 if (isvar (opP->con1))
+                 if (isvar (&opP->disp))
                    {
                      if (opP->reg == PC)
                        {
-                         add_fix ('w', opP->con1, 1);
+                         add_fix ('w', &opP->disp, 1, 0);
                        }
                      else
-                       add_fix ('w', opP->con1, 0);
+                       add_fix ('w', &opP->disp, 0, 0);
                    }
                }
              addword (nextword);
              break;
 
-           case APODX:
-           case AMIND:
-           case APRDX:
-             know (current_architecture & m68020up);
-             /* intentional fall-through */
-           case AINDX:
+           case POST:
+           case PRE:
+           case BASE:
              nextword = 0;
-             baseo = get_num (opP->con1, 80);
-             outro = get_num (opP->con2, 80);
+             baseo = get_num (&opP->disp, 80);
+             if (opP->mode == POST || opP->mode == PRE)
+               outro = get_num (&opP->odisp, 80);
              /* Figure out the `addressing mode'.
                 Also turn on the BASE_DISABLE bit, if needed.  */
              if (opP->reg == PC || opP->reg == ZPC)
                {
-                 tmpreg = 0x3b;/* 7.3 */
+                 tmpreg = 0x3b;        /* 7.3 */
                  if (opP->reg == ZPC)
                    nextword |= 0x80;
                }
-             else if (opP->reg == FAIL)
+             else if (opP->reg == 0)
                {
                  nextword |= 0x80;
-                 tmpreg = 0x30;/* 6.garbage */
+                 tmpreg = 0x30;        /* 6.garbage */
                }
-             else
+             else if (opP->reg >= ZADDR0 && opP->reg <= ZADDR7)
+               {
+                 nextword |= 0x80;
+                 tmpreg = 0x30 + opP->reg - ZADDR0;
+               }
+             else
                tmpreg = 0x30 + opP->reg - ADDR;        /* 6.areg */
 
-             siz1 = (opP->con1) ? opP->con1->e_siz : 0;
-             siz2 = (opP->con2) ? opP->con2->e_siz : 0;
+             siz1 = opP->disp.size;
+             if (opP->mode == POST || opP->mode == PRE)
+               siz2 = opP->odisp.size;
+             else
+               siz2 = SIZE_UNSPEC;
 
              /* Index register stuff */
-             if (opP->ireg >= DATA + 0 && opP->ireg <= ADDR + 7)
+             if (opP->index.reg != 0
+                 && opP->index.reg >= DATA
+                 && opP->index.reg <= ADDR7)
                {
-                 nextword |= (opP->ireg - DATA) << 12;
+                 nextword |= (opP->index.reg - DATA) << 12;
 
-                 if (opP->isiz == 0 || opP->isiz == 3)
+                 if (opP->index.size == SIZE_LONG
+                     || (opP->index.size == SIZE_UNSPEC
+                         && m68k_index_width_default == SIZE_LONG))
                    nextword |= 0x800;
-                 switch (opP->imul)
+
+                 if ((opP->index.scale != 1 
+                      && cpu_of_arch (current_architecture) < m68020)
+                     || (opP->index.scale == 8 
+                         && current_architecture == mcf5200))
+                   {
+                     opP->error =
+                       "scale factor invalid on this architecture; needs cpu32 or 68020 or higher";
+                   }
+
+                 switch (opP->index.scale)
                    {
                    case 1:
                      break;
@@ -2347,84 +2048,150 @@ m68k_ip (instring)
                      nextword |= 0x600;
                      break;
                    default:
-                     as_fatal ("failed sanity check.");
+                     abort ();
                    }
                  /* IF its simple,
                     GET US OUT OF HERE! */
 
-                 /* Must be INDEX, with an index
-                    register.  Address register
-                    cannot be ZERO-PC, and either
-                    :b was forced, or we know
-                    it will fit */
-                 if (opP->mode == AINDX
-                     && opP->reg != FAIL
-                     && opP->reg != ZPC
-                     && (siz1 == 1
-                         || (issbyte (baseo)
-                             && !isvar (opP->con1))))
+                 /* Must be INDEX, with an index register.  Address
+                    register cannot be ZERO-PC, and either :b was
+                    forced, or we know it will fit.  For a 68000 or
+                    68010, force this mode anyways, because the
+                    larger modes aren't supported.  */
+                 if (opP->mode == BASE
+                     && ((opP->reg >= ADDR0
+                          && opP->reg <= ADDR7)
+                         || opP->reg == PC))
                    {
-                     nextword += baseo & 0xff;
-                     addword (nextword);
-                     if (isvar (opP->con1))
-                       add_fix ('B', opP->con1, 0);
-                     break;
+                     if (siz1 == SIZE_BYTE
+                         || cpu_of_arch (current_architecture) < m68020
+                         || (siz1 == SIZE_UNSPEC
+                             && ! isvar (&opP->disp)
+                             && issbyte (baseo)))
+                       {
+                         nextword += baseo & 0xff;
+                         addword (nextword);
+                         if (isvar (&opP->disp))
+                           {
+                             /* Do a byte relocation.  If it doesn't
+                                fit (possible on m68000) let the
+                                fixup processing complain later.  */
+                             if (opP->reg == PC)
+                               add_fix ('B', &opP->disp, 1, 1);
+                             else
+                               add_fix ('B', &opP->disp, 0, 0);
+                           }
+                         else if (siz1 != SIZE_BYTE)
+                           {
+                             if (siz1 != SIZE_UNSPEC)
+                               as_warn ("Forcing byte displacement");
+                             if (! issbyte (baseo))
+                               opP->error = "byte displacement out of range";
+                           }
+
+                         break;
+                       }
+                     else if (siz1 == SIZE_UNSPEC
+                              && opP->reg == PC
+                              && isvar (&opP->disp)
+                              && 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),
+                                   TAB (PCINDEX, SZ_UNDEF));
+
+                         break;
+                       }
                    }
                }
              else
-               nextword |= 0x40;       /* No index reg */
+               {
+                 nextword |= 0x40;     /* No index reg */
+                 if (opP->index.reg >= ZDATA0
+                     && opP->index.reg <= ZDATA7)
+                   nextword |= (opP->index.reg - ZDATA0) << 12;
+                 else if (opP->index.reg >= ZADDR0
+                          || opP->index.reg <= ZADDR7)
+                   nextword |= (opP->index.reg - ZADDR0 + 8) << 12;
+               }
 
              /* It isn't simple.  */
+
+             if (cpu_of_arch (current_architecture) < m68020)
+               opP->error =
+                 "invalid operand mode for this architecture; needs 68020 or higher";
+
              nextword |= 0x100;
              /* If the guy specified a width, we assume that it is
                 wide enough.  Maybe it isn't.  If so, we lose.  */
              switch (siz1)
                {
-               case 0:
-                 if (isvar (opP->con1) || !issword (baseo))
+               case SIZE_UNSPEC:
+                 if (isvar (&opP->disp)
+                     ? m68k_rel32
+                     : ! issword (baseo))
                    {
-                     siz1 = 3;
+                     siz1 = SIZE_LONG;
                      nextword |= 0x30;
                    }
-                 else if (baseo == 0)
+                 else if (! isvar (&opP->disp) && baseo == 0)
                    nextword |= 0x10;
                  else
                    {
                      nextword |= 0x20;
-                     siz1 = 2;
+                     siz1 = SIZE_WORD;
                    }
                  break;
-               case 1:
-                 as_warn ("Byte dispacement won't work.  Defaulting to :w");
-               case 2:
+               case SIZE_BYTE:
+                 as_warn (":b not permitted; defaulting to :w");
+                 /* Fall through.  */
+               case SIZE_WORD:
                  nextword |= 0x20;
                  break;
-               case 3:
+               case SIZE_LONG:
                  nextword |= 0x30;
                  break;
                }
 
              /* Figure out innner displacement stuff */
-             if (opP->mode != AINDX)
+             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 0:
-                     if (isvar (opP->con2) || !issword (outro))
+                   case SIZE_UNSPEC:
+                     if (isvar (&opP->odisp)
+                         ? m68k_rel32
+                         : ! issword (outro))
                        {
-                         siz2 = 3;
+                         siz2 = SIZE_LONG;
                          nextword |= 0x3;
                        }
-                     else if (outro == 0)
+                     else if (! isvar (&opP->odisp) && outro == 0)
                        nextword |= 0x1;
                      else
                        {
                          nextword |= 0x2;
-                         siz2 = 2;
+                         siz2 = SIZE_WORD;
                        }
                      break;
                    case 1:
-                     as_warn ("Byte dispacement won't work.  Defaulting to :w");
+                     as_warn (":b not permitted; defaulting to :w");
+                     /* Fall through.  */
                    case 2:
                      nextword |= 0x2;
                      break;
@@ -2432,96 +2199,88 @@ m68k_ip (instring)
                      nextword |= 0x3;
                      break;
                    }
-                 if (opP->mode == APODX)
+                 if (opP->mode == POST
+                     && (nextword & 0x40) == 0)
                    nextword |= 0x04;
-                 else if (opP->mode == AMIND)
-                   nextword |= 0x40;
                }
              addword (nextword);
 
-             if (isvar (opP->con1))
+             if (siz1 != SIZE_UNSPEC && isvar (&opP->disp))
                {
                  if (opP->reg == PC || opP->reg == ZPC)
-                   {
-                     opP->con1->e_exp.X_add_number += 6;
-                     add_fix (siz1 == 3 ? 'l' : 'w', opP->con1, 1);
-                   }
+                   add_fix (siz1 == SIZE_LONG ? 'l' : 'w', &opP->disp, 1, 2);
                  else
-                   add_fix (siz1 == 3 ? 'l' : 'w', opP->con1, 0);
+                   add_fix (siz1 == SIZE_LONG ? 'l' : 'w', &opP->disp, 0, 0);
                }
-             if (siz1 == 3)
+             if (siz1 == SIZE_LONG)
                addword (baseo >> 16);
-             if (siz1)
+             if (siz1 != SIZE_UNSPEC)
                addword (baseo);
 
-             if (isvar (opP->con2))
-               {
-                 if (opP->reg == PC || opP->reg == ZPC)
-                   {
-                     opP->con1->e_exp.X_add_number += 6;
-                     add_fix (siz2 == 3 ? 'l' : 'w', opP->con2, 1);
-                   }
-                 else
-                   add_fix (siz2 == 3 ? 'l' : 'w', opP->con2, 0);
-               }
-             if (siz2 == 3)
+             if (siz2 != SIZE_UNSPEC && isvar (&opP->odisp))
+               add_fix (siz2 == SIZE_LONG ? 'l' : 'w', &opP->odisp, 0, 0);
+             if (siz2 == SIZE_LONG)
                addword (outro >> 16);
-             if (siz2)
+             if (siz2 != SIZE_UNSPEC)
                addword (outro);
 
              break;
 
            case ABSL:
-             nextword = get_num (opP->con1, 80);
-             switch (opP->con1->e_siz)
+             nextword = get_num (&opP->disp, 80);
+             switch (opP->disp.size)
                {
                default:
-                 as_warn ("Unknown size for absolute reference");
-               case 0:
-                 if (!isvar (opP->con1) && issword (offs (opP->con1)))
+                 abort ();
+               case SIZE_UNSPEC:
+                 if (!isvar (&opP->disp) && issword (offs (&opP->disp)))
                    {
                      tmpreg = 0x38;    /* 7.0 */
                      addword (nextword);
                      break;
                    }
-                 /* Don't generate pc relative code
-            on 68010 and 68000 */
-                 if (isvar (opP->con1)
-                     && !subs (opP->con1)
-                     && seg (opP->con1) == text_section
-                     && now_seg == text_section
+                 /* Don't generate pc relative code on 68010 and
+                    68000.  */
+                 if (isvar (&opP->disp)
+                     && !subs (&opP->disp)
+                     && adds (&opP->disp)
+#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
-                     && !flagseen['S']
+                     && !flag_long_jumps
                      && !strchr ("~%&$?", s[0]))
                    {
                      tmpreg = 0x3A;    /* 7.2 */
-                     add_frag (adds (opP->con1),
-                               offs (opP->con1),
+                     add_frag (adds (&opP->disp),
+                               offs (&opP->disp),
                                TAB (PCREL, SZ_UNDEF));
                      break;
                    }
-               case 3: /* Fall through into long */
-                 if (isvar (opP->con1))
-                   add_fix ('l', opP->con1, 0);
+                 /* Fall through into long */
+               case SIZE_LONG:
+                 if (isvar (&opP->disp))
+                   add_fix ('l', &opP->disp, 0, 0);
 
                  tmpreg = 0x39;/* 7.1 mode */
                  addword (nextword >> 16);
                  addword (nextword);
                  break;
 
-               case 2: /* Word */
-                 if (isvar (opP->con1))
-                   add_fix ('w', opP->con1, 0);
+               case SIZE_WORD: /* Word */
+                 if (isvar (&opP->disp))
+                   add_fix ('w', &opP->disp, 0, 0);
 
                  tmpreg = 0x38;/* 7.0 mode */
                  addword (nextword);
                  break;
                }
              break;
-           case DINDR:
-             as_bad ("invalid indirect register");
-             break;
-           case MSCR:
+           case CONTROL:
+           case FPREG:
            default:
              as_bad ("unknown/incorrect operand");
              /* abort(); */
@@ -2547,9 +2306,9 @@ m68k_ip (instring)
              tmpreg = 80;
              break;
            }
-         tmpreg = get_num (opP->con1, tmpreg);
-         if (isvar (opP->con1))
-           add_fix (s[1], opP->con1, 0);
+         tmpreg = get_num (&opP->disp, tmpreg);
+         if (isvar (&opP->disp))
+           add_fix (s[1], &opP->disp, 0, 0);
          switch (s[1])
            {
            case 'b':           /* Danger:  These do no check for
@@ -2557,21 +2316,38 @@ m68k_ip (instring)
                                   user beware! */
              if (!isbyte (tmpreg))
                opP->error = "out of range";
-             insop (tmpreg);
-             if (isvar (opP->con1))
-               the_ins.reloc[the_ins.nrel - 1].n = (opcode->m_codenum) * 2;
+             insop (tmpreg, opcode);
+             if (isvar (&opP->disp))
+               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))
                opP->error = "out of range";
-             insop (tmpreg);
-             if (isvar (opP->con1))
+             insop (tmpreg, opcode);
+             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':
-             insop (tmpreg);   /* Because of the way insop works, we put these two out backwards */
-             insop (tmpreg >> 16);
-             if (isvar (opP->con1))
+             /* Because of the way insop works, we put these two out
+                backwards.  */
+             insop (tmpreg, opcode);
+             insop (tmpreg >> 16, opcode);
+             if (isvar (&opP->disp))
                the_ins.reloc[the_ins.nrel - 1].n = (opcode->m_codenum) * 2;
              break;
            case '3':
@@ -2581,7 +2357,7 @@ m68k_ip (instring)
              install_operand (s[1], tmpreg);
              break;
            default:
-             as_fatal ("Internal error:  Unknown mode #%c in line %s of file \"%s\"", s[1], __LINE__, __FILE__);
+             abort ();
            }
          break;
 
@@ -2593,55 +2369,58 @@ m68k_ip (instring)
          break;
 
        case 'B':
-         tmpreg = get_num (opP->con1, 80);
+         tmpreg = get_num (&opP->disp, 80);
          switch (s[1])
            {
            case 'B':
-             /* Needs no offsetting */
-             add_fix ('B', opP->con1, 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':
-             /* Offset the displacement to be relative to byte disp location */
-             opP->con1->e_exp.X_add_number += 2;
-             add_fix ('w', opP->con1, 1);
+             add_fix ('w', &opP->disp, 1, 0);
              addword (0);
              break;
            case 'L':
            long_branch:
-             if (cpu_of_arch (current_architecture) < m68020)  /* 68000 or 010 */
+             if (cpu_of_arch (current_architecture) < m68020)
                as_warn ("Can't use long branches on 68000/68010");
              the_ins.opcode[the_ins.numo - 1] |= 0xff;
-             /* Offset the displacement to be relative to byte disp location */
-             opP->con1->e_exp.X_add_number += 4;
-             add_fix ('l', opP->con1, 1);
+             add_fix ('l', &opP->disp, 1, 0);
              addword (0);
              addword (0);
              break;
            case 'g':
-             if (subs (opP->con1))     /* We can't relax it */
+             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 BCC68000 for the case
-                where opnd is absolute (it needs
-                to use the 68000 hack since no
-                conditional abs jumps).  */
-             if (((cpu_of_arch (current_architecture) < m68020) || (0 == adds (opP->con1)))
+             /* 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
+                BCC68000 for the case where opnd is absolute (it
+                needs to use the 68000 hack since no conditional abs
+                jumps).  */
+             if (((cpu_of_arch (current_architecture) < m68020)
+                  || (0 == adds (&opP->disp)))
                  && (the_ins.opcode[0] >= 0x6200)
                  && (the_ins.opcode[0] <= 0x6f00))
-               {
-                 add_frag (adds (opP->con1), offs (opP->con1), TAB (BCC68000, SZ_UNDEF));
-               }
+               add_frag (adds (&opP->disp), offs (&opP->disp),
+                         TAB (BCC68000, SZ_UNDEF));
              else
-               {
-                 add_frag (adds (opP->con1), offs (opP->con1), TAB (ABRANCH, SZ_UNDEF));
-               }
+               add_frag (adds (&opP->disp), offs (&opP->disp),
+                         TAB (ABRANCH, SZ_UNDEF));
              break;
            case 'w':
-             if (isvar (opP->con1))
+             if (isvar (&opP->disp))
                {
 #if 1
                  /* check for DBcc instruction */
@@ -2649,48 +2428,41 @@ m68k_ip (instring)
                    {
                      /* size varies if patch */
                      /* needed for long form */
-                     add_frag (adds (opP->con1), offs (opP->con1), TAB (DBCC, SZ_UNDEF));
+                     add_frag (adds (&opP->disp), offs (&opP->disp),
+                               TAB (DBCC, SZ_UNDEF));
                      break;
                    }
 #endif
-                 /* Don't ask! */
-                 opP->con1->e_exp.X_add_number += 2;
-                 add_fix ('w', opP->con1, 1);
+                 add_fix ('w', &opP->disp, 1, 0);
                }
              addword (0);
              break;
            case 'C':           /* Fixed size LONG coproc branches */
-             the_ins.opcode[the_ins.numo - 1] |= 0x40;
-             /* Offset the displacement to be relative to byte disp location */
-             /* Coproc branches don't have a byte disp option, but they are
-          compatible with the ordinary branches, which do... */
-             opP->con1->e_exp.X_add_number += 4;
-             add_fix ('l', opP->con1, 1);
+             add_fix ('l', &opP->disp, 1, 0);
              addword (0);
              addword (0);
              break;
            case 'c':           /* Var size Coprocesssor branches */
-             if (subs (opP->con1))
+             if (subs (&opP->disp))
                {
-                 add_fix ('l', opP->con1, 1);
+                 add_fix ('l', &opP->disp, 1, 0);
                  add_frag ((symbolS *) 0, (long) 0, TAB (FBRANCH, LONG));
                }
-             else if (adds (opP->con1))
-               {
-                 add_frag (adds (opP->con1), offs (opP->con1), TAB (FBRANCH, SZ_UNDEF));
-               }
+             else if (adds (&opP->disp))
+               add_frag (adds (&opP->disp), offs (&opP->disp),
+                         TAB (FBRANCH, SZ_UNDEF));
              else
                {
-                 /* add_frag((symbolS *)0,offs(opP->con1),TAB(FBRANCH,SHORT)); */
+                 /* add_frag((symbolS *) 0, offs(&opP->disp),
+                    TAB(FBRANCH,SHORT)); */
                  the_ins.opcode[the_ins.numo - 1] |= 0x40;
-                 add_fix ('l', opP->con1, 1);
+                 add_fix ('l', &opP->disp, 1, 0);
+                 addword (0);
                  addword (0);
-                 addword (4);
                }
              break;
            default:
-             as_fatal ("Internal error:  operand type B%c unknown in line %s of file \"%s\"",
-                       s[1], __LINE__, __FILE__);
+             abort ();
            }
          break;
 
@@ -2698,28 +2470,8 @@ m68k_ip (instring)
          break;
 
        case 'd':               /* JF this is a kludge */
-         if (opP->mode == AOFF)
-           {
-             install_operand ('s', opP->reg - ADDR);
-           }
-         else
-           {
-             char *tmpP;
-
-             tmpP = opP->con1->e_end - 2;
-             opP->con1->e_beg++;
-             opP->con1->e_end -= 4;    /* point to the , */
-             baseo = m68k_reg_parse (&tmpP);
-             if (baseo < ADDR + 0 || baseo > ADDR + 7)
-               {
-                 as_bad ("Unknown address reg, using A0");
-                 baseo = 0;
-               }
-             else
-               baseo -= ADDR;
-             install_operand ('s', baseo);
-           }
-         tmpreg = get_num (opP->con1, 80);
+         install_operand ('s', opP->reg - ADDR);
+         tmpreg = get_num (&opP->disp, 80);
          if (!issword (tmpreg))
            {
              as_warn ("Expression out of range, using 0");
@@ -2733,13 +2485,11 @@ m68k_ip (instring)
          break;
 
        case 'F':
-         install_operand (s[1], opP->reg - FPREG);
+         install_operand (s[1], opP->reg - FP0);
          break;
 
        case 'I':
-         tmpreg = 1 + opP->reg - COPNUM;
-         if (tmpreg == 8)
-           tmpreg = 0;
+         tmpreg = opP->reg - COP0;
          install_operand (s[1], tmpreg);
          break;
 
@@ -2770,6 +2520,9 @@ m68k_ip (instring)
            case DTT1:
              tmpreg = 0x007;
              break;
+           case BUSCR:
+             tmpreg = 0x008;
+             break;
 
            case USP:
              tmpreg = 0x800;
@@ -2795,24 +2548,39 @@ m68k_ip (instring)
            case SRP:
              tmpreg = 0x807;
              break;
+           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:
-             as_fatal ("failed sanity check.");
+             abort ();
            }
          install_operand (s[1], tmpreg);
          break;
 
        case 'k':
-         tmpreg = get_num (opP->con1, 55);
+         tmpreg = get_num (&opP->disp, 55);
          install_operand (s[1], tmpreg & 0x7f);
          break;
 
        case 'l':
-         tmpreg = opP->reg;
+         tmpreg = opP->mask;
          if (s[1] == 'w')
            {
              if (tmpreg & 0x7FF0000)
                as_bad ("Floating point register in register list");
-             insop (reverse_16_bits (tmpreg));
+             insop (reverse_16_bits (tmpreg), opcode);
            }
          else
            {
@@ -2823,12 +2591,12 @@ m68k_ip (instring)
          break;
 
        case 'L':
-         tmpreg = opP->reg;
+         tmpreg = opP->mask;
          if (s[1] == 'w')
            {
              if (tmpreg & 0x7FF0000)
                as_bad ("Floating point register in register list");
-             insop (tmpreg);
+             insop (tmpreg, opcode);
            }
          else if (s[1] == '8')
            {
@@ -2846,31 +2614,37 @@ m68k_ip (instring)
          break;
 
        case 'M':
-         install_operand (s[1], get_num (opP->con1, 60));
+         install_operand (s[1], get_num (&opP->disp, 60));
          break;
 
        case 'O':
-         tmpreg = (opP->mode == DREG)
-           ? 0x20 + opP->reg - DATA
-           : (get_num (opP->con1, 40) & 0x1F);
+         tmpreg = ((opP->mode == DREG)
+                   ? 0x20 + opP->reg - DATA
+                   : (get_num (&opP->disp, 40) & 0x1F));
          install_operand (s[1], tmpreg);
          break;
 
        case 'Q':
-         tmpreg = get_num (opP->con1, 10);
+         tmpreg = get_num (&opP->disp, 10);
          if (tmpreg == 8)
            tmpreg = 0;
          install_operand (s[1], tmpreg);
          break;
 
        case 'R':
-       case 'r':
-         /* This depends on the fact that ADDR registers are
-        eight more than their corresponding DATA regs, so
-        the result will have the ADDR_REG bit set */
+         /* This depends on the fact that ADDR registers are eight
+            more than their corresponding DATA regs, so the result
+            will have the ADDR_REG bit set */
          install_operand (s[1], opP->reg - DATA);
          break;
 
+       case 'r':
+         if (opP->mode == AINDR)
+           install_operand (s[1], opP->reg - DATA);
+         else
+           install_operand (s[1], opP->index.reg - DATA);
+         break;
+
        case 's':
          if (opP->reg == FPI)
            tmpreg = 0x1;
@@ -2879,7 +2653,7 @@ m68k_ip (instring)
          else if (opP->reg == FPC)
            tmpreg = 0x4;
          else
-           as_fatal ("failed sanity check.");
+           abort ();
          install_operand (s[1], tmpreg);
          break;
 
@@ -2887,7 +2661,7 @@ m68k_ip (instring)
          break;
 
        case 'T':
-         install_operand (s[1], get_num (opP->con1, 30));
+         install_operand (s[1], get_num (&opP->disp, 30));
          break;
 
        case 'U':               /* Ignore it */
@@ -2925,12 +2699,14 @@ m68k_ip (instring)
              tmpreg = 1;
              break;
            default:
-             as_fatal ("failed sanity check.");
+             abort ();
            }
          install_operand (s[1], tmpreg);
          break;
 
-       case 'P':
+       case '0':
+       case '1':
+       case '2':
          switch (opP->reg)
            {
            case TC:
@@ -2949,7 +2725,7 @@ m68k_ip (instring)
              tmpreg = 7;
              break;
            default:
-             as_fatal ("failed sanity check.");
+             abort ();
            }
          install_operand (s[1], tmpreg);
          break;
@@ -2957,12 +2733,11 @@ m68k_ip (instring)
        case 'V':
          if (opP->reg == VAL)
            break;
-         as_fatal ("failed sanity check.");
+         abort ();
 
        case 'W':
          switch (opP->reg)
            {
-
            case DRP:
              tmpreg = 1;
              break;
@@ -2973,7 +2748,7 @@ m68k_ip (instring)
              tmpreg = 3;
              break;
            default:
-             as_fatal ("failed sanity check.");
+             abort ();
            }
          install_operand (s[1], tmpreg);
          break;
@@ -3004,7 +2779,7 @@ m68k_ip (instring)
              break;
 
            default:
-             as_fatal ("failed sanity check.");
+             abort ();
            }
          install_operand (s[1], tmpreg);
          break;
@@ -3025,109 +2800,27 @@ m68k_ip (instring)
              tmpreg = 3;
              break;
            default:
-             as_fatal ("failed sanity check");
+             abort ();
            }
          install_operand (s[1], tmpreg);
          break;
        case 't':
-         tmpreg = get_num (opP->con1, 20);
+         tmpreg = get_num (&opP->disp, 20);
          install_operand (s[1], tmpreg);
          break;
-       case '_':               /* used only for move16 absolute 32-bit address */
-         tmpreg = get_num (opP->con1, 80);
+       case '_':       /* used only for move16 absolute 32-bit address */
+         tmpreg = get_num (&opP->disp, 80);
          addword (tmpreg >> 16);
          addword (tmpreg & 0xFFFF);
          break;
        default:
-         as_fatal ("Internal error:  Operand type %c unknown in line %d of file \"%s\"",
-                   s[0], __LINE__, __FILE__);
+         abort ();
        }
     }
 
   /* By the time whe get here (FINALLY) the_ins contains the complete
      instruction, ready to be emitted. . . */
-}                              /* m68k_ip() */
-
-/*
- * get_regs := '/' + ?
- *     | '-' + <register>
- *     | '-' + <register> + ?
- *     | <empty>
- *     ;
- *
-
- * The idea here must be to scan in a set of registers but I don't
- * understand it.  Looks awfully sloppy to me but I don't have any doc on
- * this format so...
-
- *
- *
- */
-
-static int
-get_regs (i, str, opP)
-     int i;
-     struct m68k_op *opP;
-     char *str;
-{
-  /*                        26, 25, 24, 23-16,  15-8, 0-7 */
-  /* Low order 24 bits encoded fpc,fps,fpi,fp7-fp0,a7-a0,d7-d0 */
-  unsigned long cur_regs = 0;
-  int reg1, reg2;
-
-#define ADD_REG(x)     {     if(x==FPI) cur_regs|=(1<<24);\
-else if(x==FPS) cur_regs|=(1<<25);\
-else if(x==FPC) cur_regs|=(1<<26);\
-else cur_regs|=(1<<(x-1));  }
-
-  reg1 = i;
-  for (;;)
-    {
-      if (*str == '/')
-       {
-         ADD_REG (reg1);
-         str++;
-       }
-      else if (*str == '-')
-       {
-         str++;
-         reg2 = m68k_reg_parse (&str);
-         if (reg2 < DATA || reg2 >= FPREG + 8 || reg1 == FPI || reg1 == FPS || reg1 == FPC)
-           {
-             opP->error = "unknown register in register list";
-             return FAIL;
-           }
-         while (reg1 <= reg2)
-           {
-             ADD_REG (reg1);
-             reg1++;
-           }
-         if (*str == '\0')
-           break;
-       }
-      else if (*str == '\0')
-       {
-         ADD_REG (reg1);
-         break;
-       }
-      else
-       {
-         opP->error = "unknow character in register list";
-         return FAIL;
-       }
-      /* DJA -- Bug Fix.  Did't handle d1-d2/a1 until the following instruction was added */
-      if (*str == '/')
-       str++;
-      reg1 = m68k_reg_parse (&str);
-      if ((reg1 < DATA || reg1 >= FPREG + 8) && !(reg1 == FPI || reg1 == FPS || reg1 == FPC))
-       {
-         opP->error = "unknown register in register list";
-         return FAIL;
-       }
-    }
-  opP->reg = cur_regs;
-  return OK;
-}                              /* get_regs() */
+}
 
 static int
 reverse_16_bits (in)
@@ -3169,6 +2862,16 @@ reverse_8_bits (in)
   return out;
 }                              /* reverse_8_bits() */
 
+/* Cause an extra frag to be generated here, inserting up to 10 bytes
+   (that value is chosen in the frag_var call in md_assemble).  TYPE
+   is the subtype of the frag to be generated; its primary type is
+   rs_machine_dependent.
+
+   The TYPE parameter is also used by md_convert_frag_1 and
+   md_estimate_size_before_relax.  The appropriate type of fixup will
+   be emitted by md_convert_frag_1.
+
+   ADD becomes the FR_SYMBOL field of the frag, and OFF the FR_OFFSET.  */
 static void
 install_operand (mode, val)
      int mode;
@@ -3198,8 +2901,8 @@ install_operand (mode, val)
       the_ins.opcode[2] |= val << 6;
       break;
     case '6':
-      /* DANGER!  This is a hack to force cas2l and cas2w cmds
-                  to be three words long! */
+      /* DANGER!  This is a hack to force cas2l and cas2w cmds to be
+        three words long! */
       the_ins.numo++;
       the_ins.opcode[2] |= val;
       break;
@@ -3239,6 +2942,7 @@ install_operand (mode, val)
       break;
     case 'b':
     case 'w':
+    case 'W':
     case 'l':
       break;
     case 'e':
@@ -3296,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 */
@@ -3323,7 +3033,7 @@ crack_operand (str, opP)
     }
   c = *str;
   *str = '\0';
-  if (m68k_ip_op (beg_str, opP) == FAIL)
+  if (m68k_ip_op (beg_str, opP) != 0)
     {
       *str = c;
       return str;
@@ -3340,25 +3050,6 @@ crack_operand (str, opP)
   return str;
 }
 
-/* See the comment up above where the #define notend(... is */
-#if 0
-notend (s)
-     char *s;
-{
-  if (*s == ',')
-    return 0;
-  if (*s == '{' || *s == '}')
-    return 0;
-  if (*s != ':')
-    return 1;
-  /* This kludge here is for the division cmd, which is a kludge */
-  if (index ("aAdD#", s[1]))
-    return 0;
-  return 1;
-}
-
-#endif
-
 /* This is the guts of the machine-dependent assembler.  STR points to a
    machine dependent instruction.  This function is supposed to emit
    the frags/bytes it assembles to.
@@ -3371,145 +3062,195 @@ insert_reg (regname, regnum)
 {
   char buf[100];
   int i;
-symbolS *s;
 
 #ifdef REGISTER_PREFIX
-  buf[0] = REGISTER_PREFIX;
-  strcpy (buf + 1, regname);
-  regname = buf;
+  if (!flag_reg_prefix_optional)
+    {
+      buf[0] = REGISTER_PREFIX;
+      strcpy (buf + 1, regname);
+      regname = buf;
+    }
 #endif
 
-  symbol_table_insert (s = symbol_new (regname, reg_section, regnum, &zero_address_frag));
-
-verify_symbol_chain_2 (s);
+  symbol_table_insert (symbol_new (regname, reg_section, regnum,
+                                  &zero_address_frag));
 
   for (i = 0; regname[i]; i++)
     buf[i] = islower (regname[i]) ? toupper (regname[i]) : regname[i];
   buf[i] = '\0';
 
-  symbol_table_insert (s = symbol_new (buf, reg_section, regnum, &zero_address_frag));
-verify_symbol_chain_2 (s);
+  symbol_table_insert (symbol_new (buf, reg_section, regnum,
+                                  &zero_address_frag));
 }
 
 struct init_entry
   {
-    char *name;
+    const char *name;
     int number;
   };
 
-static CONST struct init_entry init_table[] =
+static const struct init_entry init_table[] =
 {
-  "d0", DATA0,
-  "d1", DATA1,
-  "d2", DATA2,
-  "d3", DATA3,
-  "d4", DATA4,
-  "d5", DATA5,
-  "d6", DATA6,
-  "d7", DATA7,
-  "a0", ADDR0,
-  "a1", ADDR1,
-  "a2", ADDR2,
-  "a3", ADDR3,
-  "a4", ADDR4,
-  "a5", ADDR5,
-  "a6", ADDR6,
-  "fp", ADDR6,
-  "a7", ADDR7,
-  "sp", ADDR7,
-  "fp0", FP0,
-  "fp1", FP1,
-  "fp2", FP2,
-  "fp3", FP3,
-  "fp4", FP4,
-  "fp5", FP5,
-  "fp6", FP6,
-  "fp7", FP7,
-  "fpi", FPI,
-  "fpiar", FPI,
-  "fpc", FPI,
-  "fps", FPS,
-  "fpsr", FPS,
-  "fpc", FPC,
-  "fpcr", FPC,
-
-  "cop0", COP0,
-  "cop1", COP1,
-  "cop2", COP2,
-  "cop3", COP3,
-  "cop4", COP4,
-  "cop5", COP5,
-  "cop6", COP6,
-  "cop7", COP7,
-  "pc", PC,
-  "zpc", ZPC,
-  "sr", SR,
-
-  "ccr", CCR,
-  "cc", CCR,
-
-  "usp", USP,
-  "isp", ISP,
-  "sfc", SFC,
-  "dfc", 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,
-
-  "ac", AC,
-  "bc", BC,
-  "cal", CAL,
-  "crp", CRP,
-  "drp", DRP,
-  "pcsr", PCSR,
-  "psr", PSR,
-  "scc", SCC,
-  "val", VAL,
-  "bad0", BAD0,
-  "bad1", BAD1,
-  "bad2", BAD2,
-  "bad3", BAD3,
-  "bad4", BAD4,
-  "bad5", BAD5,
-  "bad6", BAD6,
-  "bad7", BAD7,
-  "bac0", BAC0,
-  "bac1", BAC1,
-  "bac2", BAC2,
-  "bac3", BAC3,
-  "bac4", BAC4,
-  "bac5", BAC5,
-  "bac6", BAC6,
-  "bac7", BAC7,
-
-  "ic", IC,
-  "dc", DC,
-  "nc", NC,
-
-  "tt0", TT0,
-  "tt1", TT1,
+  { "d0", DATA0 },
+  { "d1", DATA1 },
+  { "d2", DATA2 },
+  { "d3", DATA3 },
+  { "d4", DATA4 },
+  { "d5", DATA5 },
+  { "d6", DATA6 },
+  { "d7", DATA7 },
+  { "a0", ADDR0 },
+  { "a1", ADDR1 },
+  { "a2", ADDR2 },
+  { "a3", ADDR3 },
+  { "a4", ADDR4 },
+  { "a5", ADDR5 },
+  { "a6", ADDR6 },
+  { "fp", ADDR6 },
+  { "a7", ADDR7 },
+  { "sp", ADDR7 },
+  { "ssp", ADDR7 },
+  { "fp0", FP0 },
+  { "fp1", FP1 },
+  { "fp2", FP2 },
+  { "fp3", FP3 },
+  { "fp4", FP4 },
+  { "fp5", FP5 },
+  { "fp6", FP6 },
+  { "fp7", FP7 },
+  { "fpi", FPI },
+  { "fpiar", FPI },
+  { "fpc", FPI },
+  { "fps", FPS },
+  { "fpsr", FPS },
+  { "fpc", FPC },
+  { "fpcr", FPC },
+  { "control", FPC },
+  { "status", FPS },
+  { "iaddr", FPI },
+
+  { "cop0", COP0 },
+  { "cop1", COP1 },
+  { "cop2", COP2 },
+  { "cop3", COP3 },
+  { "cop4", COP4 },
+  { "cop5", COP5 },
+  { "cop6", COP6 },
+  { "cop7", COP7 },
+  { "pc", PC },
+  { "zpc", ZPC },
+  { "sr", SR },
+
+  { "ccr", CCR },
+  { "cc", CCR },
+
+  /* control registers */
+  { "sfc", SFC },              /* Source Function Code */
+  { "sfcr", SFC },
+  { "dfc", DFC },              /* Destination Function Code */
+  { "dfcr", DFC },
+  { "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 },
+  { "crp", CRP },
+  { "drp", DRP },
+  { "pcsr", PCSR },
+  { "psr", PSR },
+  { "scc", SCC },
+  { "val", VAL },
+  { "bad0", BAD0 },
+  { "bad1", BAD1 },
+  { "bad2", BAD2 },
+  { "bad3", BAD3 },
+  { "bad4", BAD4 },
+  { "bad5", BAD5 },
+  { "bad6", BAD6 },
+  { "bad7", BAD7 },
+  { "bac0", BAC0 },
+  { "bac1", BAC1 },
+  { "bac2", BAC2 },
+  { "bac3", BAC3 },
+  { "bac4", BAC4 },
+  { "bac5", BAC5 },
+  { "bac6", BAC6 },
+  { "bac7", BAC7 },
+
+  { "ic", IC },
+  { "dc", DC },
+  { "nc", NC },
+
+  { "tt0", TT0 },
+  { "tt1", TT1 },
   /* 68ec030 versions of same */
-  "ac0", TT0,
-  "ac1", TT1,
+  { "ac0", TT0 },
+  { "ac1", TT1 },
   /* 68ec030 access control unit, identical to 030 MMU status reg */
-  "acusr", PSR,
-
-  0,
-
+  { "acusr", PSR },
+
+  /* Suppressed data and address registers.  */
+  { "zd0", ZDATA0 },
+  { "zd1", ZDATA1 },
+  { "zd2", ZDATA2 },
+  { "zd3", ZDATA3 },
+  { "zd4", ZDATA4 },
+  { "zd5", ZDATA5 },
+  { "zd6", ZDATA6 },
+  { "zd7", ZDATA7 },
+  { "za0", ZADDR0 },
+  { "za1", ZADDR1 },
+  { "za2", ZADDR2 },
+  { "za3", ZADDR3 },
+  { "za4", ZADDR4 },
+  { "za5", ZADDR5 },
+  { "za6", ZADDR6 },
+  { "za7", ZADDR7 },
+
+  { 0, 0 }
 };
 
-
 void
 init_regtable ()
 {
@@ -3520,81 +3261,56 @@ init_regtable ()
 
 static int no_68851, no_68881;
 
+#ifdef OBJ_AOUT
+/* a.out machine type.  Default to 68020.  */
+int m68k_aout_machtype = 2;
+#endif
+
 void
 md_assemble (str)
      char *str;
 {
-  char *er;
+  const char *er;
   short *fromP;
   char *toP = NULL;
   int m, n = 0;
   char *to_beg_P;
   int shorts_this_frag;
-  static int done_first_time;
+  fixS *fixP;
 
-  if (!done_first_time)
+  /* 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)
     {
-      done_first_time = 1;
+      char *s;
+      int fields = 0;
+      int infield = 0;
+      int inquote = 0;
 
-      if (cpu_of_arch (current_architecture) == 0)
+      for (s = str; *s != '\0'; s++)
        {
-         int cpu_type;
-
-         if (strcmp (TARGET_CPU, "m68000") == 0
-             || strcmp (TARGET_CPU, "m68302") == 0)
-           cpu_type = m68000;
-         else if (strcmp (TARGET_CPU, "m68010") == 0)
-           cpu_type = m68010;
-         else if (strcmp (TARGET_CPU, "m68020") == 0
-                  || strcmp (TARGET_CPU, "m68k") == 0)
-           cpu_type = m68020;
-         else if (strcmp (TARGET_CPU, "m68030") == 0)
-           cpu_type = m68030;
-         else if (strcmp (TARGET_CPU, "m68040") == 0)
-           cpu_type = m68040;
-         else if (strcmp (TARGET_CPU, "cpu32") == 0
-                  || strcmp (TARGET_CPU, "m68331") == 0
-                  || strcmp (TARGET_CPU, "m68332") == 0
-                  || strcmp (TARGET_CPU, "m68333") == 0
-                  || strcmp (TARGET_CPU, "m68340") == 0)
-           cpu_type = cpu32;
+         if ((*s == ' ' || *s == '\t') && ! inquote)
+           {
+             if (infield)
+               {
+                 ++fields;
+                 if (fields >= 2)
+                   {
+                     *s = '\0';
+                     break;
+                   }
+                 infield = 0;
+               }
+           }
          else
-           cpu_type = m68020;
-
-         current_architecture |= cpu_type;
-       }
-#if 0                          /* Could be doing emulation.  */
-      if (current_architecture & m68881)
-       {
-         if (current_architecture & m68000)
-           as_bad ("incompatible processors 68000 and 68881/2 specified");
-         if (current_architecture & m68010)
-           as_bad ("incompatible processors 68010 and 68881/2 specified");
-         if (current_architecture & m68040)
-           as_bad ("incompatible processors 68040 and 68881/2 specified");
-       }
-#endif
-      /* What other incompatibilities could we check for?  */
-
-      /* Toss in some default assumptions about coprocessors.  */
-      if (!no_68881
-         && (cpu_of_arch (current_architecture)
-      /* Can CPU32 have a 68881 coprocessor??  */
-             & (m68020 | m68030 | cpu32)))
-       {
-         current_architecture |= m68881;
-       }
-      if (!no_68851
-         && (cpu_of_arch (current_architecture) & m68020up) != 0
-         && cpu_of_arch (current_architecture) != m68040)
-       {
-         current_architecture |= m68851;
+           {
+             if (! infield)
+               infield = 1;
+             if (*s == '\'')
+               inquote = ! inquote;
+           }
        }
-      if (no_68881 && (current_architecture & m68881))
-       as_bad ("options for 68881 and no-68881 both given");
-      if (no_68851 && (current_architecture & m68851))
-       as_bad ("options for 68851 and no-68851 both given");
-      done_first_time = 1;
     }
 
   memset ((char *) (&the_ins), '\0', sizeof (the_ins));
@@ -3602,7 +3318,7 @@ md_assemble (str)
   er = the_ins.error;
   if (!er)
     {
-      for (n = the_ins.numargs; n; --n)
+      for (n = 0; n < the_ins.numargs; n++)
        if (the_ins.operands[n].error)
          {
            er = the_ins.operands[n].error;
@@ -3615,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 */
@@ -3638,7 +3361,7 @@ md_assemble (str)
              n = 1;
              break;
            case '3':
-             n = 2;
+             n = 1;
              break;
            case 'w':
              n = 2;
@@ -3651,14 +3374,17 @@ md_assemble (str)
                        the_ins.reloc[m].wid);
            }
 
-         fix_new (frag_now,
-                  (toP - frag_now->fr_literal) - the_ins.numo * 2 + the_ins.reloc[m].n,
-                  n,
-                  the_ins.reloc[m].add,
-                  the_ins.reloc[m].sub,
-                  the_ins.reloc[m].off,
-                  the_ins.reloc[m].pcrel,
-                  NO_RELOC);
+         fixP = fix_new_exp (frag_now,
+                             ((toP - frag_now->fr_literal)
+                              - the_ins.numo * 2 + the_ins.reloc[m].n),
+                             n,
+                             &the_ins.reloc[m].exp,
+                             the_ins.reloc[m].pcrel,
+                             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;
     }
@@ -3695,14 +3421,15 @@ md_assemble (str)
          the_ins.reloc[m].wid = 0;
          wid = (wid == 'b') ? 1 : (wid == 'w') ? 2 : (wid == 'l') ? 4 : 4000;
 
-         fix_new (frag_now,
-                  (toP - frag_now->fr_literal) - the_ins.numo * 2 + the_ins.reloc[m].n,
-                  wid,
-                  the_ins.reloc[m].add,
-                  the_ins.reloc[m].sub,
-                  the_ins.reloc[m].off,
-                  the_ins.reloc[m].pcrel,
-                  NO_RELOC);
+         fixP = fix_new_exp (frag_now,
+                             ((toP - frag_now->fr_literal)
+                              - the_ins.numo * 2 + the_ins.reloc[m].n),
+                             wid,
+                             &the_ins.reloc[m].exp,
+                             the_ins.reloc[m].pcrel,
+                             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,
                       (relax_substateT) (the_ins.fragb[n].fragty),
@@ -3731,30 +3458,18 @@ md_assemble (str)
       the_ins.reloc[m].wid = 0;
       wid = (wid == 'b') ? 1 : (wid == 'w') ? 2 : (wid == 'l') ? 4 : 4000;
 
-      fix_new (frag_now,
-              (the_ins.reloc[m].n + toP - frag_now->fr_literal) - shorts_this_frag * 2,
-              wid,
-              the_ins.reloc[m].add,
-              the_ins.reloc[m].sub,
-              the_ins.reloc[m].off,
-              the_ins.reloc[m].pcrel,
-              NO_RELOC);
+      fixP = fix_new_exp (frag_now,
+                         ((the_ins.reloc[m].n + toP - frag_now->fr_literal)
+                          - shorts_this_frag * 2),
+                         wid,
+                         &the_ins.reloc[m].exp,
+                         the_ins.reloc[m].pcrel,
+                         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;
     }
 }
 
-/* See BREAK_UP_BIG_DECL definition, above.  */
-static struct m68k_opcode *
-opcode_ptr (i)
-     int i;
-{
-#ifdef DO_BREAK_UP_BIG_DECL
-  int lim1 = sizeof (m68k_opcodes) / sizeof (m68k_opcodes[0]);
-  if (i >= lim1)
-    return m68k_opcodes_2 + (i - lim1);
-#endif
-  return m68k_opcodes + i;
-}
-
 void
 md_begin ()
 {
@@ -3769,22 +3484,29 @@ md_begin ()
      my lord ghod hath spoken, so we do it this way.  Excuse the ugly var
      names.  */
 
-  register CONST struct m68k_opcode *ins;
+  register const struct m68k_opcode *ins;
   register struct m68k_incant *hack, *slak;
-  register char *retval = 0;   /* empty string, or error msg text */
+  register const char *retval = 0;     /* empty string, or error msg text */
   register unsigned int i;
   register char c;
 
-  if ((op_hash = hash_new ()) == NULL)
-    as_fatal ("Virtual memory exhausted");
+  if (flag_mri)
+    {
+      flag_reg_prefix_optional = 1;
+      m68k_abspcadd = 1;
+      if (! m68k_rel32_from_cmdline)
+       m68k_rel32 = 0;
+    }
+
+  op_hash = hash_new ();
 
   obstack_begin (&robyn, 4000);
-  for (i = 0; i < numopcodes; i++)
+  for (i = 0; i < m68k_numopcodes; i++)
     {
       hack = slak = (struct m68k_incant *) obstack_alloc (&robyn, sizeof (struct m68k_incant));
       do
        {
-         ins = opcode_ptr (i);
+         ins = &m68k_opcodes[i];
          /* We *could* ignore insns that don't match our arch here
             but just leaving them out of the hash. */
          slak->m_operands = ins->args;
@@ -3793,8 +3515,8 @@ md_begin ()
          slak->m_opcode = ins->opcode;
          /* This is kludgey */
          slak->m_codenum = ((ins->match) & 0xffffL) ? 2 : 1;
-         if (i + 1 != numopcodes
-             && !strcmp (ins->name, opcode_ptr (i + 1)->name))
+         if (i + 1 != m68k_numopcodes
+             && !strcmp (ins->name, m68k_opcodes[i + 1].name))
            {
              slak->m_next = (struct m68k_incant *) obstack_alloc (&robyn, sizeof (struct m68k_incant));
              i++;
@@ -3806,9 +3528,57 @@ md_begin ()
       while (slak);
 
       retval = hash_insert (op_hash, ins->name, (char *) hack);
-      /* Didn't his mommy tell him about null pointers? */
-      if (retval && *retval)
-       as_bad ("Internal Error:  Can't hash %s: %s", ins->name, retval);
+      if (retval)
+       as_fatal ("Internal Error:  Can't hash %s: %s", ins->name, retval);
+    }
+
+  for (i = 0; i < m68k_numaliases; i++)
+    {
+      const char *name = m68k_opcode_aliases[i].primary;
+      const char *alias = m68k_opcode_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_insert (op_hash, alias, val);
+      if (retval)
+       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++)
@@ -3827,18 +3597,40 @@ md_begin ()
   alt_notend_table['d'] = 1;
   alt_notend_table['D'] = 1;
   alt_notend_table['#'] = 1;
+  alt_notend_table['&'] = 1;
   alt_notend_table['f'] = 1;
   alt_notend_table['F'] = 1;
 #ifdef REGISTER_PREFIX
   alt_notend_table[REGISTER_PREFIX] = 1;
 #endif
-#ifdef OPTIONAL_REGISTER_PREFIX
-  alt_notend_table[OPTIONAL_REGISTER_PREFIX] = 1;
-#endif
+
+  /* We need to put '(' in alt_notend_table to handle
+       cas2 %d0:%d2,%d3:%d4,(%a0):(%a1)
+     */
+  alt_notend_table['('] = 1;
+
+  /* We need to put '@' in alt_notend_table to handle
+       cas2 %d0:%d2,%d3:%d4,@(%d0):@(%d1)
+     */
+  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 */
+     gas expects pseudo ops to start with a dot */
   {
     int n = 0;
     while (mote_pseudo_table[n].poc_name)
@@ -3855,146 +3647,320 @@ md_begin ()
 #endif
 
   init_regtable ();
-}
 
-#if 0
-#define notend(s) ((*s == ',' || *s == '}' || *s == '{' \
-                   || (*s == ':' && strchr("aAdD#", s[1]))) \
-                  ? 0 : 1)
+#ifdef OBJ_ELF
+  record_alignment (text_section, 2);
+  record_alignment (data_section, 2);
+  record_alignment (bss_section, 2);
 #endif
-
-/* This funciton is called once, before the assembler exits.  It is
-   supposed to do any final cleanup for this part of the assembler.
-   */
-void
-md_end ()
-{
 }
 
-/* Equal to MAX_PRECISION in atof-ieee.c */
-#define MAX_LITTLENUMS 6
-
-/* Turn a string in input_line_pointer into a floating point constant of type
-   type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
-   emitted is stored in *sizeP .  An error message is returned, or NULL on OK.
-   */
-char *
-md_atof (type, litP, sizeP)
-     char type;
-     char *litP;
-     int *sizeP;
+static void
+select_control_regs ()
 {
-  int prec;
-  LITTLENUM_TYPE words[MAX_LITTLENUMS];
-  LITTLENUM_TYPE *wordP;
-  char *t;
-  char *atof_ieee ();
-
-  switch (type)
+  /* Note which set of "movec" control registers is available.  */
+  switch (cpu_of_arch (current_architecture))
     {
-    case 'f':
-    case 'F':
-    case 's':
-    case 'S':
-      prec = 2;
+    case m68000:
+      control_regs = m68000_control_regs;
       break;
-
-    case 'd':
-    case 'D':
-    case 'r':
-    case 'R':
-      prec = 4;
+    case m68010:
+      control_regs = m68010_control_regs;
       break;
-
-    case 'x':
-    case 'X':
-      prec = 6;
+    case m68020:
+    case m68030:
+      control_regs = m68020_control_regs;
       break;
-
-    case 'p':
-    case 'P':
-      prec = 6;
+    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:
-      *sizeP = 0;
-      return "Bad call to MD_ATOF()";
-    }
-  t = atof_ieee (input_line_pointer, type, words);
-  if (t)
-    input_line_pointer = t;
-
-  *sizeP = prec * sizeof (LITTLENUM_TYPE);
-  for (wordP = words; prec--;)
-    {
-      md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE));
-      litP += sizeof (LITTLENUM_TYPE);
+      abort ();
     }
-  return 0;
 }
 
-/* Turn an integer of n bytes (in val) into a stream of bytes appropriate
-   for use in the a.out file, and stores them in the array pointed to by buf.
-   This knows about the endian-ness of the target machine and does
-   THE RIGHT THING, whatever it is.  Possible values for n are 1 (byte)
-   2 (short) and 4 (long)  Floating numbers are put out as a series of
-   LITTLENUMS (shorts, here at least)
-   */
 void
-md_number_to_chars (buf, val, n)
-     char *buf;
-     valueT val;
-     int n;
+m68k_init_after_args ()
 {
-  switch (n)
+  if (cpu_of_arch (current_architecture) == 0)
     {
-    case 1:
-      *buf++ = val;
-      break;
-    case 2:
-      *buf++ = (val >> 8);
-      *buf++ = val;
-      break;
-    case 4:
-      *buf++ = (val >> 24);
-      *buf++ = (val >> 16);
-      *buf++ = (val >> 8);
-      *buf++ = val;
-      break;
-    default:
-      as_fatal ("failed sanity check.");
+      int i;
+      const char *default_cpu = TARGET_CPU;
+
+      if (*default_cpu == 'm')
+       default_cpu++;
+      for (i = 0; i < n_archs; i++)
+       if (strcasecmp (default_cpu, archs[i].name) == 0)
+         break;
+      if (i == n_archs)
+       {
+         as_bad ("unrecognized default cpu `%s' ???", TARGET_CPU);
+         current_architecture |= m68020;
+       }
+      else
+       current_architecture |= archs[i].arch;
+    }
+  /* Permit m68881 specification with all cpus; those that can't work
+     with a coprocessor could be doing emulation.  */
+  if (current_architecture & m68851)
+    {
+      if (current_architecture & m68040)
+       {
+         as_warn ("68040 and 68851 specified; mmu instructions may assemble incorrectly");
+       }
+    }
+  /* What other incompatibilities could we check for?  */
+
+  /* Toss in some default assumptions about coprocessors.  */
+  if (!no_68881
+      && (cpu_of_arch (current_architecture)
+         /* Can CPU32 have a 68881 coprocessor??  */
+         & (m68020 | m68030 | cpu32)))
+    {
+      current_architecture |= m68881;
+    }
+  if (!no_68851
+      && (cpu_of_arch (current_architecture) & m68020up) != 0
+      && (cpu_of_arch (current_architecture) & m68040up) == 0)
+    {
+      current_architecture |= m68851;
+    }
+  if (no_68881 && (current_architecture & m68881))
+    as_bad ("options for 68881 and no-68881 both given");
+  if (no_68851 && (current_architecture & m68851))
+    as_bad ("options for 68851 and no-68851 both given");
+
+#ifdef OBJ_AOUT
+  /* Work out the magic number.  This isn't very general.  */
+  if (current_architecture & m68000)
+    m68k_aout_machtype = 0;
+  else if (current_architecture & m68010)
+    m68k_aout_machtype = 1;
+  else if (current_architecture & m68020)
+    m68k_aout_machtype = 2;
+  else
+    m68k_aout_machtype = 2;
+#endif
+
+  /* Note which set of "movec" control registers is available.  */
+  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
+
+/* Turn a string in input_line_pointer into a floating point constant
+   of type type, and store the appropriate bytes in *litP.  The number
+   of LITTLENUMS emitted is stored in *sizeP .  An error message is
+   returned, or NULL on OK.  */
+
+char *
+md_atof (type, litP, sizeP)
+     char type;
+     char *litP;
+     int *sizeP;
+{
+  int prec;
+  LITTLENUM_TYPE words[MAX_LITTLENUMS];
+  LITTLENUM_TYPE *wordP;
+  char *t;
+  char *atof_ieee ();
+
+  switch (type)
+    {
+    case 'f':
+    case 'F':
+    case 's':
+    case 'S':
+      prec = 2;
+      break;
+
+    case 'd':
+    case 'D':
+    case 'r':
+    case 'R':
+      prec = 4;
+      break;
+
+    case 'x':
+    case 'X':
+      prec = 6;
+      break;
+
+    case 'p':
+    case 'P':
+      prec = 6;
+      break;
+
+    default:
+      *sizeP = 0;
+      return "Bad call to MD_ATOF()";
+    }
+  t = atof_ieee (input_line_pointer, type, words);
+  if (t)
+    input_line_pointer = t;
+
+  *sizeP = prec * sizeof (LITTLENUM_TYPE);
+  for (wordP = words; prec--;)
+    {
+      md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE));
+      litP += sizeof (LITTLENUM_TYPE);
     }
+  return 0;
+}
+
+void
+md_number_to_chars (buf, val, n)
+     char *buf;
+     valueT val;
+     int n;
+{
+  number_to_chars_bigendian (buf, val, n);
 }
 
 static void
 md_apply_fix_2 (fixP, val)
      fixS *fixP;
-     long val;
+     offsetT val;
 {
-  unsigned long upper_limit;
-  long lower_limit;
+  addressT upper_limit;
+  offsetT lower_limit;
 
-#ifdef IBM_COMPILER_SUX
-  /* This is unnecessary but it convinces the native rs6000
-     compiler to generate the code we want. */
+  /* This is unnecessary but it convinces the native rs6000 compiler
+     to generate the code we want.  */
   char *buf = fixP->fx_frag->fr_literal;
   buf += fixP->fx_where;
-#else /* IBM_COMPILER_SUX */
-  char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
-#endif /* IBM_COMPILER_SUX */
+  /* end ibm compiler workaround */
+
+  if (val & 0x80000000)
+    val |= ~(addressT)0x7fffffff;
+  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
+        machines where ints are smaller than offsetT */
     case 1:
       *buf++ = val;
       upper_limit = 0x7f;
-      lower_limit = -0x80;
+      lower_limit = - (offsetT) 0x80;
       break;
     case 2:
       *buf++ = (val >> 8);
       *buf++ = val;
       upper_limit = 0x7fff;
-      lower_limit = -0x8000;
+      lower_limit = - (offsetT) 0x8000;
       break;
     case 4:
       *buf++ = (val >> 24);
@@ -4002,30 +3968,49 @@ md_apply_fix_2 (fixP, val)
       *buf++ = (val >> 8);
       *buf++ = val;
       upper_limit = 0x7fffffff;
-      lower_limit = -0x80000000;
+      lower_limit = - (offsetT) 0x7fffffff - 1;        /* avoid constant overflow */
       break;
     default:
       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 ((unsigned) val > upper_limit && (val > 0 || val < lower_limit))
-    as_bad ("value out of range");
+  if ((addressT) val > upper_limit
+      && (val > 0 || val < lower_limit))
+    as_bad_where (fixP->fx_file, fixP->fx_line, "value out of range");
+
+  /* A one byte PC-relative reloc means a short branch.  We can't use
+     a short branch with a value of 0 or -1, because those indicate
+     different opcodes (branches with longer offsets).  */
+  if (fixP->fx_pcrel
+      && fixP->fx_size == 1
+      && (fixP->fx_addsy == NULL
+         || S_IS_DEFINED (fixP->fx_addsy))
+      && (val == 0 || val == -1))
+    as_bad_where (fixP->fx_file, fixP->fx_line, "invalid byte branch offset");
 }
 
 #ifdef BFD_ASSEMBLER
 int
 md_apply_fix (fixP, valp)
      fixS *fixP;
-     long *valp;
+     valueT *valp;
 {
-  md_apply_fix_2 (fixP, *valp);
+  md_apply_fix_2 (fixP, (addressT) *valp);
   return 1;
 }
 #else
@@ -4033,7 +4018,7 @@ void md_apply_fix (fixP, val)
      fixS *fixP;
      long val;
 {
-  md_apply_fix_2 (fixP, val);
+  md_apply_fix_2 (fixP, (addressT) val);
 }
 #endif
 
@@ -4047,26 +4032,26 @@ md_convert_frag_1 (fragP)
 {
   long disp;
   long ext = 0;
+  fixS *fixP;
 
   /* Address in object code of the displacement.  */
   register int object_address = fragP->fr_fix + fragP->fr_address;
 
-#ifdef IBM_COMPILER_SUX
-  /* This is wrong but it convinces the native rs6000 compiler to
-     generate the code we want. */
+  /* Address in gas core of the place to store the displacement.  */
+  /* This convinces the native rs6000 compiler to generate the code we
+     want. */
   register char *buffer_address = fragP->fr_literal;
   buffer_address += fragP->fr_fix;
-#else /* IBM_COMPILER_SUX */
-  /* Address in gas core of the place to store the displacement.  */
-  register char *buffer_address = fragP->fr_fix + fragP->fr_literal;
-#endif /* IBM_COMPILER_SUX */
-
-  /* No longer true:   know(fragP->fr_symbol); */
+  /* end ibm compiler workaround */
 
   /* The displacement of the address, from current location.  */
   disp = fragP->fr_symbol ? S_GET_VALUE (fragP->fr_symbol) : 0;
   disp = (disp + fragP->fr_offset) - object_address;
 
+#ifdef BFD_ASSEMBLER
+  disp += fragP->fr_symbol->sy_frag->fr_address;
+#endif
+
   switch (fragP->fr_subtype)
     {
     case TAB (BCC68000, BYTE):
@@ -4091,16 +4076,15 @@ md_convert_frag_1 (fragP)
       if (cpu_of_arch (current_architecture) < m68020)
        {
          if (fragP->fr_opcode[0] == 0x61)
+           /* BSR */
            {
              fragP->fr_opcode[0] = 0x4E;
-             fragP->fr_opcode[1] = 0xB9;       /* JBSR with ABSL LONG offset */
-             subseg_change (text_section, 0); /* @@ */
+             fragP->fr_opcode[1] = (char) 0xB9; /* JBSR with ABSL LONG offset */
 
              fix_new (fragP,
                       fragP->fr_fix,
                       4,
                       fragP->fr_symbol,
-                      0,
                       fragP->fr_offset,
                       0,
                       NO_RELOC);
@@ -4108,13 +4092,13 @@ md_convert_frag_1 (fragP)
              fragP->fr_fix += 4;
              ext = 0;
            }
+         /* BRA */
          else if (fragP->fr_opcode[0] == 0x60)
            {
              fragP->fr_opcode[0] = 0x4E;
-             fragP->fr_opcode[1] = 0xF9;       /* JMP  with ABSL LONG offset */
-             subseg_change (text_section, 0); /* @@ */
-             fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset, 0,
-                      NO_RELOC);
+             fragP->fr_opcode[1] = (char) 0xF9; /* JMP  with ABSL LONG offset */
+             fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
+                      fragP->fr_offset, 0, NO_RELOC);
              fragP->fr_fix += 4;
              ext = 0;
            }
@@ -4125,7 +4109,7 @@ md_convert_frag_1 (fragP)
        }
       else
        {
-         fragP->fr_opcode[1] = 0xff;
+         fragP->fr_opcode[1] = (char) 0xff;
          ext = 4;
        }
       break;
@@ -4139,12 +4123,10 @@ md_convert_frag_1 (fragP)
           different frag, in which case refering to them is a no-no.
           Only fr_opcode[0,1] are guaranteed to work. */
       *buffer_address++ = 0x4e;        /* put in jmp long (0x4ef9) */
-      *buffer_address++ = 0xf9;
+      *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, 0,
-              fragP->fr_offset, 0,
-              NO_RELOC);
+      fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
+              fragP->fr_offset, 0, NO_RELOC);
       fragP->fr_fix += 4;
       ext = 0;
       break;
@@ -4157,11 +4139,10 @@ md_convert_frag_1 (fragP)
       *buffer_address++ = 0x60;        /* put in bra pc+6 */
       *buffer_address++ = 0x06;
       *buffer_address++ = 0x4e;        /* put in jmp long (0x4ef9) */
-      *buffer_address++ = 0xf9;
+      *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, 0,
+      fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
               fragP->fr_offset, 0, NO_RELOC);
       fragP->fr_fix += 4;
       ext = 0;
@@ -4181,34 +4162,71 @@ 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, 0, fragP->fr_offset,
+      fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
               0, NO_RELOC);
       if ((fragP->fr_opcode[1] & 0x3F) != 0x3A)
-       as_bad ("Internal error (long PC-relative operand) for insn 0x%04lx at 0x%lx",
-               fragP->fr_opcode[0], fragP->fr_address);
+       as_bad ("Internal error (long PC-relative operand) for insn 0x%04x at 0x%lx",
+               (unsigned) fragP->fr_opcode[0],
+               (unsigned long) fragP->fr_address);
       fragP->fr_opcode[1] &= ~0x3F;
       fragP->fr_opcode[1] |= 0x39;     /* Mode 7.1 */
       fragP->fr_fix += 4;
       ext = 0;
       break;
     case TAB (PCLEA, SHORT):
-      subseg_change (text_section, 0);
       fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol,
-              (symbolS *) 0, fragP->fr_offset, 1, NO_RELOC);
+              fragP->fr_offset, 1, NO_RELOC);
       fragP->fr_opcode[1] &= ~0x3F;
-      fragP->fr_opcode[1] |= 0x3A;
+      fragP->fr_opcode[1] |= 0x3A; /* 072 - mode 7.2 */
       ext = 2;
       break;
     case TAB (PCLEA, LONG):
-      subseg_change (text_section, 0);
-      fix_new (fragP, (int) (fragP->fr_fix) + 2, 4, fragP->fr_symbol,
-              (symbolS *) 0, fragP->fr_offset + 2, 1, NO_RELOC);
+      fixP = fix_new (fragP, (int) (fragP->fr_fix) + 2, 4, fragP->fr_symbol,
+                     fragP->fr_offset, 1, NO_RELOC);
+      fixP->fx_pcrel_adjust = 2;
+      /* Already set to mode 7.3; this indicates: PC indirect with
+        suppressed index, 32-bit displacement.  */
       *buffer_address++ = 0x01;
       *buffer_address++ = 0x70;
       fragP->fr_fix += 2;
       ext = 4;
       break;
+
+    case TAB (PCINDEX, BYTE):
+      disp += 2;
+      if (!issbyte (disp))
+       {
+         as_bad ("displacement doesn't fit in one byte");
+         disp = 0;
+       }
+      assert (fragP->fr_fix >= 2);
+      buffer_address[-2] &= ~1;
+      buffer_address[-1] = disp;
+      ext = 0;
+      break;
+    case TAB (PCINDEX, SHORT):
+      disp += 2;
+      assert (issword (disp));
+      assert (fragP->fr_fix >= 2);
+      buffer_address[-2] |= 0x1;
+      buffer_address[-1] = 0x20;
+      fixP = fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol,
+                     fragP->fr_offset, (fragP->fr_opcode[1] & 077) == 073,
+                     NO_RELOC);
+      fixP->fx_pcrel_adjust = 2;
+      ext = 2;
+      break;
+    case TAB (PCINDEX, LONG):
+      disp += 2;
+      fixP = fix_new (fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol,
+                     fragP->fr_offset, (fragP->fr_opcode[1] & 077) == 073,
+                     NO_RELOC);
+      fixP->fx_pcrel_adjust = 2;
+      assert (fragP->fr_fix >= 2);
+      buffer_address[-2] |= 0x1;
+      buffer_address[-1] = 0x30;
+      ext = 4;
+      break;
     }
 
   if (ext)
@@ -4221,8 +4239,9 @@ md_convert_frag_1 (fragP)
 #ifndef BFD_ASSEMBLER
 
 void
-md_convert_frag (headers, fragP)
+md_convert_frag (headers, sec, fragP)
      object_headers *headers;
+     segT sec;
      fragS *fragP;
 {
   md_convert_frag_1 (fragP);
@@ -4233,7 +4252,7 @@ md_convert_frag (headers, fragP)
 void
 md_convert_frag (abfd, sec, fragP)
      bfd *abfd;
-     asection sec;
+     segT sec;
      fragS *fragP;
 {
   md_convert_frag_1 (fragP);
@@ -4272,20 +4291,18 @@ md_estimate_size_before_relax (fragP, segment)
            if (fragP->fr_opcode[0] == 0x61)
              {
                fragP->fr_opcode[0] = 0x4E;
-               fragP->fr_opcode[1] = 0xB9;     /* JBSR with ABSL LONG offset */
-               subseg_change (text_section, 0);
+               fragP->fr_opcode[1] = (char) 0xB9; /* JBSR with ABSL LONG offset */
                fix_new (fragP, fragP->fr_fix, 4,
-                        fragP->fr_symbol, 0, fragP->fr_offset, 0, NO_RELOC);
+                        fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC);
                fragP->fr_fix += 4;
                frag_wane (fragP);
              }
            else if (fragP->fr_opcode[0] == 0x60)
              {
                fragP->fr_opcode[0] = 0x4E;
-               fragP->fr_opcode[1] = 0xF9;     /* JMP  with ABSL LONG offset */
-               subseg_change (text_section, 0);
+               fragP->fr_opcode[1] = (char) 0xF9; /* JMP  with ABSL LONG offset */
                fix_new (fragP, fragP->fr_fix, 4,
-                        fragP->fr_symbol, 0, fragP->fr_offset, 0, NO_RELOC);
+                        fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC);
                fragP->fr_fix += 4;
                frag_wane (fragP);
              }
@@ -4297,9 +4314,9 @@ md_estimate_size_before_relax (fragP, segment)
        else
          {                     /* Symbol is still undefined.  Make it simple */
            fix_new (fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol,
-                    (symbolS *) 0, fragP->fr_offset + 4, 1, NO_RELOC);
+                    fragP->fr_offset, 1, NO_RELOC);
            fragP->fr_fix += 4;
-           fragP->fr_opcode[1] = 0xff;
+           fragP->fr_opcode[1] = (char) 0xff;
            frag_wane (fragP);
            break;
          }
@@ -4309,22 +4326,27 @@ md_estimate_size_before_relax (fragP, segment)
 
     case TAB (FBRANCH, SZ_UNDEF):
       {
-       if (S_GET_SEGMENT (fragP->fr_symbol) == segment || flagseen['l'])
+       if (S_GET_SEGMENT (fragP->fr_symbol) == segment || flag_short_refs)
          {
            fragP->fr_subtype = TAB (FBRANCH, SHORT);
            fragP->fr_var += 2;
          }
        else
          {
-           fragP->fr_subtype = TAB (FBRANCH, LONG);
-           fragP->fr_var += 4;
+           fix_new (fragP, (int) fragP->fr_fix, 4, fragP->fr_symbol,
+                    fragP->fr_offset, 1, NO_RELOC);
+           fragP->fr_fix += 4;
+           fragP->fr_opcode[1] |= 0x40; /* Turn on LONG bit */
+           frag_wane (fragP);
          }
        break;
       }                                /* TAB(FBRANCH,SZ_UNDEF) */
 
     case TAB (PCREL, SZ_UNDEF):
       {
-       if (S_GET_SEGMENT (fragP->fr_symbol) == segment || flagseen['l'])
+       if (S_GET_SEGMENT (fragP->fr_symbol) == segment
+           || flag_short_refs
+           || cpu_of_arch (current_architecture) < m68020)
          {
            fragP->fr_subtype = TAB (PCREL, SHORT);
            fragP->fr_var += 2;
@@ -4348,15 +4370,14 @@ md_estimate_size_before_relax (fragP, segment)
        /* only Bcc 68000 instructions can come here */
        /* change bcc into b!cc/jmp absl long */
        fragP->fr_opcode[0] ^= 0x01;    /* invert bcc */
-       if (flagseen['l'])
+       if (flag_short_refs)
          {
            fragP->fr_opcode[1] = 0x04; /* branch offset = 6 */
            /* JF: these were fr_opcode[2,3] */
            buffer_address[0] = 0x4e;   /* put in jmp long (0x4ef9) */
-           buffer_address[1] = 0xf8;
+           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, 0,
+           fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
                     fragP->fr_offset, 0, NO_RELOC);
            fragP->fr_fix += 2;
          }
@@ -4365,10 +4386,9 @@ md_estimate_size_before_relax (fragP, segment)
            fragP->fr_opcode[1] = 0x06; /* branch offset = 6 */
            /* JF: these were fr_opcode[2,3] */
            buffer_address[0] = 0x4e;   /* put in jmp long (0x4ef9) */
-           buffer_address[1] = 0xf9;
+           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, 0,
+           fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
                     fragP->fr_offset, 0, NO_RELOC);
            fragP->fr_fix += 4;
          }
@@ -4391,17 +4411,14 @@ md_estimate_size_before_relax (fragP, segment)
        buffer_address[1] = 0x04;
        buffer_address[2] = 0x60;       /* put in bra pc + ... */
 
-       if (flagseen['l'])
+       if (flag_short_refs)
          {
            /* JF: these were fr_opcode[5-7] */
            buffer_address[3] = 0x04;   /* plus 4 */
            buffer_address[4] = 0x4e;   /* Put in Jump Word */
-           buffer_address[5] = 0xf8;
+           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, 0,
-
-
+           fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
                     fragP->fr_offset, 0, NO_RELOC);
            fragP->fr_fix += 2;
          }
@@ -4410,10 +4427,9 @@ md_estimate_size_before_relax (fragP, segment)
            /* JF: these were fr_opcode[5-7] */
            buffer_address[3] = 0x06;   /* Plus 6 */
            buffer_address[4] = 0x4e;   /* put in jmp long (0x4ef9) */
-           buffer_address[5] = 0xf9;
+           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, 0,
+           fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
                     fragP->fr_offset, 0, NO_RELOC);
            fragP->fr_fix += 4;
          }
@@ -4424,7 +4440,9 @@ md_estimate_size_before_relax (fragP, segment)
 
     case TAB (PCLEA, SZ_UNDEF):
       {
-       if ((S_GET_SEGMENT (fragP->fr_symbol)) == segment || flagseen['l'])
+       if ((S_GET_SEGMENT (fragP->fr_symbol)) == segment
+           || flag_short_refs
+           || cpu_of_arch (current_architecture) < m68020)
          {
            fragP->fr_subtype = TAB (PCLEA, SHORT);
            fragP->fr_var += 2;
@@ -4437,23 +4455,49 @@ md_estimate_size_before_relax (fragP, segment)
        break;
       }                                /* TAB(PCLEA,SZ_UNDEF) */
 
-    default:
+    case TAB (PCINDEX, SZ_UNDEF):
+      if (S_GET_SEGMENT (fragP->fr_symbol) == segment
+         || cpu_of_arch (current_architecture) < m68020)
+       {
+         fragP->fr_subtype = TAB (PCINDEX, BYTE);
+       }
+      else
+       {
+         fragP->fr_subtype = TAB (PCINDEX, LONG);
+         fragP->fr_var += 4;
+       }
       break;
 
-    }                          /* switch on subtype looking for SZ_UNDEF's. */
+    default:
+      break;
+    }
 
   /* now that SZ_UNDEF are taken care of, check others */
   switch (fragP->fr_subtype)
     {
     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:
@@ -4503,8 +4547,7 @@ tc_aout_fix_to_chars (where, fixP, segment_address_in_file)
    * Out: GNU LD relocation length code: 0, 1, or 2.
    */
 
-  static CONST unsigned char nbytes_r_length[] =
-  {42, 0, 1, 42, 2};
+  static CONST unsigned char nbytes_r_length[] = {42, 0, 1, 42, 2};
   long r_symbolnum;
 
   know (fixP->fx_addsy != NULL);
@@ -4522,8 +4565,6 @@ tc_aout_fix_to_chars (where, fixP, segment_address_in_file)
   where[6] = r_symbolnum & 0x0ff;
   where[7] = (((fixP->fx_pcrel << 7) & 0x80) | ((nbytes_r_length[fixP->fx_size] << 5) & 0x60) |
              (((!S_IS_DEFINED (fixP->fx_addsy)) << 4) & 0x10));
-
-  return;
 }
 #endif
 
@@ -4562,8 +4603,8 @@ md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
       offset = to_addr - S_GET_VALUE (to_symbol);
       md_number_to_chars (ptr, (valueT) 0x4EF9, 2);
       md_number_to_chars (ptr + 2, (valueT) offset, 4);
-      fix_new (frag, (ptr + 2) - frag->fr_literal, 4, to_symbol, (symbolS *) 0, (long) 0, 0,
-              NO_RELOC);
+      fix_new (frag, (ptr + 2) - frag->fr_literal, 4, to_symbol, (offsetT) 0,
+              0, NO_RELOC);
     }
   else
     {
@@ -4574,7 +4615,9 @@ md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
 }
 
 #endif
-/* Different values of OK tell what its OK to return.  Things that aren't OK are an error (what a shock, no?)
+
+/* Different values of OK tell what its OK to return.  Things that
+   aren't OK are an error (what a shock, no?)
 
    0:  Everything is OK
    10:  Absolute 1:8   only
@@ -4594,252 +4637,1809 @@ get_num (exp, ok)
      struct m68k_exp *exp;
      int ok;
 {
-#ifdef TEST2
-  long l = 0;
-
-  if (!exp->e_beg)
-    return 0;
-  if (*exp->e_beg == '0')
-    {
-      if (exp->e_beg[1] == 'x')
-       sscanf (exp->e_beg + 2, "%x", &l);
-      else
-       sscanf (exp->e_beg + 1, "%O", &l);
-      return l;
-    }
-  return atol (exp->e_beg);
-#else
-  char *save_in;
-  char c_save;
-  segT section;
-
-  if (!exp)
-    {
-      /* Can't do anything */
-      return 0;
-    }
-  if (!exp->e_beg || !exp->e_end)
+  if (exp->exp.X_op == O_absent)
     {
-      seg (exp) = absolute_section;
+      /* Do the same thing the VAX asm does */
+      op (exp) = O_constant;
       adds (exp) = 0;
       subs (exp) = 0;
-      offs (exp) = (ok == 10) ? 1 : 0;
-      as_warn ("Null expression defaults to %ld", offs (exp));
-      return 0;
+      offs (exp) = 0;
+      if (ok == 10)
+       {
+         as_warn ("expression out of range: defaulting to 1");
+         offs (exp) = 1;
+       }
     }
-
-  exp->e_siz = 0;
-  if ( /* ok!=80 && */ (exp->e_end[-1] == ':' || exp->e_end[-1] == '.')
-      && (exp->e_end - exp->e_beg) >= 2)
+  else if (exp->exp.X_op == O_constant)
     {
-      switch (exp->e_end[0])
+      switch (ok)
        {
-       case 's':
-       case 'S':
-       case 'b':
-       case 'B':
-         exp->e_siz = 1;
-         exp->e_end -= 2;
+       case 10:
+         if (offs (exp) < 1 || offs (exp) > 8)
+           {
+             as_warn ("expression out of range: defaulting to 1");
+             offs (exp) = 1;
+           }
          break;
-       case 'w':
-       case 'W':
-         exp->e_siz = 2;
-         exp->e_end -= 2;
+       case 20:
+         if (offs (exp) < 0 || offs (exp) > 7)
+           goto outrange;
          break;
-       case 'l':
-       case 'L':
-         exp->e_siz = 3;
-         exp->e_end -= 2;
+       case 30:
+         if (offs (exp) < 0 || offs (exp) > 15)
+           goto outrange;
+         break;
+       case 40:
+         if (offs (exp) < 0 || offs (exp) > 32)
+           goto outrange;
+         break;
+       case 50:
+         if (offs (exp) < 0 || offs (exp) > 127)
+           goto outrange;
+         break;
+       case 55:
+         if (offs (exp) < -64 || offs (exp) > 63)
+           goto outrange;
+         break;
+       case 60:
+         if (offs (exp) < -128 || offs (exp) > 127)
+           goto outrange;
+         break;
+       case 70:
+         if (offs (exp) < 0 || offs (exp) > 4095)
+           {
+           outrange:
+             as_warn ("expression out of range: defaulting to 0");
+             offs (exp) = 0;
+           }
          break;
        default:
-         if (exp->e_end[-1] == ':')
-           as_bad ("Unknown size for expression \"%c\"", exp->e_end[0]);
          break;
        }
     }
-  c_save = exp->e_end[1];
-  exp->e_end[1] = '\0';
-  save_in = input_line_pointer;
-  input_line_pointer = exp->e_beg;
-  section = expression (&exp->e_exp);
-  if (section == pass1_section)
+  else if (exp->exp.X_op == O_big)
+    {
+      if (offs (exp) <= 0      /* flonum */
+         && (ok == 80          /* no bignums */
+             || (ok > 10       /* small-int ranges including 0 ok */
+                 /* If we have a flonum zero, a zero integer should
+                    do as well (e.g., in moveq).  */
+                 && generic_floating_point_number.exponent == 0
+                 && generic_floating_point_number.low[0] == 0)))
+       {
+         /* HACK! Turn it into a long */
+         LITTLENUM_TYPE words[6];
+
+         gen_to_words (words, 2, 8L);  /* These numbers are magic! */
+         op (exp) = O_constant;
+         adds (exp) = 0;
+         subs (exp) = 0;
+         offs (exp) = words[1] | (words[0] << 16);
+       }
+      else if (ok != 0)
+       {
+         op (exp) = O_constant;
+         adds (exp) = 0;
+         subs (exp) = 0;
+         offs (exp) = (ok == 10) ? 1 : 0;
+         as_warn ("Can't deal with expression; defaulting to %ld",
+                  offs (exp));
+       }
+    }
+  else
+    {
+      if (ok >= 10 && ok <= 70)
+       {
+         op (exp) = O_constant;
+         adds (exp) = 0;
+         subs (exp) = 0;
+         offs (exp) = (ok == 10) ? 1 : 0;
+         as_warn ("Can't deal with expression; defaulting to %ld",
+                  offs (exp));
+       }
+    }
+
+  if (exp->size != SIZE_UNSPEC)
+    {
+      switch (exp->size)
+       {
+       case SIZE_UNSPEC:
+       case SIZE_LONG:
+         break;
+       case SIZE_BYTE:
+         if (!isbyte (offs (exp)))
+           as_warn ("expression doesn't fit in BYTE");
+         break;
+       case SIZE_WORD:
+         if (!isword (offs (exp)))
+           as_warn ("expression doesn't fit in WORD");
+         break;
+       }
+    }
+
+  return offs (exp);
+}
+
+/* These are the back-ends for the various machine dependent pseudo-ops.  */
+void demand_empty_rest_of_line ();     /* Hate those extra verbose names */
+
+static void
+s_data1 (ignore)
+     int ignore;
+{
+  subseg_set (data_section, 1);
+  demand_empty_rest_of_line ();
+}
+
+static void
+s_data2 (ignore)
+     int ignore;
+{
+  subseg_set (data_section, 2);
+  demand_empty_rest_of_line ();
+}
+
+static void
+s_bss (ignore)
+     int ignore;
+{
+  /* We don't support putting frags in the BSS segment, we fake it
+     by marking in_bss, then looking at s_skip for clues.  */
+
+  subseg_set (bss_section, 0);
+  demand_empty_rest_of_line ();
+}
+
+static void
+s_even (ignore)
+     int ignore;
+{
+  register int temp;
+  register long temp_fill;
+
+  temp = 1;                    /* JF should be 2? */
+  temp_fill = get_absolute_expression ();
+  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
+s_proc (ignore)
+     int ignore;
+{
+  demand_empty_rest_of_line ();
+}
+\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
+mri_chip ()
+{
+  char *s;
+  char c;
+  int i;
+
+  s = input_line_pointer;
+  c = get_symbol_end ();
+  for (i = 0; i < n_archs; i++)
+    if (strcasecmp (s, archs[i].name) == 0)
+      break;
+  if (i >= n_archs)
+    {
+      as_bad ("%s: unrecognized processor name", s);
+      *input_line_pointer = c;
+      ignore_rest_of_line ();
+      return;
+    }
+  *input_line_pointer = c;
+
+  if (*input_line_pointer == '/')
+    current_architecture = 0;
+  else
+    current_architecture &= m68881 | m68851;
+  current_architecture |= archs[i].arch;
+
+  while (*input_line_pointer == '/')
+    {
+      ++input_line_pointer;
+      s = input_line_pointer;
+      c = get_symbol_end ();
+      if (strcmp (s, "68881") == 0)
+       current_architecture |= m68881;
+      else if (strcmp (s, "68851") == 0)
+       current_architecture |= m68851;
+      *input_line_pointer = c;
+    }
+
+  /* Update info about available control registers.  */
+  select_control_regs ();
+}
+
+/* The MRI CHIP pseudo-op.  */
+
+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 ();
+}
+
+/* The MRI FOPT pseudo-op.  */
+
+static void
+s_fopt (ignore)
+     int ignore;
+{
+  SKIP_WHITESPACE ();
+
+  if (strncasecmp (input_line_pointer, "ID=", 3) == 0)
+    {
+      int temp;
+
+      input_line_pointer += 3;
+      temp = get_absolute_expression ();
+      if (temp < 0 || temp > 7)
+       as_bad ("bad coprocessor id");
+      else
+       m68k_float_copnum = COP0 + temp;
+    }
+  else
+    {
+      as_bad ("unrecognized fopt option");
+      ignore_rest_of_line ();
+      return;
+    }
+
+  demand_empty_rest_of_line ();
+}
+
+/* The structure used to handle the MRI OPT pseudo-op.  */
+
+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;
+};
+
+/* 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[] =
+{
+  { "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 }
+};
+
+#define OPTCOUNT (sizeof opt_table / sizeof opt_table[0])
+
+/* The MRI OPT pseudo-op.  */
+
+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 == '-')
+       {
+         ++input_line_pointer;
+         t = 0;
+       }
+      else if (strncasecmp (input_line_pointer, "NO", 2) == 0)
+       {
+         input_line_pointer += 2;
+         t = 0;
+       }
+
+      s = input_line_pointer;
+      c = get_symbol_end ();
+
+      for (i = 0, o = opt_table; i < OPTCOUNT; i++, o++)
+       {
+         if (strcasecmp (s, o->name) == 0)
+           {
+             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 >= 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)
     {
-      seg (exp) = absolute_section;
-      adds (exp) = 0;
-      subs (exp) = 0;
-      offs (exp) = (ok == 10) ? 1 : 0;
-      as_warn ("Unknown expression: '%s' defaulting to %d", exp->e_beg, offs (exp));
+      as_bad ("missing do");
+      ignore_rest_of_line ();
+      return;
     }
-  else if (section == absent_section)
+  if (endstop > endstart
+      && (endstop[-1] == ' ' || endstop[-1] == '\t'))
+    --endstop;
+
+  if (! by)
     {
-      /* Do the same thing the VAX asm does */
-      seg (exp) = absolute_section;
-      adds (exp) = 0;
-      subs (exp) = 0;
-      offs (exp) = 0;
-      if (ok == 10)
-       {
-         as_warn ("expression out of range: defaulting to 1");
-         offs (exp) = 1;
-       }
+      bystart = "#1";
+      bystop = bystart + 2;
     }
-  else if (section == absolute_section)
+  else
     {
-      switch (ok)
+      SKIP_WHITESPACE ();
+      bystart = input_line_pointer;
+
+      /* Look for DO.  */
+      bystop = NULL;
+      while (! is_end_of_line[(unsigned char) *input_line_pointer])
        {
-       case 10:
-         if (offs (exp) < 1 || offs (exp) > 8)
-           {
-             as_warn ("expression out of range: defaulting to 1");
-             offs (exp) = 1;
-           }
-         break;
-       case 20:
-         if (offs (exp) < 0 || offs (exp) > 7)
-           goto outrange;
-         break;
-       case 30:
-         if (offs (exp) < 0 || offs (exp) > 15)
-           goto outrange;
-         break;
-       case 40:
-         if (offs (exp) < 0 || offs (exp) > 32)
-           goto outrange;
-         break;
-       case 50:
-         if (offs (exp) < 0 || offs (exp) > 127)
-           goto outrange;
-         break;
-       case 55:
-         if (offs (exp) < -64 || offs (exp) > 63)
-           goto outrange;
-         break;
-       case 60:
-         if (offs (exp) < -128 || offs (exp) > 127)
-           goto outrange;
-         break;
-       case 70:
-         if (offs (exp) < 0 || offs (exp) > 4095)
+         if (strncasecmp (input_line_pointer, "DO", 2) == 0
+             && (input_line_pointer[2] == '.'
+                 || ! is_part_of_name (input_line_pointer[2])))
            {
-           outrange:
-             as_warn ("expression out of range: defaulting to 0");
-             offs (exp) = 0;
+             bystop = input_line_pointer;
+             input_line_pointer += 2;
+             break;
            }
-         break;
-       default:
-         break;
-       }
-    }
-  else if (section == big_section)
-    {
-      if (offs (exp) < 0       /* flonum */
-         && (ok == 80          /* no bignums */
-             || (ok > 10       /* small-int ranges including 0 ok */
-                 /* If we have a flonum zero, a zero integer should
-                    do as well (e.g., in moveq).  */
-                 && generic_floating_point_number.exponent == 0
-                 && generic_floating_point_number.low[0] == 0)))
-       {
-         /* HACK! Turn it into a long */
-         LITTLENUM_TYPE words[6];
-
-         gen_to_words (words, 2, 8L);  /* These numbers are magic! */
-         seg (exp) = absolute_section;
-         adds (exp) = 0;
-         subs (exp) = 0;
-         offs (exp) = words[1] | (words[0] << 16);
+         ++input_line_pointer;
        }
-      else if (ok != 0)
+      if (bystop == NULL)
        {
-         seg (exp) = absolute_section;
-         adds (exp) = 0;
-         subs (exp) = 0;
-         offs (exp) = (ok == 10) ? 1 : 0;
-         as_warn ("Can't deal with expression \"%s\": defaulting to %ld", exp->e_beg, offs (exp));
+         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
     {
-      if (ok >= 10 && ok <= 70)
-       {
-         seg (exp) = absolute_section;
-         adds (exp) = 0;
-         subs (exp) = 0;
-         offs (exp) = (ok == 10) ? 1 : 0;
-         as_warn ("Can't deal with expression \"%s\": defaulting to %ld", exp->e_beg, offs (exp));
-       }
+      extent = input_line_pointer[1];
+      input_line_pointer += 2;
     }
 
-  if (input_line_pointer != exp->e_end + 1)
-    as_bad ("Ignoring junk after expression");
-  exp->e_end[1] = c_save;
-  input_line_pointer = save_in;
-  if (exp->e_siz)
+  /* 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)
     {
-      switch (exp->e_siz)
-       {
-       case 1:
-         if (!isbyte (offs (exp)))
-           as_warn ("expression doesn't fit in BYTE");
-         break;
-       case 2:
-         if (!isword (offs (exp)))
-           as_warn ("expression doesn't fit in WORD");
-         break;
-       }
+      while (! is_end_of_line[(unsigned char) *input_line_pointer])
+       ++input_line_pointer;
     }
-  return offs (exp);
-#endif
+
+  demand_empty_rest_of_line ();
 }
 
-/* These are the back-ends for the various machine dependent pseudo-ops.  */
-void demand_empty_rest_of_line ();     /* Hate those extra verbose names */
+/* Handle the MRI ENDF pseudo-op.  */
 
 static void
-s_data1 ()
+s_mri_endf (ignore)
+     int ignore;
 {
-  subseg_new (data_section, 1);
+  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_data2 ()
+s_mri_repeat (ignore)
+     int ignore;
 {
-  subseg_new (data_section, 2);
+  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_bss ()
+s_mri_until (qual)
+     int qual;
 {
-  /* We don't support putting frags in the BSS segment, we fake it
-     by marking in_bss, then looking at s_skip for clues.  */
+  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;
+    }
 
-  subseg_new (bss_section, 0);
   demand_empty_rest_of_line ();
 }
 
+/* Handle the MRI WHILE pseudo-op.  */
+
 static void
-s_even ()
+s_mri_while (qual)
+     int qual;
 {
-  register int temp;
-  register long temp_fill;
+  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;
+    }
 
-  temp = 1;                    /* JF should be 2? */
-  temp_fill = get_absolute_expression ();
-  if (!need_pass_2)            /* Never make frag if expect extra pass. */
-    frag_align (temp, (int) temp_fill);
   demand_empty_rest_of_line ();
 }
 
+/* Handle the MRI ENDW pseudo-op.  */
+
 static void
-s_proc ()
+s_mri_endw (ignore)
+     int ignore;
 {
-  demand_empty_rest_of_line ();
-}
+  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);
 
-/* s_space is defined in read.c .skip is simply an alias to it. */
+  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.
@@ -4857,133 +6457,223 @@ s_proc ()
  *             so don't use or document it, but that's the way the parsing
  *             works).
  *
- * MAYBE_FLOAT_TOO is defined below so that specifying a processor type
- * (e.g. m68020) also requests that float instructions be included.  This
- * is the default setup, mostly to avoid hassling users.  A better
- * rearrangement of this structure would be to add an option to DENY
- * floating point opcodes, for people who want to really know there's none
- * of that funny floaty stuff going on.  FIXME-later.
+ *     -pic    Indicates PIC.
+ *     -k      Indicates PIC.  (Sun 3 only.)
+ *
+ *     --bitwise-or
+ *             Permit `|' to be used in expressions.
+ *
  */
-#ifndef MAYBE_FLOAT_TOO
-#define        MAYBE_FLOAT_TOO /* m68881 */ 0  /* this is handled later */
+
+#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 (argP, cntP, vecP)
-     char **argP;
-     int *cntP;
-     char ***vecP;
+md_parse_option (c, arg)
+     int c;
+     char *arg;
 {
-  switch (**argP)
+  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':
-      (*argP)++;
+      if (*arg == 'm')
+       arg++;
       /* intentional fall-through */
     case 'm':
-      (*argP)++;
 
-      if (**argP == 'c')
+      if (arg[0] == 'n' && arg[1] == 'o' && arg[2] == '-')
        {
-         (*argP)++;
-       }                       /* allow an optional "c" */
+         int i;
+         unsigned long arch;
+         const char *oarg = arg;
 
-      if (!strcmp (*argP, "68000")
-         || !strcmp (*argP, "68008")
-         || !strcmp (*argP, "68302"))
-       {
-         current_architecture |= m68000;
-       }
-      else if (!strcmp (*argP, "68010"))
-       {
-#ifdef TE_SUN
-         omagic = 1 << 16 | OMAGIC;
-#endif
-         current_architecture |= m68010;
-       }
-      else if (!strcmp (*argP, "68020"))
-       {
-         current_architecture |= m68020 | MAYBE_FLOAT_TOO;
-       }
-      else if (!strcmp (*argP, "68030"))
-       {
-         current_architecture |= m68030 | MAYBE_FLOAT_TOO;
-       }
-      else if (!strcmp (*argP, "68040"))
-       {
-         current_architecture |= m68040 | MAYBE_FLOAT_TOO;
-       }
-#ifndef NO_68881
-      else if (!strcmp (*argP, "68881"))
-       {
-         current_architecture |= m68881;
-       }
-      else if (!strcmp (*argP, "68882"))
-       {
-         current_architecture |= m68882;
-       }
-#endif /* NO_68881 */
-      /* Even if we aren't configured to support the processor,
-        it should still be possible to assert that the user
-        doesn't have it...  */
-      else if (!strcmp (*argP, "no-68881")
-              || !strcmp (*argP, "no-68882"))
-       {
-         no_68881 = 1;
-       }
-#ifndef NO_68851
-      else if (!strcmp (*argP, "68851"))
-       {
-         current_architecture |= m68851;
-       }
-#endif /* NO_68851 */
-      else if (!strcmp (*argP, "no-68851"))
-       {
-         no_68851 = 1;
-       }
-      else if (!strcmp (*argP, "pu32") /* "cpu32" minus 'c' */
-              || !strcmp (*argP, "68331")
-              || !strcmp (*argP, "68332")
-              || !strcmp (*argP, "68333")
-              || !strcmp (*argP, "68340"))
-       {
-         current_architecture |= cpu32;
+         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;
+         if (arch == m68881)
+           no_68881 = 1;
+         else if (arch == m68851)
+           no_68851 = 1;
+         else
+           goto unknown;
        }
       else
        {
-         as_warn ("Unknown architecture, \"%s\". option ignored", *argP);
-       }                       /* switch on architecture */
+         int i;
 
-      while (**argP)
-       (*argP)++;
+         if (arg[0] == 'c' && arg[1] == '6')
+           arg++;
 
+         for (i = 0; i < n_archs; i++)
+           if (!strcmp (arg, archs[i].name))
+             {
+               unsigned long arch = archs[i].arch;
+               if (cpu_of_arch (arch))
+                 /* It's a cpu spec.  */
+                 {
+                   current_architecture &= ~m68000up;
+                   current_architecture |= arch;
+                 }
+               else if (arch == m68881)
+                 {
+                   current_architecture |= m68881;
+                   no_68881 = 0;
+                 }
+               else if (arch == m68851)
+                 {
+                   current_architecture |= m68851;
+                   no_68851 = 0;
+                 }
+               else
+                 /* ??? */
+                 abort ();
+               break;
+             }
+         if (i == n_archs)
+           {
+             as_bad ("unrecognized architecture specification `%s'", arg);
+             return 0;
+           }
+       }
       break;
 
-    case 'p':
-      if (!strcmp (*argP, "pic"))
-       {
-         (*argP) += 3;
-         break;                /* -pic, Position Independent Code */
-       }
-      else
-       {
-         return 0;
-       }                       /* pic or not */
+    case OPTION_PIC:
+    case 'k':
+      flag_want_pic = 1;
+      break;                   /* -pic, Position Independent Code */
+
+    case OPTION_REGISTER_PREFIX_OPTIONAL:
+      flag_reg_prefix_optional = 1;
+      reg_prefix_optional_seen = 1;
+      break;
+
+      /* -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:
       return 0;
     }
+
   return 1;
 }
 
-
+void
+md_show_usage (stream)
+     FILE *stream;
+{
+  fprintf(stream, "\
+680X0 options:\n\
+-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 | -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");
+  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\
+--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
 
 /* TEST2:  Test md_assemble() */
@@ -5084,17 +6774,6 @@ md_undefined_symbol (name)
   return 0;
 }
 
-/* Parse an operand that is machine-specific.
-   We just return without modifying the expression if we have nothing
-   to do.  */
-
-/* ARGSUSED */
-void
-md_operand (expressionP)
-     expressionS *expressionP;
-{
-}
-
 /* Round up a section size to the appropriate boundary.  */
 valueT
 md_section_align (segment, size)
@@ -5105,18 +6784,28 @@ md_section_align (segment, size)
 }
 
 /* Exactly what point is a PC-relative offset relative TO?
-   On the 68k, they're relative to the address of the offset, plus
-   its size. (??? Is this right?  FIXME-SOON!) */
+   On the 68k, it is relative to the address of the first extension
+   word.  The difference between the addresses of the offset and the
+   first extension word is stored in fx_pcrel_adjust. */
 long
 md_pcrel_from (fixP)
      fixS *fixP;
 {
-  return (fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address);
+  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
+/*ARGSUSED*/
 void
-tc_coff_symbol_emit_hook ()
+tc_coff_symbol_emit_hook (ignore)
+     symbolS *ignore;
 {
 }
 
@@ -5134,6 +6823,7 @@ tc_coff_sizemachdep (frag)
       return 4;
     default:
       abort ();
+      return 0;
     }
 }
 #endif
This page took 0.117706 seconds and 4 git commands to generate.