These changes clean things up a bit, and improve Solaris cross
[deliverable/binutils-gdb.git] / gas / config / tc-m68k.c
index ea60b6935bba0672b230df8264ecfc7572ff59e5..7b6df192efd1eae7d83fa256534210c2f5d858a1 100644 (file)
@@ -1,31 +1,34 @@
-/* m68k.c  All the m68020 specific stuff in one convenient, huge,
+/* tc-m68k.c  All the m68020 specific stuff in one convenient, huge,
    slow to compile, easy to find file.
-   Copyright (C) 1987, 1991 Free Software Foundation, Inc.
 
-This file is part of GAS, the GNU Assembler.
+   Copyright (C) 1987, 1991, 1992 Free Software Foundation, Inc.
 
-GAS is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+   This file is part of GAS, the GNU Assembler.
 
-GAS is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   GAS is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
 
-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.  */
+   GAS is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-#include <ctype.h>
+   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.  */
 
+#include <ctype.h>
+#define  NO_RELOC 0
 #include "as.h"
+#include "read.h"
 
 #include "obstack.h"
 
- /* note that this file includes real declarations and thus can only be included by one source file per executable. */
-#include "m68k-opcode.h"
+/* note that this file includes real declarations and thus can only be included by one source file per executable. */
+#include "opcode/m68k.h"
+
 #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
@@ -49,6 +52,8 @@ const char comment_chars[] = "|";
 /* Also note that comments like this one will always work. */
 const char line_comment_chars[] = "#";
 
+const char line_separator_chars[] = "";
+
 /* Chars that can be used to separate mant from exp in floating point nums */
 const char EXP_CHARS[] = "eE";
 
@@ -61,7 +66,7 @@ const char FLT_CHARS[] = "rRsSfFdDxXeEpP";
 /* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
    changed in read.c .  Ideally it shouldn't have to know about it at all,
    but nothing is ideal around here.
- */
  */
 
 int md_reloc_size = 8;         /* Size of relocation record */
 
@@ -75,8 +80,8 @@ static struct obstack robyn;
 #define SHORT          1
 #define LONG           2
 #define SZ_UNDEF       3
-
-#define BRANCH         1
+#undef BRANCH
+#define ABRANCH                1
 #define FBRANCH                2
 #define PCREL          3
 #define BCC68000        4
@@ -85,71 +90,73 @@ static struct obstack robyn;
 
 /* 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
-
-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)
-
-*/
+   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,
+       IMMED = 1,
+       DREG,
+       AREG,
+       AINDR,
+       ADEC,
+       AINC,
+       AOFF,
+       AINDX,
+       APODX,
+       AMIND,
+       APRDX,
+       ABSL,
+       MSCR,
+       REGLST,
+       DINDR
 };
 
 
@@ -160,11 +167,123 @@ struct m68k_exp {
        short   e_siz;          /* 0== default 1==short/byte 2==word 3==long */
 };
 
+/* 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 */
+
+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,
+};
+
 /* Internal form of an operand.  */
 struct m68k_op {
        char    *error;         /* Couldn't parse it */
        enum operand_type mode; /* What mode this instruction is in.  */
-       unsigned long   reg;            /* Base register */
+       enum _register reg;             /* Base register */
        struct m68k_exp *con1;
        int     ireg;           /* Index register */
        int     isiz;           /* 0==unspec  1==byte(?)  2==short  3==long  */
@@ -173,7 +292,7 @@ struct m68k_op {
 };
 
 /* internal form of a 68020 instruction */
-struct m68_it {
+struct m68k_it {
        char    *error;
        char    *args;          /* list of opcode info */
        int     numargs;
@@ -198,55 +317,58 @@ struct m68_it {
        struct  {
                int     n;
                symbolS *add,
-                       *sub;
+               *sub;
                long off;
                char    wid;
                char    pcrel;
        } reloc[5];             /* Five is enough??? */
 };
 
-struct m68_it the_ins;         /* the instruction being assembled */
+#define cpu_of_arch(x)         ((x) & m68000up)
+#define float_of_arch(x)       ((x) & mfloat)
+#define mmu_of_arch(x)         ((x) & mmmu)
 
+static struct m68k_it the_ins;         /* the instruction being assembled */
 
-/* Macros for adding things to the m68_it struct */
+/* 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++;\
-}
                           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++]\
-)
+                         the_ins.exprs[the_ins.nexp].e_beg=beg,\
+                         the_ins.exprs[the_ins.nexp].e_end=end,\
+                         &the_ins.exprs[the_ins.nexp++]\
+                         )
 
 
 /* The numo+1 kludge is so we can hit the low order byte of the prev word. Blecch*/
 #define add_fix(width,exp,pc_rel) {\
-       the_ins.reloc[the_ins.nrel].n= ((width)=='B') ? (the_ins.numo*2-1) : \
-               (((width)=='b') ? ((the_ins.numo-1)*2) : (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].wid=width;\
-       the_ins.reloc[the_ins.nrel++].pcrel=pc_rel;\
-}
+                                      the_ins.reloc[the_ins.nrel].n= ((width)=='B') ? (the_ins.numo*2-1) : \
+                                          (((width)=='b') ? ((the_ins.numo-1)*2) : (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].wid=width;\
+                                                              the_ins.reloc[the_ins.nrel++].pcrel=pc_rel;\
+                                                          }
 
 #define add_frag(add,off,type)  {\
-       the_ins.fragb[the_ins.nfrag].fragoff=the_ins.numo;\
-       the_ins.fragb[the_ins.nfrag].fadd=add;\
-       the_ins.fragb[the_ins.nfrag].foff=off;\
-       the_ins.fragb[the_ins.nfrag++].fragty=type;\
-}
+                                    the_ins.fragb[the_ins.nfrag].fragoff=the_ins.numo;\
+                                        the_ins.fragb[the_ins.nfrag].fadd=add;\
+                                            the_ins.fragb[the_ins.nfrag].foff=off;\
+                                                the_ins.fragb[the_ins.nfrag++].fragty=type;\
+                                            }
 
 #define isvar(exp)     ((exp) && (adds(exp) || subs(exp)))
 
@@ -256,19 +378,22 @@ struct m68_it the_ins;            /* the instruction being assembled */
 #define offs(exp)      ((exp)->e_exp.X_add_number)
 
 
-struct m68_incant {
+struct m68k_incant {
        char *m_operands;
        unsigned long m_opcode;
        short m_opnum;
        short m_codenum;
-       struct m68_incant *m_next;
+       int m_arch;
+       struct m68k_incant *m_next;
 };
 
+
+
 #define getone(x)      ((((x)->m_opcode)>>16)&0xffff)
 #define gettwo(x)      (((x)->m_opcode)&0xffff)
 
 
-#ifdef __STDC__
+#if __STDC__ == 1
 
 static char *crack_operand(char *str, struct m68k_op *opP);
 static int get_num(struct m68k_exp *exp, int ok);
@@ -284,7 +409,7 @@ static void s_data2(void);
 static void s_even(void);
 static void s_proc(void);
 
-#else /* __STDC__ */
+#else /* not __STDC__ */
 
 static char *crack_operand();
 static int get_num();
@@ -295,12 +420,15 @@ static int try_index();
 static void install_gen_operand();
 static void install_operand();
 static void s_bss();
+void s_align_bytes();
 static void s_data1();
 static void s_data2();
 static void s_even();
 static void s_proc();
 
-#endif /* __STDC__ */
+#endif /* not __STDC__ */
+
+static int current_architecture = 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 */
@@ -312,61 +440,61 @@ static void s_proc();
 /* This is currently 10 bytes for DBCC */
 
 /* The fields are:
-       How far Forward this mode will reach:
-       How far Backward this mode will reach:
-       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
- */
+   How far Forward this mode will reach:
+   How far Backward this mode will reach:
+   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[] = {
-{ 1,           1,              0,      0 },    /* First entries aren't used */
-{ 1,           1,              0,      0 },    /* For no good reason except */
-{ 1,           1,              0,      0 },    /* that the VAX doesn't either */
-{ 1,           1,              0,      0 },
-
-{ (127),       (-128),         0,      TAB(BRANCH,SHORT)},
-{ (32767),     (-32768),       2,      TAB(BRANCH,LONG) },
-{ 0,           0,              4,      0 },
-{ 1,           1,              0,      0 },
-
-{ 1,           1,              0,      0 },    /* FBRANCH doesn't come BYTE */
-{ (32767),     (-32768),       2,      TAB(FBRANCH,LONG)},
-{ 0,           0,              4,      0 },
-{ 1,           1,              0,      0 },
-
-{ 1,           1,              0,      0 },    /* PCREL doesn't come BYTE */
-{ (32767),     (-32768),       2,      TAB(PCREL,LONG)},
-{ 0,           0,              4,      0 },
-{ 1,           1,              0,      0 },
-
-{ (127),       (-128),         0,      TAB(BCC68000,SHORT)},
-{ (32767),     (-32768),       2,      TAB(BCC68000,LONG) },
-{ 0,           0,              6,      0 },    /* jmp long space */
-{ 1,           1,              0,      0 },
-
-{ 1,           1,              0,      0 },    /* DBCC doesn't come BYTE */
-{ (32767),     (-32768),       2,      TAB(DBCC,LONG) },
-{ 0,           0,              10,     0 },    /* bra/jmp long space */
-{ 1,           1,              0,      0 },
-
-{ 1,           1,              0,      0 },    /* PCLEA doesn't come BYTE */
-{ 32767,       -32768,         2,      TAB(PCLEA,LONG) },
-{ 0,           0,              6,      0 },
-{ 1,           1,              0,      0 },
-
-};
+    md_relax_table[] = {
+           { 1,                1,              0,      0 },    /* First entries aren't used */
+           { 1,                1,              0,      0 },    /* For no good reason except */
+           { 1,                1,              0,      0 },    /* that the VAX doesn't either */
+           { 1,                1,              0,      0 },
+
+           { (127),    (-128),         0,      TAB(ABRANCH,SHORT)},
+           { (32767),  (-32768),       2,      TAB(ABRANCH,LONG) },
+           { 0,                0,              4,      0 },
+           { 1,                1,              0,      0 },
+
+           { 1,                1,              0,      0 },    /* FBRANCH doesn't come BYTE */
+           { (32767),  (-32768),       2,      TAB(FBRANCH,LONG)},
+           { 0,                0,              4,      0 },
+           { 1,                1,              0,      0 },
+
+           { 1,                1,              0,      0 },    /* PCREL doesn't come BYTE */
+           { (32767),  (-32768),       2,      TAB(PCREL,LONG)},
+           { 0,                0,              4,      0 },
+           { 1,                1,              0,      0 },
+
+           { (127),    (-128),         0,      TAB(BCC68000,SHORT)},
+           { (32767),  (-32768),       2,      TAB(BCC68000,LONG) },
+           { 0,                0,              6,      0 },    /* jmp long space */
+           { 1,                1,              0,      0 },
+
+           { 1,                1,              0,      0 },    /* DBCC doesn't come BYTE */
+           { (32767),  (-32768),       2,      TAB(DBCC,LONG) },
+           { 0,                0,              10,     0 },    /* bra/jmp long space */
+           { 1,                1,              0,      0 },
+
+           { 1,                1,              0,      0 },    /* PCLEA doesn't come BYTE */
+           { 32767,    -32768,         2,      TAB(PCLEA,LONG) },
+           { 0,                0,              6,      0 },
+           { 1,                1,              0,      0 },
+
+    };
 
 /* These are the machine dependent pseudo-ops.  These are included so
    the assembler can work on the output from the SUN C compiler, which
    generates these.
- */
  */
 
 /* This table describes all the machine specific pseudo-ops the assembler
    has to support.  The fields are:
-         pseudo-op name without dot
-         function to call to execute this pseudo-op
-         Integer arg to pass to the function
- */
+   pseudo-op name without dot
+   function to call to execute this pseudo-op
+   Integer arg to pass to the function
  */
 const pseudo_typeS md_pseudo_table[] = {
        { "data1",      s_data1,        0       },
        { "data2",      s_data2,        0       },
@@ -374,10 +502,40 @@ const pseudo_typeS md_pseudo_table[] = {
        { "even",       s_even,         0       },
        { "skip",       s_space,        0       },
        { "proc",       s_proc,         0       },
+#ifdef TE_SUN3
+        { "align",      s_align_bytes,  0       },
+#endif
        { 0,            0,              0       }
 };
 
 
+/* The mote pseudo ops are put into the opcode table, since they
+   don't start with a . they look like opcodes to gas.  
+   */
+extern void obj_coff_section();
+
+const pseudo_typeS mote_pseudo_table[] =
+{
+
+ { "dc.l", cons,4},
+ { "dc", cons,2},
+ { "dc.w", cons,2},
+ { "dc.b", cons,1},
+
+ { "ds.l", s_space,4},
+ { "ds", s_space,2},
+ { "ds.w", s_space,2},
+ { "ds.b", s_space,1},
+
+ { "xdef", s_globl, 0},
+ { "align", s_align_ptwo, 0},
+#ifdef M68KCOFF
+ { "sect", obj_coff_section,0},
+ { "section", obj_coff_section,0},
+#endif
+  0,
+};
+
 /* #define isbyte(x)   ((x)>=-128 && (x)<=127) */
 /* #define isword(x)   ((x)>=-32768 && (x)<=32767) */
 
@@ -392,59 +550,10 @@ const pseudo_typeS md_pseudo_table[] = {
 
 extern char *input_line_pointer;
 
-#define FAIL   0
-#define OK     1
-
-/* 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 DATA   1               /*   1- 8 == data registers 0-7 */
-#define ADDR   (DATA+8)        /*   9-16 == address regs 0-7 */
-#define FPREG  (ADDR+8)        /*  17-24 Eight FP registers */
-#define COPNUM (FPREG+8)       /*  25-32 Co-processor #1-#8 */
-
-#define PC     (COPNUM+8)      /*  33 Program counter */
-#define ZPC    (PC+1)          /*  34 Hack for Program space, but 0 addressing */
-#define SR     (ZPC+1)         /*  35 Status Reg */
-#define CCR    (SR+1)          /*  36 Condition code Reg */
-
-/* These have to be in order for the movec instruction to work. */
-#define USP    (CCR+1)         /*  37 User Stack Pointer */
-#define ISP    (USP+1)         /*  38 Interrupt stack pointer */
-#define SFC    (ISP+1)         /*  39 */
-#define DFC    (SFC+1)         /*  40 */
-#define CACR   (DFC+1)         /*  41 */
-#define VBR    (CACR+1)        /*  42 */
-#define CAAR   (VBR+1)         /*  43 */
-#define MSP    (CAAR+1)        /*  44 */
-
-#define FPI    (MSP+1)         /* 45 */
-#define FPS    (FPI+1)         /* 46 */
-#define FPC    (FPS+1)         /* 47 */
-/*
- * these defines should be in m68k.c but
- * i put them here to keep all the m68851 stuff
- * together -rab
- * JF--Make sure these #s don't clash with the ones in m68k.c
- * That would be BAD.
- */
-#define TC     (FPC+1)         /* 48 */
-#define DRP    (TC+1)          /* 49 */
-#define SRP    (DRP+1)         /* 50 */
-#define CRP    (SRP+1)         /* 51 */
-#define CAL    (CRP+1)         /* 52 */
-#define VAL    (CAL+1)         /* 53 */
-#define SCC    (VAL+1)         /* 54 */
-#define AC     (SCC+1)         /* 55 */
-#define BAD    (AC+1)          /* 56,57,58,59, 60,61,62,63 */
-#define BAC    (BAD+8)         /* 64,65,66,67, 68,69,70,71 */
-#define PSR    (BAC+8)         /* 72 */
-#define PCSR   (PSR+1)         /* 73 */
-
-
-/* Note that COPNUM==processor #1 -- COPNUM+7==#8, which stores as 000 */
-/* I think. . .  */
-
-#define        SP      ADDR+7
+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
@@ -455,7 +564,7 @@ static char mklower_table[256];
 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])])))
                                                          alt_notend_table[(unsigned char)(s[1])])))
 
 #if 0
 #define mklower(c)     (isupper(c) ? tolower(c) : c)
@@ -465,439 +574,68 @@ static char alt_notend_table[256];
 /* JF modified this to handle cases where the first part of a symbol name
    looks like a register */
 
-int
+/*
+ * m68k_reg_parse() := if it looks like a register, return it's token &
+ * advance the pointer.
+ */
+
+enum _register
 m68k_reg_parse(ccp)
-register char **ccp;
+     register char **ccp;
 {
-       register char c1,
-               c2,
-               c3,
-               c4;
-       register int n = 0,
-               ret = FAIL;
-
-       c1=mklower(ccp[0][0]);
-#ifdef REGISTER_PREFIX
-       if(c1!=REGISTER_PREFIX)
-               return FAIL;
-       c1=mklower(ccp[0][1]);
-       c2=mklower(ccp[0][2]);
-       c3=mklower(ccp[0][3]);
-       c4=mklower(ccp[0][4]);
-#else
-       c2=mklower(ccp[0][1]);
-       c3=mklower(ccp[0][2]);
-       c4=mklower(ccp[0][3]);
-#endif
-       switch(c1) {
-       case 'a':
-               if(c2>='0' && c2<='7') {
-                       n=2;
-                       ret=ADDR+c2-'0';
-               }
-#ifdef m68851
-               else if (c2 == 'c') {
-                       n = 2;
-                       ret = AC;
-               }
-#endif
-               break;
-#ifdef m68851
-       case 'b':
-               if (c2 == 'a') {
-                       if (c3 == 'd') {
-                               if (c4 >= '0' && c4 <= '7') {
-                                       n = 4;
-                                       ret = BAD + c4 - '0';
-                               }
-                       }
-                       if (c3 == 'c') {
-                               if (c4 >= '0' && c4 <= '7') {
-                                       n = 4;
-                                       ret = BAC + c4 - '0';
-                               }
-                       }
-               }
-               break;
-#endif
-       case 'c':
-#ifdef m68851
-               if (c2 == 'a' && c3 == 'l') {
-                       n = 3;
-                       ret = CAL;
-               } else
-#endif
-                       /* This supports both CCR and CC as the ccr reg. */
-               if(c2=='c' && c3=='r') {
-                       n=3;
-                       ret = CCR;
-               } else if(c2=='c') {
-                       n=2;
-                       ret = CCR;
-               } else if(c2=='a' && (c3=='a' || c3=='c') && c4=='r') {
-                       n=4;
-                       ret = c3=='a' ? CAAR : CACR;
-               }
-#ifdef m68851
-               else if (c2 == 'r' && c3 == 'p') {
-                       n = 3;
-                       ret = (CRP);
-               }
-#endif
-               break;
-       case 'd':
-               if(c2>='0' && c2<='7') {
-                       n=2;
-                       ret = DATA+c2-'0';
-               } else if(c2=='f' && c3=='c') {
-                       n=3;
-                       ret = DFC;
-               }
-#ifdef m68851
-               else if (c2 == 'r' && c3 == 'p') {
-                       n = 3;
-                       ret = (DRP);
-               }
-#endif
-               break;
-       case 'f':
-               if(c2=='p') {
-                       if(c3>='0' && c3<='7') {
-                               n=3;
-                               ret = FPREG+c3-'0';
-                               if(c4==':')
-                                       ccp[0][3]=',';
-                       } else if(c3=='i') {
-                               n=3;
-                               ret = FPI;
-                       } else if(c3=='s') {
-                               n= (c4 == 'r' ? 4 : 3);
-                               ret = FPS;
-                       } else if(c3=='c') {
-                               n= (c4 == 'r' ? 4 : 3);
-                               ret = FPC;
-                       }
-               }
-               break;
-       case 'i':
-               if(c2=='s' && c3=='p') {
-                       n=3;
-                       ret = ISP;
-               }
-               break;
-       case 'm':
-               if(c2=='s' && c3=='p') {
-                       n=3;
-                       ret = MSP;
-               }
-               break;
-       case 'p':
-               if(c2=='c') {
-#ifdef m68851
-                       if(c3 == 's' && c4=='r') {
-                               n=4;
-                               ret = (PCSR);
-                       } else
-#endif
-                       {
-                               n=2;
-                               ret = PC;
-                       }
-               }
-#ifdef m68851
-               else if (c2 == 's' && c3 == 'r') {
-                       n = 3;
-                       ret = (PSR);
-               }
-#endif
-               break;
-       case 's':
-#ifdef m68851
-               if (c2 == 'c' && c3 == 'c') {
-                       n = 3;
-                       ret = (SCC);
-               } else if (c2 == 'r' && c3 == 'p') {
-                       n = 3;
-                       ret = (SRP);
-               } else
-#endif
-               if(c2=='r') {
-                       n=2;
-                       ret = SR;
-               } else if(c2=='p') {
-                       n=2;
-                       ret = ADDR+7;
-               } else if(c2=='f' && c3=='c') {
-                       n=3;
-                       ret = SFC;
-               }
-               break;
-#ifdef m68851
-       case 't':
-               if(c2 == 'c') {
-                       n=2;
-                       ret=TC;
-               }
-               break;
-#endif
-       case 'u':
-               if(c2=='s' && c3=='p') {
-                       n=3;
-                       ret = USP;
-               }
-               break;
-       case 'v':
-#ifdef m68851
-               if (c2 == 'a' && c3 == 'l') {
-                       n = 3;
-                       ret = (VAL);
-               } else
-#endif
-               if(c2=='b' && c3=='r') {
-                       n=3;
-                       ret = VBR;
-               }
-               break;
-       case 'z':
-               if(c2=='p' && c3=='c') {
-                       n=3;
-                       ret = ZPC;
-               }
-               break;
-       default:
-               break;
-       }
-       if(n) {
+  char *start = *ccp;
+
 #ifdef REGISTER_PREFIX
-               n++;
+  if (*start == REGISTER_PREFIX)
+    ++start;
 #endif
-               if(isalnum(ccp[0][n]) || ccp[0][n]=='_')
-                       ret=FAIL;
-               else
-                       ccp[0]+=n;
-       } else
-               ret = FAIL;
-       return ret;
-}
 
-#define SKIP_WHITE()   { str++; if(*str==' ') str++;}
-
-int
-m68k_ip_op(str,opP)
-char *str;
-register struct m68k_op *opP;
-{
-       char    *strend;
-       long    i;
-       char    *parse_index();
+  if (isalpha(*start) &&  is_name_beginner(*start))
+  {
+    char c;
+    char *p = start;
+    symbolS *symbolP;
 
-       if(*str==' ')
-               str++;
-               /* Find the end of the string */
-       if(!*str) {
-               /* Out of gas */
-               opP->error="Missing operand";
-               return FAIL;
-       }
-       for(strend=str;*strend;strend++)
-               ;
-       --strend;
+    c = *p++;
+    while (isalpha(c) || isdigit(c) || c == '_')
+      {
+       c = *p++;
+      }
 
-               /* Guess what:  A constant.  Shar and enjoy */
-       if(*str=='#') {
-               str++;
-               opP->con1=add_exp(str,strend);
-               opP->mode=IMMED;
-               return OK;
-       }
-       i=m68k_reg_parse(&str);
-       if((i==FAIL || *str!='\0') && *str!='@') {
-               char *stmp;
+    * -- p = 0;
+    symbolP = symbol_find(start);
+    *p  = c;
 
-               if(i!=FAIL && (*str=='/' || *str=='-')) {
-                       opP->mode=REGLST;
-                       return get_regs(i,str,opP);
-               }
-               if ((stmp=strchr(str,'@')) != '\0') {
-                       opP->con1=add_exp(str,stmp-1);
-                       if(stmp==strend) {
-                               opP->mode=AINDX;
-                               return OK;
-                       }
-                       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;
-               }
-               opP->mode=ABSL;
-               opP->con1=add_exp(str,strend);
-               return OK;
-       }
-       opP->reg=i;
-       if(*str=='\0') {
-               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;
-       }
-       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(*str!='@')
-               abort();
-       str++;
-       switch(*str) {
-       case '\0':
-               opP->mode=AINDR;
-               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;
+    if (symbolP && S_GET_SEGMENT(symbolP) == SEG_REGISTER)
+    {
+      *ccp = p;
+      return  S_GET_VALUE(symbolP);
+    }
+  }
+  return FAIL;
 
-               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(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 */
-                       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!='@' || str[1]!='(') {
-               opP->error="junk after indirect";
-               return FAIL;
-       }
-       str+=2;
-       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;
+#define SKIP_WHITE()   { str++; if(*str==' ') str++;}
+#define SKIP_W()       { ss++; if(*ss==' ') ss++;}
 
-               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;
-                       }
-               }
-               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;
-}
+/* Parse an index specification using Motorola syntax.  */
 
-static int try_index(s,opP)
+static int
+try_moto_index(s,opP)
 char **s;
 struct m68k_op *opP;
 {
        register int    i;
        char    *ss;
-#define SKIP_W()       { ss++; if(*ss==' ') 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;
        }
@@ -910,14 +648,94 @@ struct m68k_op *opP;
                *s=ss;
                return OK;
        }
-       if(*ss!=':') {
-               opP->error="Missing : in index register";
+       if(*ss!='.') {
+               opP->error="Missing . in index register";
                *s=ss;
                return FAIL;
        }
        SKIP_W();
-       switch(*ss) {
-       case 'w':
+       if(mklower(*ss)=='w') opP->isiz=2;
+       else if(mklower(*ss)=='l') opP->isiz=3;
+       else {
+               opP->error="Size spec not .W or .L";
+               *s=ss;
+               return FAIL;
+       }
+       SKIP_W();
+       if(*ss=='.' || *ss=='*') {
+               SKIP_W();
+               switch(*ss) {
+               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;
+               }
+               SKIP_W();
+       } else opP->imul=1;
+       if(*ss!=')') {
+               opP->error="Missing )";
+               *s=ss;
+               return FAIL;
+       }
+       SKIP_W();
+       *s=ss;
+       return OK;
+}
+
+/*
+ *
+ * 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> | ' ' ;
+ *
+ */
+
+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;
                break;
@@ -938,6 +756,11 @@ struct m68k_op *opP;
                case '2':
                case '4':
                case '8':
+                       if (cpu_of_arch(current_architecture) < m68020) {
+                               opP->error="no index scaling in pre-68020's";
+                               *s=ss;
+                               return FAIL;
+                       }
                        opP->imul= *ss-'0';
                        break;
                default:
@@ -957,6 +780,507 @@ struct m68k_op *opP;
        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.  */
+
+int
+    m68k_ip_op(str,opP)
+char *str;
+register struct m68k_op *opP;
+{
+       char    *strend;
+       long    i;
+       char    *parse_index();
+       int needp;
+
+       if (*str==' ') {
+               str++;
+       } /* Find the beginning of the string */
+
+       if(!*str) {
+               opP->error="Missing operand";
+               return FAIL;
+       } /* Out of gas */
+
+       for(strend = str; *strend; strend++)
+         ;
+       --strend;
+
+       if(*str=='#') {
+               str++;
+               opP->con1=add_exp(str,strend);
+               opP->mode=IMMED;
+               return OK;
+       } /* Guess what:  A constant.  Shar and enjoy */
+
+       i = m68k_reg_parse(&str);
+
+        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;
+               }
+          }
+
+       if (*str!='@') {
+               char *stmp;
+
+               if ((stmp=strchr(str,'@')) != 0) {
+                       opP->con1=add_exp(str,stmp-1);
+                       if(stmp==strend) {
+                               opP->mode=AINDX;
+                               return(OK);
+                       }
+
+                       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(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 */
+               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() */
+
+
+#ifdef M68KCOFF
+
+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 TEST1   /* TEST1 tests m68k_ip_op(), which parses operands */
 main()
 {
@@ -965,17 +1289,17 @@ main()
 
        for(;;) {
                if(!gets(buf))
-                       break;
-               bzero(&thark,sizeof(thark));
+                   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("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("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("Iadd: '%.*s'",1+thark.e_iadd-thark.b_iadd,thark.b_iadd);
                printf("\n");
        }
        exit(0);
@@ -985,12 +1309,12 @@ main()
 
 
 static struct hash_control*   op_hash = NULL;  /* handle of the OPCODE hash table
-                                  NULL means any use before m68_ip_begin()
-                                  will crash */
+                                                  NULL means any use before m68k_ip_begin()
+                                                  will crash */
 
 \f
 /*
- *             m 6 8 _ i p ( )
+ *             m 6 8 _ i p ( )
  *
  * This converts a string into a 68k instruction.
  * The string must be a bare single instruction in sun format
@@ -1009,1122 +1333,1365 @@ static struct hash_control*   op_hash = NULL;       /* handle of the OPCODE hash table
  * 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 m86_ip_begin() once and m86_ip_end() never before using
+ * 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
-m68_ip (instring)
-char   *instring;
+void m68k_ip (instring)
+     char *instring;
 {
-       register char *p;
-       register struct m68k_op *opP;
-       register struct m68_incant *opcode;
-       register char *s;
-       register int tmpreg,
-               baseo,
-               outro,
-               nextword;
-       int     siz1,
-               siz2;
-       char    c;
-       int     losing;
-       int     opsfound;
-       char    *crack_operand();
-       LITTLENUM_TYPE words[6];
-       LITTLENUM_TYPE *wordp;
-
-       if (*instring == ' ')
-               instring++;                     /* skip leading whitespace */
+  register char *p;
+  register struct m68k_op *opP;
+  register struct m68k_incant *opcode;
+  register char *s;
+  register int tmpreg = 0, baseo = 0, outro = 0, nextword;
+  char *pdot, *pdotmove;
+  int siz1, siz2;
+  char c;
+  int  losing;
+  int  opsfound;
+  char *crack_operand();
+  LITTLENUM_TYPE words[6];
+  LITTLENUM_TYPE *wordp;
+  unsigned long ok_arch = 0;
+
+  if (*instring == ' ')
+    instring++;                        /* skip leading whitespace */
 
   /* Scan up to end of operation-code, which MUST end in end-of-string
      or exactly 1 space. */
-       for (p = instring; *p != '\0'; p++)
-               if (*p == ' ')
-                       break;
-
-
-       if (p == instring) {
-               the_ins.error = "No operator";
-               the_ins.opcode[0] = NULL;
-               /* the_ins.numo=1; */
-               return;
-       }
+  pdot = 0;
+  for (p = instring; *p != '\0'; p++) {
+    if (*p == ' ')
+      break;
+    if (*p == '.')
+      pdot = p;
+  }
+
+  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. */   
-       c = *p;
-       *p = '\0';
-       opcode = (struct m68_incant *)hash_find (op_hash, instring);
-       *p = c;
-
-       if (opcode == NULL) {
-               the_ins.error = "Unknown operator";
-               the_ins.opcode[0] = NULL;
-               /* the_ins.numo=1; */
-               return;
-       }
+     look it up in the hash table, then fix it back.
+     Remove a dot, first, since the opcode tables have none.  */
+  if (pdot != NULL) {
+    for (pdotmove=pdot; pdotmove<p; pdotmove++)
+      *pdotmove=pdotmove[1];
+    p--;
+  }
+
+  c = *p;
+  *p = '\0';
+  opcode = (struct m68k_incant *)hash_find (op_hash, instring);
+  *p = c;
+
+  if (pdot != NULL) {
+    for (pdotmove=p; pdotmove>pdot; pdotmove--)
+      *pdotmove=pdotmove[-1];
+    *pdot='.';
+    ++p;
+  }
+
+  if (opcode == NULL) {
+    the_ins.error = "Unknown operator";
+    the_ins.opcode[0] = NULL;
+    /* the_ins.numo=1; */
+    return;
+  }
 
   /* found a legitimate opcode, start matching operands */
-       for(opP= &the_ins.operands[0];*p;opP++) {
-               p = crack_operand (p, opP);
-               if(opP->error) {
-                       the_ins.error=opP->error;
-                       return;
-               }
-       }
+  while (*p == ' ') ++p;
 
-       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 */
-       if(opcode->m_operands[0]=='I') {
-               int     n;
 
-               for(n=opsfound;n>0;--n)
-                       the_ins.operands[n]=the_ins.operands[n-1];
+   if (opcode->m_operands == 0) {
+     char *old = input_line_pointer;
+     *old = '\n';
+     input_line_pointer = p;
+     /* Ahh - it's a motorola style psuedo op */
+     mote_pseudo_table[opcode->m_opnum].poc_handler
+      ( mote_pseudo_table[opcode->m_opnum].poc_val);
+     input_line_pointer = old;
+     *old = 0;
 
-               /* bcopy((char *)(&the_ins.operands[0]),(char *)(&the_ins.operands[1]),opsfound*sizeof(the_ins.operands[0])); */
-               bzero((char *)(&the_ins.operands[0]),sizeof(the_ins.operands[0]));
-               the_ins.operands[0].mode=MSCR;
-               the_ins.operands[0].reg=COPNUM;         /* COP #1 */
-               opsfound++;
-       }
-               /* We've got the operands.  Find an opcode that'll
-                  accept them */
-       for(losing=0;;) {
-               if(opsfound!=opcode->m_opnum)
-                       losing++;
-               else 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:
-                                  non-alpha first, then alpha by letter.  lower-case goes directly
-                                  before uppercase counterpart. */
-                               /* Code with multiple case ...: gets sorted by the lowest case ...
-                                  it belongs to.  I hope this makes sense. */
-                       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++;
-                               break;
+     return;
+   }
 
-                       case '#':
-                               if(opP->mode!=IMMED)
-                                       losing++;
-                               else {
-                                       long t;
-
-                                       t=get_num(opP->con1,80);
-                                       if(s[1]=='b' && !isbyte(t))
-                                               losing++;
-                                       else if(s[1]=='w' && !isword(t))
-                                               losing++;
-                               }
-                               break;
-
-                       case '^':
-                       case 'T':
-                               if(opP->mode!=IMMED)
-                                       losing++;
-                               break;
-
-                       case '$':
-                               if(opP->mode==MSCR || opP->mode==AREG ||
- opP->mode==IMMED || opP->reg==PC || opP->reg==ZPC || opP->mode==REGLST)
-                                       losing++;
-                               break;
-
-                       case '%':
-                               if(opP->mode==MSCR || opP->reg==PC ||
- opP->reg==ZPC || opP->mode==REGLST)
-                                       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++;
-                               break;
-
-                       case '*':
-                               if(opP->mode==MSCR || opP->mode==REGLST)
-                                       losing++;
-                               break;
-
-                       case '+':
-                               if(opP->mode!=AINC)
-                                       losing++;
-                               break;
-
-                       case '-':
-                               if(opP->mode!=ADEC)
-                                       losing++;
-                               break;
-
-                       case '/':
-                               if(opP->mode==MSCR || opP->mode==AREG ||
- opP->mode==AINC || opP->mode==ADEC || opP->mode==IMMED || opP->mode==REGLST)
-                                       losing++;
-                               break;
-
-                       case ';':
-                               if(opP->mode==MSCR || opP->mode==AREG || opP->mode==REGLST)
-                                       losing++;
-                               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++;
-                               break;
-
-                       case '@':
-                               if(opP->mode==MSCR || opP->mode==AREG ||
- opP->mode==IMMED || opP->mode==REGLST)
-                                       losing++;
-                               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++;
-                               break;
-
-                       case 'A':
-                               if(opP->mode!=AREG)
-                                       losing++;
-                               break;
-
-                       case 'B':       /* FOO */
-                               if(opP->mode!=ABSL)
-                                       losing++;
-                               break;
-
-                       case 'C':
-                               if(opP->mode!=MSCR || 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]!=')'))
-                                       losing++;
-                               break;
-
-                       case 'D':
-                               if(opP->mode!=DREG)
-                                       losing++;
-                               break;
-
-                       case 'F':
-                               if(opP->mode!=MSCR || opP->reg<(FPREG+0) || opP->reg>(FPREG+7))
-                                       losing++;
-                               break;
+  for(opP = &the_ins.operands[0]; *p; opP++) {
 
-                       case 'I':
-                               if(opP->mode!=MSCR || opP->reg<COPNUM ||
- opP->reg>=COPNUM+7)
-                                       losing++;
-                               break;
-
-                       case 'J':
-                               if(opP->mode!=MSCR || opP->reg<USP || opP->reg>MSP)
-                                       losing++;
-                               break;
-
-                       case 'k':
-                               if(opP->mode!=IMMED)
-                                       losing++;
-                               break;
-
-                       case 'l':
-                       case 'L':
-                               if(opP->mode==DREG || opP->mode==AREG || opP->mode==FPREG) {
-                                       if(s[1]=='8')
-                                               losing++;
-                                       else {
-                                               opP->mode=REGLST;
-                                               opP->reg=1<<(opP->reg-DATA);
-                                       }
-                               } else if(opP->mode!=REGLST) {
-                                       losing++;
-                               } else if(s[1]=='8' && opP->reg&0x0FFffFF)
-                                       losing++;
-                               else if(s[1]=='3' && opP->reg&0x7000000)
-                                       losing++;
-                               break;
-
-                       case 'M':
-                               if(opP->mode!=IMMED)
-                                       losing++;
-                               else {
-                                       long t;
-
-                                       t=get_num(opP->con1,80);
-                                       if(!issbyte(t) || isvar(opP->con1))
-                                               losing++;
-                               }
-                               break;
-
-                       case 'O':
-                               if(opP->mode!=DREG && opP->mode!=IMMED)
-                                       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++;
-                               }
-                               break;
-
-                       case 'R':
-                               if(opP->mode!=DREG && opP->mode!=AREG)
-                                       losing++;
-                               break;
-
-                       case 's':
-                               if(opP->mode!=MSCR || !(opP->reg==FPI || opP->reg==FPS || opP->reg==FPC))
-                                       losing++;
-                               break;
-
-                       case 'S':
-                               if(opP->mode!=MSCR || opP->reg!=SR)
-                                       losing++;
-                               break;
-
-                       case 'U':
-                               if(opP->mode!=MSCR || opP->reg!=USP)
-                                       losing++;
-                               break;
-
-                       /* JF these are out of order.  We could put them
-                          in order if we were willing to put up with
-                          bunches of #ifdef m68851s in the code */
-#ifdef m68851
-                       /* Memory addressing mode used by pflushr */
-                       case '|':
-                               if(opP->mode==MSCR || opP->mode==DREG ||
- opP->mode==AREG || opP->mode==REGLST)
-                                       losing++;
-                               break;
-
-                       case 'f':
-                               if (opP->mode != MSCR || (opP->reg != SFC && opP->reg != DFC))
-                                       losing++;
-                               break;
-
-                       case 'P':
-                               if (opP->mode != MSCR || (opP->reg != TC && opP->reg != CAL &&
-                                   opP->reg != VAL && opP->reg != SCC && opP->reg != AC))
-                                       losing++;
-                               break;
-
-                       case 'V':
-                               if (opP->reg != VAL)
-                                       losing++;
-                               break;
-
-                       case 'W':
-                               if (opP->mode != MSCR || (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)))
-                                       losing++;
-                               break;
-
-                       case 'Y':
-                               if (opP->reg != PSR)
-                                       losing++;
-                               break;
+    p = crack_operand(p, opP);
 
-                       case 'Z':
-                               if (opP->reg != PCSR)
-                                       losing++;
-                               break;
-#endif
-                       default:
-                               as_fatal("Internal error:  Operand mode %c unknown in line %s of file \"%s\"",
-                                        *s, __LINE__, __FILE__);
-                       }
-               }
-               if(!losing)
-                       break;
-               opcode=opcode->m_next;
-               if(!opcode) {           /* Fell off the end */
-                       the_ins.error="instruction/operands mismatch";
-                       return;
-               }
-               losing=0;
-       }
-       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);
-
-       for(s=the_ins.args,opP= &the_ins.operands[0];*s;s+=2,opP++) {
-                       /* This switch is a doozy.
-                          What the first step; its a big one! */
-               switch(s[0]) {
-
-               case '*':
-               case '~':
-               case '%':
-               case ';':
-               case '@':
-               case '!':
-               case '&':
-               case '$':
-               case '?':
-               case '/':
-#ifdef m68851
-               case '|':
-#endif
-                       switch(opP->mode) {
-                       case IMMED:
-                               tmpreg=0x3c;    /* 7.4 */
-                               if (strchr("bwl",s[1])) nextword=get_num(opP->con1,80);
-                               else nextword=nextword=get_num(opP->con1,0);
-                               if(isvar(opP->con1))
-                                       add_fix(s[1],opP->con1,0);
-                               switch(s[1]) {
-                               case 'b':
-                                       if(!isbyte(nextword))
-                                               opP->error="operand out of range";
-                                       addword(nextword);
-                                       baseo=0;
-                                       break;
-                               case 'w':
-                                       if(!isword(nextword))
-                                               opP->error="operand out of range";
-                                       addword(nextword);
-                                       baseo=0;
-                                       break;
-                               case 'l':
-                                       addword(nextword>>16);
-                                       addword(nextword);
-                                       baseo=0;
-                                       break;
-
-                               case 'f':
-                                       baseo=2;
-                                       outro=8;
-                                       break;
-                               case 'F':
-                                       baseo=4;
-                                       outro=11;
-                                       break;
-                               case 'x':
-                                       baseo=6;
-                                       outro=15;
-                                       break;
-                               case 'p':
-                                       baseo=6;
-                                       outro= -1;
-                                       break;
-                               default:
-                                       as_fatal("Internal error:  Can't decode %c%c in line %s of file \"%s\"",
-                                                *s, s[1], __LINE__, __FILE__);
-                               }
-                               if(!baseo)
-                                       break;
-
-                               /* We gotta put out some float */
-                               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 */
-                               if(offs(opP->con1)>0) {
-                                       as_warn("Bignum assumed to be binary bit-pattern");
-                                       if(offs(opP->con1)>baseo) {
-                                               as_warn("Bignum too big for %c format; truncated",s[1]);
-                                               offs(opP->con1)=baseo;
-                                       }
-                                       baseo-=offs(opP->con1);
-                                       for(wordp=generic_bignum+offs(opP->con1)-1;offs(opP->con1)--;--wordp)
-                                               addword(*wordp);
-                                       while(baseo--)
-                                               addword(0);
-                                       break;
-                               }
-                               gen_to_words(words,baseo,(long)outro);
-                               for (wordp=words;baseo--;wordp++)
-                                       addword(*wordp);
-                               break;
-                       case DREG:
-                               tmpreg=opP->reg-DATA; /* 0.dreg */
-                               break;
-                       case AREG:
-                               tmpreg=0x08+opP->reg-ADDR; /* 1.areg */
-                               break;
-                       case AINDR:
-                               tmpreg=0x10+opP->reg-ADDR; /* 2.areg */
-                               break;
-                       case ADEC:
-                               tmpreg=0x20+opP->reg-ADDR; /* 4.areg */
-                               break;
-                       case AINC:
-                               tmpreg=0x18+opP->reg-ADDR; /* 3.areg */
-                               break;
-                       case AOFF:
-
-                               nextword=get_num(opP->con1,80);
-                               /* Force into index mode.  Hope this works */
-
-                               /* We do the first bit for 32-bit displacements,
-                                  and the second bit for 16 bit ones.  It is
-                                  possible that we should make the default be
-                                  WORD instead of LONG, but I think that'd
-                                  break GCC, so we put up with a little
-                                  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))) {
-
-                                       if(opP->reg==PC)
-                                               tmpreg=0x3B;    /* 7.3 */
-                                       else
-                                               tmpreg=0x30+opP->reg-ADDR;      /* 6.areg */
-                                       if(isvar(opP->con1)) {
-                                               if(opP->reg==PC) {
-                                                      add_frag(adds(opP->con1),
-                                                        offs(opP->con1),
-                                                        TAB(PCLEA,SZ_UNDEF));
-                                                       break;
-                                               } else {
-                                                       addword(0x0170);
-                                                       add_fix('l',opP->con1,1);
-                                               }
-                                       } else
-                                               addword(0x0170);
-                                       addword(nextword>>16);
-                               } else {
-                                       if(opP->reg==PC)
-                                               tmpreg=0x3A; /* 7.2 */
-                                       else
-                                               tmpreg=0x28+opP->reg-ADDR; /* 5.areg */
-
-                                       if(isvar(opP->con1)) {
-                                               if(opP->reg==PC) {
-                                                       add_fix('w',opP->con1,1);
-                                               } else
-                                                       add_fix('w',opP->con1,0);
-                                               }
-                               }
-                               addword(nextword);
-                               break;
-                       case AINDX:
-                       case APODX:
-                       case AMIND:
-                       case APRDX:
-                               nextword=0;
-                               baseo=get_num(opP->con1,80);
-                               outro=get_num(opP->con2,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 */
-                                       if(opP->reg==ZPC)
-                                               nextword|=0x80;
-                               } else if(opP->reg==FAIL) {
-                                       nextword|=0x80;
-                                       tmpreg=0x30;    /* 6.garbage */
-                               } else tmpreg=0x30+opP->reg-ADDR; /* 6.areg */
-
-                               siz1= (opP->con1) ? opP->con1->e_siz : 0;
-                               siz2= (opP->con2) ? opP->con2->e_siz : 0;
-
-                                       /* Index register stuff */
-                               if(opP->ireg>=DATA+0 && opP->ireg<=ADDR+7) {
-                                       nextword|=(opP->ireg-DATA)<<12;
-
-                                       if(opP->isiz==0 || opP->isiz==3)
-                                               nextword|=0x800;
-                                       switch(opP->imul) {
-                                       case 1: break;
-                                       case 2: nextword|=0x200; break;
-                                       case 4: nextword|=0x400; break;
-                                       case 8: nextword|=0x600; break;
-                                       default: 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)))) {
-                                               nextword +=baseo&0xff;
-                                               addword(nextword);
-                                               if(isvar(opP->con1))
-                                                       add_fix('B',opP->con1,0);
-                                               break;
-                                       }
-                               } else
-                                       nextword|=0x40; /* No index reg */
-
-                                       /* It aint simple */
-                               nextword|=0x100;
-                                       /* If the guy specified a width, we assume that
-                                          it is wide enough.  Maybe it isn't.  Ifso, we lose
-                                        */
-                               switch(siz1) {
-                               case 0:
-                                       if(isvar(opP->con1) || !issword(baseo)) {
-                                               siz1=3;
-                                               nextword|=0x30;
-                                       } else if(baseo==0)
-                                               nextword|=0x10;
-                                       else {  
-                                               nextword|=0x20;
-                                               siz1=2;
-                                       }
-                                       break;
-                               case 1:
-                                       as_warn("Byte dispacement won't work.  Defaulting to :w");
-                               case 2:
-                                       nextword|=0x20;
-                                       break;
-                               case 3:
-                                       nextword|=0x30;
-                                       break;
-                               }
-
-                                       /* Figure out innner displacement stuff */
-                               if(opP->mode!=AINDX) {
-                                       switch(siz2) {
-                                       case 0:
-                                               if(isvar(opP->con2) || !issword(outro)) {
-                                                       siz2=3;
-                                                       nextword|=0x3;
-                                               } else if(outro==0)
-                                                       nextword|=0x1;
-                                               else {  
-                                                       nextword|=0x2;
-                                                       siz2=2;
-                                               }
-                                               break;
-                                       case 1:
-                                               as_warn("Byte dispacement won't work.  Defaulting to :w");
-                                       case 2:
-                                               nextword|=0x2;
-                                               break;
-                                       case 3:
-                                               nextword|=0x3;
-                                               break;
-                                       }
-                                       if(opP->mode==APODX) nextword|=0x04;
-                                       else if(opP->mode==AMIND) nextword|=0x40;
-                               }
-                               addword(nextword);
-
-                               if(isvar(opP->con1)) {
-                                       if(opP->reg==PC || opP->reg==ZPC) {
-                                               add_fix(siz1==3 ? 'l' : 'w',opP->con1,1);
-                                               opP->con1->e_exp.X_add_number+=6;
-                                       } else
-                                               add_fix(siz1==3 ? 'l' : 'w',opP->con1,0);
-                               }
-                               if(siz1==3)
-                                       addword(baseo>>16);
-                               if(siz1)
-                                       addword(baseo);
-
-                               if(isvar(opP->con2)) {
-                                       if(opP->reg==PC || opP->reg==ZPC) {
-                                               add_fix(siz2==3 ? 'l' : 'w',opP->con2,1);
-                                               opP->con1->e_exp.X_add_number+=6;
-                                       } else
-                                               add_fix(siz2==3 ? 'l' : 'w',opP->con2,0);
-                               }
-                               if(siz2==3)
-                                       addword(outro>>16);
-                               if(siz2)
-                                       addword(outro);
+    if (opP->error) {
+      the_ins.error=opP->error;
+      return;
+    }
+  }
+
+  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 */
+  if (opcode->m_operands[0]=='I') {
+    int        n;
+
+    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 */
+    opsfound++;
+  }
+
+  /* We've got the operands.  Find an opcode that'll accept them */
+  for (losing = 0; ; ) {
+    /* if we didn't get the right number of ops,
+       or we have no common model with this pattern
+       then reject this pattern. */
+
+    if (opsfound != opcode->m_opnum
+       || ((opcode->m_arch & current_architecture) == 0))
+      {
+       ++losing;
+       ok_arch |= opcode->m_arch;
+      }
+    else {
+      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:
+          non-alpha first, then alpha by letter.  lower-case goes directly
+          before uppercase counterpart. */
+       /* Code with multiple case ...: gets sorted by the lowest case ...
+          it belongs to.  I hope this makes sense. */
+       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++;
+         break;
+
+       case '`':
+         switch (opP->mode) {
+         case MSCR: case IMMED: case DREG: case AREG:
+         case AINC: case REGLST: case AINDR:
+           losing++;
+         }
+         break;
+
+       case '#':
+         if(opP->mode!=IMMED)
+           losing++;
+         else {
+           long t;
+
+           t=get_num(opP->con1,80);
+           if(s[1]=='b' && !isbyte(t))
+             losing++;
+           else if(s[1]=='w' && !isword(t))
+             losing++;
+         }
+         break;
+
+       case '^':
+       case 'T':
+         if(opP->mode!=IMMED)
+           losing++;
+         break;
+
+       case '$':
+         if(opP->mode==MSCR || opP->mode==AREG ||
+            opP->mode==IMMED || opP->reg==PC || opP->reg==ZPC || opP->mode==REGLST)
+           losing++;
+         break;
+
+       case '%':
+         if(opP->mode==MSCR || opP->reg==PC ||
+            opP->reg==ZPC || opP->mode==REGLST)
+           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++;
+         break;
+
+       case '*':
+         if(opP->mode==MSCR || opP->mode==REGLST)
+           losing++;
+         break;
 
-                               break;
+       case '+':
+         if(opP->mode!=AINC)
+           losing++;
+         break;
 
-                       case ABSL:
-                               nextword=get_num(opP->con1,80);
-                               switch(opP->con1->e_siz) {
-                               default:
-                                       as_warn("Unknown size for absolute reference");
-                               case 0:
-                                       if(!isvar(opP->con1) && issword(offs(opP->con1))) {
-                                               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)==SEG_TEXT &&
-                                          now_seg==SEG_TEXT &&
-                                          flagseen['m']==0 &&
-                                           !strchr("~%&$?", s[0])) {
-                                               tmpreg=0x3A; /* 7.2 */
-                                               add_frag(adds(opP->con1),
-                                                        offs(opP->con1),
-                                                        TAB(PCREL,SZ_UNDEF));
-                                               break;
-                                       }
-                               case 3:         /* Fall through into long */
-                                       if(isvar(opP->con1))
-                                               add_fix('l',opP->con1,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);
-
-                                       tmpreg=0x38;    /* 7.0 mode */
-                                       addword(nextword);
-                                       break;
-                               }
-                               break;
-                       case MSCR:
-                       default:
-                               as_bad("unknown/incorrect operand");
-                               /* abort(); */
-                       }
-                       install_gen_operand(s[1],tmpreg);
-                       break;
+       case '-':
+         if(opP->mode!=ADEC)
+           losing++;
+         break;
+
+       case '/':
+         if(opP->mode==MSCR || opP->mode==AREG ||
+            opP->mode==AINC || opP->mode==ADEC || opP->mode==IMMED || opP->mode==REGLST)
+           losing++;
+         break;
+
+       case ';':
+         if(opP->mode==MSCR || opP->mode==AREG || opP->mode==REGLST)
+           losing++;
+         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++;
+         break;
+
+       case '@':
+         if(opP->mode==MSCR || opP->mode==AREG ||
+            opP->mode==IMMED || opP->mode==REGLST)
+           losing++;
+         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++;
+         break;
 
-               case '#':
-               case '^':
-                       switch(s[1]) {  /* JF: I hate floating point! */
-                       case 'j':
-                               tmpreg=70;
-                               break;
-                       case '8':
-                               tmpreg=20;
-                               break;
-                       case 'C':
-                               tmpreg=50;
-                               break;
-                       case '3':
-                       default:
-                               tmpreg=80;
-                               break;
-                       }
-                       tmpreg=get_num(opP->con1,tmpreg);
-                       if(isvar(opP->con1))
-                               add_fix(s[1],opP->con1,0);
-                       switch(s[1]) {
-                       case 'b':       /* Danger:  These do no check for
-                                          certain types of overflow.
-                                          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;
-                               break;
-                       case 'w':
-                               if(!isword(tmpreg))
-                                       opP->error="out of range";
-                               insop(tmpreg);
-                               if(isvar(opP->con1))
-                                       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))
-                                       the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2;
-                               break;
-                       case '3':
-                               tmpreg&=0xFF;
-                       case '8':
-                       case 'C':
-                               install_operand(s[1],tmpreg);
-                               break;
-                       default:
-                               as_fatal("Internal error:  Unknown mode #%c in line %s of file \"%s\"", s[1], __LINE__, __FILE__);
-                       }
-                       break;
+       case '3':
+         if (opP->mode != MSCR || (opP->reg != TT0 && opP->reg != TT1))
+           losing++;
+         break;
+
+       case 'A':
+         if(opP->mode!=AREG)
+           losing++;
+         break;
+       case 'a':
+         if (opP->mode != AINDR) {
+           ++losing;
+         } /* if not address register indirect */
+         break;
+       case 'B':               /* FOO */
+         if(opP->mode!=ABSL || (flagseen['S'] && instring[0] == 'j'
+                                && instring[1] == 'b'
+                                && instring[2] == 's'
+                                && instring[3] == 'r'))
+           losing++;
+         break;
 
-               case '+':
-               case '-':
-               case 'A':
-                       install_operand(s[1],opP->reg-ADDR);
-                       break;
+       case 'C':
+         if(opP->mode!=MSCR || opP->reg!=CCR)
+           losing++;
+         break;
 
-               case 'B':
-                       tmpreg=get_num(opP->con1,80);
-                       switch(s[1]) {
-                       case 'B':
-                               /* Needs no offsetting */
-                               add_fix('B',opP->con1,1);
-                               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);
-                               addword(0);
-                               break;
-                       case 'L':
-                       long_branch:
-                               if(flagseen['m'])       /* 68000 or 010 */
-                                       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);
-                               addword(0);
-                               addword(0);
-                               break;
-                       case 'g':
-                               if(subs(opP->con1))      /* We can't relax it */
-                                       goto long_branch;
-
-                               /* 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(
-                                (flagseen['m'] || (0==adds(opP->con1)))
-                                && (the_ins.opcode[0] >= 0x6200) &&
-                                   (the_ins.opcode[0] <= 0x6f00)) {
-                                 add_frag(adds(opP->con1),offs(opP->con1),TAB(BCC68000,SZ_UNDEF));
-                               } else {
-                                 add_frag(adds(opP->con1),offs(opP->con1),TAB(BRANCH,SZ_UNDEF));
-                               }
-                               break;
-                       case 'w':
-                               if(isvar(opP->con1)) {
-                                   /* check for DBcc instruction */
-                                       if ((the_ins.opcode[0] & 0xf0f8) ==0x50c8) {
-                                           /* size varies if patch */
-                                           /* needed for long form */
-                                               add_frag(adds(opP->con1),offs(opP->con1),TAB(DBCC,SZ_UNDEF));
-                                               break;
-                                       }
-
-                                               /* Don't ask! */
-                                       opP->con1->e_exp.X_add_number+=2;
-                                       add_fix('w',opP->con1,1);
-                               }
-                               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);
-                               addword(0);
-                               addword(0);
-                               break;
-                       case 'c':               /* Var size Coprocesssor branches */
-                               if(subs(opP->con1)) {
-                                       add_fix('l',opP->con1,1);
-                                       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 {
-                                       /* add_frag((symbolS *)0,offs(opP->con1),TAB(FBRANCH,SHORT)); */
-                                       the_ins.opcode[the_ins.numo-1]|=0x40;
-                                       add_fix('l',opP->con1,1);
-                                       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__);
-                       }
-                       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]!=')'))
+           losing++;
+         break;
 
-               case 'C':               /* Ignore it */
-                       break;
+       case 'D':
+         if(opP->mode!=DREG)
+           losing++;
+         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);
-                       if(!issword(tmpreg)) {
-                               as_warn("Expression out of range, using 0");
-                               tmpreg=0;
-                       }
-                       addword(tmpreg);
-                       break;
+       case 'F':
+         if(opP->mode!=MSCR || opP->reg<(FPREG+0) || opP->reg>(FPREG+7))
+           losing++;
+         break;
+
+       case 'I':
+         if(opP->mode!=MSCR || opP->reg<COPNUM ||
+            opP->reg>=COPNUM+7)
+           losing++;
+         break;
+
+       case 'J':
+         if (opP->mode != MSCR
+             || 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)) {
+           losing++;
+         } /* doesn't cut it */
+         break;
 
-               case 'D':
-                       install_operand(s[1],opP->reg-DATA);
-                       break;
+       case 'k':
+         if(opP->mode!=IMMED)
+           losing++;
+         break;
 
-               case 'F':
-                       install_operand(s[1],opP->reg-FPREG);
-                       break;
+       case 'l':
+       case 'L':
+         if(opP->mode==DREG || opP->mode==AREG || opP->mode==FPREG) {
+           if(s[1]=='8')
+             losing++;
+           else {
+             opP->mode=REGLST;
+             opP->reg=1<<(opP->reg-DATA);
+           }
+         } else if(opP->mode!=REGLST) {
+           losing++;
+         } else if(s[1]=='8' && opP->reg&0x0FFffFF)
+           losing++;
+         else if(s[1]=='3' && opP->reg&0x7000000)
+           losing++;
+         break;
+
+       case 'M':
+         if(opP->mode!=IMMED)
+           losing++;
+         else {
+           long t;
+
+           t=get_num(opP->con1,80);
+           if(!issbyte(t) || isvar(opP->con1))
+             losing++;
+         }
+         break;
+
+       case 'O':
+         if(opP->mode!=DREG && opP->mode!=IMMED)
+           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++;
+         }
+         break;
 
-               case 'I':
-                       tmpreg=1+opP->reg-COPNUM;
-                       if(tmpreg==8)
-                               tmpreg=0;
-                       install_operand(s[1],tmpreg);
-                       break;
+       case 'R':
+         if(opP->mode!=DREG && opP->mode!=AREG)
+           losing++;
+         break;
 
-               case 'J':               /* JF foo */
-                       switch(opP->reg) {
-                       case SFC:
-                               tmpreg=0;
-                               break;
-                       case DFC:
-                               tmpreg=0x001;
-                               break;
-                       case CACR:
-                               tmpreg=0x002;
-                               break;
-                       case USP:
-                               tmpreg=0x800;
-                               break;
-                       case VBR:
-                               tmpreg=0x801;
-                               break;
-                       case CAAR:
-                               tmpreg=0x802;
-                               break;
-                       case MSP:
-                               tmpreg=0x803;
-                               break;
-                       case ISP:
-                               tmpreg=0x804;
-                               break;
-                       default:
-                               abort();
-                       }
-                       install_operand(s[1],tmpreg);
-                       break;
+       case 'r':
+         if (opP->mode!=AINDR && opP->mode!=DINDR)
+           losing++;
+         break;
 
-               case 'k':
-                       tmpreg=get_num(opP->con1,55);
-                       install_operand(s[1],tmpreg&0x7f);
-                       break;
+       case 's':
+         if(opP->mode!=MSCR || !(opP->reg==FPI || opP->reg==FPS || opP->reg==FPC))
+           losing++;
+         break;
 
-               case 'l':
-                       tmpreg=opP->reg;
-                       if(s[1]=='w') {
-                               if(tmpreg&0x7FF0000)
-                                       as_bad("Floating point register in register list");
-                               insop(reverse_16_bits(tmpreg));
-                       } else {
-                               if(tmpreg&0x700FFFF)
-                                       as_bad("Wrong register in floating-point reglist");
-                               install_operand(s[1],reverse_8_bits(tmpreg>>16));
-                       }
-                       break;
+       case 'S':
+         if(opP->mode!=MSCR || opP->reg!=SR)
+           losing++;
+         break;
 
-               case 'L':
-                       tmpreg=opP->reg;
-                       if(s[1]=='w') {
-                               if(tmpreg&0x7FF0000)
-                                       as_bad("Floating point register in register list");
-                               insop(tmpreg);
-                       } else if(s[1]=='8') {
-                               if(tmpreg&0x0FFFFFF)
-                                       as_bad("incorrect register in reglist");
-                               install_operand(s[1],tmpreg>>24);
-                       } else {
-                               if(tmpreg&0x700FFFF)
-                                       as_bad("wrong register in floating-point reglist");
-                               else
-                                       install_operand(s[1],tmpreg>>16);
-                       }
-                       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++;
+           }
+         break;
+
+       case 'U':
+         if(opP->mode!=MSCR || opP->reg!=USP)
+           losing++;
+         break;
+
+         /* JF these are out of order.  We could put them
+            in order if we were willing to put up with
+            bunches of #ifdef m68851s in the code.
+
+            Don't forget that you need these operands
+            to use 68030 MMU instructions.  */
+#ifndef NO_68851
+         /* Memory addressing mode used by pflushr */
+       case '|':
+         if(opP->mode==MSCR || opP->mode==DREG ||
+            opP->mode==AREG || opP->mode==REGLST)
+           losing++;
+         break;
 
-               case 'M':
-                       install_operand(s[1],get_num(opP->con1,60));
-                       break;
+       case 'f':
+         if (opP->mode != MSCR || (opP->reg != SFC && opP->reg != DFC))
+           losing++;
+         break;
 
-               case 'O':
-                       tmpreg= (opP->mode==DREG)
-                               ? 0x20+opP->reg-DATA
-                               : (get_num(opP->con1,40)&0x1F);
-                       install_operand(s[1],tmpreg);
-                       break;
+       case 'P':
+         if (opP->mode != MSCR
+             || (opP->reg != TC && opP->reg != CAL
+                 && opP->reg != VAL && opP->reg != SCC && opP->reg != AC))
+           losing++;
+         break;
 
-               case 'Q':
-                       tmpreg=get_num(opP->con1,10);
-                       if(tmpreg==8)
-                               tmpreg=0;
-                       install_operand(s[1],tmpreg);
-                       break;
+       case 'V':
+         if (opP->reg != VAL)
+           losing++;
+         break;
 
-               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 */
-                       install_operand(s[1],opP->reg-DATA);
-                       break;
+       case 'W':
+         if (opP->mode != MSCR
+             || (opP->reg != DRP && opP->reg != SRP
+                 && opP->reg != CRP))
+           losing++;
+         break;
 
-               case 's':
-                       if(opP->reg==FPI) tmpreg=0x1;
-                       else if(opP->reg==FPS) tmpreg=0x2;
-                       else if(opP->reg==FPC) tmpreg=0x4;
-                       else abort();
-                       install_operand(s[1],tmpreg);
-                       break;
+       case 'X':
+         if (opP->mode != MSCR ||
+             (!(opP->reg >= BAD && opP->reg <= BAD+7) &&
+              !(opP->reg >= BAC && opP->reg <= BAC+7)))
+           losing++;
+         break;
+
+       case 'Y':
+         if (opP->reg != PSR)
+           losing++;
+         break;
+
+       case 'Z':
+         if (opP->reg != PCSR)
+           losing++;
+         break;
+#endif
+       case 'c':
+         if (opP->reg != NC
+             && opP->reg != IC
+             && opP->reg != DC
+             && opP->reg != BC) {
+           losing++;
+         } /* not a cache specifier. */
+         break;
+
+       case '_':
+         if (opP->mode != ABSL) {
+           ++losing;
+         } /* not absolute */
+         break;
 
-               case 'S':       /* Ignore it */
-                       break;
+       default:
+         as_fatal("Internal error:  Operand mode %c unknown in line %d of file \"%s\"",
+                  *s, __LINE__, __FILE__);
+       } /* switch on type of operand */
+
+       if (losing)
+         break;
+      } /* for each operand */
+    } /* if immediately wrong */
+
+    if (!losing) {
+      break;
+    } /* got it. */
+
+    opcode = opcode->m_next;
+
+    if (!opcode) {
+      if (ok_arch
+         && !(ok_arch & current_architecture))
+       {
+         char buf[200], *cp;
+         int len;
+         strcpy (buf, "invalid instruction for this architecture; needs ");
+         cp = buf + strlen (buf);
+         switch (ok_arch)
+           {
+           case mfloat:
+             strcpy (cp, "fpu (68040 or 68881/68882)");
+             break;
+           case mmmu:
+             strcpy (cp, "mmu (68030 or 68851)");
+             break;
+           case m68020up:
+             strcpy (cp, "68020 or higher");
+             break;
+           case m68000up:
+             strcpy (cp, "68000 or higher");
+             break;
+           case m68010up:
+             strcpy (cp, "68010 or higher");
+             break;
+           default:
+             {
+               int got_one = 0, idx;
+               const static struct {
+                 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 (got_one)
+                         {
+                           strcpy (cp, " or ");
+                           cp += strlen (cp);
+                         }
+                       got_one = 1;
+                       strcpy (cp, archs[idx].name);
+                       cp += strlen (cp);
+                     }
+                 }
+             }
+           }
+         len = cp - buf + 1;
+         cp = malloc (len);
+         strcpy (cp, buf);
+         the_ins.error = cp;
+       }
+      else
+       the_ins.error = "operands mismatch";
+      return;
+    } /* Fell off the end */
+
+    losing = 0;
+  }
+
+  /* now assemble it */
+
+  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);
+
+  for (s = the_ins.args, opP = &the_ins.operands[0]; *s; s += 2, opP++) {
+    /* This switch is a doozy.
+       Watch the first step; its a big one! */
+    switch(s[0]) {
+
+    case '*':
+    case '~':
+    case '%':
+    case ';':
+    case '@':
+    case '!':
+    case '&':
+    case '$':
+    case '?':
+    case '/':
+    case '`':
+#ifndef NO_68851
+    case '|':
+#endif
+      switch(opP->mode) {
+      case IMMED:
+       tmpreg=0x3c;            /* 7.4 */
+       if (strchr("bwl",s[1])) nextword=get_num(opP->con1,80);
+       else nextword=nextword=get_num(opP->con1,0);
+       if(isvar(opP->con1))
+         add_fix(s[1],opP->con1,0);
+       switch(s[1]) {
+       case 'b':
+         if(!isbyte(nextword))
+           opP->error="operand out of range";
+         addword(nextword);
+         baseo=0;
+         break;
+       case 'w':
+         if(!isword(nextword))
+           opP->error="operand out of range";
+         addword(nextword);
+         baseo=0;
+         break;
+       case 'l':
+         addword(nextword>>16);
+         addword(nextword);
+         baseo=0;
+         break;
 
-               case 'T':
-                       install_operand(s[1],get_num(opP->con1,30));
-                       break;
+       case 'f':
+         baseo=2;
+         outro=8;
+         break;
+       case 'F':
+         baseo=4;
+         outro=11;
+         break;
+       case 'x':
+         baseo=6;
+         outro=15;
+         break;
+       case 'p':
+         baseo=6;
+         outro= -1;
+         break;
+       default:
+         as_fatal("Internal error:  Can't decode %c%c in line %s of file \"%s\"",
+                  *s, s[1], __LINE__, __FILE__);
+       }
+       if(!baseo)
+         break;
+
+       /* We gotta put out some float */
+       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 */
+       if(offs(opP->con1)>0) {
+         if(offs(opP->con1)>baseo) {
+           as_warn("Bignum too big for %c format; truncated",s[1]);
+           offs(opP->con1)=baseo;
+         }
+         baseo-=offs(opP->con1);
+         for(wordp=generic_bignum+offs(opP->con1)-1;offs(opP->con1)--;--wordp)
+           addword(*wordp);
+         while(baseo--)
+           addword(0);
+         break;
+       }
+       gen_to_words(words,baseo,(long)outro);
+       for (wordp=words;baseo--;wordp++)
+         addword(*wordp);
+       break;
+      case DREG:
+       tmpreg=opP->reg-DATA;   /* 0.dreg */
+       break;
+      case AREG:
+       tmpreg=0x08+opP->reg-ADDR; /* 1.areg */
+       break;
+      case AINDR:
+       tmpreg=0x10+opP->reg-ADDR; /* 2.areg */
+       break;
+      case ADEC:
+       tmpreg=0x20+opP->reg-ADDR; /* 4.areg */
+       break;
+      case AINC:
+       tmpreg=0x18+opP->reg-ADDR; /* 3.areg */
+       break;
+      case AOFF:
+
+       nextword=get_num(opP->con1,80);
+       /* Force into index mode.  Hope this works */
+
+       /* We do the first bit for 32-bit displacements,
+          and the second bit for 16 bit ones.  It is
+          possible that we should make the default be
+          WORD instead of LONG, but I think that'd
+          break GCC, so we put up with a little
+          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))) {
+
+         if(opP->reg==PC)
+           tmpreg=0x3B;                /* 7.3 */
+         else
+           tmpreg=0x30+opP->reg-ADDR; /* 6.areg */
+         if(isvar(opP->con1)) {
+           if(opP->reg==PC) {
+             add_frag(adds(opP->con1),
+                      offs(opP->con1),
+                      TAB(PCLEA,SZ_UNDEF));
+             break;
+           } else {
+             addword(0x0170);
+             add_fix('l',opP->con1,0);
+           }
+         } else
+           addword(0x0170);
+         addword(nextword>>16);
+                  } else {
+                    if(opP->reg==PC)
+                      tmpreg=0x3A;             /* 7.2 */
+                    else
+                      tmpreg=0x28+opP->reg-ADDR; /* 5.areg */
+
+                    if(isvar(opP->con1)) {
+                      if(opP->reg==PC) {
+                        add_fix('w',opP->con1,1);
+                      } else
+                        add_fix('w',opP->con1,0);
+                    }
+                  }
+       addword(nextword);
+       break;
 
-               case 'U':       /* Ignore it */
-                       break;
+      case APODX:
+      case AMIND:
+      case APRDX:
+       know(current_architecture & m68020up);
+       /* intentional fall-through */
+      case AINDX:
+       nextword=0;
+       baseo=get_num(opP->con1,80);
+       outro=get_num(opP->con2,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 */
+         if(opP->reg==ZPC)
+           nextword|=0x80;
+       } else if(opP->reg==FAIL) {
+         nextword|=0x80;
+         tmpreg=0x30;          /* 6.garbage */
+       } else tmpreg=0x30+opP->reg-ADDR; /* 6.areg */
+
+       siz1= (opP->con1) ? opP->con1->e_siz : 0;
+       siz2= (opP->con2) ? opP->con2->e_siz : 0;
+
+       /* Index register stuff */
+       if(opP->ireg>=DATA+0 && opP->ireg<=ADDR+7) {
+         nextword|=(opP->ireg-DATA)<<12;
+
+         if(opP->isiz==0 || opP->isiz==3)
+           nextword|=0x800;
+         switch(opP->imul) {
+         case 1: break;
+         case 2: nextword|=0x200; break;
+         case 4: nextword|=0x400; break;
+         case 8: nextword|=0x600; break;
+         default: as_fatal("failed sanity check.");
+         }
+         /* 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)))) {
+           nextword +=baseo&0xff;
+           addword(nextword);
+           if(isvar(opP->con1))
+             add_fix('B',opP->con1,0);
+           break;
+         }
+       } else
+         nextword|=0x40;               /* No index reg */
+
+       /* It aint simple */
+       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)) {
+           siz1=3;
+           nextword|=0x30;
+         } else if(baseo==0)
+           nextword|=0x10;
+         else {
+           nextword|=0x20;
+           siz1=2;
+         }
+         break;
+       case 1:
+         as_warn("Byte dispacement won't work.  Defaulting to :w");
+       case 2:
+         nextword|=0x20;
+         break;
+       case 3:
+         nextword|=0x30;
+         break;
+       }
 
-#ifdef m68851
-                       /* JF: These are out of order, I fear. */
-               case 'f':
-                       switch (opP->reg) {
-                       case SFC:
-                               tmpreg=0;
-                               break;
-                       case DFC:
-                               tmpreg=1;
-                               break;
-                       default:
-                               abort();
-                       }
-                       install_operand(s[1],tmpreg);
-                       break;
+       /* Figure out innner displacement stuff */
+       if(opP->mode!=AINDX) {
+         switch(siz2) {
+         case 0:
+           if(isvar(opP->con2) || !issword(outro)) {
+             siz2=3;
+             nextword|=0x3;
+           } else if(outro==0)
+             nextword|=0x1;
+           else {
+             nextword|=0x2;
+             siz2=2;
+           }
+           break;
+         case 1:
+           as_warn("Byte dispacement won't work.  Defaulting to :w");
+         case 2:
+           nextword|=0x2;
+           break;
+         case 3:
+           nextword|=0x3;
+           break;
+         }
+         if(opP->mode==APODX) nextword|=0x04;
+         else if(opP->mode==AMIND) nextword|=0x40;
+       }
+       addword(nextword);
+
+       if(isvar(opP->con1)) {
+         if(opP->reg==PC || opP->reg==ZPC) {
+           add_fix(siz1==3 ? 'l' : 'w',opP->con1,1);
+           opP->con1->e_exp.X_add_number+=6;
+         } else
+           add_fix(siz1==3 ? 'l' : 'w',opP->con1,0);
+       }
+       if(siz1==3)
+         addword(baseo>>16);
+       if(siz1)
+         addword(baseo);
+
+       if(isvar(opP->con2)) {
+         if(opP->reg==PC || opP->reg==ZPC) {
+           add_fix(siz2==3 ? 'l' : 'w',opP->con2,1);
+           opP->con1->e_exp.X_add_number+=6;
+         } else
+           add_fix(siz2==3 ? 'l' : 'w',opP->con2,0);
+       }
+       if(siz2==3)
+         addword(outro>>16);
+       if(siz2)
+         addword(outro);
 
-               case 'P':
-                       switch(opP->reg) {
-                       case TC:
-                               tmpreg=0;
-                               break;
-                       case CAL:
-                               tmpreg=4;
-                               break;
-                       case VAL:
-                               tmpreg=5;
-                               break;
-                       case SCC:
-                               tmpreg=6;
-                               break;
-                       case AC:
-                               tmpreg=7;
-                               break;
-                       default:
-                               abort();
-                       }
-                       install_operand(s[1],tmpreg);
-                       break;
+       break;
 
-               case 'V':
-                       if (opP->reg == VAL)
-                               break;
-                       abort();
+      case ABSL:
+       nextword=get_num(opP->con1,80);
+       switch(opP->con1->e_siz) {
+       default:
+         as_warn("Unknown size for absolute reference");
+       case 0:
+         if(!isvar(opP->con1) && issword(offs(opP->con1))) {
+           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) == SEG_TEXT
+            && now_seg == SEG_TEXT
+            && cpu_of_arch(current_architecture) >= m68020
+            && !flagseen['S']
+            && !strchr("~%&$?", s[0])) {
+           tmpreg=0x3A;                /* 7.2 */
+           add_frag(adds(opP->con1),
+                    offs(opP->con1),
+                    TAB(PCREL,SZ_UNDEF));
+           break;
+         }
+       case 3:                 /* Fall through into long */
+         if(isvar(opP->con1))
+           add_fix('l',opP->con1,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);
+
+         tmpreg=0x38;          /* 7.0 mode */
+         addword(nextword);
+         break;
+       }
+       break;
+      case DINDR:
+       as_bad("invalid indirect register");
+       break;
+      case MSCR:
+      default:
+       as_bad("unknown/incorrect operand");
+       /* abort(); */
+      }
+      install_gen_operand(s[1],tmpreg);
+      break;
+
+    case '#':
+    case '^':
+      switch(s[1]) {           /* JF: I hate floating point! */
+      case 'j':
+       tmpreg=70;
+       break;
+      case '8':
+       tmpreg=20;
+       break;
+      case 'C':
+       tmpreg=50;
+       break;
+      case '3':
+      default:
+       tmpreg=80;
+       break;
+      }
+      tmpreg=get_num(opP->con1,tmpreg);
+      if(isvar(opP->con1))
+       add_fix(s[1],opP->con1,0);
+      switch(s[1]) {
+      case 'b':                        /* Danger:  These do no check for
+                                  certain types of overflow.
+                                  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;
+       break;
+      case 'w':
+       if(!isword(tmpreg))
+         opP->error="out of range";
+       insop(tmpreg);
+       if(isvar(opP->con1))
+         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))
+         the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2;
+       break;
+      case '3':
+       tmpreg&=0xFF;
+      case '8':
+      case 'C':
+       install_operand(s[1],tmpreg);
+       break;
+      default:
+       as_fatal("Internal error:  Unknown mode #%c in line %s of file \"%s\"", s[1], __LINE__, __FILE__);
+      }
+      break;
+
+    case '+':
+    case '-':
+    case 'A':
+    case 'a':
+      install_operand(s[1],opP->reg-ADDR);
+      break;
+
+    case 'B':
+      tmpreg=get_num(opP->con1,80);
+      switch(s[1]) {
+      case 'B':
+       /* Needs no offsetting */
+       add_fix('B',opP->con1,1);
+       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);
+       addword(0);
+       break;
+      case 'L':
+      long_branch:
+       if (cpu_of_arch(current_architecture) < m68020) /* 68000 or 010 */
+         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);
+       addword(0);
+       addword(0);
+       break;
+      case 'g':
+       if(subs(opP->con1))     /* We can't relax it */
+         goto long_branch;
+
+       /* 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)))
+           && (the_ins.opcode[0] >= 0x6200)
+           && (the_ins.opcode[0] <= 0x6f00)) {
+         add_frag(adds(opP->con1),offs(opP->con1),TAB(BCC68000,SZ_UNDEF));
+           } else {
+             add_frag(adds(opP->con1),offs(opP->con1),TAB(ABRANCH,SZ_UNDEF));
+           }
+       break;
+      case 'w':
+       if(isvar(opP->con1)) {
+         /* check for DBcc instruction */
+         if ((the_ins.opcode[0] & 0xf0f8) ==0x50c8) {
+           /* size varies if patch */
+           /* needed for long form */
+           add_frag(adds(opP->con1),offs(opP->con1),TAB(DBCC,SZ_UNDEF));
+           break;
+         }
+
+         /* Don't ask! */
+         opP->con1->e_exp.X_add_number+=2;
+         add_fix('w',opP->con1,1);
+       }
+       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);
+       addword(0);
+       addword(0);
+       break;
+      case 'c':                        /* Var size Coprocesssor branches */
+       if(subs(opP->con1)) {
+         add_fix('l',opP->con1,1);
+         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 {
+         /* add_frag((symbolS *)0,offs(opP->con1),TAB(FBRANCH,SHORT)); */
+         the_ins.opcode[the_ins.numo-1]|=0x40;
+         add_fix('l',opP->con1,1);
+         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__);
+      }
+      break;
+
+    case 'C':                  /* Ignore it */
+      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);
+      if(!issword(tmpreg)) {
+       as_warn("Expression out of range, using 0");
+       tmpreg=0;
+      }
+      addword(tmpreg);
+      break;
+
+    case 'D':
+      install_operand(s[1],opP->reg-DATA);
+      break;
+
+    case 'F':
+      install_operand(s[1],opP->reg-FPREG);
+      break;
+
+    case 'I':
+      tmpreg=1+opP->reg-COPNUM;
+      if(tmpreg==8)
+       tmpreg=0;
+      install_operand(s[1],tmpreg);
+      break;
+
+    case 'J':                  /* JF foo */
+      switch(opP->reg) {
+      case SFC:   tmpreg=0x000; break;
+      case DFC:   tmpreg=0x001; break;
+      case CACR:  tmpreg=0x002; break;
+      case TC:    tmpreg=0x003; break;
+      case ITT0:  tmpreg=0x004; break;
+      case ITT1:  tmpreg=0x005; break;
+      case DTT0:  tmpreg=0x006; break;
+      case DTT1:  tmpreg=0x007; break;
+
+      case USP:   tmpreg=0x800; break;
+      case VBR:   tmpreg=0x801; break;
+      case CAAR:  tmpreg=0x802; break;
+      case MSP:   tmpreg=0x803; break;
+      case ISP:   tmpreg=0x804; break;
+      case MMUSR: tmpreg=0x805; break;
+      case URP:   tmpreg=0x806; break;
+      case SRP:   tmpreg=0x807; break;
+      default:
+       as_fatal("failed sanity check.");
+      }
+      install_operand(s[1],tmpreg);
+      break;
+
+    case 'k':
+      tmpreg=get_num(opP->con1,55);
+      install_operand(s[1],tmpreg&0x7f);
+      break;
+
+    case 'l':
+      tmpreg=opP->reg;
+      if(s[1]=='w') {
+       if(tmpreg&0x7FF0000)
+         as_bad("Floating point register in register list");
+       insop(reverse_16_bits(tmpreg));
+      } else {
+       if(tmpreg&0x700FFFF)
+         as_bad("Wrong register in floating-point reglist");
+       install_operand(s[1],reverse_8_bits(tmpreg>>16));
+      }
+      break;
+
+    case 'L':
+      tmpreg=opP->reg;
+      if(s[1]=='w') {
+       if(tmpreg&0x7FF0000)
+         as_bad("Floating point register in register list");
+       insop(tmpreg);
+      } else if(s[1]=='8') {
+       if(tmpreg&0x0FFFFFF)
+         as_bad("incorrect register in reglist");
+       install_operand(s[1],tmpreg>>24);
+      } else {
+       if(tmpreg&0x700FFFF)
+         as_bad("wrong register in floating-point reglist");
+       else
+         install_operand(s[1],tmpreg>>16);
+      }
+      break;
+
+    case 'M':
+      install_operand(s[1],get_num(opP->con1,60));
+      break;
+
+    case 'O':
+      tmpreg= (opP->mode==DREG)
+       ? 0x20+opP->reg-DATA
+         : (get_num(opP->con1,40)&0x1F);
+      install_operand(s[1],tmpreg);
+      break;
+
+    case 'Q':
+      tmpreg=get_num(opP->con1,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 */
+      install_operand(s[1],opP->reg-DATA);
+      break;
+
+    case 's':
+      if(opP->reg==FPI) tmpreg=0x1;
+      else if(opP->reg==FPS) tmpreg=0x2;
+      else if(opP->reg==FPC) tmpreg=0x4;
+      else as_fatal("failed sanity check.");
+      install_operand(s[1],tmpreg);
+      break;
+
+    case 'S':                  /* Ignore it */
+      break;
+
+    case 'T':
+      install_operand(s[1],get_num(opP->con1,30));
+      break;
+
+    case 'U':                  /* Ignore it */
+      break;
+
+    case 'c':
+      switch (opP->reg) {
+      case NC: tmpreg = 0; break;
+      case DC: tmpreg = 1; break;
+      case IC: tmpreg = 2; break;
+      case BC: tmpreg = 3; break;
+      default:
+       as_fatal("failed sanity check");
+      } /* switch on cache token */
+      install_operand(s[1], tmpreg);
+      break;
+#ifndef NO_68851
+      /* JF: These are out of order, I fear. */
+    case 'f':
+      switch (opP->reg) {
+      case SFC:
+       tmpreg=0;
+       break;
+      case DFC:
+       tmpreg=1;
+       break;
+      default:
+       as_fatal("failed sanity check.");
+      }
+      install_operand(s[1],tmpreg);
+      break;
 
-               case 'W':
-                       switch(opP->reg) {
+    case 'P':
+      switch(opP->reg) {
+      case TC:
+       tmpreg=0;
+       break;
+      case CAL:
+       tmpreg=4;
+       break;
+      case VAL:
+       tmpreg=5;
+       break;
+      case SCC:
+       tmpreg=6;
+       break;
+      case AC:
+       tmpreg=7;
+       break;
+      default:
+       as_fatal("failed sanity check.");
+      }
+      install_operand(s[1],tmpreg);
+      break;
 
-                       case DRP:
-                               tmpreg=1;
-                               break;
-                       case SRP:
-                               tmpreg=2;
-                               break;
-                       case CRP:
-                               tmpreg=3;
-                               break;
-                       default:
-                               abort();
-                       }
-                       install_operand(s[1],tmpreg);
-                       break;
+    case 'V':
+      if (opP->reg == VAL)
+       break;
+      as_fatal("failed sanity check.");
 
-               case 'X':
-                       switch (opP->reg) {
-                       case BAD: case BAD+1: case BAD+2: case BAD+3:
-                       case BAD+4: case BAD+5: case BAD+6: case BAD+7:
-                               tmpreg = (4 << 10) | ((opP->reg - BAD) << 2);
-                               break;
+    case 'W':
+      switch(opP->reg) {
 
-                       case BAC: case BAC+1: case BAC+2: case BAC+3:
-                       case BAC+4: case BAC+5: case BAC+6: case BAC+7:
-                               tmpreg = (5 << 10) | ((opP->reg - BAC) << 2);
-                               break;
+      case DRP:
+       tmpreg=1;
+       break;
+      case SRP:
+       tmpreg=2;
+       break;
+      case CRP:
+       tmpreg=3;
+       break;
+      default:
+       as_fatal("failed sanity check.");
+      }
+      install_operand(s[1],tmpreg);
+      break;
+
+    case 'X':
+      switch (opP->reg) {
+      case BAD: case BAD+1: case BAD+2: case BAD+3:
+      case BAD+4: case BAD+5: case BAD+6: case BAD+7:
+       tmpreg = (4 << 10) | ((opP->reg - BAD) << 2);
+       break;
 
-                       default:
-                               abort();
-                       }
-                       install_operand(s[1], tmpreg);
-                       break;
-               case 'Y':
-                       if (opP->reg == PSR)
-                               break;
-                       abort();
+      case BAC: case BAC+1: case BAC+2: case BAC+3:
+      case BAC+4: case BAC+5: case BAC+6: case BAC+7:
+       tmpreg = (5 << 10) | ((opP->reg - BAC) << 2);
+       break;
 
-               case 'Z':
-                       if (opP->reg == PCSR)
-                               break;
-                       abort();
+      default:
+       as_fatal("failed sanity check.");
+      }
+      install_operand(s[1], tmpreg);
+      break;
+    case 'Y':
+      know(opP->reg == PSR);
+      break;
+    case 'Z':
+      know(opP->reg == PCSR);
+      break;
 #endif /* m68851 */
-               default:
-                       as_fatal("Internal error:  Operand type %c unknown in line %s of file \"%s\"", s[0], __LINE__, __FILE__);
-               }
+    case '3':
+      switch (opP->reg)
+       {
+       case TT0:
+         tmpreg = 2;
+         break;
+       case TT1:
+         tmpreg = 3;
+         break;
+       default:
+         as_fatal ("failed sanity check");
        }
-       /* By the time whe get here (FINALLY) the_ins contains the complete
-          instruction, ready to be emitted. . . */
-}
+      install_operand (s[1], tmpreg);
+      break;
+    case 't':
+      tmpreg = get_num (opP->con1, 20);
+      install_operand (s[1], tmpreg);
+      break;
+    case '_':          /* used only for move16 absolute 32-bit address */
+      tmpreg=get_num(opP->con1,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__);
+    }
+  }
+
+  /* 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;
@@ -2135,12 +2702,12 @@ char *str;
        /* Low order 24 bits encoded fpc,fps,fpi,fp7-fp0,a7-a0,d7-d0 */
        unsigned long cur_regs = 0;
        int     reg1,
-               reg2;
+       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));  }
+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(;;) {
@@ -2159,7 +2726,7 @@ char *str;
                                reg1++;
                        }
                        if(*str=='\0')
-                               break;
+                           break;
                } else if(*str=='\0') {
                        ADD_REG(reg1);
                        break;
@@ -2167,9 +2734,9 @@ char *str;
                        opP->error="unknow character in register list";
                        return FAIL;
                }
-/* DJA -- Bug Fix.  Did't handle d1-d2/a1 until the following instruction was added */
+               /* DJA -- Bug Fix.  Did't handle d1-d2/a1 until the following instruction was added */
                if (*str=='/')
-                 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";
@@ -2187,12 +2754,12 @@ int in;
        int n;
 
        static int mask[16] = {
-0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,
-0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000
-       };
+               0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,
+               0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000
+           };
        for(n=0;n<16;n++) {
                if(in&mask[n])
-                       out|=mask[15-n];
+                   out|=mask[15-n];
        }
        return out;
 } /* reverse_16_bits() */
@@ -2204,12 +2771,12 @@ int in;
        int n;
 
        static int mask[8] = {
-0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,
+               0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,
        };
 
        for(n=0;n<8;n++) {
                if(in&mask[n])
-                       out|=mask[7-n];
+                   out|=mask[7-n];
        }
        return out;
 } /* reverse_8_bits() */
@@ -2241,8 +2808,8 @@ int 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;
@@ -2252,7 +2819,7 @@ int val;
        case '8':
                the_ins.opcode[1]|=val<<10;
                break;
-#ifdef m68851
+#ifndef NO_68851
        case '9':
                the_ins.opcode[1]|=val<<5;
                break;
@@ -2284,9 +2851,16 @@ int val;
        case 'w':
        case 'l':
                break;
+       case 'e':
+               the_ins.opcode[0] |= (val << 6);
+               break;
+       case 'L':
+               the_ins.opcode[1] = (val >> 16);
+               the_ins.opcode[2] = val & 0xffff;
+               break;
        case 'c':
        default:
-               abort();
+               as_fatal("failed sanity check.");
        }
 } /* install_operand() */
 
@@ -2299,7 +2873,7 @@ int val;
                the_ins.opcode[0]|=val;
                break;
        case 'd':
-                       /* This is a kludge!!! */
+               /* This is a kludge!!! */
                the_ins.opcode[0]|=(val&0x07)<<9|(val&0x38)<<3;
                break;
        case 'b':
@@ -2313,10 +2887,15 @@ int val;
                break;
                /* more stuff goes here */
        default:
-               abort();
+               as_fatal("failed sanity check.");
        }
 } /* install_gen_operand() */
 
+/*
+ * verify that we have some number of paren pairs, do m68k_ip_op(), and
+ * then deal with the bitfield hack.
+ */
+
 static char *crack_operand(str,opP)
 register char *str;
 register struct m68k_op *opP;
@@ -2351,11 +2930,11 @@ register struct m68k_op *opP;
        }
        *str=c;
        if(c=='}')
-               c= *++str;              /* JF bitfield hack */
+           c= *++str;          /* JF bitfield hack */
        if(c) {
                c= *++str;
                if(!c)
-                       as_bad("Missing operand");
+                   as_bad("Missing operand");
        }
        return str;
 }
@@ -2367,41 +2946,245 @@ char *s;
 {
        if(*s==',') return 0;
        if(*s=='{' || *s=='}')
-               return 0;
+           return 0;
        if(*s!=':') return 1;
-               /* This kludge here is for the division cmd, which is a kludge */
+       /* 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 funciton is supposed to emit
-   the frags/bytes it assembles to.
- */
+/* 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.
+   */
+
+void
+insert_reg(regname, regnum)
+char *regname;
+int regnum;
+{
+  char buf[100];
+  int i;
+  symbol_table_insert(symbol_new(regname, SEG_REGISTER, 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(symbol_new(buf, SEG_REGISTER, regnum, &zero_address_frag));
+}
+
+static const struct {
+char *name;
+int number;
+} 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,
+  /* 68ec030 versions of same */
+  "ac0",       TT0,
+  "ac1",       TT1,
+  /* 68ec030 access control unit, identical to 030 MMU status reg */
+  "acusr",     PSR,
+
+  0,
+
+};
+
+
+void
+init_regtable()
+{
+  int i;
+  for (i = 0; init_table[i].name; i++)
+    insert_reg(init_table[i].name, init_table[i].number);
+}
+
+static int no_68851, no_68881;
+
 void
 md_assemble(str)
-char *str;
+     char *str;
 {
        char *er;
        short   *fromP;
-       char    *toP;
-       int     m,n;
+       char    *toP = NULL;
+       int     m,n = 0;
        char    *to_beg_P;
        int     shorts_this_frag;
+       static int done_first_time;
+
+       if (!done_first_time)
+         {
+           done_first_time = 1;
+
+           if (cpu_of_arch (current_architecture) == 0)
+             {
+               int cpu_type;
+
+#ifndef TARGET_CPU
+               cpu_type = m68020;
+#else
+               if (strcmp (TARGET_CPU, "m68000") == 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)
+                 cpu_type = cpu32;
+               else
+                 cpu_type = m68020;
+#endif
 
-       bzero((char *)(&the_ins),sizeof(the_ins));      /* JF for paranoia sake */
-       m68_ip(str);
+               current_architecture |= cpu_type;
+             }
+           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");
+             }
+           /* What other incompatibilities ought we to 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)
+             {
+               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");
+           done_first_time = 1;
+         }
+
+       memset((char *)(&the_ins), '\0', sizeof(the_ins));      /* JF for paranoia sake */
+       m68k_ip(str);
        er=the_ins.error;
        if(!er) {
                for(n=the_ins.numargs;n;--n)
-                       if(the_ins.operands[n].error) {
-                               er=the_ins.operands[n].error;
-                               break;
-                       }
+                   if(the_ins.operands[n].error) {
+                           er=the_ins.operands[n].error;
+                           break;
+                   }
        }
        if(er) {
-               as_bad("\"%s\" -- Statement '%s' ignored",er,str);
+               as_bad("%s -- statement `%s' ignored",er,str);
                return;
        }
 
@@ -2413,7 +3196,7 @@ char *str;
                        toP+=2;
                        fromP++;
                }
-                       /* put out symbol-dependent info */
+               /* put out symbol-dependent info */
                for(m=0;m<the_ins.nrel;m++) {
                        switch(the_ins.reloc[m].wid) {
                        case 'B':
@@ -2447,7 +3230,7 @@ char *str;
                return;
        }
 
-               /* There's some frag hacking */
+       /* There's some frag hacking */
        for(n=0,fromP= &the_ins.opcode[0];n<the_ins.nfrag;n++) {
                int wid;
 
@@ -2469,22 +3252,22 @@ char *str;
                        }
                        wid=the_ins.reloc[m].wid;
                        if(wid==0)
-                               continue;
+                           continue;
                        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,
+                               (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);
                }
-               know(the_ins.fragb[n].fadd);
+               /* know(the_ins.fragb[n].fadd); */
                (void)frag_var(rs_machine_dependent,10,0,(relax_substateT)(the_ins.fragb[n].fragty),
- the_ins.fragb[n].fadd,the_ins.fragb[n].foff,to_beg_P);
                             the_ins.fragb[n].fadd,the_ins.fragb[n].foff,to_beg_P);
        }
        n=(the_ins.numo-the_ins.fragb[n-1].fragoff);
        shorts_this_frag=0;
@@ -2502,31 +3285,30 @@ char *str;
 
                wid=the_ins.reloc[m].wid;
                if(wid==0)
-                       continue;
+                   continue;
                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)-/* the_ins.numo */ 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);
+                       (the_ins.reloc[m].n + toP-frag_now->fr_literal)-/* the_ins.numo */ 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);
        }
 }
 
-/* This function is called once, at assembler startup time.  This should
-   set up all the tables, etc that the MD part of the assembler needs
- */
+
+
 void
-md_begin()
+    md_begin()
 {
-/*
- * md_begin -- set up hash tables with 68000 instructions.
- * similar to what the vax assembler does.  ---phr
- */
+       /*
       * md_begin -- set up hash tables with 68000 instructions.
       * similar to what the vax assembler does.  ---phr
       */
        /* RMS claims the thing to do is take the m68k-opcode.h table, and make
           a copy of it at runtime, adding in the information we want but isn't
           there.  I think it'd be better to have an awk script hack the table
@@ -2535,41 +3317,44 @@ md_begin()
           names.  */
 
        register const struct m68k_opcode *ins;
-       register struct m68_incant *hack,
-               *slak;
+       register struct m68k_incant *hack,
+       *slak;
        register 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");
+           as_fatal("Virtual memory exhausted");
 
        obstack_begin(&robyn,4000);
        for (ins = m68k_opcodes; ins < endop; ins++) {
-               hack=slak=(struct m68_incant *)obstack_alloc(&robyn,sizeof(struct m68_incant));
+               hack=slak=(struct m68k_incant *)obstack_alloc(&robyn,sizeof(struct m68k_incant));
                do {
+                       /* we *could* ignore insns that don't match our
+                          arch here but just leaving them out of the
+                          hash. */
                        slak->m_operands=ins->args;
                        slak->m_opnum=strlen(slak->m_operands)/2;
+                       slak->m_arch = ins->arch;
                        slak->m_opcode=ins->opcode;
-                               /* This is kludgey */
+                       /* This is kludgey */
                        slak->m_codenum=((ins->match)&0xffffL) ? 2 : 1;
                        if((ins+1)!=endop && !strcmp(ins->name,(ins+1)->name)) {
-                               slak->m_next=(struct m68_incant *)
-obstack_alloc(&robyn,sizeof(struct m68_incant));
+                               slak->m_next=(struct m68k_incant *) obstack_alloc(&robyn,sizeof(struct m68k_incant));
                                ins++;
                        } else
-                               slak->m_next=0;
+                           slak->m_next=0;
                        slak=slak->m_next;
                } while(slak);
 
                retval = hash_insert (op_hash, ins->name,(char *)hack);
-                       /* Didn't his mommy tell him about null pointers? */
+               /* Didn't his mommy tell him about null pointers? */
                if(retval && *retval)
-                       as_fatal("Internal Error:  Can't hash %s: %s",ins->name,retval);
+                   as_bad("Internal Error:  Can't hash %s: %s",ins->name,retval);
        }
 
        for (i = 0; i < sizeof(mklower_table) ; i++)
-               mklower_table[i] = (isupper(c = (char) i)) ? tolower(c) : c;
+           mklower_table[i] = (isupper(c = (char) i)) ? tolower(c) : c;
 
        for (i = 0 ; i < sizeof(notend_table) ; i++) {
                notend_table[i] = 0;
@@ -2588,19 +3373,39 @@ obstack_alloc(&robyn,sizeof(struct m68_incant));
 #ifdef REGISTER_PREFIX
        alt_notend_table[REGISTER_PREFIX] = 1;
 #endif
+
+#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 */
+       {
+        int n = 0;
+        while (mote_pseudo_table[n].poc_name)
+        {
+               hack=(struct m68k_incant *)
+                 obstack_alloc(&robyn,sizeof(struct m68k_incant));        
+               hash_insert(op_hash, 
+                           mote_pseudo_table[n].poc_name, (char *)hack);
+               hack->m_operands = 0;
+               hack->m_opnum = n;
+               n++;
+        }
+       }
+#endif
+
+       init_regtable();
 }
 
 #if 0
 #define notend(s) ((*s == ',' || *s == '}' || *s == '{' \
-                   || (*s == ':' && strchr("aAdD#", s[1]))) \
-               ? 0 : 1)
+                   || (*s == ':' && strchr("aAdD#", s[1]))) \
+                  ? 0 : 1)
 #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()
+    md_end()
 {
 }
 
@@ -2610,9 +3415,9 @@ md_end()
 /* 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)
+    md_atof(type,litP,sizeP)
 char type;
 char *litP;
 int *sizeP;
@@ -2654,7 +3459,7 @@ int *sizeP;
        }
        t=atof_ieee(input_line_pointer,type,words);
        if(t)
-               input_line_pointer=t;
+           input_line_pointer=t;
 
        *sizeP=prec * sizeof(LITTLENUM_TYPE);
        for(wordP=words;prec--;) {
@@ -2670,9 +3475,9 @@ int *sizeP;
    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)
+    md_number_to_chars(buf,val,n)
 char   *buf;
 long   val;
 int n;
@@ -2692,16 +3497,23 @@ int n;
                *buf++=val;
                break;
        default:
-               abort();
+               as_fatal("failed sanity check.");
        }
 }
 
 void
-md_apply_fix(fixP, val)
-       fixS *fixP;
-       long val;
+    md_apply_fix(fixP, val)
+fixS *fixP;
+long val;
 {
+#ifdef IBM_COMPILER_SUX
+       /* 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 */
 
        switch(fixP->fx_size) {
        case 1:
@@ -2726,201 +3538,258 @@ md_apply_fix(fixP, val)
 /* *fragP has been relaxed to its final size, and now needs to have
    the bytes inside it modified to conform to the new size  There is UGLY
    MAGIC here. ..
- */
  */
 void
-md_convert_frag(headers, fragP)
+    md_convert_frag(headers, fragP)
 object_headers *headers;
 register fragS *fragP;
 {
-  long disp;
-  long ext;
+       long disp;
+       long ext = 0;
 
-  /* Address in object code of the displacement.  */
-  register int object_address = fragP -> fr_fix + fragP -> fr_address;
+       /* 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. */
-  register char *buffer_address = fragP -> fr_literal;
-  buffer_address += fragP -> fr_fix;
      /* This is wrong but it 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;
+       /* 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); */
-
-  /* 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;
-
-  switch(fragP->fr_subtype) {
-  case TAB(BCC68000,BYTE):
-  case TAB(BRANCH,BYTE):
-    know(issbyte(disp));
-    if(disp==0)
-      as_bad("short branch with zero offset: use :w");
-    fragP->fr_opcode[1]=disp;
-    ext=0;
-    break;
-  case TAB(DBCC,SHORT):
-    know(issword(disp));
-    ext=2;
-    break;
-  case TAB(BCC68000,SHORT):
-  case TAB(BRANCH,SHORT):
-    know(issword(disp));
-    fragP->fr_opcode[1]=0x00;
-    ext=2;
-    break;
-  case TAB(BRANCH,LONG):
-    if(flagseen['m']) {
-      if(fragP->fr_opcode[0]==0x61) {
-       fragP->fr_opcode[0]= 0x4E;
-       fragP->fr_opcode[1]= 0xB9;      /* JBSR with ABSL LONG offset */
-       subseg_change(SEG_TEXT, 0);
-
-       fix_new(fragP,
-               fragP->fr_fix,
-               4,
-               fragP->fr_symbol,
-               0,
-               fragP->fr_offset,
-               0,
-               NO_RELOC);
+       /* No longer true:   know(fragP->fr_symbol); */
 
-       fragP->fr_fix+=4;
+       /* 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;
+
+       switch(fragP->fr_subtype) {
+       case TAB(BCC68000,BYTE):
+    case TAB(ABRANCH,BYTE):
+       know(issbyte(disp));
+       if(disp==0)
+           as_bad("short branch with zero offset: use :w");
+       fragP->fr_opcode[1]=disp;
        ext=0;
-      } else if(fragP->fr_opcode[0]==0x60) {
-        fragP->fr_opcode[0]= 0x4E;
-        fragP->fr_opcode[1]= 0xF9;      /* JMP  with ABSL LONG offset */
-        subseg_change(SEG_TEXT, 0);
-        fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset,0,
-                               NO_RELOC);
-        fragP->fr_fix+=4;
-        ext=0;
-      }else {
-        as_bad("Long branch offset not supported.");
-      }
-    } else {
-      fragP->fr_opcode[1]=0xff;
-      ext=4;
-    }
-    break;
-  case TAB(BCC68000,LONG):
-       /* only Bcc 68000 instructions can come here */
-        /* change bcc into b!cc/jmp absl long */
-       fragP->fr_opcode[0] ^= 0x01; /* invert bcc */
+       break;
+ case TAB(DBCC,SHORT):
+     know(issword(disp));
+       ext=2;
+       break;
+ case TAB(BCC68000,SHORT):
+ case TAB(ABRANCH,SHORT):
+     know(issword(disp));
+       fragP->fr_opcode[1]=0x00;
+       ext=2;
+       break;
+ case TAB(ABRANCH,LONG):
+     if (cpu_of_arch(current_architecture) < m68020) {
+            if (fragP->fr_opcode[0]==0x61) {
+                    fragP->fr_opcode[0]= 0x4E;
+                    fragP->fr_opcode[1]= 0xB9; /* JBSR with ABSL LONG offset */
+                    subseg_change(SEG_TEXT, 0);
+
+                    fix_new(fragP,
+                            fragP->fr_fix,
+                            4,
+                            fragP->fr_symbol,
+                            0,
+                            fragP->fr_offset,
+                            0,
+                            NO_RELOC);
+
+                    fragP->fr_fix+=4;
+                    ext=0;
+            } else if (fragP->fr_opcode[0]==0x60) {
+                    fragP->fr_opcode[0]= 0x4E;
+                    fragP->fr_opcode[1]= 0xF9;      /* JMP  with ABSL LONG offset */
+                    subseg_change(SEG_TEXT, 0);
+                    fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset,0,
+                            NO_RELOC);
+                    fragP->fr_fix+=4;
+                    ext=0;
+            } else {
+                    as_bad("Long branch offset not supported.");
+            }
+     } else {
+            fragP->fr_opcode[1]=0xff;
+            ext=4;
+     }
+       break;
+ case TAB(BCC68000,LONG):
+     /* only Bcc 68000 instructions can come here */
+     /* change bcc into b!cc/jmp absl long */
+     fragP->fr_opcode[0] ^= 0x01; /* invert bcc */
         fragP->fr_opcode[1] = 0x6;   /* branch offset = 6 */
 
        /* JF: these used to be fr_opcode[2,3], but they may be in a
           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++ = 0x4e;  /* put in jmp long (0x4ef9) */
+        *buffer_address++ = 0xf9;
         fragP->fr_fix += 2;         /* account for jmp instruction */
         subseg_change(SEG_TEXT,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, 0,
+               fragP->fr_offset,0,
+               NO_RELOC);
         fragP->fr_fix += 4;
         ext=0;
        break;
 case TAB(DBCC,LONG):
-        /* only DBcc 68000 instructions can come here */
-        /* change dbcc into dbcc/jmp absl long */
-       /* JF: these used to be fr_opcode[2-7], but that's wrong */
-        *buffer_address++ = 0x00;  /* branch offset = 4 */
-        *buffer_address++ = 0x04;  
-        *buffer_address++ = 0x60;  /* put in bra pc+6 */ 
-        *buffer_address++ = 0x06;  
-        *buffer_address++ = 0x4e;  /* put in jmp long (0x4ef9) */ 
-        *buffer_address++ = 0xf9;  
+ case TAB(DBCC,LONG):
+     /* only DBcc 68000 instructions can come here */
+     /* change dbcc into dbcc/jmp absl long */
+     /* JF: these used to be fr_opcode[2-7], but that's wrong */
+     *buffer_address++ = 0x00;  /* branch offset = 4 */
+        *buffer_address++ = 0x04;
+        *buffer_address++ = 0x60;  /* put in bra pc+6 */
+        *buffer_address++ = 0x06;
+        *buffer_address++ = 0x4e;  /* put in jmp long (0x4ef9) */
+        *buffer_address++ = 0xf9;
 
         fragP->fr_fix += 6;         /* account for bra/jmp instructions */
         subseg_change(SEG_TEXT,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, 0,
+               fragP->fr_offset,0,
+               NO_RELOC);
         fragP->fr_fix += 4;
         ext=0;
-    break;
-  case TAB(FBRANCH,SHORT):
-    know((fragP->fr_opcode[1]&0x40)==0);
-    ext=2;
-    break;
-  case TAB(FBRANCH,LONG):
-    fragP->fr_opcode[1]|=0x40; /* Turn on LONG bit */
-    ext=4;
-    break;
-  case TAB(PCREL,SHORT):
-    ext=2;
-    break;
-  case TAB(PCREL,LONG):
-    /* 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(SEG_TEXT,0);
-    fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, 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);
-    fragP->fr_opcode[1]&= ~0x3F;
-    fragP->fr_opcode[1]|=0x39; /* Mode 7.1 */
-    fragP->fr_fix+=4;
-    /* md_number_to_chars(buffer_address,
-                      (long)(fragP->fr_symbol->sy_value + fragP->fr_offset),
-                      4); */
-    ext=0;
-    break;
-  case TAB(PCLEA,SHORT):
-    subseg_change(SEG_TEXT,0);
-    fix_new(fragP,(int)(fragP->fr_fix),2,fragP->fr_symbol,(symbolS *)0,fragP->fr_offset,1,
-                               NO_RELOC);
-    fragP->fr_opcode[1] &= ~0x3F;
-    fragP->fr_opcode[1] |= 0x3A;
-    ext=2;
-    break;
-  case TAB(PCLEA,LONG):
-    subseg_change(SEG_TEXT,0);
-    fix_new(fragP,(int)(fragP->fr_fix)+2,4,fragP->fr_symbol,(symbolS *)0,fragP->fr_offset+2,1,
-                               NO_RELOC);
-    *buffer_address++ = 0x01;
-    *buffer_address++ = 0x70;
-    fragP->fr_fix+=2;
-    /* buffer_address+=2; */
-    ext=4;
-    break;
-
-  } /* switch on subtype */
-
-  if (ext) {
-         md_number_to_chars(buffer_address, (long) disp, (int) ext);
-         fragP->fr_fix += ext;
-/*       H_SET_TEXT_SIZE(headers, H_GET_TEXT_SIZE(headers) + ext); */
-  } /* if extending */
-
-  know((fragP->fr_next == NULL)
-       || ((fragP->fr_next->fr_address - fragP->fr_address)
-          == (fragP->fr_fix)));
-
-  return;
+       break;
+ case TAB(FBRANCH,SHORT):
+     know((fragP->fr_opcode[1]&0x40)==0);
+       ext=2;
+       break;
+ case TAB(FBRANCH,LONG):
+     fragP->fr_opcode[1]|=0x40;        /* Turn on LONG bit */
+       ext=4;
+       break;
+ case TAB(PCREL,SHORT):
+     ext=2;
+       break;
+ case TAB(PCREL,LONG):
+     /* 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(SEG_TEXT,0);
+       fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, 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);
+       fragP->fr_opcode[1]&= ~0x3F;
+       fragP->fr_opcode[1]|=0x39;      /* Mode 7.1 */
+       fragP->fr_fix+=4;
+       /* md_number_to_chars(buffer_address,
+          (long)(fragP->fr_symbol->sy_value + fragP->fr_offset),
+          4); */
+       ext=0;
+       break;
+ case TAB(PCLEA,SHORT):
+     subseg_change(SEG_TEXT,0);
+       fix_new(fragP,(int)(fragP->fr_fix),2,fragP->fr_symbol,(symbolS *)0,fragP->fr_offset,1,
+               NO_RELOC);
+       fragP->fr_opcode[1] &= ~0x3F;
+       fragP->fr_opcode[1] |= 0x3A;
+       ext=2;
+       break;
+ case TAB(PCLEA,LONG):
+     subseg_change(SEG_TEXT,0);
+       fix_new(fragP,(int)(fragP->fr_fix)+2,4,fragP->fr_symbol,(symbolS *)0,fragP->fr_offset+2,1,
+               NO_RELOC);
+       *buffer_address++ = 0x01;
+       *buffer_address++ = 0x70;
+       fragP->fr_fix+=2;
+       /* buffer_address+=2; */
+       ext=4;
+       break;
+
+} /* switch on subtype */
+
+       if (ext) {
+               md_number_to_chars(buffer_address, (long) disp, (int) ext);
+               fragP->fr_fix += ext;
+               /*        H_SET_TEXT_SIZE(headers, H_GET_TEXT_SIZE(headers) + ext); */
+       } /* if extending */
+
+       return;
 } /* md_convert_frag() */
 
 /* Force truly undefined symbols to their maximum size, and generally set up
    the frag list to be relaxed
- */
  */
 int md_estimate_size_before_relax(fragP, segment)
 register fragS *fragP;
 segT segment;
 {
        int     old_fix;
-       register char *buffer_address = fragP -> fr_fix + fragP -> fr_literal;
+       register char *buffer_address = fragP->fr_fix + fragP->fr_literal;
 
-       old_fix=fragP->fr_fix;
+       old_fix = fragP->fr_fix;
 
        /* handle SZ_UNDEF first, it can be changed to BYTE or SHORT */
-       switch(fragP->fr_subtype) {
+       switch (fragP->fr_subtype) {
+
+       case TAB(ABRANCH,SZ_UNDEF): {
+               if((fragP->fr_symbol != NULL)   /* Not absolute */
+                  && S_GET_SEGMENT(fragP->fr_symbol) == segment) {
+                       fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),BYTE);
+                       break;
+               } else if((fragP->fr_symbol == 0) || (cpu_of_arch(current_architecture) < m68020)) {
+                       /* On 68000, or for absolute value, switch to abs long */
+                       /* FIXME, we should check abs val, pick short or long */
+                       if(fragP->fr_opcode[0]==0x61) {
+                               fragP->fr_opcode[0]= 0x4E;
+                               fragP->fr_opcode[1]= 0xB9;      /* JBSR with ABSL LONG offset */
+                               subseg_change(SEG_TEXT, 0);
+                               fix_new(fragP, fragP->fr_fix, 4,
+                                       fragP->fr_symbol, 0, 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(SEG_TEXT, 0);
+                               fix_new(fragP, fragP->fr_fix, 4,
+                                       fragP->fr_symbol, 0, fragP->fr_offset, 0, NO_RELOC);
+                               fragP->fr_fix+=4;
+                               frag_wane(fragP);
+                       } else {
+                               as_warn("Long branch offset to extern symbol not supported.");
+                       }
+               } 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_fix+=4;
+                       fragP->fr_opcode[1]=0xff;
+                       frag_wane(fragP);
+                       break;
+               }
+
+               break;
+       } /* case TAB(ABRANCH,SZ_UNDEF) */
+
+       case TAB(FBRANCH,SZ_UNDEF): {
+               if(S_GET_SEGMENT(fragP->fr_symbol) == segment || flagseen['l']) {
+                       fragP->fr_subtype = TAB(FBRANCH,SHORT);
+                       fragP->fr_var += 2;
+               } else {
+                       fragP->fr_subtype = TAB(FBRANCH,LONG);
+                       fragP->fr_var += 4;
+               }
+               break;
+       } /* TAB(FBRANCH,SZ_UNDEF) */
+
+       case TAB(PCREL,SZ_UNDEF): {
+               if(S_GET_SEGMENT(fragP->fr_symbol) == segment || flagseen['l']) {
+                       fragP->fr_subtype = TAB(PCREL,SHORT);
+                       fragP->fr_var += 2;
+               } else {
+                       fragP->fr_subtype = TAB(PCREL,LONG);
+                       fragP->fr_var += 4;
+               }
+               break;
+       } /* TAB(PCREL,SZ_UNDEF) */
 
        case TAB(BCC68000,SZ_UNDEF): {
                if((fragP->fr_symbol != NULL)
@@ -2934,22 +3803,22 @@ segT segment;
                if(flagseen['l']) {
                        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[0] = 0x4e;  /* put in jmp long (0x4ef9) */
                        buffer_address[1] = 0xf8;
                        fragP->fr_fix += 2;          /* account for jmp instruction */
                        subseg_change(SEG_TEXT,0);
-                       fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0, 
-                                                        fragP->fr_offset, 0, NO_RELOC);
+                       fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0,
+                               fragP->fr_offset, 0, NO_RELOC);
                        fragP->fr_fix += 2;
                } else {
                        fragP->fr_opcode[1] = 0x06;   /* branch offset = 6 */
                        /* JF: these were fr_opcode[2,3] */
-                       buffer_address[2] = 0x4e;  /* put in jmp long (0x4ef9) */ 
-                       buffer_address[3] = 0xf9;
+                       buffer_address[0] = 0x4e;  /* put in jmp long (0x4ef9) */
+                       buffer_address[1] = 0xf9;
                        fragP->fr_fix += 2;          /* account for jmp instruction */
                        subseg_change(SEG_TEXT,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, 0,
+                               fragP->fr_offset, 0, NO_RELOC);
                        fragP->fr_fix += 4;
                }
                frag_wane(fragP);
@@ -2966,9 +3835,9 @@ segT segment;
                /* change dbcc into dbcc/jmp absl long */
                /* JF: these used to be fr_opcode[2-4], which is wrong. */
                buffer_address[0] = 0x00;  /* branch offset = 4 */
-               buffer_address[1] = 0x04;  
+               buffer_address[1] = 0x04;
                buffer_address[2] = 0x60;  /* put in bra pc + ... */
+
                if(flagseen['l']) {
                        /* JF: these were fr_opcode[5-7] */
                        buffer_address[3] = 0x04; /* plus 4 */
@@ -2976,18 +3845,20 @@ segT segment;
                        buffer_address[5] = 0xf8;
                        fragP->fr_fix += 6;       /* account for bra/jmp instruction */
                        subseg_change(SEG_TEXT,0);
-                       fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0, 
-                                                        fragP->fr_offset, 0, NO_RELOC);
+                       fix_new(fragP, fragP->fr_fix, 2, fragP->fr_symbol, 0,
+
+
+                               fragP->fr_offset, 0, NO_RELOC);
                        fragP->fr_fix += 2;
                } else {
                        /* 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[4] = 0x4e;  /* put in jmp long (0x4ef9) */
+                       buffer_address[5] = 0xf9;
                        fragP->fr_fix += 6;       /* account for bra/jmp instruction */
                        subseg_change(SEG_TEXT,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, 0,
+                               fragP->fr_offset, 0, NO_RELOC);
                        fragP->fr_fix += 4;
                }
 
@@ -2995,43 +3866,6 @@ segT segment;
                break;
        } /* case TAB(DBCC,SZ_UNDEF) */
 
-       case TAB(BRANCH,SZ_UNDEF): {
-               if((fragP->fr_symbol != NULL)   /* Not absolute */
-                  && S_GET_SEGMENT(fragP->fr_symbol) == segment) {
-                        fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),BYTE);
-                        break;
-               } else if((fragP->fr_symbol == 0) || flagseen['m']) {
-                       /* On 68000, or for absolute value, switch to abs long */
-                       /* FIXME, we should check abs val, pick short or long */
-                       if(fragP->fr_opcode[0]==0x61) {
-                               fragP->fr_opcode[0]= 0x4E;
-                               fragP->fr_opcode[1]= 0xB9;      /* JBSR with ABSL LONG offset */
-                               subseg_change(SEG_TEXT, 0);
-                               fix_new(fragP, fragP->fr_fix, 4, 
-                                       fragP->fr_symbol, 0, 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(SEG_TEXT, 0);
-                               fix_new(fragP, fragP->fr_fix, 4, 
-                                       fragP->fr_symbol, 0, fragP->fr_offset, 0, NO_RELOC);
-                               fragP->fr_fix+=4;
-                               frag_wane(fragP);
-                       } else {
-                               as_warn("Long branch offset to extern symbol not supported.");
-                       }
-               } 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_fix+=4;
-                       fragP->fr_opcode[1]=0xff;
-                       frag_wane(fragP);
-                       break;
-               }
-       } /* case TAB(BRANCH,SZ_UNDEF) */
-
        case TAB(PCLEA,SZ_UNDEF): {
                if ((S_GET_SEGMENT(fragP->fr_symbol))==segment || flagseen['l']) {
                        fragP->fr_subtype=TAB(PCLEA,SHORT);
@@ -3043,64 +3877,89 @@ segT segment;
                break;
        } /* TAB(PCLEA,SZ_UNDEF) */
 
-       case TAB(PCREL,SZ_UNDEF): {
-               if(S_GET_SEGMENT(fragP->fr_symbol) == segment || flagseen['l']) {
-                       fragP->fr_subtype = TAB(PCREL,SHORT);
-                       fragP->fr_var += 2;
-               } else {
-                       fragP->fr_subtype = TAB(PCREL,LONG);
-                       fragP->fr_var += 4;
-               }
-               break;
-       } /* TAB(PCREL,SZ_UNDEF) */
-
        default:
                break;
-       }
+
+       } /* switch on subtype looking for SZ_UNDEF's. */
 
        /* now that SZ_UNDEF are taken care of, check others */
-       switch(fragP->fr_subtype) {
+       switch (fragP->fr_subtype) {
        case TAB(BCC68000,BYTE):
-       case TAB(BRANCH,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) {
-                       fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),SHORT);
-                       fragP->fr_var+=2;
-               }
-               break;
-       default:
-               break;
+    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) {
+               fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),SHORT);
+               fragP->fr_var+=2;
        }
+       break;
+ default:
+       break;
+}
        return fragP->fr_var + fragP->fr_fix - old_fix;
 }
 
 #if defined(OBJ_AOUT) | defined(OBJ_BOUT)
-/* the bit-field entries in the relocation_info struct plays hell 
+/* the bit-field entries in the relocation_info struct plays hell
    with the byte-order problems of cross-assembly.  So as a hack,
    I added this mach. dependent ri twiddler.  Ugly, but it gets
    you there. -KWK */
 /* on m68k: first 4 bytes are normal unsigned long, next three bytes
-are symbolnum, most sig. byte first.  Last byte is broken up with
-bit 7 as pcrel, bits 6 & 5 as length, bit 4 as pcrel, and the lower
-nibble as nuthin. (on Sun 3 at least) */
+   are symbolnum, most sig. byte first.  Last byte is broken up with
+   bit 7 as pcrel, bits 6 & 5 as length, bit 4 as pcrel, and the lower
+   nibble as nuthin. (on Sun 3 at least) */
 /* Translate the internal relocation information into target-specific
    format. */
+#ifdef comment
 void
-md_ri_to_chars(the_bytes, ri)
-     char *the_bytes;
-     struct reloc_info_generic *ri;
+    md_ri_to_chars(the_bytes, ri)
+char *the_bytes;
+struct reloc_info_generic *ri;
 {
-  /* this is easy */
-  md_number_to_chars(the_bytes, ri->r_address, 4);
-  /* now the fun stuff */
-  the_bytes[4] = (ri->r_symbolnum >> 16) & 0x0ff;
-  the_bytes[5] = (ri->r_symbolnum >> 8) & 0x0ff;
-  the_bytes[6] = ri->r_symbolnum & 0x0ff;
-  the_bytes[7] = (((ri->r_pcrel << 7)  & 0x80) | ((ri->r_length << 5) & 0x60) | 
-    ((ri->r_extern << 4)  & 0x10)); 
+       /* this is easy */
+       md_number_to_chars(the_bytes, ri->r_address, 4);
+       /* now the fun stuff */
+       the_bytes[4] = (ri->r_symbolnum >> 16) & 0x0ff;
+       the_bytes[5] = (ri->r_symbolnum >> 8) & 0x0ff;
+       the_bytes[6] = ri->r_symbolnum & 0x0ff;
+       the_bytes[7] = (((ri->r_pcrel << 7)  & 0x80) | ((ri->r_length << 5) & 0x60) |
+                       ((ri->r_extern << 4)  & 0x10));
 }
+#endif /* comment */
+
+void tc_aout_fix_to_chars(where, fixP, segment_address_in_file)
+char *where;
+fixS *fixP;
+relax_addressT segment_address_in_file;
+{
+       /*
+        * In: length of relocation (or of address) in chars: 1, 2 or 4.
+        * Out: GNU LD relocation length code: 0, 1, or 2.
+        */
+
+       static unsigned char nbytes_r_length [] = { 42, 0, 1, 42, 2 };
+       long r_symbolnum;
+
+       know(fixP->fx_addsy != NULL);
+
+       md_number_to_chars(where,
+                          fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
+                          4);
+
+       r_symbolnum = (S_IS_DEFINED(fixP->fx_addsy)
+                      ? S_GET_TYPE(fixP->fx_addsy)
+                      : fixP->fx_addsy->sy_number);
+
+       where[4] = (r_symbolnum >> 16) & 0x0ff;
+       where[5] = (r_symbolnum >> 8) & 0x0ff;
+       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;
+} /* tc_aout_fix_to_chars() */
+
 #endif /* OBJ_AOUT or OBJ_BOUT */
 
 #ifndef WORKING_DOT_WORD
@@ -3108,10 +3967,10 @@ const int md_short_jump_size = 4;
 const int md_long_jump_size = 6;
 
 void
-md_create_short_jump(ptr,from_addr,to_addr,frag,to_symbol)
+    md_create_short_jump(ptr,from_addr,to_addr,frag,to_symbol)
 char   *ptr;
 long   from_addr,
-       to_addr;
+    to_addr;
 fragS  *frag;
 symbolS        *to_symbol;
 {
@@ -3124,21 +3983,21 @@ symbolS *to_symbol;
 }
 
 void
-md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol)
+    md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol)
 char   *ptr;
 long   from_addr,
-       to_addr;
+    to_addr;
 fragS  *frag;
 symbolS        *to_symbol;
 {
        long offset;
 
-       if (flagseen['m']) {
+       if (cpu_of_arch(current_architecture) < m68020) {
                offset=to_addr-S_GET_VALUE(to_symbol);
                md_number_to_chars(ptr  ,(long)0x4EF9,2);
                md_number_to_chars(ptr+2,(long)offset,4);
                fix_new(frag,(ptr+2)-frag->fr_literal,4,to_symbol,(symbolS *)0,(long)0,0,
-                               NO_RELOC);
+                       NO_RELOC);
        } else {
                offset=to_addr - (from_addr+2);
                md_number_to_chars(ptr  ,(long)0x60ff,2);
@@ -3149,18 +4008,18 @@ symbolS *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?)
 
-       0:  Everything is OK
-       10:  Absolute 1:8       only
-       20:  Absolute 0:7       only
-       30:  absolute 0:15      only
-       40:  Absolute 0:31      only
-       50:  absolute 0:127     only
-       55:  absolute -64:63    only
-       60:  absolute -128:127  only
-       70:  absolute 0:4095    only
-       80:  No bignums
+   0:  Everything is OK
+   10:  Absolute 1:8   only
+   20:  Absolute 0:7   only
+   30:  absolute 0:15  only
+   40:  Absolute 0:31  only
+   50:  absolute 0:127 only
+   55:  absolute -64:63    only
+   60:  absolute -128:127      only
+   70:  absolute 0:4095        only
+   80:  No bignums
 
-*/
+   */
 
 static int get_num(exp,ok)
 struct m68k_exp *exp;
@@ -3170,12 +4029,12 @@ int ok;
        long    l = 0;
 
        if(!exp->e_beg)
-               return 0;
+           return 0;
        if(*exp->e_beg=='0') {
                if(exp->e_beg[1]=='x')
-                       sscanf(exp->e_beg+2,"%x",&l);
+                   sscanf(exp->e_beg+2,"%x",&l);
                else
-                       sscanf(exp->e_beg+1,"%O",&l);
+                   sscanf(exp->e_beg+1,"%O",&l);
                return l;
        }
        return atol(exp->e_beg);
@@ -3197,26 +4056,31 @@ int ok;
        }
 
        exp->e_siz=0;
-       if(/* ok!=80 && */exp->e_end[-1]==':' && (exp->e_end-exp->e_beg)>=2) {
+       if(/* ok!=80 && */ (exp->e_end[-1]==':' || exp->e_end[-1]=='.')
+          && (exp->e_end-exp->e_beg)>=2) {
                switch(exp->e_end[0]) {
                case 's':
                case 'S':
                case 'b':
                case 'B':
                        exp->e_siz=1;
+                       exp->e_end-=2;
                        break;
                case 'w':
                case 'W':
                        exp->e_siz=2;
+                       exp->e_end-=2;
                        break;
                case 'l':
                case 'L':
                        exp->e_siz=3;
+                       exp->e_end-=2;
                        break;
                default:
-                       as_bad("Unknown size for expression \"%c\"",exp->e_end[0]);
+                       if (exp->e_end[-1] == ':')
+                         as_bad("Unknown size for expression \"%c\"",exp->e_end[0]);
+                       break;
                }
-               exp->e_end-=2;
        }
        c_save=exp->e_end[1];
        exp->e_end[1]='\0';
@@ -3252,27 +4116,27 @@ int ok;
                        break;
                case 20:
                        if(offs(exp)<0 || offs(exp)>7)
-                               goto outrange;
+                           goto outrange;
                        break;
                case 30:
                        if(offs(exp)<0 || offs(exp)>15)
-                               goto outrange;
+                           goto outrange;
                        break;
                case 40:
                        if(offs(exp)<0 || offs(exp)>32)
-                               goto outrange;
+                           goto outrange;
                        break;
                case 50:
                        if(offs(exp)<0 || offs(exp)>127)
-                               goto outrange;
+                           goto outrange;
                        break;
                case 55:
                        if(offs(exp)<-64 || offs(exp)>63)
-                               goto outrange;
+                           goto outrange;
                        break;
                case 60:
                        if(offs(exp)<-128 || offs(exp)>127)
-                               goto outrange;
+                           goto outrange;
                        break;
                case 70:
                        if(offs(exp)<0 || offs(exp)>4095) {
@@ -3285,12 +4149,25 @@ int ok;
                        break;
                }
                break;
-       case SEG_TEXT:
-       case SEG_DATA:
-       case SEG_BSS:
-       case SEG_UNKNOWN:
-       case SEG_DIFFERENCE:
-               if(ok>=10 && ok<=70) {
+       case SEG_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! */
+                   seg(exp)=SEG_ABSOLUTE;
+                   adds(exp)=0;
+                   subs(exp)=0;
+                   offs(exp)=words[1]|(words[0]<<16);
+                 }
+               else if(ok!=0) {
                        seg(exp)=SEG_ABSOLUTE;
                        adds(exp)=0;
                        subs(exp)=0;
@@ -3298,16 +4175,13 @@ int ok;
                        as_warn("Can't deal with expression \"%s\": defaulting to %ld",exp->e_beg,offs(exp));
                }
                break;
-       case SEG_BIG:
-               if(ok==80 && offs(exp)<0) {     /* HACK! Turn it into a long */
-                       LITTLENUM_TYPE words[6];
-
-                       gen_to_words(words,2,8L);/* These numbers are magic! */
-                       seg(exp)=SEG_ABSOLUTE;
-                       adds(exp)=0;
-                       subs(exp)=0;
-                       offs(exp)=words[1]|(words[0]<<16);
-               } else if(ok!=0) {
+       default:
+       case SEG_TEXT:
+       case SEG_DATA:
+       case SEG_BSS:
+       case SEG_UNKNOWN:
+       case SEG_DIFFERENCE:
+               if(ok>=10 && ok<=70) {
                        seg(exp)=SEG_ABSOLUTE;
                        adds(exp)=0;
                        subs(exp)=0;
@@ -3315,22 +4189,22 @@ int ok;
                        as_warn("Can't deal with expression \"%s\": defaulting to %ld",exp->e_beg,offs(exp));
                }
                break;
-       default:
-               abort();
+
+
        }
        if(input_line_pointer!=exp->e_end+1)
-               as_bad("Ignoring junk after expression");
+           as_bad("Ignoring junk after expression");
        exp->e_end[1]=c_save;
        input_line_pointer=save_in;
        if(exp->e_siz) {
                switch(exp->e_siz) {
                case 1:
                        if(!isbyte(offs(exp)))
-                               as_warn("expression doesn't fit in BYTE");
+                           as_warn("expression doesn't fit in BYTE");
                        break;
                case 2:
                        if(!isword(offs(exp)))
-                               as_warn("expression doesn't fit in WORD");
+                           as_warn("expression doesn't fit in WORD");
                        break;
                }
        }
@@ -3351,10 +4225,12 @@ static void s_data2() {
        demand_empty_rest_of_line();
 } /* s_data2() */
 
-static void s_bss() {
-       /* We don't support putting frags in the BSS segment, but we
-          can put them into initialized data for now... */
-       subseg_new(SEG_DATA,255);       /* FIXME-SOON */
+static void s_bss()
+{
+       /* 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_new(SEG_BSS, 0);
        demand_empty_rest_of_line();
 } /* s_bss() */
 
@@ -3365,7 +4241,7 @@ static void s_even() {
        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);
+           frag_align (temp, (int)temp_fill);
        demand_empty_rest_of_line();
 } /* s_even() */
 
@@ -3375,8 +4251,35 @@ static void s_proc() {
 
 /* s_space is defined in read.c .skip is simply an alias to it. */
 
-int
-md_parse_option(argP,cntP,vecP)
+/*
+ * md_parse_option
+ *     Invocation line includes a switch not recognized by the base assembler.
+ *     See if it's a processor-specific option.  These are:
+ *
+ *     -[A]m[c]68000, -[A]m[c]68008, -[A]m[c]68010, -[A]m[c]68020, -[A]m[c]68030, -[A]m[c]68040
+ *     -[A]m[c]68881, -[A]m[c]68882, -[A]m[c]68851
+ *             Select the architecture.  Instructions or features not
+ *             supported by the selected architecture cause fatal
+ *             errors.  More than one may be specified.  The default is
+ *             -m68020 -m68851 -m68881.  Note that -m68008 is a synonym
+ *             for -m68000, and -m68882 is a synonym for -m68881.
+ *     -[A]m[c]no-68851, -[A]m[c]no-68881
+ *             Don't accept 688?1 instructions.  (The "c" is kind of silly,
+ *             so don't use or document it, but that's the way the parsing
+ *             works).
+ *
+ * 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.
+ */
+#ifndef MAYBE_FLOAT_TOO
+#define        MAYBE_FLOAT_TOO /* m68881 */ 0 /* this is handled later */
+#endif
+
+int md_parse_option(argP,cntP,vecP)
 char **argP;
 int *cntP;
 char ***vecP;
@@ -3386,33 +4289,74 @@ char ***vecP;
                           rather than 16 bit one */
                break;
 
+       case 'S': /* -S means that jbsr's always turn into jsr's.  */
+               break;
+
+       case 'A':
+               (*argP)++;
+               /* intentional fall-through */
        case 'm':
-               /* Gas almost ignores this option! */
                (*argP)++;
-               if(**argP=='c')
+
+               if (**argP=='c') {
                        (*argP)++;
-               if(!strcmp(*argP,"68000"))
-                       flagseen['m']=2;
-               else if(!strcmp(*argP,"68010")) {
+               } /* allow an optional "c" */
+
+               if (!strcmp(*argP, "68000")
+                   || !strcmp(*argP, "68008")) {
+                       current_architecture |= m68000;
+               } else if (!strcmp(*argP, "68010")) {
 #ifdef TE_SUN
                        omagic= 1<<16|OMAGIC;
 #endif
-                       flagseen['m']=1;
-               } else if(!strcmp(*argP,"68020"))
-                       flagseen['m']=0;
-               else
-                       as_warn("Unknown -m option ignored");
-               while(**argP)
-                       (*argP)++;
+                       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")) { /* "-mcpu32" */
+                 current_architecture |= cpu32;
+               } else {
+                       as_warn("Unknown architecture, \"%s\". option ignored", *argP);
+               } /* switch on architecture */
+
+               while(**argP) (*argP)++;
+
                break;
 
        case 'p':
                if (!strcmp(*argP,"pic")) {
                        (*argP) += 3;
                        break;          /* -pic, Position Independent Code */
-               }
-               else
-                       return 0;
+               } else {
+                       return(0);
+               } /* pic or not */
+
        default:
                return 0;
        }
@@ -3427,30 +4371,30 @@ char ***vecP;
 
 main()
 {
-       struct m68_it the_ins;
+       struct m68k_it the_ins;
        char buf[120];
        char *cp;
        int     n;
 
-       m68_ip_begin();
+       m68k_ip_begin();
        for(;;) {
                if(!gets(buf) || !*buf)
-                       break;
+                   break;
                if(buf[0]=='|' || buf[1]=='.')
-                       continue;
+                   continue;
                for(cp=buf;*cp;cp++)
-                       if(*cp=='\t')
-                               *cp=' ';
+                   if(*cp=='\t')
+                       *cp=' ';
                if(is_label(buf))
-                       continue;
-               bzero(&the_ins,sizeof(the_ins));
-               m68_ip(&the_ins,buf);
+                   continue;
+               memset(&the_ins, '\0', sizeof(the_ins));
+               m68k_ip(&the_ins,buf);
                if(the_ins.error) {
                        printf("Error %s in %s\n",the_ins.error,buf);
                } else {
                        printf("Opcode(%d.%s): ",the_ins.numo,the_ins.args);
                        for(n=0;n<the_ins.numo;n++)
-                               printf(" 0x%x",the_ins.opcode[n]&0xffff);
+                           printf(" 0x%x",the_ins.opcode[n]&0xffff);
                        printf("    ");
                        print_the_insn(&the_ins.opcode[0],stdout);
                        (void)putchar('\n');
@@ -3462,14 +4406,14 @@ main()
                        }
                        printf("mode %d, reg %d, ",the_ins.operands[n].mode,the_ins.operands[n].reg);
                        if(the_ins.operands[n].b_const)
-                               printf("Constant: '%.*s', ",1+the_ins.operands[n].e_const-the_ins.operands[n].b_const,the_ins.operands[n].b_const);
+                           printf("Constant: '%.*s', ",1+the_ins.operands[n].e_const-the_ins.operands[n].b_const,the_ins.operands[n].b_const);
                        printf("ireg %d, isiz %d, imul %d, ",the_ins.operands[n].ireg,the_ins.operands[n].isiz,the_ins.operands[n].imul);
                        if(the_ins.operands[n].b_iadd)
-                               printf("Iadd: '%.*s',",1+the_ins.operands[n].e_iadd-the_ins.operands[n].b_iadd,the_ins.operands[n].b_iadd);
+                           printf("Iadd: '%.*s',",1+the_ins.operands[n].e_iadd-the_ins.operands[n].b_iadd,the_ins.operands[n].b_iadd);
                        (void)putchar('\n');
                }
        }
-       m68_ip_end();
+       m68k_ip_end();
        return 0;
 }
 
@@ -3477,11 +4421,11 @@ is_label(str)
 char *str;
 {
        while(*str==' ')
-               str++;
+           str++;
        while(*str && *str!=' ')
-               str++;
+           str++;
        if(str[-1]==':' || str[1]=='=')
-               return 1;
+           return 1;
        return 0;
 }
 
@@ -3489,20 +4433,20 @@ char *str;
 
 /* Possible states for relaxation:
 
-0 0    branch offset   byte    (bra, etc)
-0 1                    word
-0 2                    long
+   0 0 branch offset   byte    (bra, etc)
+   0 1                 word
+   0 2                 long
 
-1 0    indexed offsets byte    a0@(32,d4:w:1) etc
-1 1                    word
-1 2                    long
+   1 0 indexed offsets byte    a0@(32,d4:w:1) etc
+   1 1                 word
+   1 2                 long
 
-2 0    two-offset index word-word a0@(32,d4)@(45) etc
-2 1                    word-long
-2 2                    long-word
-2 3                    long-long
+   2 0 two-offset index word-word a0@(32,d4)@(45) etc
+   2 1                 word-long
+   2 2                 long-word
+   2 3                 long-long
 
-*/
+   */
 
 
 
@@ -3513,23 +4457,6 @@ abort()
        exit(12);
 }
 
-char *index(s,c)
-char *s;
-{
-       while(*s!=c) {
-               if(!*s) return 0;
-               s++;
-       }
-       return s;
-}
-
-bzero(s,n)
-char *s;
-{
-       while(n--)
-               *s++=0;
-}
-
 print_frags()
 {
        fragS *fragP;
@@ -3537,7 +4464,7 @@ print_frags()
 
        for(fragP=text_frag_root;fragP;fragP=fragP->fr_next) {
                printf("addr %lu  next 0x%x  fix %ld  var %ld  symbol 0x%x  offset %ld\n",
- fragP->fr_address,fragP->fr_next,fragP->fr_fix,fragP->fr_var,fragP->fr_symbol,fragP->fr_offset);
                     fragP->fr_address,fragP->fr_next,fragP->fr_fix,fragP->fr_var,fragP->fr_symbol,fragP->fr_offset);
                printf("opcode 0x%x  type %d  subtype %d\n\n",fragP->fr_opcode,fragP->fr_type,fragP->fr_subtype);
        }
        fflush(stdout);
@@ -3562,228 +4489,60 @@ char *format;
 
 /* ARGSUSED */
 symbolS *
-md_undefined_symbol (name)
-     char *name;
+    md_undefined_symbol (name)
+char *name;
 {
-  return 0;
+       return 0;
 }
 
-/* Parse an operand that is machine-specific.  
+/* 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;
+    md_operand (expressionP)
+expressionS *expressionP;
 {
 }
 
 /* Round up a section size to the appropriate boundary.  */
 long
-md_section_align (segment, size)
-     segT segment;
-     long size;
+    md_section_align (segment, size)
+segT segment;
+long size;
 {
-  return size;         /* Byte alignment is fine */
+       return size;            /* Byte alignment is fine */
 }
 
 /* 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!) */
 long
-md_pcrel_from (fixP)
-     fixS *fixP;
+    md_pcrel_from (fixP)
+fixS *fixP;
 {
-  return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
+       return(fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address);
 }
 
-/* Opcode table for m68000/m68020 and m68881.
-   Copyright (C) 1989, Free Software Foundation.
-
-This file is part of GDB, the GNU Debugger and GAS, the GNU Assembler.
-
-Both GDB and GAS are free software; you can redistribute and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GDB and GAS are distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GDB or GAS; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
-   
-/* We store four bytes of opcode for all opcodes because that
-   is the most any of them need.  The actual length of an instruction
-   is always at least 2 bytes, and is as much longer as necessary to
-   hold the operands it has.
-
-   The match component is a mask saying which bits must match
-   particular opcode in order for an instruction to be an instance
-   of that opcode.
-
-   The args component is a string containing two characters
-   for each operand of the instruction.  The first specifies
-   the kind of operand; the second, the place it is stored.  */
-
-/* Kinds of operands:
-   D  data register only.  Stored as 3 bits.
-   A  address register only.  Stored as 3 bits.
-   R  either kind of register.  Stored as 4 bits.
-   F  floating point coprocessor register only.   Stored as 3 bits.
-   O  an offset (or width): immediate data 0-31 or data register.
-      Stored as 6 bits in special format for BF... insns.
-   +  autoincrement only.  Stored as 3 bits (number of the address register).
-   -  autodecrement only.  Stored as 3 bits (number of the address register).
-   Q  quick immediate data.  Stored as 3 bits.
-      This matches an immediate operand only when value is in range 1 .. 8.
-   M  moveq immediate data.  Stored as 8 bits.
-      This matches an immediate operand only when value is in range -128..127
-   T  trap vector immediate data.  Stored as 4 bits.
-
-   k  K-factor for fmove.p instruction.   Stored as a 7-bit constant or
-      a three bit register offset, depending on the field type.
-
-   #  immediate data.  Stored in special places (b, w or l)
-      which say how many bits to store.
-   ^  immediate data for floating point instructions.   Special places
-      are offset by 2 bytes from '#'...
-   B  pc-relative address, converted to an offset
-      that is treated as immediate data.
-   d  displacement and register.  Stores the register as 3 bits
-      and stores the displacement in the entire second word.
-
-   C  the CCR.  No need to store it; this is just for filtering validity.
-   S  the SR.  No need to store, just as with CCR.
-   U  the USP.  No need to store, just as with CCR.
-
-   I  Coprocessor ID.   Not printed if 1.   The Coprocessor ID is always
-      extracted from the 'd' field of word one, which means that an extended
-      coprocessor opcode can be skipped using the 'i' place, if needed.
-
-   s  System Control register for the floating point coprocessor.
-   S  List of system control registers for floating point coprocessor.
-
-   J  Misc register for movec instruction, stored in 'j' format.
-       Possible values:
-       000     SFC     Source Function Code reg
-       001     DFC     Data Function Code reg
-       002     CACR    Cache Control Register
-       800     USP     User Stack Pointer
-       801     VBR     Vector Base reg
-       802     CAAR    Cache Address Register
-       803     MSP     Master Stack Pointer
-       804     ISP     Interrupt Stack Pointer
-
-    L  Register list of the type d0-d7/a0-a7 etc.
-       (New!  Improved!  Can also hold fp0-fp7, as well!)
-       The assembler tries to see if the registers match the insn by
-       looking at where the insn wants them stored.
-
-    l  Register list like L, but with all the bits reversed.
-       Used for going the other way. . .
-
- They are all stored as 6 bits using an address mode and a register number;
- they differ in which addressing modes they match.
-
-   *  all                                      (modes 0-6,7.*)
-   ~  alterable memory                         (modes 2-6,7.0,7.1)(not 0,1,7.~)
-   %  alterable                                        (modes 0-6,7.0,7.1)(not 7.~)
-   ;  data                                     (modes 0,2-6,7.*)(not 1)
-   @  data, but not immediate                  (modes 0,2-6,7.? ? ?)(not 1,7.?)  This may really be ;, the 68020 book says it is
-   !  control                                  (modes 2,5,6,7.*-)(not 0,1,3,4,7.4)
-   &  alterable control                                (modes 2,5,6,7.0,7.1)(not 0,1,7.? ? ?)
-   $  alterable data                           (modes 0,2-6,7.0,7.1)(not 1,7.~)
-   ?  alterable control, or data register      (modes 0,2,5,6,7.0,7.1)(not 1,3,4,7.~)
-   /  control, or data register                        (modes 0,2,5,6,7.0,7.1,7.2,7.3)(not 1,3,4,7.4)
-*/
-
-/* JF: for the 68851 */
-/*
-   I didn't use much imagination in choosing the 
-   following codes, so many of them aren't very
-   mnemonic. -rab
-
-   P  pmmu register
-       Possible values:
-       000     TC      Translation Control reg
-       100     CAL     Current Access Level
-       101     VAL     Validate Access Level
-       110     SCC     Stack Change Control
-       111     AC      Access Control
-
-   W  wide pmmu registers
-       Possible values:
-       001     DRP     Dma Root Pointer
-       010     SRP     Supervisor Root Pointer
-       011     CRP     Cpu Root Pointer
-
-   f   function code register
-       0       SFC
-       1       DFC
-
-   V   VAL register only
-
-   X   BADx, BACx
-       100     BAD     Breakpoint Acknowledge Data
-       101     BAC     Breakpoint Acknowledge Control
-
-   Y   PSR
-   Z   PCSR
-
-   |   memory          (modes 2-6, 7.*)
-
-*/
-
-/* Places to put an operand, for non-general operands:
-   s  source, low bits of first word.
-   d  dest, shifted 9 in first word
-   1  second word, shifted 12
-   2  second word, shifted 6
-   3  second word, shifted 0
-   4  third word, shifted 12
-   5  third word, shifted 6
-   6  third word, shifted 0
-   7  second word, shifted 7
-   8  second word, shifted 10
-   D  store in both place 1 and place 3; for divul and divsl.
-   b  second word, low byte
-   w  second word (entire)
-   l  second and third word (entire)
-   g  branch offset for bra and similar instructions.
-      The place to store depends on the magnitude of offset.
-   t  store in both place 7 and place 8; for floating point operations
-   c  branch offset for cpBcc operations.
-      The place to store is word two if bit six of word one is zero,
-      and words two and three if bit six of word one is one.
-   i  Increment by two, to skip over coprocessor extended operands.   Only
-      works with the 'I' format.
-   k  Dynamic K-factor field.   Bits 6-4 of word 2, used as a register number.
-      Also used for dynamic fmovem instruction.
-   C  floating point coprocessor constant - 7 bits.  Also used for static
-      K-factors...
-   j  Movec register #, stored in 12 low bits of second word.
-
- Places to put operand, for general operands:
-   d  destination, shifted 6 bits in first word
-   b  source, at low bit of first word, and immediate uses one byte
-   w  source, at low bit of first word, and immediate uses two bytes
-   l  source, at low bit of first word, and immediate uses four bytes
-   s  source, at low bit of first word.
-      Used sometimes in contexts where immediate is not allowed anyway.
-   f  single precision float, low bit of 1st word, immediate uses 4 bytes
-   F  double precision float, low bit of 1st word, immediate uses 8 bytes
-   x  extended precision float, low bit of 1st word, immediate uses 12 bytes
-   p  packed float, low bit of 1st word, immediate uses 12 bytes
-*/
-
-#define one(x) ((x) << 16)
-#define two(x, y) (((x) << 16) + y)
+void 
+tc_coff_symbol_emit_hook ()
+{
+}
 
+int 
+tc_coff_sizemachdep(frag)
+fragS *frag;
+{
+  switch (frag->fr_subtype & 0x3) 
+  {
+   case BYTE: return 1;
+   case SHORT: return 2;
+   case LONG: return 4;
+   default: abort();
+  }
+
+}
 /*
  * Local Variables:
  * comment-column: 0
@@ -3792,3 +4551,4 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  */
 
 /* end of tc-m68k.c */
+
This page took 0.100068 seconds and 4 git commands to generate.