OSDN Git Service

Update function declarations to ISO C90 formatting
[pf3gnuchains/pf3gnuchains3x.git] / opcodes / m68k-dis.c
index c24c2ad..3504467 100644 (file)
@@ -15,7 +15,8 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
 
 #include "sysdep.h"
 #include "dis-asm.h"
 
 #include "opcode/m68k.h"
 
-/* Local function prototypes */
-
-static int fetch_data (struct disassemble_info *, bfd_byte *);
-static void dummy_print_address (bfd_vma, struct disassemble_info *);
-static int fetch_arg (unsigned char *, int, int, disassemble_info *);
-static void print_base (int, bfd_vma, disassemble_info *);
-static unsigned char * print_indexed (int, unsigned char *, bfd_vma, disassemble_info *);
-static int print_insn_arg (const char *, unsigned char *, unsigned char *,
-                          bfd_vma, disassemble_info *);
-static bfd_boolean m68k_valid_ea (char code, int val);
+/* Local function prototypes.  */
 
 const char * const fpcr_names[] =
 {
-    "", "%fpiar", "%fpsr", "%fpiar/%fpsr", "%fpcr",
-    "%fpiar/%fpcr", "%fpsr/%fpcr", "%fpiar/%fpsr/%fpcr"
+  "", "%fpiar", "%fpsr", "%fpiar/%fpsr", "%fpcr",
+  "%fpiar/%fpcr", "%fpsr/%fpcr", "%fpiar/%fpsr/%fpcr"
 };
 
 static char *const reg_names[] =
 {
-    "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
-    "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp",
-    "%ps", "%pc"
+  "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
+  "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp",
+  "%ps", "%pc"
 };
 
 /* Name of register halves for MAC/EMAC.
    Seperate from reg_names since 'spu', 'fpl' look weird.  */
 static char *const reg_half_names[] =
 {
-    "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
-    "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7",
-    "%ps", "%pc"
+  "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
+  "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7",
+  "%ps", "%pc"
 };
 
 /* Sign-extend an (unsigned char).  */
@@ -112,7 +104,8 @@ static char *const reg_half_names[] =
 
 #include <setjmp.h>
 
-struct private {
+struct private
+{
   /* Points to first byte not fetched.  */
   bfd_byte *max_fetched;
   bfd_byte the_buffer[MAXLEN];
@@ -148,350 +141,442 @@ fetch_data (struct disassemble_info *info, bfd_byte *addr)
   return 1;
 }
 \f
-/* This function is used to print to the bit-bucket. */
+/* This function is used to print to the bit-bucket.  */
 static int
-#ifdef __STDC__
 dummy_printer (FILE *file ATTRIBUTE_UNUSED,
-              const char *format ATTRIBUTE_UNUSED, ...)
-#else
-dummy_printer (FILE *file ATTRIBUTE_UNUSED)
-#endif
+              const char *format ATTRIBUTE_UNUSED,
+              ...)
 {
   return 0;
 }
 
 static void
-dummy_print_address (vma, info)
-     bfd_vma vma ATTRIBUTE_UNUSED;
-     struct disassemble_info *info ATTRIBUTE_UNUSED;
+dummy_print_address (bfd_vma vma ATTRIBUTE_UNUSED,
+                    struct disassemble_info *info ATTRIBUTE_UNUSED)
 {
 }
 
-/* Try to match the current instruction to best and if so, return the
-   number of bytes consumed from the instruction stream, else zero.  */
+/* Fetch BITS bits from a position in the instruction specified by CODE.
+   CODE is a "place to put an argument", or 'x' for a destination
+   that is a general address (mode and register).
+   BUFFER contains the instruction.  */
 
 static int
-match_insn_m68k (bfd_vma memaddr, disassemble_info * info,
-                const struct m68k_opcode * best, struct private * priv)
+fetch_arg (unsigned char *buffer,
+          int code,
+          int bits,
+          disassemble_info *info)
 {
-  unsigned char *save_p;
-  unsigned char *p;
-  const char *d;
-
-  bfd_byte *buffer = priv->the_buffer;
-  fprintf_ftype save_printer = info->fprintf_func;
-  void (* save_print_address) (bfd_vma, struct disassemble_info *)
-    = info->print_address_func;
-
-  /* Point at first word of argument data,
-     and at descriptor for first argument.  */
-  p = buffer + 2;
+  int val = 0;
 
-  /* Figure out how long the fixed-size portion of the instruction is.
-     The only place this is stored in the opcode table is
-     in the arguments--look for arguments which specify fields in the 2nd
-     or 3rd words of the instruction.  */
-  for (d = best->args; *d; d += 2)
+  switch (code)
     {
-      /* I don't think it is necessary to be checking d[0] here;
-        I suspect all this could be moved to the case statement below.  */
-      if (d[0] == '#')
-       {
-         if (d[1] == 'l' && p - buffer < 6)
-           p = buffer + 6;
-         else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8')
-           p = buffer + 4;
-       }
+    case '/': /* MAC/EMAC mask bit.  */
+      val = buffer[3] >> 5;
+      break;
 
-      if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4)
-       p = buffer + 4;
+    case 'G': /* EMAC ACC load.  */
+      val = ((buffer[3] >> 3) & 0x2) | ((~buffer[1] >> 7) & 0x1);
+      break;
 
-      switch (d[1])
-       {
-       case '1':
-       case '2':
-       case '3':
-       case '7':
-       case '8':
-       case '9':
-       case 'i':
-         if (p - buffer < 4)
-           p = buffer + 4;
-         break;
-       case '4':
-       case '5':
-       case '6':
-         if (p - buffer < 6)
-           p = buffer + 6;
-         break;
-       default:
-         break;
-       }
-    }
+    case 'H': /* EMAC ACC !load.  */
+      val = ((buffer[3] >> 3) & 0x2) | ((buffer[1] >> 7) & 0x1);
+      break;
 
-  /* pflusha is an exceptions.  It takes no arguments but is two words
-     long.  Recognize it by looking at the lower 16 bits of the mask.  */
-  if (p - buffer < 4 && (best->match & 0xFFFF) != 0)
-    p = buffer + 4;
+    case ']': /* EMAC ACCEXT bit.  */
+      val = buffer[0] >> 2;
+      break;
 
-  /* lpstop is another exception.  It takes a one word argument but is
-     three words long.  */
-  if (p - buffer < 6
-      && (best->match & 0xffff) == 0xffff
-      && best->args[0] == '#'
-      && best->args[1] == 'w')
-    {
-      /* Copy the one word argument into the usual location for a one
-        word argument, to simplify printing it.  We can get away with
-        this because we know exactly what the second word is, and we
-        aren't going to print anything based on it.  */
-      p = buffer + 6;
-      FETCH_DATA (info, p);
-      buffer[2] = buffer[4];
-      buffer[3] = buffer[5];
-    }
+    case 'I': /* MAC/EMAC scale factor.  */
+      val = buffer[2] >> 1;
+      break;
 
-  FETCH_DATA (info, p);
+    case 'F': /* EMAC ACCx.  */
+      val = buffer[0] >> 1;
+      break;
 
-  d = best->args;
+    case 'f':
+      val = buffer[1];
+      break;
 
-  save_p = p;
-  info->print_address_func = dummy_print_address;
-  info->fprintf_func = (fprintf_ftype) dummy_printer;
+    case 's':
+      val = buffer[1];
+      break;
 
-  /* We scan the operands twice.  The first time we don't print anything,
-     but look for errors. */
-  for (; *d; d += 2)
-    {
-      int eaten = print_insn_arg (d, buffer, p, memaddr + (p - buffer), info);
+    case 'd':                  /* Destination, for register or quick.  */
+      val = (buffer[0] << 8) + buffer[1];
+      val >>= 9;
+      break;
 
-      if (eaten >= 0)
-       p += eaten;
-      else if (eaten == -1)
-       {
-         info->fprintf_func = save_printer;
-         info->print_address_func = save_print_address;
-         return 0;
-       }
-      else
-       {
-         info->fprintf_func (info->stream,
-                             /* xgettext:c-format */
-                             _("<internal error in opcode table: %s %s>\n"),
-                             best->name,  best->args);
-         info->fprintf_func = save_printer;
-         info->print_address_func = save_print_address;
-         return 2;
-       }
-    }
+    case 'x':                  /* Destination, for general arg.  */
+      val = (buffer[0] << 8) + buffer[1];
+      val >>= 6;
+      break;
 
-  p = save_p;
-  info->fprintf_func = save_printer;
-  info->print_address_func = save_print_address;
+    case 'k':
+      FETCH_DATA (info, buffer + 3);
+      val = (buffer[3] >> 4);
+      break;
 
-  d = best->args;
+    case 'C':
+      FETCH_DATA (info, buffer + 3);
+      val = buffer[3];
+      break;
 
-  info->fprintf_func (info->stream, "%s", best->name);
+    case '1':
+      FETCH_DATA (info, buffer + 3);
+      val = (buffer[2] << 8) + buffer[3];
+      val >>= 12;
+      break;
 
-  if (*d)
-    info->fprintf_func (info->stream, " ");
+    case '2':
+      FETCH_DATA (info, buffer + 3);
+      val = (buffer[2] << 8) + buffer[3];
+      val >>= 6;
+      break;
 
-  while (*d)
-    {
-      p += print_insn_arg (d, buffer, p, memaddr + (p - buffer), info);
-      d += 2;
+    case '3':
+    case 'j':
+      FETCH_DATA (info, buffer + 3);
+      val = (buffer[2] << 8) + buffer[3];
+      break;
 
-      if (*d && *(d - 2) != 'I' && *d != 'k')
-       info->fprintf_func (info->stream, ",");
-    }
+    case '4':
+      FETCH_DATA (info, buffer + 5);
+      val = (buffer[4] << 8) + buffer[5];
+      val >>= 12;
+      break;
 
-  return p - buffer;
-}
+    case '5':
+      FETCH_DATA (info, buffer + 5);
+      val = (buffer[4] << 8) + buffer[5];
+      val >>= 6;
+      break;
 
-/* Print the m68k instruction at address MEMADDR in debugged memory,
-   on INFO->STREAM.  Returns length of the instruction, in bytes.  */
+    case '6':
+      FETCH_DATA (info, buffer + 5);
+      val = (buffer[4] << 8) + buffer[5];
+      break;
 
-int
-print_insn_m68k (bfd_vma memaddr, disassemble_info *info)
-{
-  int i;
-  const char *d;
-  unsigned int arch_mask;
-  struct private priv;
-  bfd_byte *buffer = priv.the_buffer;
-  int major_opcode;
-  static int numopcodes[16];
-  static const struct m68k_opcode **opcodes[16];
-  int val;
+    case '7':
+      FETCH_DATA (info, buffer + 3);
+      val = (buffer[2] << 8) + buffer[3];
+      val >>= 7;
+      break;
 
-  if (!opcodes[0])
-    {
-      /* Speed up the matching by sorting the opcode
-        table on the upper four bits of the opcode.  */
-      const struct m68k_opcode **opc_pointer[16];
+    case '8':
+      FETCH_DATA (info, buffer + 3);
+      val = (buffer[2] << 8) + buffer[3];
+      val >>= 10;
+      break;
 
-      /* First count how many opcodes are in each of the sixteen buckets.  */
-      for (i = 0; i < m68k_numopcodes; i++)
-       numopcodes[(m68k_opcodes[i].opcode >> 28) & 15]++;
+    case '9':
+      FETCH_DATA (info, buffer + 3);
+      val = (buffer[2] << 8) + buffer[3];
+      val >>= 5;
+      break;
 
-      /* Then create a sorted table of pointers
-        that point into the unsorted table.  */
-      opc_pointer[0] = xmalloc (sizeof (struct m68k_opcode *)
-                               * m68k_numopcodes);
-      opcodes[0] = opc_pointer[0];
+    case 'e':
+      val = (buffer[1] >> 6);
+      break;
 
-      for (i = 1; i < 16; i++)
-       {
-         opc_pointer[i] = opc_pointer[i - 1] + numopcodes[i - 1];
-         opcodes[i] = opc_pointer[i];
-       }
+    case 'm':
+      val = (buffer[1] & 0x40 ? 0x8 : 0)
+       | ((buffer[0] >> 1) & 0x7)
+       | (buffer[3] & 0x80 ? 0x10 : 0);
+      break;
 
-      for (i = 0; i < m68k_numopcodes; i++)
-       *opc_pointer[(m68k_opcodes[i].opcode >> 28) & 15]++ = &m68k_opcodes[i];
-    }
+    case 'n':
+      val = (buffer[1] & 0x40 ? 0x8 : 0) | ((buffer[0] >> 1) & 0x7);
+      break;
 
-  info->private_data = (PTR) &priv;
-  /* Tell objdump to use two bytes per chunk
-     and six bytes per line for displaying raw data.  */
-  info->bytes_per_chunk = 2;
-  info->bytes_per_line = 6;
-  info->display_endian = BFD_ENDIAN_BIG;
-  priv.max_fetched = priv.the_buffer;
-  priv.insn_start = memaddr;
+    case 'o':
+      val = (buffer[2] >> 4) | (buffer[3] & 0x80 ? 0x10 : 0);
+      break;
 
-  if (setjmp (priv.bailout) != 0)
-    /* Error return.  */
-    return -1;
+    case 'M':
+      val = (buffer[1] & 0xf) | (buffer[3] & 0x40 ? 0x10 : 0);
+      break;
 
-  switch (info->mach)
+    case 'N':
+      val = (buffer[3] & 0xf) | (buffer[3] & 0x40 ? 0x10 : 0);
+      break;
+
+    case 'h':
+      val = buffer[2] >> 2;
+      break;
+
+    default:
+      abort ();
+    }
+
+  switch (bits)
     {
+    case 1:
+      return val & 1;
+    case 2:
+      return val & 3;
+    case 3:
+      return val & 7;
+    case 4:
+      return val & 017;
+    case 5:
+      return val & 037;
+    case 6:
+      return val & 077;
+    case 7:
+      return val & 0177;
+    case 8:
+      return val & 0377;
+    case 12:
+      return val & 07777;
     default:
-    case 0:
-      arch_mask = (unsigned int) -1;
+      abort ();
+    }
+}
+
+/* Check if an EA is valid for a particular code.  This is required
+   for the EMAC instructions since the type of source address determines
+   if it is a EMAC-load instruciton if the EA is mode 2-5, otherwise it
+   is a non-load EMAC instruction and the bits mean register Ry.
+   A similar case exists for the movem instructions where the register
+   mask is interpreted differently for different EAs.  */
+
+static bfd_boolean
+m68k_valid_ea (char code, int val)
+{
+  int mode, mask;
+#define M(n0,n1,n2,n3,n4,n5,n6,n70,n71,n72,n73,n74) \
+  (n0 | n1 << 1 | n2 << 2 | n3 << 3 | n4 << 4 | n5 << 5 | n6 << 6 \
+   | n70 << 7 | n71 << 8 | n72 << 9 | n73 << 10 | n74 << 11)
+
+  switch (code)
+    {
+    case '*':
+      mask = M (1,1,1,1,1,1,1,1,1,1,1,1);
       break;
-    case bfd_mach_m68000:
-      arch_mask = m68000|m68881|m68851;
+    case '~':
+      mask = M (0,0,1,1,1,1,1,1,1,0,0,0);
       break;
-    case bfd_mach_m68008:
-      arch_mask = m68008|m68881|m68851;
+    case '%':
+      mask = M (1,1,1,1,1,1,1,1,1,0,0,0);
       break;
-    case bfd_mach_m68010:
-      arch_mask = m68010|m68881|m68851;
+    case ';':
+      mask = M (1,0,1,1,1,1,1,1,1,1,1,1);
       break;
-    case bfd_mach_m68020:
-      arch_mask = m68020|m68881|m68851;
+    case '@':
+      mask = M (1,0,1,1,1,1,1,1,1,1,1,0);
       break;
-    case bfd_mach_m68030:
-      arch_mask = m68030|m68881|m68851;
+    case '!':
+      mask = M (0,0,1,0,0,1,1,1,1,1,1,0);
       break;
-    case bfd_mach_m68040:
-      arch_mask = m68040|m68881|m68851;
+    case '&':
+      mask = M (0,0,1,0,0,1,1,1,1,0,0,0);
       break;
-    case bfd_mach_m68060:
-      arch_mask = m68060|m68881|m68851;
+    case '$':
+      mask = M (1,0,1,1,1,1,1,1,1,0,0,0);
       break;
-    case bfd_mach_mcf5200:
-      arch_mask = mcfisa_a;
+    case '?':
+      mask = M (1,0,1,0,0,1,1,1,1,0,0,0);
       break;
-    case bfd_mach_mcf521x:
-    case bfd_mach_mcf528x:
-      arch_mask = mcfisa_a|mcfhwdiv|mcfisa_aa|mcfusp|mcfemac;
+    case '/':
+      mask = M (1,0,1,0,0,1,1,1,1,1,1,0);
       break;
-    case bfd_mach_mcf5206e:
-      arch_mask = mcfisa_a|mcfhwdiv|mcfmac;
+    case '|':
+      mask = M (0,0,1,0,0,1,1,1,1,1,1,0);
       break;
-    case bfd_mach_mcf5249:
-      arch_mask = mcfisa_a|mcfhwdiv|mcfemac;
+    case '>':
+      mask = M (0,0,1,0,1,1,1,1,1,0,0,0);
       break;
-    case bfd_mach_mcf5307:
-      arch_mask = mcfisa_a|mcfhwdiv|mcfmac;
+    case '<':
+      mask = M (0,0,1,1,0,1,1,1,1,1,1,0);
       break;
-    case bfd_mach_mcf5407:
-      arch_mask = mcfisa_a|mcfhwdiv|mcfisa_b|mcfmac;
+    case 'm':
+      mask = M (1,1,1,1,1,0,0,0,0,0,0,0);
       break;
-    case bfd_mach_mcf547x:
-    case bfd_mach_mcf548x:
-    case bfd_mach_mcfv4e:
-      arch_mask = mcfisa_a|mcfhwdiv|mcfisa_b|mcfusp|cfloat|mcfemac;
+    case 'n':
+      mask = M (0,0,0,0,0,1,0,0,0,1,0,0);
+      break;
+    case 'o':
+      mask = M (0,0,0,0,0,0,1,1,1,0,1,1);
+      break;
+    case 'p':
+      mask = M (1,1,1,1,1,1,0,0,0,0,0,0);
+      break;
+    case 'q':
+      mask = M (1,0,1,1,1,1,0,0,0,0,0,0);
+      break;
+    case 'v':
+      mask = M (1,0,1,1,1,1,0,1,1,0,0,0);
+      break;
+    case 'b':
+      mask = M (1,0,1,1,1,1,0,0,0,1,0,0);
+      break;
+    case 'w':
+      mask = M (0,0,1,1,1,1,0,0,0,1,0,0);
+      break;
+    case 'y':
+      mask = M (0,0,1,0,0,1,0,0,0,0,0,0);
+      break;
+    case 'z':
+      mask = M (0,0,1,0,0,1,0,0,0,1,0,0);
+      break;
+    case '4':
+      mask = M (0,0,1,1,1,1,0,0,0,0,0,0);
       break;
+    default:
+      abort ();
     }
+#undef M
 
-  FETCH_DATA (info, buffer + 2);
-  major_opcode = (buffer[0] >> 4) & 15;
-
-  for (i = 0; i < numopcodes[major_opcode]; i++)
-    {
-      const struct m68k_opcode *opc = opcodes[major_opcode][i];
-      unsigned long opcode = opc->opcode;
-      unsigned long match = opc->match;
+  mode = (val >> 3) & 7;
+  if (mode == 7)
+    mode += val & 7;
+  return (mask & (1 << mode)) != 0;
+}
 
-      if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24)))
-         && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16)))
-         /* Only fetch the next two bytes if we need to.  */
-         && (((0xffff & match) == 0)
-             ||
-             (FETCH_DATA (info, buffer + 4)
-              && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8)))
-              && ((0xff & buffer[3] & match) == (0xff & opcode)))
-             )
-         && (opc->arch & arch_mask) != 0)
-       {
-         /* Don't use for printout the variants of divul and divsl
-            that have the same register number in two places.
-            The more general variants will match instead.  */
-         for (d = opc->args; *d; d += 2)
-           if (d[1] == 'D')
-             break;
+/* Print a base register REGNO and displacement DISP, on INFO->STREAM.
+   REGNO = -1 for pc, -2 for none (suppressed).  */
 
-         /* Don't use for printout the variants of most floating
-            point coprocessor instructions which use the same
-            register number in two places, as above.  */
-         if (*d == '\0')
-           for (d = opc->args; *d; d += 2)
-             if (d[1] == 't')
-               break;
+static void
+print_base (int regno, bfd_vma disp, disassemble_info *info)
+{
+  if (regno == -1)
+    {
+      (*info->fprintf_func) (info->stream, "%%pc@(");
+      (*info->print_address_func) (disp, info);
+    }
+  else
+    {
+      char buf[50];
 
-         /* Don't match fmovel with more than one register;
-            wait for fmoveml.  */
-         if (*d == '\0')
-           {
-             for (d = opc->args; *d; d += 2)
-               {
-                 if (d[0] == 's' && d[1] == '8')
-                   {
-                     val = fetch_arg (buffer, d[1], 3, info);
-                     if ((val & (val - 1)) != 0)
-                       break;
-                   }
-               }
-           }
+      if (regno == -2)
+       (*info->fprintf_func) (info->stream, "@(");
+      else if (regno == -3)
+       (*info->fprintf_func) (info->stream, "%%zpc@(");
+      else
+       (*info->fprintf_func) (info->stream, "%s@(", reg_names[regno]);
 
-         if (*d == '\0')
-           if ((val = match_insn_m68k (memaddr, info, opc, & priv)))
-             return val;
-       }
+      sprintf_vma (buf, disp);
+      (*info->fprintf_func) (info->stream, "%s", buf);
     }
-
-  /* Handle undefined instructions.  */
-  info->fprintf_func (info->stream, "0%o", (buffer[0] << 8) + buffer[1]);
-  return 2;
 }
 
-/* Returns number of bytes "eaten" by the operand, or
-   return -1 if an invalid operand was found, or -2 if
-   an opcode tabe error was found.  */
-
-/* ADDR is the pc for this arg to be relative to.  */
+/* Print an indexed argument.  The base register is BASEREG (-1 for pc).
+   P points to extension word, in buffer.
+   ADDR is the nominal core address of that extension word.  */
 
-static int
-print_insn_arg (const char *d, unsigned char *buffer,
-               unsigned char *p0, bfd_vma addr,
-               disassemble_info *info)
+static unsigned char *
+print_indexed (int basereg,
+              unsigned char *p,
+              bfd_vma addr,
+              disassemble_info *info)
 {
-  int val = 0;
-  int place = d[1];
-  unsigned char *p = p0;
-  int regno;
+  int word;
+  static char *const scales[] = { "", ":2", ":4", ":8" };
+  bfd_vma base_disp;
+  bfd_vma outer_disp;
+  char buf[40];
+  char vmabuf[50];
+
+  word = NEXTWORD (p);
+
+  /* Generate the text for the index register.
+     Where this will be output is not yet determined.  */
+  sprintf (buf, "%s:%c%s",
+          reg_names[(word >> 12) & 0xf],
+          (word & 0x800) ? 'l' : 'w',
+          scales[(word >> 9) & 3]);
+
+  /* Handle the 68000 style of indexing.  */
+
+  if ((word & 0x100) == 0)
+    {
+      base_disp = word & 0xff;
+      if ((base_disp & 0x80) != 0)
+       base_disp -= 0x100;
+      if (basereg == -1)
+       base_disp += addr;
+      print_base (basereg, base_disp, info);
+      (*info->fprintf_func) (info->stream, ",%s)", buf);
+      return p;
+    }
+
+  /* Handle the generalized kind.  */
+  /* First, compute the displacement to add to the base register.  */
+  if (word & 0200)
+    {
+      if (basereg == -1)
+       basereg = -3;
+      else
+       basereg = -2;
+    }
+  if (word & 0100)
+    buf[0] = '\0';
+  base_disp = 0;
+  switch ((word >> 4) & 3)
+    {
+    case 2:
+      base_disp = NEXTWORD (p);
+      break;
+    case 3:
+      base_disp = NEXTLONG (p);
+    }
+  if (basereg == -1)
+    base_disp += addr;
+
+  /* Handle single-level case (not indirect).  */
+  if ((word & 7) == 0)
+    {
+      print_base (basereg, base_disp, info);
+      if (buf[0] != '\0')
+       (*info->fprintf_func) (info->stream, ",%s", buf);
+      (*info->fprintf_func) (info->stream, ")");
+      return p;
+    }
+
+  /* Two level.  Compute displacement to add after indirection.  */
+  outer_disp = 0;
+  switch (word & 3)
+    {
+    case 2:
+      outer_disp = NEXTWORD (p);
+      break;
+    case 3:
+      outer_disp = NEXTLONG (p);
+    }
+
+  print_base (basereg, base_disp, info);
+  if ((word & 4) == 0 && buf[0] != '\0')
+    {
+      (*info->fprintf_func) (info->stream, ",%s", buf);
+      buf[0] = '\0';
+    }
+  sprintf_vma (vmabuf, outer_disp);
+  (*info->fprintf_func) (info->stream, ")@(%s", vmabuf);
+  if (buf[0] != '\0')
+    (*info->fprintf_func) (info->stream, ",%s", buf);
+  (*info->fprintf_func) (info->stream, ")");
+
+  return p;
+}
+
+/* Returns number of bytes "eaten" by the operand, or
+   return -1 if an invalid operand was found, or -2 if
+   an opcode tabe error was found.
+   ADDR is the pc for this arg to be relative to.  */
+
+static int
+print_insn_arg (const char *d,
+               unsigned char *buffer,
+               unsigned char *p0,
+               bfd_vma addr,
+               disassemble_info *info)
+{
+  int val = 0;
+  int place = d[1];
+  unsigned char *p = p0;
+  int regno;
   const char *regname;
   unsigned char *p1;
   double flval;
@@ -675,7 +760,7 @@ print_insn_arg (const char *d, unsigned char *buffer,
       else if (place == 'C')
        {
          val = fetch_arg (buffer, place, 7, info);
-         if (val > 63)         /* This is a signed constant. */
+         if (val > 63)         /* This is a signed constant.  */
            val -= 128;
          (*info->fprintf_func) (info->stream, "{#%d}", val);
        }
@@ -724,7 +809,7 @@ print_insn_arg (const char *d, unsigned char *buffer,
        }
       else if (place == 'c')
        {
-         if (buffer[1] & 0x40)         /* If bit six is one, long offset */
+         if (buffer[1] & 0x40)         /* If bit six is one, long offset */
            disp = NEXTLONG (p);
          else
            disp = NEXTWORD (p);
@@ -756,7 +841,7 @@ print_insn_arg (const char *d, unsigned char *buffer,
       val = fetch_arg(buffer, place, 1, info);
       (*info->fprintf_func) (info->stream, "%%accext%s", val==0 ? "01" : "23");
       break;
-      
+
     case 'i':
       val = fetch_arg(buffer, place, 2, info);
       if (val == 1)
@@ -771,7 +856,7 @@ print_insn_arg (const char *d, unsigned char *buffer,
       /* Get coprocessor ID... */
       val = fetch_arg (buffer, 'd', 3, info);
 
-      if (val != 1)                            /* Unusual coprocessor ID? */
+      if (val != 1)                            /* Unusual coprocessor ID?  */
        (*info->fprintf_func) (info->stream, "(cpid=%d) ", val);
       break;
 
@@ -946,7 +1031,8 @@ print_insn_arg (const char *d, unsigned char *buffer,
              }
            if (*d == 'l')
              {
-               register int newval = 0;
+               int newval = 0;
+
                for (regno = 0; regno < 16; ++regno)
                  if (val & (0x8000 >> regno))
                    newval |= 1 << regno;
@@ -958,6 +1044,7 @@ print_insn_arg (const char *d, unsigned char *buffer,
              if (val & (1 << regno))
                {
                  int first_regno;
+
                  if (doneany)
                    (*info->fprintf_func) (info->stream, "/");
                  doneany = 1;
@@ -982,7 +1069,8 @@ print_insn_arg (const char *d, unsigned char *buffer,
              }
            if (*d == 'l')
              {
-               register int newval = 0;
+               int newval = 0;
+
                for (regno = 0; regno < 8; ++regno)
                  if (val & (0x80 >> regno))
                    newval |= 1 << regno;
@@ -1007,7 +1095,7 @@ print_insn_arg (const char *d, unsigned char *buffer,
          }
        else if (place == '8')
          {
-           /* fmoveml for FP status registers */
+           /* fmoveml for FP status registers */
            (*info->fprintf_func) (info->stream, "%s",
                                   fpcr_names[fetch_arg (buffer, place, 3,
                                                         info)]);
@@ -1028,6 +1116,7 @@ print_insn_arg (const char *d, unsigned char *buffer,
       {
        int val = fetch_arg (buffer, place, 5, info);
        char *name = 0;
+
        switch (val)
          {
          case 2: name = "%tt0"; break;
@@ -1046,6 +1135,7 @@ print_insn_arg (const char *d, unsigned char *buffer,
          case 0x1d:
            {
              int break_reg = ((buffer[3] >> 2) & 7);
+
              (*info->fprintf_func)
                (info->stream, val == 0x1c ? "%%bad%d" : "%%bac%d",
                 break_reg);
@@ -1062,6 +1152,7 @@ print_insn_arg (const char *d, unsigned char *buffer,
     case 'f':
       {
        int fc = fetch_arg (buffer, place, 5, info);
+
        if (fc == 1)
          (*info->fprintf_func) (info->stream, "%%dfc");
        else if (fc == 0)
@@ -1079,6 +1170,7 @@ print_insn_arg (const char *d, unsigned char *buffer,
     case 't':
       {
        int level = fetch_arg (buffer, place, 3, info);
+
        (*info->fprintf_func) (info->stream, "%d", level);
       }
       break;
@@ -1106,406 +1198,314 @@ print_insn_arg (const char *d, unsigned char *buffer,
   return p - p0;
 }
 
-/* Check if an EA is valid for a particular code.  This is required
-   for the EMAC instructions since the type of source address determines
-   if it is a EMAC-load instruciton if the EA is mode 2-5, otherwise it
-   is a non-load EMAC instruction and the bits mean register Ry.
-   A similar case exists for the movem instructions where the register
-   mask is interpreted differently for different EAs.  */
-
-static bfd_boolean
-m68k_valid_ea (char code, int val)
-{
-  int mode, mask;
-#define M(n0,n1,n2,n3,n4,n5,n6,n70,n71,n72,n73,n74) \
-  (n0 | n1 << 1 | n2 << 2 | n3 << 3 | n4 << 4 | n5 << 5 | n6 << 6 \
-   | n70 << 7 | n71 << 8 | n72 << 9 | n73 << 10 | n74 << 11)
-
-  switch (code)
-    {
-    case '*':
-      mask = M (1,1,1,1,1,1,1,1,1,1,1,1);
-      break;
-    case '~':
-      mask = M (0,0,1,1,1,1,1,1,1,0,0,0);
-      break;
-    case '%':
-      mask = M (1,1,1,1,1,1,1,1,1,0,0,0);
-      break;
-    case ';':
-      mask = M (1,0,1,1,1,1,1,1,1,1,1,1);
-      break;
-    case '@':
-      mask = M (1,0,1,1,1,1,1,1,1,1,1,0);
-      break;
-    case '!':
-      mask = M (0,0,1,0,0,1,1,1,1,1,1,0);
-      break;
-    case '&':
-      mask = M (0,0,1,0,0,1,1,1,1,0,0,0);
-      break;
-    case '$':
-      mask = M (1,0,1,1,1,1,1,1,1,0,0,0);
-      break;
-    case '?':
-      mask = M (1,0,1,0,0,1,1,1,1,0,0,0);
-      break;
-    case '/':
-      mask = M (1,0,1,0,0,1,1,1,1,1,1,0);
-      break;
-    case '|':
-      mask = M (0,0,1,0,0,1,1,1,1,1,1,0);
-      break;
-    case '>':
-      mask = M (0,0,1,0,1,1,1,1,1,0,0,0);
-      break;
-    case '<':
-      mask = M (0,0,1,1,0,1,1,1,1,1,1,0);
-      break;
-    case 'm':
-      mask = M (1,1,1,1,1,0,0,0,0,0,0,0);
-      break;
-    case 'n':
-      mask = M (0,0,0,0,0,1,0,0,0,1,0,0);
-      break;
-    case 'o':
-      mask = M (0,0,0,0,0,0,1,1,1,0,1,1);
-      break;
-    case 'p':
-      mask = M (1,1,1,1,1,1,0,0,0,0,0,0);
-      break;
-    case 'q':
-      mask = M (1,0,1,1,1,1,0,0,0,0,0,0);
-      break;
-    case 'v':
-      mask = M (1,0,1,1,1,1,0,1,1,0,0,0);
-      break;
-    case 'b':
-      mask = M (1,0,1,1,1,1,0,0,0,1,0,0);
-      break;
-    case 'w':
-      mask = M (0,0,1,1,1,1,0,0,0,1,0,0);
-      break;
-    case 'y':
-      mask = M (0,0,1,0,0,1,0,0,0,0,0,0);
-      break;
-    case 'z':
-      mask = M (0,0,1,0,0,1,0,0,0,1,0,0);
-      break;
-    case '4':
-      mask = M (0,0,1,1,1,1,0,0,0,0,0,0);
-      break;
-    default:
-      abort ();
-    }
-#undef M
-
-  mode = (val >> 3) & 7;
-  if (mode == 7)
-    mode += val & 7;
-  return (mask & (1 << mode)) != 0;
-}
-
-/* Fetch BITS bits from a position in the instruction specified by CODE.
-   CODE is a "place to put an argument", or 'x' for a destination
-   that is a general address (mode and register).
-   BUFFER contains the instruction.  */
+/* Try to match the current instruction to best and if so, return the
+   number of bytes consumed from the instruction stream, else zero.  */
 
 static int
-fetch_arg (unsigned char *buffer, int code, int bits,
-          disassemble_info *info)
+match_insn_m68k (bfd_vma memaddr,
+                disassemble_info * info,
+                const struct m68k_opcode * best,
+                struct private * priv)
 {
-  int val = 0;
+  unsigned char *save_p;
+  unsigned char *p;
+  const char *d;
 
-  switch (code)
-    {
-    case '/': /* MAC/EMAC mask bit.  */
-      val = buffer[3] >> 5;
-      break;
+  bfd_byte *buffer = priv->the_buffer;
+  fprintf_ftype save_printer = info->fprintf_func;
+  void (* save_print_address) (bfd_vma, struct disassemble_info *)
+    = info->print_address_func;
 
-    case 'G': /* EMAC ACC load.  */
-      val = ((buffer[3] >> 3) & 0x2) | ((~buffer[1] >> 7) & 0x1);
-      break;
+  /* Point at first word of argument data,
+     and at descriptor for first argument.  */
+  p = buffer + 2;
 
-    case 'H': /* EMAC ACC !load.  */
-      val = ((buffer[3] >> 3) & 0x2) | ((buffer[1] >> 7) & 0x1);
-      break;
+  /* Figure out how long the fixed-size portion of the instruction is.
+     The only place this is stored in the opcode table is
+     in the arguments--look for arguments which specify fields in the 2nd
+     or 3rd words of the instruction.  */
+  for (d = best->args; *d; d += 2)
+    {
+      /* I don't think it is necessary to be checking d[0] here;
+        I suspect all this could be moved to the case statement below.  */
+      if (d[0] == '#')
+       {
+         if (d[1] == 'l' && p - buffer < 6)
+           p = buffer + 6;
+         else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8')
+           p = buffer + 4;
+       }
 
-    case ']': /* EMAC ACCEXT bit.  */
-      val = buffer[0] >> 2;
-      break;
+      if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4)
+       p = buffer + 4;
 
-    case 'I': /* MAC/EMAC scale factor.  */
-      val = buffer[2] >> 1;
-      break;
-
-    case 'F': /* EMAC ACCx.  */
-      val = buffer[0] >> 1;
-      break;
-
-    case 'f':
-      val = buffer[1];
-      break;
-
-    case 's':
-      val = buffer[1];
-      break;
-
-    case 'd':                  /* Destination, for register or quick.  */
-      val = (buffer[0] << 8) + buffer[1];
-      val >>= 9;
-      break;
-
-    case 'x':                  /* Destination, for general arg */
-      val = (buffer[0] << 8) + buffer[1];
-      val >>= 6;
-      break;
-
-    case 'k':
-      FETCH_DATA (info, buffer + 3);
-      val = (buffer[3] >> 4);
-      break;
-
-    case 'C':
-      FETCH_DATA (info, buffer + 3);
-      val = buffer[3];
-      break;
-
-    case '1':
-      FETCH_DATA (info, buffer + 3);
-      val = (buffer[2] << 8) + buffer[3];
-      val >>= 12;
-      break;
-
-    case '2':
-      FETCH_DATA (info, buffer + 3);
-      val = (buffer[2] << 8) + buffer[3];
-      val >>= 6;
-      break;
-
-    case '3':
-    case 'j':
-      FETCH_DATA (info, buffer + 3);
-      val = (buffer[2] << 8) + buffer[3];
-      break;
-
-    case '4':
-      FETCH_DATA (info, buffer + 5);
-      val = (buffer[4] << 8) + buffer[5];
-      val >>= 12;
-      break;
+      switch (d[1])
+       {
+       case '1':
+       case '2':
+       case '3':
+       case '7':
+       case '8':
+       case '9':
+       case 'i':
+         if (p - buffer < 4)
+           p = buffer + 4;
+         break;
+       case '4':
+       case '5':
+       case '6':
+         if (p - buffer < 6)
+           p = buffer + 6;
+         break;
+       default:
+         break;
+       }
+    }
 
-    case '5':
-      FETCH_DATA (info, buffer + 5);
-      val = (buffer[4] << 8) + buffer[5];
-      val >>= 6;
-      break;
+  /* pflusha is an exceptions.  It takes no arguments but is two words
+     long.  Recognize it by looking at the lower 16 bits of the mask.  */
+  if (p - buffer < 4 && (best->match & 0xFFFF) != 0)
+    p = buffer + 4;
 
-    case '6':
-      FETCH_DATA (info, buffer + 5);
-      val = (buffer[4] << 8) + buffer[5];
-      break;
+  /* lpstop is another exception.  It takes a one word argument but is
+     three words long.  */
+  if (p - buffer < 6
+      && (best->match & 0xffff) == 0xffff
+      && best->args[0] == '#'
+      && best->args[1] == 'w')
+    {
+      /* Copy the one word argument into the usual location for a one
+        word argument, to simplify printing it.  We can get away with
+        this because we know exactly what the second word is, and we
+        aren't going to print anything based on it.  */
+      p = buffer + 6;
+      FETCH_DATA (info, p);
+      buffer[2] = buffer[4];
+      buffer[3] = buffer[5];
+    }
 
-    case '7':
-      FETCH_DATA (info, buffer + 3);
-      val = (buffer[2] << 8) + buffer[3];
-      val >>= 7;
-      break;
+  FETCH_DATA (info, p);
 
-    case '8':
-      FETCH_DATA (info, buffer + 3);
-      val = (buffer[2] << 8) + buffer[3];
-      val >>= 10;
-      break;
+  d = best->args;
 
-    case '9':
-      FETCH_DATA (info, buffer + 3);
-      val = (buffer[2] << 8) + buffer[3];
-      val >>= 5;
-      break;
+  save_p = p;
+  info->print_address_func = dummy_print_address;
+  info->fprintf_func = (fprintf_ftype) dummy_printer;
 
-    case 'e':
-      val = (buffer[1] >> 6);
-      break;
+  /* We scan the operands twice.  The first time we don't print anything,
+     but look for errors.  */
+  for (; *d; d += 2)
+    {
+      int eaten = print_insn_arg (d, buffer, p, memaddr + (p - buffer), info);
 
-    case 'm':
-      val = (buffer[1] & 0x40 ? 0x8 : 0)
-       | ((buffer[0] >> 1) & 0x7)
-       | (buffer[3] & 0x80 ? 0x10 : 0);
-      break;
+      if (eaten >= 0)
+       p += eaten;
+      else if (eaten == -1)
+       {
+         info->fprintf_func = save_printer;
+         info->print_address_func = save_print_address;
+         return 0;
+       }
+      else
+       {
+         info->fprintf_func (info->stream,
+                             /* xgettext:c-format */
+                             _("<internal error in opcode table: %s %s>\n"),
+                             best->name,  best->args);
+         info->fprintf_func = save_printer;
+         info->print_address_func = save_print_address;
+         return 2;
+       }
+    }
 
-    case 'n':
-      val = (buffer[1] & 0x40 ? 0x8 : 0) | ((buffer[0] >> 1) & 0x7);
-      break;
+  p = save_p;
+  info->fprintf_func = save_printer;
+  info->print_address_func = save_print_address;
 
-    case 'o':
-      val = (buffer[2] >> 4) | (buffer[3] & 0x80 ? 0x10 : 0);
-      break;
+  d = best->args;
 
-    case 'M':
-      val = (buffer[1] & 0xf) | (buffer[3] & 0x40 ? 0x10 : 0);
-      break;
+  info->fprintf_func (info->stream, "%s", best->name);
 
-    case 'N':
-      val = (buffer[3] & 0xf) | (buffer[3] & 0x40 ? 0x10 : 0);
-      break;
+  if (*d)
+    info->fprintf_func (info->stream, " ");
 
-    case 'h':
-      val = buffer[2] >> 2;
-      break;
+  while (*d)
+    {
+      p += print_insn_arg (d, buffer, p, memaddr + (p - buffer), info);
+      d += 2;
 
-    default:
-      abort ();
+      if (*d && *(d - 2) != 'I' && *d != 'k')
+       info->fprintf_func (info->stream, ",");
     }
 
-  switch (bits)
-    {
-    case 1:
-      return val & 1;
-    case 2:
-      return val & 3;
-    case 3:
-      return val & 7;
-    case 4:
-      return val & 017;
-    case 5:
-      return val & 037;
-    case 6:
-      return val & 077;
-    case 7:
-      return val & 0177;
-    case 8:
-      return val & 0377;
-    case 12:
-      return val & 07777;
-    default:
-      abort ();
-    }
+  return p - buffer;
 }
 
-/* Print an indexed argument.  The base register is BASEREG (-1 for pc).
-   P points to extension word, in buffer.
-   ADDR is the nominal core address of that extension word.  */
+/* Print the m68k instruction at address MEMADDR in debugged memory,
+   on INFO->STREAM.  Returns length of the instruction, in bytes.  */
 
-static unsigned char *
-print_indexed (int basereg, unsigned char *p,
-              bfd_vma addr, disassemble_info *info)
+int
+print_insn_m68k (bfd_vma memaddr, disassemble_info *info)
 {
-  int word;
-  static char *const scales[] = { "", ":2", ":4", ":8" };
-  bfd_vma base_disp;
-  bfd_vma outer_disp;
-  char buf[40];
-  char vmabuf[50];
-
-  word = NEXTWORD (p);
-
-  /* Generate the text for the index register.
-     Where this will be output is not yet determined.  */
-  sprintf (buf, "%s:%c%s",
-          reg_names[(word >> 12) & 0xf],
-          (word & 0x800) ? 'l' : 'w',
-          scales[(word >> 9) & 3]);
-
-  /* Handle the 68000 style of indexing.  */
+  int i;
+  const char *d;
+  unsigned int arch_mask;
+  struct private priv;
+  bfd_byte *buffer = priv.the_buffer;
+  int major_opcode;
+  static int numopcodes[16];
+  static const struct m68k_opcode **opcodes[16];
+  int val;
 
-  if ((word & 0x100) == 0)
+  if (!opcodes[0])
     {
-      base_disp = word & 0xff;
-      if ((base_disp & 0x80) != 0)
-       base_disp -= 0x100;
-      if (basereg == -1)
-       base_disp += addr;
-      print_base (basereg, base_disp, info);
-      (*info->fprintf_func) (info->stream, ",%s)", buf);
-      return p;
-    }
+      /* Speed up the matching by sorting the opcode
+        table on the upper four bits of the opcode.  */
+      const struct m68k_opcode **opc_pointer[16];
 
-  /* Handle the generalized kind.  */
-  /* First, compute the displacement to add to the base register.  */
+      /* First count how many opcodes are in each of the sixteen buckets.  */
+      for (i = 0; i < m68k_numopcodes; i++)
+       numopcodes[(m68k_opcodes[i].opcode >> 28) & 15]++;
 
-  if (word & 0200)
-    {
-      if (basereg == -1)
-       basereg = -3;
-      else
-       basereg = -2;
-    }
-  if (word & 0100)
-    buf[0] = '\0';
-  base_disp = 0;
-  switch ((word >> 4) & 3)
-    {
-    case 2:
-      base_disp = NEXTWORD (p);
-      break;
-    case 3:
-      base_disp = NEXTLONG (p);
-    }
-  if (basereg == -1)
-    base_disp += addr;
+      /* Then create a sorted table of pointers
+        that point into the unsorted table.  */
+      opc_pointer[0] = xmalloc (sizeof (struct m68k_opcode *)
+                               * m68k_numopcodes);
+      opcodes[0] = opc_pointer[0];
 
-  /* Handle single-level case (not indirect) */
+      for (i = 1; i < 16; i++)
+       {
+         opc_pointer[i] = opc_pointer[i - 1] + numopcodes[i - 1];
+         opcodes[i] = opc_pointer[i];
+       }
 
-  if ((word & 7) == 0)
-    {
-      print_base (basereg, base_disp, info);
-      if (buf[0] != '\0')
-       (*info->fprintf_func) (info->stream, ",%s", buf);
-      (*info->fprintf_func) (info->stream, ")");
-      return p;
+      for (i = 0; i < m68k_numopcodes; i++)
+       *opc_pointer[(m68k_opcodes[i].opcode >> 28) & 15]++ = &m68k_opcodes[i];
     }
 
-  /* Two level.  Compute displacement to add after indirection.  */
+  info->private_data = (PTR) &priv;
+  /* Tell objdump to use two bytes per chunk
+     and six bytes per line for displaying raw data.  */
+  info->bytes_per_chunk = 2;
+  info->bytes_per_line = 6;
+  info->display_endian = BFD_ENDIAN_BIG;
+  priv.max_fetched = priv.the_buffer;
+  priv.insn_start = memaddr;
 
-  outer_disp = 0;
-  switch (word & 3)
+  if (setjmp (priv.bailout) != 0)
+    /* Error return.  */
+    return -1;
+
+  switch (info->mach)
     {
-    case 2:
-      outer_disp = NEXTWORD (p);
+    default:
+    case 0:
+      arch_mask = (unsigned int) -1;
+      break;
+    case bfd_mach_m68000:
+      arch_mask = m68000|m68881|m68851;
+      break;
+    case bfd_mach_m68008:
+      arch_mask = m68008|m68881|m68851;
+      break;
+    case bfd_mach_m68010:
+      arch_mask = m68010|m68881|m68851;
+      break;
+    case bfd_mach_m68020:
+      arch_mask = m68020|m68881|m68851;
+      break;
+    case bfd_mach_m68030:
+      arch_mask = m68030|m68881|m68851;
+      break;
+    case bfd_mach_m68040:
+      arch_mask = m68040|m68881|m68851;
+      break;
+    case bfd_mach_m68060:
+      arch_mask = m68060|m68881|m68851;
+      break;
+    case bfd_mach_mcf5200:
+      arch_mask = mcfisa_a;
+      break;
+    case bfd_mach_mcf521x:
+    case bfd_mach_mcf528x:
+      arch_mask = mcfisa_a|mcfhwdiv|mcfisa_aa|mcfusp|mcfemac;
+      break;
+    case bfd_mach_mcf5206e:
+      arch_mask = mcfisa_a|mcfhwdiv|mcfmac;
+      break;
+    case bfd_mach_mcf5249:
+      arch_mask = mcfisa_a|mcfhwdiv|mcfemac;
+      break;
+    case bfd_mach_mcf5307:
+      arch_mask = mcfisa_a|mcfhwdiv|mcfmac;
+      break;
+    case bfd_mach_mcf5407:
+      arch_mask = mcfisa_a|mcfhwdiv|mcfisa_b|mcfmac;
+      break;
+    case bfd_mach_mcf547x:
+    case bfd_mach_mcf548x:
+    case bfd_mach_mcfv4e:
+      arch_mask = mcfisa_a|mcfhwdiv|mcfisa_b|mcfusp|cfloat|mcfemac;
       break;
-    case 3:
-      outer_disp = NEXTLONG (p);
     }
 
-  print_base (basereg, base_disp, info);
-  if ((word & 4) == 0 && buf[0] != '\0')
-    {
-      (*info->fprintf_func) (info->stream, ",%s", buf);
-      buf[0] = '\0';
-    }
-  sprintf_vma (vmabuf, outer_disp);
-  (*info->fprintf_func) (info->stream, ")@(%s", vmabuf);
-  if (buf[0] != '\0')
-    (*info->fprintf_func) (info->stream, ",%s", buf);
-  (*info->fprintf_func) (info->stream, ")");
+  FETCH_DATA (info, buffer + 2);
+  major_opcode = (buffer[0] >> 4) & 15;
 
-  return p;
-}
+  for (i = 0; i < numopcodes[major_opcode]; i++)
+    {
+      const struct m68k_opcode *opc = opcodes[major_opcode][i];
+      unsigned long opcode = opc->opcode;
+      unsigned long match = opc->match;
 
-/* Print a base register REGNO and displacement DISP, on INFO->STREAM.
-   REGNO = -1 for pc, -2 for none (suppressed).  */
+      if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24)))
+         && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16)))
+         /* Only fetch the next two bytes if we need to.  */
+         && (((0xffff & match) == 0)
+             ||
+             (FETCH_DATA (info, buffer + 4)
+              && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8)))
+              && ((0xff & buffer[3] & match) == (0xff & opcode)))
+             )
+         && (opc->arch & arch_mask) != 0)
+       {
+         /* Don't use for printout the variants of divul and divsl
+            that have the same register number in two places.
+            The more general variants will match instead.  */
+         for (d = opc->args; *d; d += 2)
+           if (d[1] == 'D')
+             break;
 
-static void
-print_base (int regno, bfd_vma disp, disassemble_info *info)
-{
-  if (regno == -1)
-    {
-      (*info->fprintf_func) (info->stream, "%%pc@(");
-      (*info->print_address_func) (disp, info);
-    }
-  else
-    {
-      char buf[50];
+         /* Don't use for printout the variants of most floating
+            point coprocessor instructions which use the same
+            register number in two places, as above.  */
+         if (*d == '\0')
+           for (d = opc->args; *d; d += 2)
+             if (d[1] == 't')
+               break;
 
-      if (regno == -2)
-       (*info->fprintf_func) (info->stream, "@(");
-      else if (regno == -3)
-       (*info->fprintf_func) (info->stream, "%%zpc@(");
-      else
-       (*info->fprintf_func) (info->stream, "%s@(", reg_names[regno]);
+         /* Don't match fmovel with more than one register;
+            wait for fmoveml.  */
+         if (*d == '\0')
+           {
+             for (d = opc->args; *d; d += 2)
+               {
+                 if (d[0] == 's' && d[1] == '8')
+                   {
+                     val = fetch_arg (buffer, d[1], 3, info);
+                     if ((val & (val - 1)) != 0)
+                       break;
+                   }
+               }
+           }
 
-      sprintf_vma (buf, disp);
-      (*info->fprintf_func) (info->stream, "%s", buf);
+         if (*d == '\0')
+           if ((val = match_insn_m68k (memaddr, info, opc, & priv)))
+             return val;
+       }
     }
+
+  /* Handle undefined instructions.  */
+  info->fprintf_func (info->stream, "0%o", (buffer[0] << 8) + buffer[1]);
+  return 2;
 }