This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] S12Z: opcodes: Separate the decoding of operations from their display.


This change adds an abstraction layer between the decoding of machine
operations and their disassembled textual representation.  This allows
the decoding routines to be re-used for other purposes (at the expense)
of slightly slower running time.

ChangeLog: opcodes/

   * s12z-opc.c: New file.
   * s12z-opc.h: New file.
   * s12z-dis.c: Removed all code not directly related to display
     of instructions.  Used the interface provided by the new files
     instead.
   * Makefile.am (TARGET_LIBOPCODES_CFILES) Add s12z-opc.c.
   * Makefile.in: regenerate.
   * configure.ac (bfd_s12z_arch): Correct the dependencies.
   * configure: regenerate.
---
 opcodes/Makefile.am  |    1 +
 opcodes/Makefile.in  |    2 +
 opcodes/configure    |    2 +-
 opcodes/configure.ac |    2 +-
 opcodes/s12z-dis.c   | 2828 +++++---------------------------------------------
 opcodes/s12z-opc.c   | 2701 +++++++++++++++++++++++++++++++++++++++++++++++
 opcodes/s12z-opc.h   |  267 +++++
 7 files changed, 3241 insertions(+), 2562 deletions(-)
 create mode 100644 opcodes/s12z-opc.c
 create mode 100644 opcodes/s12z-opc.h

diff --git a/opcodes/Makefile.am b/opcodes/Makefile.am
index cf26ddf4bc..ccffbb58c9 100644
--- a/opcodes/Makefile.am
+++ b/opcodes/Makefile.am
@@ -176,6 +176,7 @@ TARGET_LIBOPCODES_CFILES = \
 	m68k-dis.c \
 	m68k-opc.c \
 	s12z-dis.c \
+	s12z-opc.c \
 	mcore-dis.c \
 	mep-asm.c \
 	mep-desc.c \
diff --git a/opcodes/configure.ac b/opcodes/configure.ac
index 7384684bc0..d7b1e2ec88 100644
--- a/opcodes/configure.ac
+++ b/opcodes/configure.ac
@@ -287,7 +287,7 @@ if test x${all_targets} = xfalse ; then
 	bfd_m68hc12_arch)	ta="$ta m68hc11-dis.lo m68hc11-opc.lo" ;;
 	bfd_m9s12x_arch)	ta="$ta m68hc11-dis.lo m68hc11-opc.lo" ;;
 	bfd_m9s12xg_arch)	ta="$ta m68hc11-dis.lo m68hc11-opc.lo" ;;
-	bfd_s12z_arch)	ta="$ta s12z-dis.lo m68hc11-opc.lo" ;;
+	bfd_s12z_arch)		ta="$ta s12z-dis.lo s12z-opc.lo" ;;
 	bfd_m68k_arch)		ta="$ta m68k-dis.lo m68k-opc.lo" ;;
 	bfd_mcore_arch)		ta="$ta mcore-dis.lo" ;;
 	bfd_mep_arch)		ta="$ta mep-asm.lo mep-desc.lo mep-dis.lo mep-ibld.lo mep-opc.lo" using_cgen=yes ;;
diff --git a/opcodes/s12z-dis.c b/opcodes/s12z-dis.c
index 719f172bcc..9c32209d0d 100644
--- a/opcodes/s12z-dis.c
+++ b/opcodes/s12z-dis.c
@@ -29,266 +29,51 @@
 #include "bfd.h"
 #include "dis-asm.h"
 
-
 #include "disassemble.h"
 
-static int
-read_memory (bfd_vma memaddr, bfd_byte* buffer, int size,
-             struct disassemble_info* info)
-{
-  int status = (*info->read_memory_func) (memaddr, buffer, size, info);
-  if (status != 0)
-    {
-      (*info->memory_error_func) (status, memaddr, info);
-      return -1;
-    }
-  return 0;
-}
-
-typedef int (* insn_bytes_f) (bfd_vma memaddr,
-			      struct disassemble_info* info);
-
-typedef void (*operands_f) (bfd_vma memaddr, struct disassemble_info* info);
-
-enum OPR_MODE
-  {
-    OPR_IMMe4,
-    OPR_REG,
-    OPR_OFXYS,
-    OPR_XY_PRE_INC,
-    OPR_XY_POST_INC,
-    OPR_XY_PRE_DEC,
-    OPR_XY_POST_DEC,
-    OPR_S_PRE_DEC,
-    OPR_S_POST_INC,
-    OPR_REG_DIRECT,
-    OPR_REG_INDIRECT,
-    OPR_IDX_DIRECT,
-    OPR_IDX_INDIRECT,
-    OPR_EXT1,
-    OPR_IDX2_REG,
-    OPR_IDX3_DIRECT,
-    OPR_IDX3_INDIRECT,
-
-    OPR_EXT18,
-    OPR_IDX3_DIRECT_REG,
-    OPR_EXT3_DIRECT,
-    OPR_EXT3_INDIRECT
-  };
-
-struct opr_pb
-{
-  uint8_t mask;
-  uint8_t value;
-  int n_operands;
-  enum OPR_MODE mode;
-};
-
-static const  struct opr_pb opr_pb[] = {
-  {0xF0, 0x70, 1, OPR_IMMe4},
-  {0xF8, 0xB8, 1, OPR_REG},
-  {0xC0, 0x40, 1, OPR_OFXYS},
-  {0xEF, 0xE3, 1, OPR_XY_PRE_INC},
-  {0xEF, 0xE7, 1, OPR_XY_POST_INC},
-  {0xEF, 0xC3, 1, OPR_XY_PRE_DEC},
-  {0xEF, 0xC7, 1, OPR_XY_POST_DEC},
-  {0xFF, 0xFB, 1, OPR_S_PRE_DEC},
-  {0xFF, 0xFF, 1, OPR_S_POST_INC},
-  {0xC8, 0x88, 1, OPR_REG_DIRECT},
-  {0xE8, 0xC8, 1, OPR_REG_INDIRECT},
-
-  {0xCE, 0xC0, 2, OPR_IDX_DIRECT},
-  {0xCE, 0xC4, 2, OPR_IDX_INDIRECT},
-  {0xC0, 0x00, 2, OPR_EXT1},
-
-  {0xC8, 0x80, 3, OPR_IDX2_REG},
-  {0xFA, 0xF8, 3, OPR_EXT18},
-
-  {0xCF, 0xC2, 4, OPR_IDX3_DIRECT},
-  {0xCF, 0xC6, 4, OPR_IDX3_INDIRECT},
-
-  {0xF8, 0xE8, 4, OPR_IDX3_DIRECT_REG},
-  {0xFF, 0xFA, 4, OPR_EXT3_DIRECT},
-  {0xFF, 0xFE, 4, OPR_EXT3_INDIRECT},
-};
-
-
-/* Return the number of bytes in a OPR operand, including the XB postbyte.
-   It does not include any preceeding opcodes. */
-static int
-opr_n_bytes (bfd_vma memaddr, struct disassemble_info* info)
-{
-  bfd_byte xb;
-  int status = read_memory (memaddr, &xb, 1, info);
-  if (status < 0)
-    return status;
-
-  size_t i;
-  for (i = 0; i < sizeof (opr_pb) / sizeof (opr_pb[0]); ++i)
-    {
-      const struct opr_pb *pb = opr_pb + i;
-      if ((xb & pb->mask) == pb->value)
-	{
-	  return pb->n_operands;
-	}
-    }
-
-  return 1;
-}
-
-static int
-opr_n_bytes_p1 (bfd_vma memaddr, struct disassemble_info* info)
-{
-  return 1 + opr_n_bytes (memaddr, info);
-}
-
-static int
-opr_n_bytes2 (bfd_vma memaddr, struct disassemble_info* info)
-{
-  int s = opr_n_bytes (memaddr, info);
-  s += opr_n_bytes (memaddr + s, info);
-  return s + 1;
-}
-
-enum BB_MODE
-  {
-    BB_REG_REG_REG,
-    BB_REG_REG_IMM,
-    BB_REG_OPR_REG,
-    BB_OPR_REG_REG,
-    BB_REG_OPR_IMM,
-    BB_OPR_REG_IMM
-  };
+#include "s12z-opc.h"
 
-struct opr_bb
+struct mem_read_abstraction
 {
-  uint8_t mask;
-  uint8_t value;
-  int n_operands;
-  bool opr;
-  enum BB_MODE mode;
+  struct mem_read_abstraction_base base;
+  bfd_vma memaddr;
+  struct disassemble_info* info;
 };
 
-static const struct opr_bb bb_modes[] =
-  {
-    {0x60, 0x00, 2, false, BB_REG_REG_REG},
-    {0x60, 0x20, 3, false, BB_REG_REG_IMM},
-    {0x70, 0x40, 2, true,  BB_REG_OPR_REG},
-    {0x70, 0x50, 2, true,  BB_OPR_REG_REG},
-    {0x70, 0x60, 3, true,  BB_REG_OPR_IMM},
-    {0x70, 0x70, 3, true,  BB_OPR_REG_IMM}
-  };
-
-static int
-bfextins_n_bytes (bfd_vma memaddr, struct disassemble_info* info)
-{
-  bfd_byte bb;
-  int status = read_memory (memaddr, &bb, 1, info);
-  if (status < 0)
-    return status;
-
-  size_t i;
-  const struct opr_bb *bbs = 0;
-  for (i = 0; i < sizeof (bb_modes) / sizeof (bb_modes[0]); ++i)
-    {
-      bbs = bb_modes + i;
-      if ((bb & bbs->mask) == bbs->value)
-	{
-	  break;
-	}
-    }
-
-  int n = bbs->n_operands;
-  if (bbs->opr)
-    n += opr_n_bytes (memaddr + n - 1, info);
-
-  return n;
-}
-
-static int
-single (bfd_vma memaddr ATTRIBUTE_UNUSED,
-	struct disassemble_info* info ATTRIBUTE_UNUSED)
-{
-  return 1;
-}
-
-static int
-two (bfd_vma memaddr ATTRIBUTE_UNUSED,
-     struct disassemble_info* info ATTRIBUTE_UNUSED)
-{
-  return 2;
-}
-
-static int
-three (bfd_vma memaddr ATTRIBUTE_UNUSED,
-       struct disassemble_info* info ATTRIBUTE_UNUSED)
-{
-  return 3;
-}
-
-static int
-four (bfd_vma memaddr ATTRIBUTE_UNUSED,
-      struct disassemble_info* info ATTRIBUTE_UNUSED)
+static void
+advance (struct mem_read_abstraction_base *b)
 {
-  return 4;
+  struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b;
+  mra->memaddr ++;
 }
 
-static int
-five (bfd_vma memaddr ATTRIBUTE_UNUSED,
-      struct disassemble_info* info ATTRIBUTE_UNUSED)
+static bfd_vma
+posn (struct mem_read_abstraction_base *b)
 {
-  return 5;
+  struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b;
+  return mra->memaddr;
 }
 
 static int
-pcrel_15bit (bfd_vma memaddr, struct disassemble_info* info)
+abstract_read_memory (struct mem_read_abstraction_base *b,
+		      int offset,
+		      size_t n, bfd_byte *bytes)
 {
-  bfd_byte byte;
-  int status = read_memory (memaddr, &byte, 1, info);
-  if (status < 0)
-    return status;
-  return (byte & 0x80) ? 3 : 2;
-}
+  struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b;
 
+  int status =
+    (*mra->info->read_memory_func) (mra->memaddr + offset,
+				    bytes, n, mra->info);
 
-
-
-static void
-operand_separator (struct disassemble_info *info)
-{
-  if ((info->flags & 0x2))
-    {
-      (*info->fprintf_func) (info->stream, ", ");
-    }
-  else
+  if (status != 0)
     {
-      (*info->fprintf_func) (info->stream, " ");
+      (*mra->info->memory_error_func) (status, mra->memaddr, mra->info);
+      return -1;
     }
-
-  info->flags |= 0x2;
-}
-
-
-
-static void
-imm1 (bfd_vma memaddr, struct disassemble_info* info)
-{
-  bfd_byte byte;
-  int status = read_memory (memaddr, &byte, 1, info);
-  if (status < 0)
-    return;
-
-  operand_separator (info);
-  (*info->fprintf_func) (info->stream, "#%d", byte);
-}
-
-static void
-trap_decode (bfd_vma memaddr, struct disassemble_info* info)
-{
-  imm1 (memaddr - 1, info);
+  return 0;
 }
 
-
+/* Start of disassembly file.  */
 const struct reg registers[S12Z_N_REGISTERS] =
   {
     {"d2", 2},
@@ -311,58 +96,128 @@ const struct reg registers[S12Z_N_REGISTERS] =
     {"ccw", 2}
   };
 
-static char *
-xys_from_postbyte (uint8_t postbyte)
-{
-  char *reg = "?";
-  switch ((postbyte & 0x30) >> 4)
-    {
-    case 0:
-      reg = "x";
-      break;
-    case 1:
-      reg = "y";
-      break;
-    case 2:
-      reg = "s";
-      break;
-    default:
-      reg = "?";
-      break;
-    }
-  return reg;
-}
+static const char *mnemonics[] =
+  {
+    "!!invalid!!",
+    "psh",
+    "pul",
+    "tbne", "tbeq", "tbpl", "tbmi", "tbgt", "tble",
+    "dbne", "dbeq", "dbpl", "dbmi", "dbgt", "dble",
+    "sex",
+    "exg",
+    "lsl", "lsr",
+    "asl", "asr",
+    "rol", "ror",
+    "bfins", "bfext",
+
+    "trap",
+
+    "ld",
+    "st",
+    "cmp",
+
+    "stop",
+    "wai",
+    "sys",
+
+    "minu",
+    "mins",
+    "maxu",
+    "maxs",
+
+    "abs",
+    "adc",
+    "bit",
+    "sbc",
+    "rti",
+    "clb",
+    "eor",
+
+    "sat",
+
+    "nop",
+    "bgnd",
+    "brclr",
+    "brset",
+    "rts",
+    "lea",
+    "mov",
+
+    "bra",
+    "bsr",
+    "bhi",
+    "bls",
+    "bcc",
+    "bcs",
+    "bne",
+    "beq",
+    "bvc",
+    "bvs",
+    "bpl",
+    "bmi",
+    "bge",
+    "blt",
+    "bgt",
+    "ble",
+    "inc",
+    "clr",
+    "dec",
+
+    "add",
+    "sub",
+    "and",
+    "or",
+
+    "tfr",
+    "jmp",
+    "jsr",
+    "com",
+    "andcc",
+    "neg",
+    "orcc",
+    "bclr",
+    "bset",
+    "btgl",
+    "swi",
+
+    "mulu",
+    "divu",
+    "modu",
+    "macu",
+    "qmulu",
+
+    "muls",
+    "divs",
+    "mods",
+    "macs",
+    "qmuls",
+
+    NULL
+  };
+
 
-static char *
-xysp_from_postbyte (uint8_t postbyte)
+static void
+operand_separator (struct disassemble_info *info)
 {
-  char *reg = "?";
-  switch ((postbyte & 0x30) >> 4)
-    {
-    case 0:
-      reg = "x";
-      break;
-    case 1:
-      reg = "y";
-      break;
-    case 2:
-      reg = "s";
-      break;
-    default:
-      reg = "p";
-      break;
-    }
-  return reg;
+  if ((info->flags & 0x2))
+    (*info->fprintf_func) (info->stream, ",");
+
+  (*info->fprintf_func) (info->stream, " ");
+
+  info->flags |= 0x2;
 }
 
-/* Render the symbol name whose value is ADDR or the adddress itself if there is
-   no symbol. */
+/* Render the symbol name whose value is ADDR + BASE or the adddress itself if
+   there is no symbol.  If BASE is non zero, then the a PC relative adddress is
+   assumend (ie BASE is the value in the PC.  */
 static void
-decode_possible_symbol (bfd_vma addr, struct disassemble_info *info)
+decode_possible_symbol (bfd_vma addr, bfd_vma base,
+                        struct disassemble_info *info, bool relative)
 {
-  if (!info->symbol_at_address_func (addr, info))
+  const char *fmt = relative  ? "*%+" BFD_VMA_FMT "d" : "%" BFD_VMA_FMT "d";
+  if (!info->symbol_at_address_func (addr + base, info))
     {
-      (*info->fprintf_func) (info->stream, "%" BFD_VMA_FMT "d", addr);
+      (*info->fprintf_func) (info->stream, fmt, addr);
     }
   else
     {
@@ -371,7 +226,7 @@ decode_possible_symbol (bfd_vma addr, struct disassemble_info *info)
       for (j = 0; j < info->symtab_size; ++j)
 	{
 	  sym = info->symtab[j];
-	  if (bfd_asymbol_value (sym) == addr)
+	  if (bfd_asymbol_value (sym) == addr + base)
 	    {
 	      break;
 	    }
@@ -379,2305 +234,158 @@ decode_possible_symbol (bfd_vma addr, struct disassemble_info *info)
       if (j < info->symtab_size)
 	(*info->fprintf_func) (info->stream, "%s", bfd_asymbol_name (sym));
       else
-        (*info->fprintf_func) (info->stream, "%" BFD_VMA_FMT "d", addr);
+        (*info->fprintf_func) (info->stream, fmt, addr);
     }
 }
 
-static void ld_18bit_decode (bfd_vma memaddr, struct disassemble_info* info);
 
+/* Emit the disassembled text for OPR */
 static void
-ext24_decode (bfd_vma memaddr, struct disassemble_info* info)
+opr_emit_disassembly (const struct operand *opr,
+		      struct disassemble_info *info)
 {
-  uint8_t buffer[3];
-  int status = read_memory (memaddr, buffer, 3, info);
-  if (status < 0)
-    return;
-
-  int i;
-  uint32_t addr = 0;
-  for (i = 0; i < 3; ++i)
-    {
-      addr <<= 8;
-      addr |= buffer[i];
-    }
-
   operand_separator (info);
-  decode_possible_symbol (addr, info);
-}
-
-
-static uint32_t
-decode_signed_value (bfd_vma memaddr, struct disassemble_info* info, short size)
-{
-  assert (size >0);
-  assert (size <= 4);
-  bfd_byte buffer[4];
-  if (0 > read_memory (memaddr, buffer, size, info))
-    {
-      return 0;
-    }
-
-  int i;
-  uint32_t value = 0;
-  for (i = 0; i < size; ++i)
-    {
-      value |= buffer[i] << (8 * (size - i - 1));
-    }
-
-  if (buffer[0] & 0x80)
-    {
-      /* Deal with negative values */
-      value -= 0x1UL << (size * 8);
-    }
-  return value;
-}
-
-
-static void
-opr_decode (bfd_vma memaddr, struct disassemble_info* info)
-{
-  bfd_byte postbyte;
-  int status = read_memory (memaddr, &postbyte, 1, info);
-  if (status < 0)
-    return;
-
-  enum OPR_MODE mode = -1;
-  size_t i;
-  for (i = 0; i < sizeof (opr_pb) / sizeof (opr_pb[0]); ++i)
-    {
-      const struct opr_pb *pb = opr_pb + i;
-      if ((postbyte & pb->mask) == pb->value)
-	{
-	  mode = pb->mode;
-	  break;
-	}
-    }
 
-  operand_separator (info);
-  switch (mode)
+  switch (opr->cl)
     {
-    case OPR_IMMe4:
-      {
-	int n;
-	uint8_t x = (postbyte & 0x0F);
-	if (x == 0)
-	  n = -1;
-	else
-	  n = x;
-
-	(*info->fprintf_func) (info->stream, "#%d", n);
-	break;
-      }
-    case OPR_REG:
-      {
-	uint8_t x = (postbyte & 0x07);
-	(*info->fprintf_func) (info->stream, "%s", registers[x].name);
-	break;
-      }
-    case OPR_OFXYS:
-      {
-	const char *reg  = xys_from_postbyte (postbyte);
-	(*info->fprintf_func) (info->stream, "(%d,%s)", postbyte & 0x0F, reg);
-	break;
-      }
-    case OPR_REG_DIRECT:
-      {
-	(*info->fprintf_func) (info->stream, "(%s,%s)", registers[postbyte & 0x07].name,
-			       xys_from_postbyte (postbyte));
-	break;
-      }
-    case OPR_REG_INDIRECT:
-      {
-	(*info->fprintf_func) (info->stream, "[%s,%s]", registers[postbyte & 0x07].name,
-			       (postbyte & 0x10) ? "y": "x");
-	break;
-      }
-
-    case OPR_IDX_INDIRECT:
-      {
-	uint8_t x1;
-	read_memory (memaddr + 1, &x1, 1, info);
-	int idx = x1;
-
-	if (postbyte & 0x01)
-	  {
-	    /* Deal with negative values */
-	    idx -= 0x1UL << 8;
-	  }
-
-	(*info->fprintf_func) (info->stream, "[%d,%s]", idx,
-			       xysp_from_postbyte (postbyte));
-	break;
-      }
-
-    case OPR_IDX3_DIRECT:
-      {
-	uint8_t x[3];
-	read_memory (memaddr + 1, x, 3, info);
-	int idx = x[0] << 16 | x[1] << 8 | x[2];
-
-	if (x[0] & 0x80)
-	  {
-	    /* Deal with negative values */
-	    idx -= 0x1UL << 24;
-	  }
-
-	(*info->fprintf_func) (info->stream, "(%d,%s)", idx,
-			       xysp_from_postbyte (postbyte));
-	break;
-      }
-
-    case OPR_IDX3_DIRECT_REG:
-      {
-	uint8_t x[3];
-	read_memory (memaddr + 1, x, 3, info);
-	int idx = x[0] << 16 | x[1] << 8 | x[2];
-
-	if (x[0] & 0x80)
-	  {
-	    /* Deal with negative values */
-	    idx -= 0x1UL << 24;
-	  }
-
-	(*info->fprintf_func) (info->stream, "(%d,%s)", idx,
-			       registers[postbyte & 0x07].name);
-	break;
-      }
-
-    case OPR_IDX3_INDIRECT:
-      {
-	uint8_t x[3];
-	read_memory (memaddr + 1, x, 3, info);
-	int idx = x[0] << 16 | x[1] << 8 | x[2];
-
-	if (x[0] & 0x80)
-	  {
-	    /* Deal with negative values */
-	    idx -= 0x1UL << 24;
-	  }
-
-	(*info->fprintf_func) (info->stream, "[%d,%s]", idx,
-			       xysp_from_postbyte (postbyte));
-	break;
-      }
-
-    case OPR_IDX_DIRECT:
-      {
-	uint8_t x1;
-	read_memory (memaddr + 1, &x1, 1, info);
-	int idx = x1;
-
-	if (postbyte & 0x01)
-	  {
-	    /* Deal with negative values */
-	    idx -= 0x1UL << 8;
-	  }
-
-	(*info->fprintf_func) (info->stream, "(%d,%s)", idx,
-			       xysp_from_postbyte (postbyte));
-	break;
-      }
-
-    case OPR_IDX2_REG:
-      {
-	uint8_t x[2];
-	read_memory (memaddr + 1, x, 2, info);
-	uint32_t offset = x[1] | x[0] << 8 ;
-	offset |= (postbyte & 0x30) << 12;
-
-	(*info->fprintf_func) (info->stream, "(%d,%s)", offset,
-			       registers[postbyte & 0x07].name);
-	break;
-      }
-
-    case OPR_XY_PRE_INC:
-      {
-	(*info->fprintf_func) (info->stream, "(+%s)",
-			       (postbyte & 0x10) ? "y": "x");
-
-	break;
-      }
-    case OPR_XY_POST_INC:
-      {
-	(*info->fprintf_func) (info->stream, "(%s+)",
-			       (postbyte & 0x10) ? "y": "x");
-
-	break;
-      }
-    case OPR_XY_PRE_DEC:
-      {
-	(*info->fprintf_func) (info->stream, "(-%s)",
-			       (postbyte & 0x10) ? "y": "x");
-
-	break;
-      }
-    case OPR_XY_POST_DEC:
-      {
-	(*info->fprintf_func) (info->stream, "(%s-)",
-			       (postbyte & 0x10) ? "y": "x");
-
-	break;
-      }
-    case OPR_S_PRE_DEC:
-      {
-	(*info->fprintf_func) (info->stream, "(-s)");
-	break;
-      }
-    case OPR_S_POST_INC:
-      {
-	(*info->fprintf_func) (info->stream, "(s+)");
-	break;
-      }
-
-    case OPR_EXT18:
-      {
-	const size_t size = 2;
-	bfd_byte buffer[4];
-	status = read_memory (memaddr + 1, buffer, size, info);
-	if (status < 0)
-	  return;
-
-	uint32_t ext18 = 0;
-	for (i = 0; i < size; ++i)
-	  {
-	    ext18 <<= 8;
-	    ext18 |= buffer[i];
-	  }
-
-	ext18 |= (postbyte & 0x01) << 16;
-	ext18 |= (postbyte & 0x04) << 15;
-
-	decode_possible_symbol (ext18, info);
-	break;
-      }
-
-    case OPR_EXT1:
+    case OPND_CL_IMMEDIATE:
+      (*info->fprintf_func) (info->stream, "#%d",
+			     ((struct immediate_operand *) opr)->value);
+      break;
+    case OPND_CL_REGISTER:
       {
-	uint8_t x1 = 0;
-	read_memory (memaddr + 1, &x1, 1, info);
-	int16_t addr;
-	addr = x1;
-	addr |= (postbyte & 0x3f) << 8;
-
-	decode_possible_symbol (addr, info);
-	break;
+        int r = ((struct register_operand*) opr)->reg;
+	(*info->fprintf_func) (info->stream, "%s", registers[r].name);
       }
-
-    case OPR_EXT3_DIRECT:
+      break;
+    case OPND_CL_REGISTER_ALL16:
+      (*info->fprintf_func) (info->stream, "%s", "ALL16b");
+      break;
+    case OPND_CL_REGISTER_ALL:
+      (*info->fprintf_func) (info->stream, "%s", "ALL");
+      break;
+    case OPND_CL_BIT_FIELD:
+      (*info->fprintf_func) (info->stream, "#%d:%d",
+                             ((struct bitfield_operand*)opr)->width,
+                             ((struct bitfield_operand*)opr)->offset);
+      break;
+    case OPND_CL_SIMPLE_MEMORY:
       {
-	const size_t size = 3;
-	bfd_byte buffer[4];
-	status = read_memory (memaddr + 1, buffer, size, info);
-	if (status < 0)
-	  return;
-
-	uint32_t ext24 = 0;
-	for (i = 0; i < size; ++i)
-	  {
-	    ext24 |= buffer[i] << (8 * (size - i - 1));
-	  }
-
-	decode_possible_symbol (ext24, info);
-	break;
+        struct simple_memory_operand *mo =
+	  (struct simple_memory_operand *) opr;
+	decode_possible_symbol (mo->addr, mo->base, info, mo->relative);
       }
-
-    case OPR_EXT3_INDIRECT:
+      break;
+    case OPND_CL_MEMORY:
       {
-	const size_t size = 3;
-	bfd_byte buffer[4];
-	status = read_memory (memaddr + 1, buffer, size, info);
-	if (status < 0)
-	  return;
+        int used_reg = 0;
+        struct memory_operand *mo = (struct memory_operand *) opr;
+	(*info->fprintf_func) (info->stream, "%c", mo->indirect ? '[' : '(');
 
-	uint32_t ext24 = 0;
-	for (i = 0; i < size; ++i)
-	  {
-	    ext24 |= buffer[i] << (8 * (size - i - 1));
-	  }
+        if (mo->base_offset != 0)
+          {
+            (*info->fprintf_func) (info->stream, "%d", mo->base_offset);
+          }
+        else if (mo->n_regs > 0)
+          {
+	    const char *fmt;
+	    switch (mo->mutation)
+	      {
+	      case OPND_RM_PRE_DEC:
+		fmt = "-%s";
+		break;
+	      case OPND_RM_PRE_INC:
+		fmt = "+%s";
+		break;
+	      case OPND_RM_POST_DEC:
+		fmt = "%s-";
+		break;
+	      case OPND_RM_POST_INC:
+		fmt = "%s+";
+		break;
+	      case OPND_RM_NONE:
+	      default:
+		fmt = "%s";
+		break;
+	      }
+            (*info->fprintf_func) (info->stream, fmt,
+				   registers[mo->regs[0]].name);
+            used_reg = 1;
+          }
 
-	(*info->fprintf_func) (info->stream, "[%d]", ext24);
+        if (mo->n_regs > used_reg)
+          {
+            (*info->fprintf_func) (info->stream, ",%s",
+				   registers[mo->regs[used_reg]].name);
+          }
 
-	break;
+	(*info->fprintf_func) (info->stream, "%c",
+			       mo->indirect ? ']' : ')');
       }
-
-    default:
-      (*info->fprintf_func) (info->stream, "Unknown OPR mode #0x%x (%d)", postbyte, mode);
-    }
+      break;
+    };
 }
 
+static const char shift_size_table[] = {
+  'b', 'w', 'p', 'l'
+};
 
-static void
-opr_decode2 (bfd_vma memaddr, struct disassemble_info* info)
+int
+print_insn_s12z (bfd_vma memaddr, struct disassemble_info* info)
 {
-  int n = opr_n_bytes (memaddr, info);
-  opr_decode (memaddr, info);
-  opr_decode (memaddr + n, info);
-}
+  enum operator operator = OP_INVALID;
+  int n_operands = 0;
+
+  /* The longest instruction in S12Z can have 6 operands.
+     (Most have 3 or less.  Only PSH and PUL have so many.  */
+  struct operand *operands[6];
+
+  struct mem_read_abstraction mra;
+  mra.base.read = (void *) abstract_read_memory ;
+  mra.base.advance = advance ;
+  mra.base.posn = posn;
+  mra.memaddr = memaddr;
+  mra.info = info;
+
+  short osize = -1;
+  int n_bytes =
+    decode_s12z (&operator, &osize, &n_operands, operands,
+		 (struct mem_read_abstraction_base *) &mra);
+
+  (info->fprintf_func) (info->stream, "%s", mnemonics[(long)operator]);
+  
+  /* Ship out size sufficies for those instructions which
+     need them.  */
+  if (osize == -1)
+    {
+      bool suffix = false;
+      for (int o = 0; o < n_operands; ++o)
+	{
+	  if (operands[o]->osize != -1)
+	    {
+	      if (!suffix)
+		{
+		  (*mra.info->fprintf_func) (mra.info->stream, "%c", '.');
+		  suffix = true;
+		}
+	      (*mra.info->fprintf_func) (mra.info->stream, "%c",
+				     shift_size_table[operands[o]->osize]);
+	    }
+	}
+    }
+  else
+    {
+      (*mra.info->fprintf_func) (mra.info->stream, ".%c",
+			     shift_size_table[osize]);
+    }
 
-static void
-imm1234 (bfd_vma memaddr, struct disassemble_info* info, int base)
-{
-  bfd_byte opcode;
-  int status = read_memory (memaddr - 1, &opcode, 1, info);
-  if (status < 0)
-    return;
 
-  opcode -= base;
-
-  int size = registers[opcode & 0xF].bytes;
-
-  uint32_t imm = decode_signed_value (memaddr, info, size);
-  operand_separator (info);
-  (*info->fprintf_func) (info->stream, "#%d", imm);
-}
-
-
-/* Special case of LD and CMP with register S and IMM operand */
-static void
-reg_s_imm (bfd_vma memaddr, struct disassemble_info* info)
-{
-  operand_separator (info);
-  (*info->fprintf_func) (info->stream, "s");
-
-  uint32_t imm = decode_signed_value (memaddr, info, 3);
-  operand_separator (info);
-  (*info->fprintf_func) (info->stream, "#%d", imm);
-}
-
-/* Special case of LD, CMP and ST with register S and OPR operand */
-static void
-reg_s_opr (bfd_vma memaddr, struct disassemble_info* info)
-{
-  operand_separator (info);
-  (*info->fprintf_func) (info->stream, "s");
-
-  opr_decode (memaddr, info);
-}
-
-static void
-imm1234_8base (bfd_vma memaddr, struct disassemble_info* info)
-{
-  imm1234 (memaddr, info, 8);
-}
-
-static void
-imm1234_0base (bfd_vma memaddr, struct disassemble_info* info)
-{
-  imm1234 (memaddr, info, 0);
-}
-
-static void
-tfr (bfd_vma memaddr, struct disassemble_info* info)
-{
-  bfd_byte byte;
-  int status = read_memory (memaddr, &byte, 1, info);
-  if (status < 0)
-    return;
-
-  operand_separator (info);
-  (*info->fprintf_func) (info->stream, "%s, %s",
-			 registers[byte >> 4].name,
-			 registers[byte & 0xF].name);
-}
-
-
-static void
-reg (bfd_vma memaddr, struct disassemble_info* info)
-{
-  bfd_byte byte;
-  int status = read_memory (memaddr - 1, &byte, 1, info);
-  if (status < 0)
-    return;
-
-  operand_separator (info);
-  (*info->fprintf_func) (info->stream, "%s", registers[byte & 0x07].name);
-}
-
-static void
-reg_xy (bfd_vma memaddr, struct disassemble_info* info)
-{
-  bfd_byte byte;
-  int status = read_memory (memaddr - 1, &byte, 1, info);
-  if (status < 0)
-    return;
-
-  operand_separator (info);
-  (*info->fprintf_func) (info->stream, "%s", (byte & 0x01) ? "y" : "x");
-}
-
-static void
-lea_reg_xys_opr (bfd_vma memaddr, struct disassemble_info* info)
-{
-  bfd_byte byte;
-  int status = read_memory (memaddr - 1, &byte, 1, info);
-  if (status < 0)
-    return;
-
-  char *reg_xys = NULL;
-  switch (byte & 0x03)
-    {
-    case 0x00:
-      reg_xys = "x";
-      break;
-    case 0x01:
-      reg_xys = "y";
-      break;
-    case 0x02:
-      reg_xys = "s";
-      break;
-    }
-
-  operand_separator (info);
-  (*info->fprintf_func) (info->stream, "%s", reg_xys);
-  opr_decode (memaddr, info);
-}
-
-
-
-static void
-lea_reg_xys (bfd_vma memaddr, struct disassemble_info* info)
-{
-  bfd_byte byte;
-  int status = read_memory (memaddr - 1, &byte, 1, info);
-  if (status < 0)
-    return;
-
-  char *reg_xys = NULL;
-  switch (byte & 0x03)
-    {
-    case 0x00:
-      reg_xys = "x";
-      break;
-    case 0x01:
-      reg_xys = "y";
-      break;
-    case 0x02:
-      reg_xys = "s";
-      break;
-    }
-
-  status = read_memory (memaddr, &byte, 1, info);
-  if (status < 0)
-    return;
-
-  int8_t v = byte;
-
-  operand_separator (info);
-  (*info->fprintf_func) (info->stream, "%s, (%d,%s)", reg_xys, v, reg_xys);
-}
-
-
-/* PC Relative offsets of size 15 or 7 bits */
-static void
-rel_15_7 (bfd_vma memaddr, struct disassemble_info* info, int offset)
-{
-  bfd_byte upper;
-  int status = read_memory (memaddr, &upper, 1, info);
-  if (status < 0)
-    return;
-
-  bool rel_size = (upper & 0x80);
-
-  int16_t addr = upper;
-  if (rel_size)
-    {
-      /* 15 bits.  Get the next byte */
-      bfd_byte lower;
-      status = read_memory (memaddr + 1, &lower, 1, info);
-      if (status < 0)
-	return;
-
-      addr <<= 8;
-      addr |= lower;
-      addr &= 0x7FFF;
-
-      bool negative = (addr & 0x4000);
-      addr &= 0x3FFF;
-      if (negative)
-	addr = addr - 0x4000;
-    }
-  else
-    {
-      /* 7 bits. */
-      bool negative = (addr & 0x40);
-      addr &= 0x3F;
-      if (negative)
-	addr = addr - 0x40;
-    }
-
-  operand_separator (info);
-  if (!info->symbol_at_address_func (addr + memaddr - offset, info))
-    {
-      (*info->fprintf_func) (info->stream, "*%+d", addr);
-    }
-  else
-    {
-      asymbol *sym = NULL;
-      int i;
-      for (i = 0; i < info->symtab_size; ++i)
-	{
-	  sym = info->symtab[i];
-	  if (bfd_asymbol_value (sym) == addr + memaddr - offset)
-	    {
-	      break;
-	    }
-	}
-      if (i < info->symtab_size)
-	(*info->fprintf_func) (info->stream, "%s", bfd_asymbol_name (sym));
-      else
-        (*info->fprintf_func) (info->stream, "*%+d", addr);
-    }
-}
-
-
-/* PC Relative offsets of size 15 or 7 bits */
-static void
-decode_rel_15_7 (bfd_vma memaddr, struct disassemble_info* info)
-{
-  rel_15_7 (memaddr, info, 1);
-}
-
-struct opcode
-{
-  const char *mnemonic;
-  insn_bytes_f insn_bytes;
-  operands_f operands;
-  operands_f operands2;
-};
-
-static int shift_n_bytes (bfd_vma memaddr, struct disassemble_info* info);
-static int mov_imm_opr_n_bytes (bfd_vma memaddr, struct disassemble_info* info);
-static int loop_prim_n_bytes (bfd_vma memaddr, struct disassemble_info* info);
-static void mov_imm_opr (bfd_vma memaddr, struct disassemble_info* info);
-static void bm_rel_decode (bfd_vma memaddr, struct disassemble_info* info);
-static int bm_rel_n_bytes (bfd_vma memaddr, struct disassemble_info* info);
-static int mul_n_bytes (bfd_vma memaddr, struct disassemble_info* info);
-static void mul_decode (bfd_vma memaddr, struct disassemble_info* info);
-static int bm_n_bytes (bfd_vma memaddr, struct disassemble_info* info);
-static void bm_decode (bfd_vma memaddr, struct disassemble_info* info);
-
-static void
-cmp_xy (bfd_vma memaddr ATTRIBUTE_UNUSED, struct disassemble_info* info)
-{
-  operand_separator (info);
-  (*info->fprintf_func) (info->stream, "x, y");
-}
-
-static void
-sub_d6_x_y (bfd_vma memaddr ATTRIBUTE_UNUSED, struct disassemble_info* info)
-{
-  operand_separator (info);
-  (*info->fprintf_func) (info->stream, "d6, x, y");
-}
-
-static void
-sub_d6_y_x (bfd_vma memaddr ATTRIBUTE_UNUSED, struct disassemble_info* info)
-{
-  operand_separator (info);
-  (*info->fprintf_func) (info->stream, "d6, y, x");
-}
-
-static const char shift_size_table[] = {
-  'b', 'w', 'p', 'l'
-};
-
-static const struct opcode page2[] =
-  {
-    [0x00] = {"ld",  opr_n_bytes_p1, 0, reg_s_opr},
-    [0x01] = {"st",  opr_n_bytes_p1, 0, reg_s_opr},
-    [0x02] = {"cmp", opr_n_bytes_p1, 0, reg_s_opr},
-    [0x03] = {"ld",  four, 0, reg_s_imm},
-    [0x04] = {"cmp", four, 0, reg_s_imm},
-    [0x05] = {"stop", single, 0, 0},
-    [0x06] = {"wai",  single, 0, 0},
-    [0x07] = {"sys",  single, 0, 0},
-    [0x08] = {NULL,  bfextins_n_bytes, 0, 0},  /* BFEXT / BFINS */
-    [0x09] = {NULL,  bfextins_n_bytes, 0, 0},
-    [0x0a] = {NULL,  bfextins_n_bytes, 0, 0},
-    [0x0b] = {NULL,  bfextins_n_bytes, 0, 0},
-    [0x0c] = {NULL,  bfextins_n_bytes, 0, 0},
-    [0x0d] = {NULL,  bfextins_n_bytes, 0, 0},
-    [0x0e] = {NULL,  bfextins_n_bytes, 0, 0},
-    [0x0f] = {NULL,  bfextins_n_bytes, 0, 0},
-    [0x10] = {"minu", opr_n_bytes_p1, reg, opr_decode},
-    [0x11] = {"minu", opr_n_bytes_p1, reg, opr_decode},
-    [0x12] = {"minu", opr_n_bytes_p1, reg, opr_decode},
-    [0x13] = {"minu", opr_n_bytes_p1, reg, opr_decode},
-    [0x14] = {"minu", opr_n_bytes_p1, reg, opr_decode},
-    [0x15] = {"minu", opr_n_bytes_p1, reg, opr_decode},
-    [0x16] = {"minu", opr_n_bytes_p1, reg, opr_decode},
-    [0x17] = {"minu", opr_n_bytes_p1, reg, opr_decode},
-    [0x18] = {"maxu", opr_n_bytes_p1, reg, opr_decode},
-    [0x19] = {"maxu", opr_n_bytes_p1, reg, opr_decode},
-    [0x1a] = {"maxu", opr_n_bytes_p1, reg, opr_decode},
-    [0x1b] = {"maxu", opr_n_bytes_p1, reg, opr_decode},
-    [0x1c] = {"maxu", opr_n_bytes_p1, reg, opr_decode},
-    [0x1d] = {"maxu", opr_n_bytes_p1, reg, opr_decode},
-    [0x1e] = {"maxu", opr_n_bytes_p1, reg, opr_decode},
-    [0x1f] = {"maxu", opr_n_bytes_p1, reg, opr_decode},
-    [0x20] = {"mins", opr_n_bytes_p1, reg, opr_decode},
-    [0x21] = {"mins", opr_n_bytes_p1, reg, opr_decode},
-    [0x22] = {"mins", opr_n_bytes_p1, reg, opr_decode},
-    [0x23] = {"mins", opr_n_bytes_p1, reg, opr_decode},
-    [0x24] = {"mins", opr_n_bytes_p1, reg, opr_decode},
-    [0x25] = {"mins", opr_n_bytes_p1, reg, opr_decode},
-    [0x26] = {"mins", opr_n_bytes_p1, reg, opr_decode},
-    [0x27] = {"mins", opr_n_bytes_p1, reg, opr_decode},
-    [0x28] = {"maxs", opr_n_bytes_p1, reg, opr_decode},
-    [0x29] = {"maxs", opr_n_bytes_p1, reg, opr_decode},
-    [0x2a] = {"maxs", opr_n_bytes_p1, reg, opr_decode},
-    [0x2b] = {"maxs", opr_n_bytes_p1, reg, opr_decode},
-    [0x2c] = {"maxs", opr_n_bytes_p1, reg, opr_decode},
-    [0x2d] = {"maxs", opr_n_bytes_p1, reg, opr_decode},
-    [0x2e] = {"maxs", opr_n_bytes_p1, reg, opr_decode},
-    [0x2f] = {"maxs", opr_n_bytes_p1, reg, opr_decode},
-    [0x30] = {"div", mul_n_bytes, mul_decode, 0},
-    [0x31] = {"div", mul_n_bytes, mul_decode, 0},
-    [0x32] = {"div", mul_n_bytes, mul_decode, 0},
-    [0x33] = {"div", mul_n_bytes, mul_decode, 0},
-    [0x34] = {"div", mul_n_bytes, mul_decode, 0},
-    [0x35] = {"div", mul_n_bytes, mul_decode, 0},
-    [0x36] = {"div", mul_n_bytes, mul_decode, 0},
-    [0x37] = {"div", mul_n_bytes, mul_decode, 0},
-    [0x38] = {"mod", mul_n_bytes, mul_decode, 0},
-    [0x39] = {"mod", mul_n_bytes, mul_decode, 0},
-    [0x3a] = {"mod", mul_n_bytes, mul_decode, 0},
-    [0x3b] = {"mod", mul_n_bytes, mul_decode, 0},
-    [0x3c] = {"mod", mul_n_bytes, mul_decode, 0},
-    [0x3d] = {"mod", mul_n_bytes, mul_decode, 0},
-    [0x3e] = {"mod", mul_n_bytes, mul_decode, 0},
-    [0x3f] = {"mod", mul_n_bytes, mul_decode, 0},
-    [0x40] = {"abs", single, reg, 0},
-    [0x41] = {"abs", single, reg, 0},
-    [0x42] = {"abs", single, reg, 0},
-    [0x43] = {"abs", single, reg, 0},
-    [0x44] = {"abs", single, reg, 0},
-    [0x45] = {"abs", single, reg, 0},
-    [0x46] = {"abs", single, reg, 0},
-    [0x47] = {"abs", single, reg, 0},
-    [0x48] = {"mac", mul_n_bytes, mul_decode, 0},
-    [0x49] = {"mac", mul_n_bytes, mul_decode, 0},
-    [0x4a] = {"mac", mul_n_bytes, mul_decode, 0},
-    [0x4b] = {"mac", mul_n_bytes, mul_decode, 0},
-    [0x4c] = {"mac", mul_n_bytes, mul_decode, 0},
-    [0x4d] = {"mac", mul_n_bytes, mul_decode, 0},
-    [0x4e] = {"mac", mul_n_bytes, mul_decode, 0},
-    [0x4f] = {"mac", mul_n_bytes, mul_decode, 0},
-    [0x50] = {"adc", three, reg, imm1234_0base},
-    [0x51] = {"adc", three, reg, imm1234_0base},
-    [0x52] = {"adc", three, reg, imm1234_0base},
-    [0x53] = {"adc", three, reg, imm1234_0base},
-    [0x54] = {"adc", two,   reg, imm1234_0base},
-    [0x55] = {"adc", two,   reg, imm1234_0base},
-    [0x56] = {"adc", five,  reg, imm1234_0base},
-    [0x57] = {"adc", five,  reg, imm1234_0base},
-    [0x58] = {"bit", three, reg, imm1234_8base},
-    [0x59] = {"bit", three, reg, imm1234_8base},
-    [0x5a] = {"bit", three, reg, imm1234_8base},
-    [0x5b] = {"bit", three, reg, imm1234_8base},
-    [0x5c] = {"bit", two,   reg, imm1234_8base},
-    [0x5d] = {"bit", two,   reg, imm1234_8base},
-    [0x5e] = {"bit", five,  reg, imm1234_8base},
-    [0x5f] = {"bit", five,  reg, imm1234_8base},
-    [0x60] = {"adc", opr_n_bytes_p1, reg, opr_decode},
-    [0x61] = {"adc", opr_n_bytes_p1, reg, opr_decode},
-    [0x62] = {"adc", opr_n_bytes_p1, reg, opr_decode},
-    [0x63] = {"adc", opr_n_bytes_p1, reg, opr_decode},
-    [0x64] = {"adc", opr_n_bytes_p1, reg, opr_decode},
-    [0x65] = {"adc", opr_n_bytes_p1, reg, opr_decode},
-    [0x66] = {"adc", opr_n_bytes_p1, reg, opr_decode},
-    [0x67] = {"adc", opr_n_bytes_p1, reg, opr_decode},
-    [0x68] = {"bit", opr_n_bytes_p1, reg, opr_decode},
-    [0x69] = {"bit", opr_n_bytes_p1, reg, opr_decode},
-    [0x6a] = {"bit", opr_n_bytes_p1, reg, opr_decode},
-    [0x6b] = {"bit", opr_n_bytes_p1, reg, opr_decode},
-    [0x6c] = {"bit", opr_n_bytes_p1, reg, opr_decode},
-    [0x6d] = {"bit", opr_n_bytes_p1, reg, opr_decode},
-    [0x6e] = {"bit", opr_n_bytes_p1, reg, opr_decode},
-    [0x6f] = {"bit", opr_n_bytes_p1, reg, opr_decode},
-    [0x70] = {"sbc", three, reg, imm1234_0base},
-    [0x71] = {"sbc", three, reg, imm1234_0base},
-    [0x72] = {"sbc", three, reg, imm1234_0base},
-    [0x73] = {"sbc", three, reg, imm1234_0base},
-    [0x74] = {"sbc", two,   reg, imm1234_0base},
-    [0x75] = {"sbc", two,   reg, imm1234_0base},
-    [0x76] = {"sbc", five,  reg, imm1234_0base},
-    [0x77] = {"sbc", five,  reg, imm1234_0base},
-    [0x78] = {"eor", three, reg, imm1234_8base},
-    [0x79] = {"eor", three, reg, imm1234_8base},
-    [0x7a] = {"eor", three, reg, imm1234_8base},
-    [0x7b] = {"eor", three, reg, imm1234_8base},
-    [0x7c] = {"eor", two,   reg, imm1234_8base},
-    [0x7d] = {"eor", two,   reg, imm1234_8base},
-    [0x7e] = {"eor", five,  reg, imm1234_8base},
-    [0x7f] = {"eor", five,  reg, imm1234_8base},
-    [0x80] = {"sbc", opr_n_bytes_p1, reg, opr_decode},
-    [0x81] = {"sbc", opr_n_bytes_p1, reg, opr_decode},
-    [0x82] = {"sbc", opr_n_bytes_p1, reg, opr_decode},
-    [0x83] = {"sbc", opr_n_bytes_p1, reg, opr_decode},
-    [0x84] = {"sbc", opr_n_bytes_p1, reg, opr_decode},
-    [0x85] = {"sbc", opr_n_bytes_p1, reg, opr_decode},
-    [0x86] = {"sbc", opr_n_bytes_p1, reg, opr_decode},
-    [0x87] = {"sbc", opr_n_bytes_p1, reg, opr_decode},
-    [0x88] = {"eor", opr_n_bytes_p1, reg,    opr_decode},
-    [0x89] = {"eor", opr_n_bytes_p1, reg,    opr_decode},
-    [0x8a] = {"eor", opr_n_bytes_p1, reg,    opr_decode},
-    [0x8b] = {"eor", opr_n_bytes_p1, reg,    opr_decode},
-    [0x8c] = {"eor", opr_n_bytes_p1, reg,    opr_decode},
-    [0x8d] = {"eor", opr_n_bytes_p1, reg,    opr_decode},
-    [0x8e] = {"eor", opr_n_bytes_p1, reg,    opr_decode},
-    [0x8f] = {"eor", opr_n_bytes_p1, reg,    opr_decode},
-    [0x90] = {"rti",  single, 0, 0},
-    [0x91] = {"clb",   two, tfr, 0},
-    [0x92] = {"trap",  single, trap_decode, 0},
-    [0x93] = {"trap",  single, trap_decode, 0},
-    [0x94] = {"trap",  single, trap_decode, 0},
-    [0x95] = {"trap",  single, trap_decode, 0},
-    [0x96] = {"trap",  single, trap_decode, 0},
-    [0x97] = {"trap",  single, trap_decode, 0},
-    [0x98] = {"trap",  single, trap_decode, 0},
-    [0x99] = {"trap",  single, trap_decode, 0},
-    [0x9a] = {"trap",  single, trap_decode, 0},
-    [0x9b] = {"trap",  single, trap_decode, 0},
-    [0x9c] = {"trap",  single, trap_decode, 0},
-    [0x9d] = {"trap",  single, trap_decode, 0},
-    [0x9e] = {"trap",  single, trap_decode, 0},
-    [0x9f] = {"trap",  single, trap_decode, 0},
-    [0xa0] = {"sat", single, reg, 0},
-    [0xa1] = {"sat", single, reg, 0},
-    [0xa2] = {"sat", single, reg, 0},
-    [0xa3] = {"sat", single, reg, 0},
-    [0xa4] = {"sat", single, reg, 0},
-    [0xa5] = {"sat", single, reg, 0},
-    [0xa6] = {"sat", single, reg, 0},
-    [0xa7] = {"sat", single, reg, 0},
-    [0xa8] = {"trap",  single, trap_decode, 0},
-    [0xa9] = {"trap",  single, trap_decode, 0},
-    [0xaa] = {"trap",  single, trap_decode, 0},
-    [0xab] = {"trap",  single, trap_decode, 0},
-    [0xac] = {"trap",  single, trap_decode, 0},
-    [0xad] = {"trap",  single, trap_decode, 0},
-    [0xae] = {"trap",  single, trap_decode, 0},
-    [0xaf] = {"trap",  single, trap_decode, 0},
-    [0xb0] = {"qmul", mul_n_bytes, mul_decode, 0},
-    [0xb1] = {"qmul", mul_n_bytes, mul_decode, 0},
-    [0xb2] = {"qmul", mul_n_bytes, mul_decode, 0},
-    [0xb3] = {"qmul", mul_n_bytes, mul_decode, 0},
-    [0xb4] = {"qmul", mul_n_bytes, mul_decode, 0},
-    [0xb5] = {"qmul", mul_n_bytes, mul_decode, 0},
-    [0xb6] = {"qmul", mul_n_bytes, mul_decode, 0},
-    [0xb7] = {"qmul", mul_n_bytes, mul_decode, 0},
-    [0xb8] = {"trap",  single, trap_decode, 0},
-    [0xb9] = {"trap",  single, trap_decode, 0},
-    [0xba] = {"trap",  single, trap_decode, 0},
-    [0xbb] = {"trap",  single, trap_decode, 0},
-    [0xbc] = {"trap",  single, trap_decode, 0},
-    [0xbd] = {"trap",  single, trap_decode, 0},
-    [0xbe] = {"trap",  single, trap_decode, 0},
-    [0xbf] = {"trap",  single, trap_decode, 0},
-    [0xc0] = {"trap",  single, trap_decode, 0},
-    [0xc1] = {"trap",  single, trap_decode, 0},
-    [0xc2] = {"trap",  single, trap_decode, 0},
-    [0xc3] = {"trap",  single, trap_decode, 0},
-    [0xc4] = {"trap",  single, trap_decode, 0},
-    [0xc5] = {"trap",  single, trap_decode, 0},
-    [0xc6] = {"trap",  single, trap_decode, 0},
-    [0xc7] = {"trap",  single, trap_decode, 0},
-    [0xc8] = {"trap",  single, trap_decode, 0},
-    [0xc9] = {"trap",  single, trap_decode, 0},
-    [0xca] = {"trap",  single, trap_decode, 0},
-    [0xcb] = {"trap",  single, trap_decode, 0},
-    [0xcc] = {"trap",  single, trap_decode, 0},
-    [0xcd] = {"trap",  single, trap_decode, 0},
-    [0xce] = {"trap",  single, trap_decode, 0},
-    [0xcf] = {"trap",  single, trap_decode, 0},
-    [0xd0] = {"trap",  single, trap_decode, 0},
-    [0xd1] = {"trap",  single, trap_decode, 0},
-    [0xd2] = {"trap",  single, trap_decode, 0},
-    [0xd3] = {"trap",  single, trap_decode, 0},
-    [0xd4] = {"trap",  single, trap_decode, 0},
-    [0xd5] = {"trap",  single, trap_decode, 0},
-    [0xd6] = {"trap",  single, trap_decode, 0},
-    [0xd7] = {"trap",  single, trap_decode, 0},
-    [0xd8] = {"trap",  single, trap_decode, 0},
-    [0xd9] = {"trap",  single, trap_decode, 0},
-    [0xda] = {"trap",  single, trap_decode, 0},
-    [0xdb] = {"trap",  single, trap_decode, 0},
-    [0xdc] = {"trap",  single, trap_decode, 0},
-    [0xdd] = {"trap",  single, trap_decode, 0},
-    [0xde] = {"trap",  single, trap_decode, 0},
-    [0xdf] = {"trap",  single, trap_decode, 0},
-    [0xe0] = {"trap",  single, trap_decode, 0},
-    [0xe1] = {"trap",  single, trap_decode, 0},
-    [0xe2] = {"trap",  single, trap_decode, 0},
-    [0xe3] = {"trap",  single, trap_decode, 0},
-    [0xe4] = {"trap",  single, trap_decode, 0},
-    [0xe5] = {"trap",  single, trap_decode, 0},
-    [0xe6] = {"trap",  single, trap_decode, 0},
-    [0xe7] = {"trap",  single, trap_decode, 0},
-    [0xe8] = {"trap",  single, trap_decode, 0},
-    [0xe9] = {"trap",  single, trap_decode, 0},
-    [0xea] = {"trap",  single, trap_decode, 0},
-    [0xeb] = {"trap",  single, trap_decode, 0},
-    [0xec] = {"trap",  single, trap_decode, 0},
-    [0xed] = {"trap",  single, trap_decode, 0},
-    [0xee] = {"trap",  single, trap_decode, 0},
-    [0xef] = {"trap",  single, trap_decode, 0},
-    [0xf0] = {"trap",  single, trap_decode, 0},
-    [0xf1] = {"trap",  single, trap_decode, 0},
-    [0xf2] = {"trap",  single, trap_decode, 0},
-    [0xf3] = {"trap",  single, trap_decode, 0},
-    [0xf4] = {"trap",  single, trap_decode, 0},
-    [0xf5] = {"trap",  single, trap_decode, 0},
-    [0xf6] = {"trap",  single, trap_decode, 0},
-    [0xf7] = {"trap",  single, trap_decode, 0},
-    [0xf8] = {"trap",  single, trap_decode, 0},
-    [0xf9] = {"trap",  single, trap_decode, 0},
-    [0xfa] = {"trap",  single, trap_decode, 0},
-    [0xfb] = {"trap",  single, trap_decode, 0},
-    [0xfc] = {"trap",  single, trap_decode, 0},
-    [0xfd] = {"trap",  single, trap_decode, 0},
-    [0xfe] = {"trap",  single, trap_decode, 0},
-    [0xff] = {"trap",  single, trap_decode, 0},
-  };
-
-static const struct opcode page1[] =
-  {
-    [0x00] = {"bgnd", single, 0, 0},
-    [0x01] = {"nop",  single, 0, 0},
-    [0x02] = {"brclr", bm_rel_n_bytes, bm_rel_decode, 0},
-    [0x03] = {"brset", bm_rel_n_bytes, bm_rel_decode, 0},
-    [0x04] = {NULL,   two,    0, 0}, /* psh/pul */
-    [0x05] = {"rts",  single, 0, 0},
-    [0x06] = {"lea", opr_n_bytes_p1, reg, opr_decode},
-    [0x07] = {"lea", opr_n_bytes_p1, reg, opr_decode},
-    [0x08] = {"lea", opr_n_bytes_p1, lea_reg_xys_opr, 0},
-    [0x09] = {"lea", opr_n_bytes_p1, lea_reg_xys_opr, 0},
-    [0x0a] = {"lea", opr_n_bytes_p1, lea_reg_xys_opr, 0},
-    [0x0b] = {NULL, loop_prim_n_bytes, 0, 0}, /* Loop primitives TBcc / DBcc */
-    [0x0c] = {"mov.b", mov_imm_opr_n_bytes, mov_imm_opr, 0},
-    [0x0d] = {"mov.w", mov_imm_opr_n_bytes, mov_imm_opr, 0},
-    [0x0e] = {"mov.p", mov_imm_opr_n_bytes, mov_imm_opr, 0},
-    [0x0f] = {"mov.l", mov_imm_opr_n_bytes, mov_imm_opr, 0},
-    [0x10] = {NULL,   shift_n_bytes, 0, 0},  /* lsr/lsl/asl/asr/rol/ror */
-    [0x11] = {NULL,   shift_n_bytes, 0, 0},
-    [0x12] = {NULL,   shift_n_bytes, 0, 0},
-    [0x13] = {NULL,   shift_n_bytes, 0, 0},
-    [0x14] = {NULL,   shift_n_bytes, 0, 0},
-    [0x15] = {NULL,   shift_n_bytes, 0, 0},
-    [0x16] = {NULL,   shift_n_bytes, 0, 0},
-    [0x17] = {NULL,   shift_n_bytes, 0, 0},
-    [0x18] = {"lea",  two, lea_reg_xys, NULL},
-    [0x19] = {"lea",  two, lea_reg_xys, NULL},
-    [0x1a] = {"lea",  two, lea_reg_xys, NULL},
-    /* 0x1b PG2 */
-    [0x1c] = {"mov.b", opr_n_bytes2, 0, opr_decode2},
-    [0x1d] = {"mov.w", opr_n_bytes2, 0, opr_decode2},
-    [0x1e] = {"mov.p", opr_n_bytes2, 0, opr_decode2},
-    [0x1f] = {"mov.l", opr_n_bytes2, 0, opr_decode2},
-    [0x20] = {"bra",  pcrel_15bit, decode_rel_15_7, 0},
-    [0x21] = {"bsr",  pcrel_15bit, decode_rel_15_7, 0},
-    [0x22] = {"bhi",  pcrel_15bit, decode_rel_15_7, 0},
-    [0x23] = {"bls",  pcrel_15bit, decode_rel_15_7, 0},
-    [0x24] = {"bcc",  pcrel_15bit, decode_rel_15_7, 0},
-    [0x25] = {"bcs",  pcrel_15bit, decode_rel_15_7, 0},
-    [0x26] = {"bne",  pcrel_15bit, decode_rel_15_7, 0},
-    [0x27] = {"beq",  pcrel_15bit, decode_rel_15_7, 0},
-    [0x28] = {"bvc",  pcrel_15bit, decode_rel_15_7, 0},
-    [0x29] = {"bvs",  pcrel_15bit, decode_rel_15_7, 0},
-    [0x2a] = {"bpl",  pcrel_15bit, decode_rel_15_7, 0},
-    [0x2b] = {"bmi",  pcrel_15bit, decode_rel_15_7, 0},
-    [0x2c] = {"bge",  pcrel_15bit, decode_rel_15_7, 0},
-    [0x2d] = {"blt",  pcrel_15bit, decode_rel_15_7, 0},
-    [0x2e] = {"bgt",  pcrel_15bit, decode_rel_15_7, 0},
-    [0x2f] = {"ble",  pcrel_15bit, decode_rel_15_7, 0},
-    [0x30] = {"inc", single, reg, 0},
-    [0x31] = {"inc", single, reg, 0},
-    [0x32] = {"inc", single, reg, 0},
-    [0x33] = {"inc", single, reg, 0},
-    [0x34] = {"inc", single, reg, 0},
-    [0x35] = {"inc", single, reg, 0},
-    [0x36] = {"inc", single, reg, 0},
-    [0x37] = {"inc", single, reg, 0},
-    [0x38] = {"clr", single, reg, 0},
-    [0x39] = {"clr", single, reg, 0},
-    [0x3a] = {"clr", single, reg, 0},
-    [0x3b] = {"clr", single, reg, 0},
-    [0x3c] = {"clr", single, reg, 0},
-    [0x3d] = {"clr", single, reg, 0},
-    [0x3e] = {"clr", single, reg, 0},
-    [0x3f] = {"clr", single, reg, 0},
-    [0x40] = {"dec", single, reg, 0},
-    [0x41] = {"dec", single, reg, 0},
-    [0x42] = {"dec", single, reg, 0},
-    [0x43] = {"dec", single, reg, 0},
-    [0x44] = {"dec", single, reg, 0},
-    [0x45] = {"dec", single, reg, 0},
-    [0x46] = {"dec", single, reg, 0},
-    [0x47] = {"dec", single, reg, 0},
-    [0x48] = {"mul", mul_n_bytes, mul_decode, 0},
-    [0x49] = {"mul", mul_n_bytes, mul_decode, 0},
-    [0x4a] = {"mul", mul_n_bytes, mul_decode, 0},
-    [0x4b] = {"mul", mul_n_bytes, mul_decode, 0},
-    [0x4c] = {"mul", mul_n_bytes, mul_decode, 0},
-    [0x4d] = {"mul", mul_n_bytes, mul_decode, 0},
-    [0x4e] = {"mul", mul_n_bytes, mul_decode, 0},
-    [0x4f] = {"mul", mul_n_bytes, mul_decode, 0},
-    [0x50] = {"add", three, reg, imm1234_0base},
-    [0x51] = {"add", three, reg, imm1234_0base},
-    [0x52] = {"add", three, reg, imm1234_0base},
-    [0x53] = {"add", three, reg, imm1234_0base},
-    [0x54] = {"add", two,   reg, imm1234_0base},
-    [0x55] = {"add", two,   reg, imm1234_0base},
-    [0x56] = {"add", five,  reg, imm1234_0base},
-    [0x57] = {"add", five,  reg, imm1234_0base},
-    [0x58] = {"and", three, reg, imm1234_8base},
-    [0x59] = {"and", three, reg, imm1234_8base},
-    [0x5a] = {"and", three, reg, imm1234_8base},
-    [0x5b] = {"and", three, reg, imm1234_8base},
-    [0x5c] = {"and", two,   reg, imm1234_8base},
-    [0x5d] = {"and", two,   reg, imm1234_8base},
-    [0x5e] = {"and", five,  reg, imm1234_8base},
-    [0x5f] = {"and", five,  reg, imm1234_8base},
-    [0x60] = {"add", opr_n_bytes_p1, reg, opr_decode},
-    [0x61] = {"add", opr_n_bytes_p1, reg, opr_decode},
-    [0x62] = {"add", opr_n_bytes_p1, reg, opr_decode},
-    [0x63] = {"add", opr_n_bytes_p1, reg, opr_decode},
-    [0x64] = {"add", opr_n_bytes_p1, reg, opr_decode},
-    [0x65] = {"add", opr_n_bytes_p1, reg, opr_decode},
-    [0x66] = {"add", opr_n_bytes_p1, reg, opr_decode},
-    [0x67] = {"add", opr_n_bytes_p1, reg, opr_decode},
-    [0x68] = {"and", opr_n_bytes_p1, reg, opr_decode},
-    [0x69] = {"and", opr_n_bytes_p1, reg, opr_decode},
-    [0x6a] = {"and", opr_n_bytes_p1, reg, opr_decode},
-    [0x6b] = {"and", opr_n_bytes_p1, reg, opr_decode},
-    [0x6c] = {"and", opr_n_bytes_p1, reg, opr_decode},
-    [0x6d] = {"and", opr_n_bytes_p1, reg, opr_decode},
-    [0x6e] = {"and", opr_n_bytes_p1, reg, opr_decode},
-    [0x6f] = {"and", opr_n_bytes_p1, reg, opr_decode},
-    [0x70] = {"sub", three, reg, imm1234_0base},
-    [0x71] = {"sub", three, reg, imm1234_0base},
-    [0x72] = {"sub", three, reg, imm1234_0base},
-    [0x73] = {"sub", three, reg, imm1234_0base},
-    [0x74] = {"sub", two,   reg, imm1234_0base},
-    [0x75] = {"sub", two,   reg, imm1234_0base},
-    [0x76] = {"sub", five,  reg, imm1234_0base},
-    [0x77] = {"sub", five,  reg, imm1234_0base},
-    [0x78] = {"or", three, reg, imm1234_8base},
-    [0x79] = {"or", three, reg, imm1234_8base},
-    [0x7a] = {"or", three, reg, imm1234_8base},
-    [0x7b] = {"or", three, reg, imm1234_8base},
-    [0x7c] = {"or", two,   reg, imm1234_8base},
-    [0x7d] = {"or", two,   reg, imm1234_8base},
-    [0x7e] = {"or", five,  reg, imm1234_8base},
-    [0x7f] = {"or", five,  reg, imm1234_8base},
-    [0x80] = {"sub", opr_n_bytes_p1, reg,    opr_decode},
-    [0x81] = {"sub", opr_n_bytes_p1, reg,    opr_decode},
-    [0x82] = {"sub", opr_n_bytes_p1, reg,    opr_decode},
-    [0x83] = {"sub", opr_n_bytes_p1, reg,    opr_decode},
-    [0x84] = {"sub", opr_n_bytes_p1, reg,    opr_decode},
-    [0x85] = {"sub", opr_n_bytes_p1, reg,    opr_decode},
-    [0x86] = {"sub", opr_n_bytes_p1, reg,    opr_decode},
-    [0x87] = {"sub", opr_n_bytes_p1, reg,    opr_decode},
-    [0x88] = {"or", opr_n_bytes_p1, reg,    opr_decode},
-    [0x89] = {"or", opr_n_bytes_p1, reg,    opr_decode},
-    [0x8a] = {"or", opr_n_bytes_p1, reg,    opr_decode},
-    [0x8b] = {"or", opr_n_bytes_p1, reg,    opr_decode},
-    [0x8c] = {"or", opr_n_bytes_p1, reg,    opr_decode},
-    [0x8d] = {"or", opr_n_bytes_p1, reg,    opr_decode},
-    [0x8e] = {"or", opr_n_bytes_p1, reg,    opr_decode},
-    [0x8f] = {"or", opr_n_bytes_p1, reg,    opr_decode},
-    [0x90] = {"ld", three,  reg, imm1234_0base},
-    [0x91] = {"ld", three,  reg, imm1234_0base},
-    [0x92] = {"ld", three,  reg, imm1234_0base},
-    [0x93] = {"ld", three,  reg, imm1234_0base},
-    [0x94] = {"ld", two,    reg, imm1234_0base},
-    [0x95] = {"ld", two,    reg, imm1234_0base},
-    [0x96] = {"ld", five,   reg, imm1234_0base},
-    [0x97] = {"ld", five,   reg, imm1234_0base},
-    [0x98] = {"ld", four,   reg_xy, imm1234_0base},
-    [0x99] = {"ld", four,   reg_xy, imm1234_0base},
-    [0x9a] = {"clr", single, reg_xy, 0},
-    [0x9b] = {"clr", single, reg_xy, 0},
-    [0x9c] = {"inc.b", opr_n_bytes_p1, 0, opr_decode},
-    [0x9d] = {"inc.w", opr_n_bytes_p1, 0, opr_decode},
-    [0x9e] = {"tfr", two, tfr, NULL},
-    [0x9f] = {"inc.l", opr_n_bytes_p1, 0, opr_decode},
-    [0xa0] = {"ld", opr_n_bytes_p1, reg,    opr_decode},
-    [0xa1] = {"ld", opr_n_bytes_p1, reg,    opr_decode},
-    [0xa2] = {"ld", opr_n_bytes_p1, reg,    opr_decode},
-    [0xa3] = {"ld", opr_n_bytes_p1, reg,    opr_decode},
-    [0xa4] = {"ld", opr_n_bytes_p1, reg,    opr_decode},
-    [0xa5] = {"ld", opr_n_bytes_p1, reg,    opr_decode},
-    [0xa6] = {"ld", opr_n_bytes_p1, reg,    opr_decode},
-    [0xa7] = {"ld", opr_n_bytes_p1, reg,    opr_decode},
-    [0xa8] = {"ld", opr_n_bytes_p1, reg_xy, opr_decode},
-    [0xa9] = {"ld", opr_n_bytes_p1, reg_xy, opr_decode},
-    [0xaa] = {"jmp", opr_n_bytes_p1, opr_decode, 0},
-    [0xab] = {"jsr", opr_n_bytes_p1, opr_decode, 0},
-    [0xac] = {"dec.b", opr_n_bytes_p1, 0, opr_decode},
-    [0xad] = {"dec.w", opr_n_bytes_p1, 0, opr_decode},
-    [0xae] = {NULL,   two, 0, 0},  /* EXG / SEX */
-    [0xaf] = {"dec.l", opr_n_bytes_p1, 0, opr_decode},
-    [0xb0] = {"ld", four,  reg, ext24_decode},
-    [0xb1] = {"ld", four,  reg, ext24_decode},
-    [0xb2] = {"ld", four,  reg, ext24_decode},
-    [0xb3] = {"ld", four,  reg, ext24_decode},
-    [0xb4] = {"ld", four,  reg, ext24_decode},
-    [0xb5] = {"ld", four,  reg, ext24_decode},
-    [0xb6] = {"ld", four,  reg, ext24_decode},
-    [0xb7] = {"ld", four,  reg, ext24_decode},
-    [0xb8] = {"ld", four,  reg_xy, ext24_decode},
-    [0xb9] = {"ld", four,  reg_xy, ext24_decode},
-    [0xba] = {"jmp", four, ext24_decode, 0},
-    [0xbb] = {"jsr", four, ext24_decode, 0},
-    [0xbc] = {"clr.b", opr_n_bytes_p1, 0, opr_decode},
-    [0xbd] = {"clr.w", opr_n_bytes_p1, 0, opr_decode},
-    [0xbe] = {"clr.p", opr_n_bytes_p1, 0, opr_decode},
-    [0xbf] = {"clr.l", opr_n_bytes_p1, 0, opr_decode},
-    [0xc0] = {"st", opr_n_bytes_p1, reg,    opr_decode},
-    [0xc1] = {"st", opr_n_bytes_p1, reg,    opr_decode},
-    [0xc2] = {"st", opr_n_bytes_p1, reg,    opr_decode},
-    [0xc3] = {"st", opr_n_bytes_p1, reg,    opr_decode},
-    [0xc4] = {"st", opr_n_bytes_p1, reg,    opr_decode},
-    [0xc5] = {"st", opr_n_bytes_p1, reg,    opr_decode},
-    [0xc6] = {"st", opr_n_bytes_p1, reg,    opr_decode},
-    [0xc7] = {"st", opr_n_bytes_p1, reg,    opr_decode},
-    [0xc8] = {"st", opr_n_bytes_p1, reg_xy, opr_decode},
-    [0xc9] = {"st", opr_n_bytes_p1, reg_xy, opr_decode},
-    [0xca] = {"ld", three, reg_xy, ld_18bit_decode},
-    [0xcb] = {"ld", three, reg_xy, ld_18bit_decode},
-    [0xcc] = {"com.b", opr_n_bytes_p1, NULL, opr_decode},
-    [0xcd] = {"com.w", opr_n_bytes_p1, NULL, opr_decode},
-    [0xce] = {"andcc", two, imm1, 0},
-    [0xcf] = {"com.l", opr_n_bytes_p1, NULL, opr_decode},
-    [0xd0] = {"st", four,  reg, ext24_decode},
-    [0xd1] = {"st", four,  reg, ext24_decode},
-    [0xd2] = {"st", four,  reg, ext24_decode},
-    [0xd3] = {"st", four,  reg, ext24_decode},
-    [0xd4] = {"st", four,  reg, ext24_decode},
-    [0xd5] = {"st", four,  reg, ext24_decode},
-    [0xd6] = {"st", four,  reg, ext24_decode},
-    [0xd7] = {"st", four,  reg, ext24_decode},
-    [0xd8] = {"st", four,  reg_xy, ext24_decode},
-    [0xd9] = {"st", four,  reg_xy, ext24_decode},
-    [0xda] = {"ld", three, reg_xy, ld_18bit_decode},
-    [0xdb] = {"ld", three, reg_xy, ld_18bit_decode},
-    [0xdc] = {"neg.b", opr_n_bytes_p1, NULL, opr_decode},
-    [0xdd] = {"neg.w", opr_n_bytes_p1, NULL, opr_decode},
-    [0xde] = {"orcc",  two,  imm1, 0},
-    [0xdf] = {"neg.l", opr_n_bytes_p1, NULL, opr_decode},
-    [0xe0] = {"cmp", three,  reg, imm1234_0base},
-    [0xe1] = {"cmp", three,  reg, imm1234_0base},
-    [0xe2] = {"cmp", three,  reg, imm1234_0base},
-    [0xe3] = {"cmp", three,  reg, imm1234_0base},
-    [0xe4] = {"cmp", two,    reg, imm1234_0base},
-    [0xe5] = {"cmp", two,    reg, imm1234_0base},
-    [0xe6] = {"cmp", five,   reg, imm1234_0base},
-    [0xe7] = {"cmp", five,   reg, imm1234_0base},
-    [0xe8] = {"cmp", four,   reg_xy, imm1234_0base},
-    [0xe9] = {"cmp", four,   reg_xy, imm1234_0base},
-    [0xea] = {"ld", three, reg_xy, ld_18bit_decode},
-    [0xeb] = {"ld", three, reg_xy, ld_18bit_decode},
-    [0xec] = {"bclr", bm_n_bytes, bm_decode, 0},
-    [0xed] = {"bset", bm_n_bytes, bm_decode, 0},
-    [0xee] = {"btgl", bm_n_bytes, bm_decode, 0},
-    [0xef] = {"!!invalid!!", NULL, NULL, NULL}, /* SPARE */
-    [0xf0] = {"cmp", opr_n_bytes_p1, reg,    opr_decode},
-    [0xf1] = {"cmp", opr_n_bytes_p1, reg,    opr_decode},
-    [0xf2] = {"cmp", opr_n_bytes_p1, reg,    opr_decode},
-    [0xf3] = {"cmp", opr_n_bytes_p1, reg,    opr_decode},
-    [0xf4] = {"cmp", opr_n_bytes_p1, reg,    opr_decode},
-    [0xf5] = {"cmp", opr_n_bytes_p1, reg,    opr_decode},
-    [0xf6] = {"cmp", opr_n_bytes_p1, reg,    opr_decode},
-    [0xf7] = {"cmp", opr_n_bytes_p1, reg,    opr_decode},
-    [0xf8] = {"cmp", opr_n_bytes_p1, reg_xy, opr_decode},
-    [0xf9] = {"cmp", opr_n_bytes_p1, reg_xy, opr_decode},
-    [0xfa] = {"ld",  three, reg_xy, ld_18bit_decode},
-    [0xfb] = {"ld",  three, reg_xy, ld_18bit_decode},
-    [0xfc] = {"cmp", single, cmp_xy, 0},
-    [0xfd] = {"sub", single, sub_d6_x_y, 0},
-    [0xfe] = {"sub", single, sub_d6_y_x, 0},
-    [0xff] = {"swi", single, 0, 0}
-  };
-
-
-static const char *oprregs1[] =
-  {
-    "d3", "d2", "d1", "d0", "ccl", "cch"
-  };
-
-static const char *oprregs2[] =
-  {
-    "y", "x", "d7", "d6", "d5", "d4"
-  };
-
-
-
-
-enum MUL_MODE
-  {
-    MUL_REG_REG,
-    MUL_REG_OPR,
-    MUL_REG_IMM,
-    MUL_OPR_OPR
-  };
-
-struct mb
-{
-  uint8_t mask;
-  uint8_t value;
-  enum MUL_MODE mode;
-};
-
-static const struct mb mul_table[] = {
-  {0x40, 0x00, MUL_REG_REG},
-
-  {0x47, 0x40, MUL_REG_OPR},
-  {0x47, 0x41, MUL_REG_OPR},
-  {0x47, 0x43, MUL_REG_OPR},
-
-  {0x47, 0x44, MUL_REG_IMM},
-  {0x47, 0x45, MUL_REG_IMM},
-  {0x47, 0x47, MUL_REG_IMM},
-
-  {0x43, 0x42, MUL_OPR_OPR},
-};
-
-static void
-mul_decode (bfd_vma memaddr, struct disassemble_info* info)
-{
-  uint8_t mb;
-  int status = read_memory (memaddr, &mb, 1, info);
-  if (status < 0)
-    return;
-
-
-  uint8_t byte;
-  status = read_memory (memaddr - 1, &byte, 1, info);
-  if (status < 0)
-    return;
-
-  (*info->fprintf_func) (info->stream, "%c", (mb & 0x80) ? 's' : 'u');
-
-  enum MUL_MODE mode = -1;
-  size_t i;
-  for (i = 0; i < sizeof (mul_table) / sizeof (mul_table[0]); ++i)
-    {
-      const struct mb *mm = mul_table + i;
-      if ((mb & mm->mask) == mm->value)
-	{
-	  mode = mm->mode;
-	  break;
-	}
-    }
-
-  switch (mode)
-    {
-    case MUL_REG_REG:
-      break;
-    case MUL_OPR_OPR:
-      {
-	int size1 = (mb & 0x30) >> 4;
-	int size2 = (mb & 0x0c) >> 2;
-	(*info->fprintf_func) (info->stream, ".%c%c",
-			       shift_size_table [size1],
-			       shift_size_table [size2]);
-      }
-      break;
-    default:
-      {
-	int size = (mb & 0x3);
-	(*info->fprintf_func) (info->stream, ".%c", shift_size_table [size]);
-      }
-      break;
-    }
-
-  operand_separator (info);
-  (*info->fprintf_func) (info->stream, "%s", registers[byte & 0x7].name);
-
-  switch (mode)
-    {
-    case MUL_REG_REG:
-    case MUL_REG_IMM:
-    case MUL_REG_OPR:
-      operand_separator (info);
-      (*info->fprintf_func) (info->stream, "%s", registers[(mb & 0x38) >> 3].name);
-      break;
-    default:
-      break;
-    }
-
-  switch (mode)
-    {
-    case MUL_REG_IMM:
-      operand_separator (info);
-      int size = (mb & 0x3);
-      uint32_t imm = decode_signed_value (memaddr + 1, info, size + 1);
-      (*info->fprintf_func) (info->stream, "#%d", imm);
-      break;
-    case MUL_REG_REG:
-      operand_separator (info);
-      (*info->fprintf_func) (info->stream, "%s", registers[mb & 0x07].name);
-      break;
-    case MUL_REG_OPR:
-      opr_decode (memaddr + 1, info);
-      break;
-    case MUL_OPR_OPR:
-      {
-	int first = opr_n_bytes (memaddr + 1, info);
-	opr_decode (memaddr + 1, info);
-	opr_decode (memaddr + first + 1, info);
-	break;
-      }
-    }
-}
-
-
-static int
-mul_n_bytes (bfd_vma memaddr, struct disassemble_info* info)
-{
-  int nx = 2;
-  uint8_t mb;
-  int status = read_memory (memaddr, &mb, 1, info);
-  if (status < 0)
-    return 0;
-
-  enum MUL_MODE mode = -1;
-  size_t i;
-  for (i = 0; i < sizeof (mul_table) / sizeof (mul_table[0]); ++i)
-    {
-      const struct mb *mm = mul_table + i;
-      if ((mb & mm->mask) == mm->value)
-	{
-	  mode = mm->mode;
-	  break;
-	}
-    }
-
-  int size = (mb & 0x3) + 1;
-
-  switch (mode)
-    {
-    case MUL_REG_IMM:
-      nx += size;
-      break;
-    case MUL_REG_REG:
-      break;
-    case MUL_REG_OPR:
-      nx += opr_n_bytes (memaddr + 1, info);
-      break;
-    case MUL_OPR_OPR:
-      {
-	int first = opr_n_bytes (memaddr + nx - 1, info);
-	nx += first;
-	int second = opr_n_bytes (memaddr + nx - 1, info);
-	nx += second;
-      }
-      break;
-    }
-
-  return nx;
-}
-
-
- /* The NXP documentation is vague about BM_RESERVED0 and BM_RESERVED1,
-    and contains obvious typos.
-    However the Freescale tools and experiments with the chip itself
-    seem to indicate that they behave like BM_REG_IMM and BM_OPR_REG
-    respectively.  */
-
-enum BM_MODE {
-  BM_REG_IMM,
-  BM_RESERVED0,
-  BM_OPR_B,
-  BM_OPR_W,
-  BM_OPR_L,
-  BM_OPR_REG,
-  BM_RESERVED1
-};
-
-struct bm
-{
-  uint8_t mask;
-  uint8_t value;
-  enum BM_MODE mode;
-};
-
-static const  struct bm bm_table[] = {
-  { 0xC6, 0x04,     BM_REG_IMM},
-  { 0x84, 0x00,     BM_REG_IMM},
-  { 0x06, 0x06,     BM_REG_IMM},
-  { 0xC6, 0x44,     BM_RESERVED0},
-  // 00
-  { 0x8F, 0x80,     BM_OPR_B},
-  { 0x8E, 0x82,     BM_OPR_W},
-  { 0x8C, 0x88,     BM_OPR_L},
-
-  { 0x83, 0x81,     BM_OPR_REG},
-  { 0x87, 0x84,     BM_RESERVED1},
-};
-
-static void
-bm_decode (bfd_vma memaddr, struct disassemble_info* info)
-{
-  uint8_t bm;
-  int status = read_memory (memaddr, &bm, 1, info);
-  if (status < 0)
-    return;
-
-  size_t i;
-  enum BM_MODE mode = -1;
-  for (i = 0; i < sizeof (bm_table) / sizeof (bm_table[0]); ++i)
-    {
-      const struct bm *bme = bm_table + i;
-      if ((bm & bme->mask) == bme->value)
-	{
-	  mode = bme->mode;
-	  break;
-	}
-    }
-
-  switch (mode)
-    {
-    case BM_REG_IMM:
-    case BM_RESERVED0:
-      operand_separator (info);
-      (*info->fprintf_func) (info->stream, "%s", registers[bm & 0x07].name);
-      break;
-    case BM_OPR_B:
-      (*info->fprintf_func) (info->stream, ".%c", 'b');
-      opr_decode (memaddr + 1, info);
-      break;
-    case BM_OPR_W:
-      (*info->fprintf_func) (info->stream, ".%c", 'w');
-      opr_decode (memaddr + 1, info);
-      break;
-    case BM_OPR_L:
-      (*info->fprintf_func) (info->stream, ".%c", 'l');
-      opr_decode (memaddr + 1, info);
-      break;
-    case BM_OPR_REG:
-    case BM_RESERVED1:
-      {
-	uint8_t xb;
-	read_memory (memaddr + 1, &xb, 1, info);
-	/* Don't emit a size suffix for register operands */
-	if ((xb & 0xF8) != 0xB8)
-	  (*info->fprintf_func) (info->stream, ".%c", shift_size_table[(bm & 0x0c) >> 2]);
-	opr_decode (memaddr + 1, info);
-      }
-      break;
-    }
-
-  uint8_t imm = 0;
-  operand_separator (info);
-  switch (mode)
-    {
-    case BM_REG_IMM:
-      {
-	imm = (bm & 0x38) >> 3;
-	(*info->fprintf_func) (info->stream, "#%d", imm);
-      }
-      break;
-    case BM_OPR_L:
-      imm |= (bm & 0x03) << 3;
-      /* fallthrough */
-    case BM_OPR_W:
-      imm |= (bm & 0x01) << 3;
-      /* fallthrough */
-    case BM_OPR_B:
-      imm |= (bm & 0x70) >> 4;
-      (*info->fprintf_func) (info->stream, "#%d", imm);
-      break;
-    case BM_OPR_REG:
-    case BM_RESERVED1:
-      (*info->fprintf_func) (info->stream, "%s", registers[(bm & 0x70) >> 4].name);
-      break;
-    case BM_RESERVED0:
-      assert (0);
-      break;
-    }
-}
-
-
-static void
-bm_rel_decode (bfd_vma memaddr, struct disassemble_info* info)
-{
-  uint8_t bm;
-  int status = read_memory (memaddr, &bm, 1, info);
-  if (status < 0)
-    return;
-
-  size_t i;
-  enum BM_MODE mode = -1;
-  for (i = 0; i < sizeof (bm_table) / sizeof (bm_table[0]); ++i)
-    {
-      const struct bm *bme = bm_table + i;
-      if ((bm & bme->mask) == bme->value)
-	{
-	  mode = bme->mode;
-	  break;
-	}
-    }
-
-  switch (mode)
-    {
-    case BM_REG_IMM:
-    case BM_RESERVED0:
-      break;
-    case BM_OPR_B:
-      (*info->fprintf_func) (info->stream, ".%c", 'b');
-      break;
-    case BM_OPR_W:
-      (*info->fprintf_func) (info->stream, ".%c", 'w');
-      break;
-    case BM_OPR_L:
-      (*info->fprintf_func) (info->stream, ".%c", 'l');
-      break;
-    case BM_OPR_REG:
-    case BM_RESERVED1:
-      {
-	uint8_t xb;
-	read_memory (memaddr + 1, &xb, 1, info);
-	/* Don't emit a size suffix for register operands */
-	if ((xb & 0xF8) != 0xB8)
-	  (*info->fprintf_func) (info->stream, ".%c",
-				 shift_size_table[(bm & 0x0C) >> 2]);
-      }
-      break;
-    }
-
-  int n = 1;
-  switch (mode)
-    {
-    case BM_REG_IMM:
-    case BM_RESERVED0:
-      operand_separator (info);
-      (*info->fprintf_func) (info->stream, "%s", registers[bm & 0x07].name);
-      break;
-    case BM_OPR_B:
-    case BM_OPR_W:
-    case BM_OPR_L:
-      opr_decode (memaddr + 1, info);
-      n = 1 + opr_n_bytes (memaddr + 1, info);
-      break;
-    case BM_OPR_REG:
-    case BM_RESERVED1:
-      opr_decode (memaddr + 1, info);
-      break;
-    }
-
-
-  int imm = 0;
-  operand_separator (info);
-  switch (mode)
-    {
-    case BM_OPR_L:
-      imm |= (bm & 0x02) << 3;
-      /* fall through */
-    case BM_OPR_W:
-      imm |= (bm & 0x01) << 3;
-      /* fall through */
-    case BM_OPR_B:
-      imm |= (bm & 0x70) >> 4;
-      (*info->fprintf_func) (info->stream, "#%d", imm);
-      break;
-    case BM_RESERVED0:
-      imm = (bm & 0x38) >> 3;
-      (*info->fprintf_func) (info->stream, "#%d", imm);
-      break;
-    case BM_REG_IMM:
-      imm = (bm & 0xF8) >> 3;
-      (*info->fprintf_func) (info->stream, "#%d", imm);
-      break;
-    case BM_OPR_REG:
-    case BM_RESERVED1:
-      (*info->fprintf_func) (info->stream, "%s", registers[(bm & 0x70) >> 4].name);
-      n += opr_n_bytes (memaddr + 1, info);
-      break;
-    }
-
-  rel_15_7 (memaddr + n, info, n + 1);
-}
-
-static int
-bm_n_bytes (bfd_vma memaddr, struct disassemble_info* info)
-{
-  uint8_t bm;
-  int status = read_memory (memaddr, &bm, 1, info);
-  if (status < 0)
-    return status;
-
-  size_t i;
-  enum BM_MODE mode = -1;
-  for (i = 0; i < sizeof (bm_table) / sizeof (bm_table[0]); ++i)
-    {
-      const struct bm *bme = bm_table + i;
-      if ((bm & bme->mask) == bme->value)
-	{
-	  mode = bme->mode;
-	  break;
-	}
-    }
-
-  int n = 2;
-  switch (mode)
-    {
-    case BM_REG_IMM:
-    case BM_RESERVED0:
-      break;
-
-    case BM_OPR_B:
-    case BM_OPR_W:
-    case BM_OPR_L:
-      n += opr_n_bytes (memaddr + 1, info);
-      break;
-    case BM_OPR_REG:
-    case BM_RESERVED1:
-      n += opr_n_bytes (memaddr + 1, info);
-      break;
-  }
-
-  return n;
-}
-
-static int
-bm_rel_n_bytes (bfd_vma memaddr, struct disassemble_info* info)
-{
-  int n = 1 + bm_n_bytes (memaddr, info);
-
-  bfd_byte rb;
-  int status = read_memory (memaddr + n - 2, &rb, 1, info);
-  if (status != 0)
-    return status;
-
-  if (rb & 0x80)
-    n++;
-
-  return n;
-}
-
-
-
-
-
-/* shift direction */
-enum SB_DIR
-  {
-    SB_LEFT,
-    SB_RIGHT
-  };
-
-enum SB_TYPE
-  {
-    SB_ARITHMETIC,
-    SB_LOGICAL
-  };
-
-
-enum SB_MODE
-  {
-    SB_REG_REG_N_EFF,
-    SB_REG_REG_N,
-    SB_REG_OPR_EFF,
-    SB_ROT,
-    SB_REG_OPR_OPR,
-    SB_OPR_N
-  };
-
-struct sb
-{
-  uint8_t mask;
-  uint8_t value;
-  enum SB_MODE mode;
-};
-
-static const  struct sb sb_table[] = {
-  {0x30, 0x00,     SB_REG_REG_N_EFF},
-  {0x30, 0x10,     SB_REG_REG_N},
-  {0x34, 0x20,     SB_REG_OPR_EFF},
-  {0x34, 0x24,     SB_ROT},
-  {0x34, 0x30,     SB_REG_OPR_OPR},
-  {0x34, 0x34,     SB_OPR_N},
-};
-
-static int
-shift_n_bytes (bfd_vma memaddr, struct disassemble_info* info)
-{
-  bfd_byte sb;
-  int status = read_memory (memaddr++, &sb, 1, info);
-  if (status != 0)
-    return status;
-
-  size_t i;
-  enum SB_MODE mode = -1;
-  for (i = 0; i < sizeof (sb_table) / sizeof (sb_table[0]); ++i)
-    {
-      const struct sb *sbe = sb_table + i;
-      if ((sb & sbe->mask) == sbe->value)
-	mode = sbe->mode;
-    }
-
-  switch (mode)
-    {
-    case SB_REG_REG_N_EFF:
-      return 2;
-      break;
-    case SB_REG_OPR_EFF:
-    case SB_ROT:
-	return 2 + opr_n_bytes (memaddr, info);
-      break;
-    case SB_REG_OPR_OPR:
-      {
-	int opr1 = opr_n_bytes (memaddr, info);
-	int opr2 = 0;
-	if ((sb & 0x30) != 0x20)
-	  opr2 = opr_n_bytes (memaddr + opr1, info);
-	return 2 + opr1 + opr2;
-      }
-      break;
-    default:
-      return 3;
-    }
-
-  /* not reached */
-  return -1;
-}
-
-
-static int
-mov_imm_opr_n_bytes (bfd_vma memaddr, struct disassemble_info* info)
-{
-  bfd_byte byte;
-  int status = read_memory (memaddr - 1, &byte, 1, info);
-  if (status < 0)
-    return status;
-
-  int size = byte - 0x0c + 1;
-
-  return size + opr_n_bytes (memaddr + size, info) + 1;
-}
-
-static void
-mov_imm_opr (bfd_vma memaddr, struct disassemble_info* info)
-{
-  bfd_byte byte;
-  int status = read_memory (memaddr - 1, &byte, 1, info);
-  if (status < 0)
-    return ;
-
-  int size = byte - 0x0c + 1;
-  uint32_t imm = decode_signed_value (memaddr, info, size);
-
-  operand_separator (info);
-  (*info->fprintf_func) (info->stream, "#%d", imm);
-  opr_decode (memaddr + size, info);
-}
-
-
-
-static void
-ld_18bit_decode (bfd_vma memaddr, struct disassemble_info* info)
-{
-  size_t size = 3;
-  bfd_byte buffer[3];
-  int status = read_memory (memaddr, buffer + 1, 2, info);
-  if (status < 0)
-    return ;
-
-
-  status = read_memory (memaddr - 1, buffer, 1, info);
-  if (status < 0)
-    return ;
-
-  buffer[0] = (buffer[0] & 0x30) >> 4;
-
-  size_t i;
-  uint32_t imm = 0;
-  for (i = 0; i < size; ++i)
-    {
-      imm |= buffer[i] << (8 * (size - i - 1));
-    }
-
-  operand_separator (info);
-  (*info->fprintf_func) (info->stream, "#%d", imm);
-}
-
-
-
-/* Loop Primitives */
-
-enum LP_MODE {
-  LP_REG,
-  LP_XY,
-  LP_OPR
-};
-
-struct lp
-{
-  uint8_t mask;
-  uint8_t value;
-  enum LP_MODE mode;
-};
-
-static const struct lp lp_mode[] = {
-  {0x08, 0x00, LP_REG},
-  {0x0C, 0x08, LP_XY},
-  {0x0C, 0x0C, LP_OPR},
-};
-
-
-static const char *lb_condition[] =
-  {
-    "ne", "eq", "pl", "mi", "gt", "le",
-    "??", "??"
-  };
-
-static int
-loop_prim_n_bytes (bfd_vma memaddr, struct disassemble_info* info)
-{
-  int mx = 0;
-  uint8_t lb;
-  read_memory (memaddr + mx++, &lb, 1, info);
-
-  enum LP_MODE mode = -1;
-  size_t i;
-  for (i = 0; i < sizeof (lp_mode) / sizeof (lp_mode[0]); ++i)
-    {
-      const struct lp *pb = lp_mode + i;
-      if ((lb & pb->mask) == pb->value)
-	{
-	  mode = pb->mode;
-	  break;
-	}
-    }
-
-  if (mode == LP_OPR)
-    {
-      mx += opr_n_bytes (memaddr + mx, info) ;
-    }
-
-  uint8_t rb;
-  read_memory (memaddr + mx++, &rb, 1, info);
-  if (rb & 0x80)
-    mx++;
-
-  return mx + 1;
-}
-
-
-
-
-static int
-print_insn_exg_sex (bfd_vma memaddr, struct disassemble_info* info)
-{
-  uint8_t eb;
-  int status = read_memory (memaddr, &eb, 1, info);
-  if (status < 0)
-    return -1;
-
-  const struct reg *first =  &registers[(eb & 0xf0) >> 4];
-  const struct reg *second = &registers[(eb & 0xf)];
-
-  if (first->bytes < second->bytes)
-    (*info->fprintf_func) (info->stream, "sex");
-  else
-    (*info->fprintf_func) (info->stream, "exg");
-
-  operand_separator (info);
-  (*info->fprintf_func) (info->stream, "%s", first->name);
-  operand_separator (info);
-  (*info->fprintf_func) (info->stream, "%s", second->name);
-  return 0;
-}
-
-
-
-static int
-print_insn_loop_primitive (bfd_vma memaddr, struct disassemble_info* info)
-{
-  int offs = 1;
-  uint8_t lb;
-  int status = read_memory (memaddr, &lb, 1, info);
-
-  char mnemonic[7];
-  int x = 0;
-  mnemonic[x++] = (lb & 0x80) ? 'd' : 't';
-  mnemonic[x++] = 'b';
-  stpcpy (mnemonic + x, lb_condition [(lb & 0x70) >> 4]);
-  x += 2;
-
-  const char *reg_dxy  = NULL;
-  enum LP_MODE mode = -1;
-  size_t i;
-  for (i = 0; i < sizeof (lp_mode) / sizeof (lp_mode[0]); ++i)
-    {
-      const struct lp *pb = lp_mode + i;
-      if ((lb & pb->mask) == pb->value)
-	{
-	  mode = pb->mode;
-	  break;
-	}
-    }
-
-  switch (mode)
-    {
-    case LP_REG:
-      reg_dxy = registers [lb & 0x07].name;
-      break;
-    case LP_XY:
-      reg_dxy = (lb & 0x1) ? "y" : "x";
-      break;
-    case LP_OPR:
-      mnemonic[x++] = '.';
-      mnemonic[x++] = shift_size_table [lb & 0x03];
-      offs += opr_n_bytes (memaddr + 1, info);
-      break;
-    }
-
-  mnemonic[x++] = '\0';
-
-  (*info->fprintf_func) (info->stream, "%s", mnemonic);
-
-  if (mode == LP_OPR)
-    opr_decode (memaddr + 1, info);
-  else
-    {
-      operand_separator (info);
-      (*info->fprintf_func) (info->stream, "%s", reg_dxy);
-    }
-
-  rel_15_7 (memaddr + offs, info, offs + 1);
-
-  return status;
-}
-
-
-static int
-print_insn_shift (bfd_vma memaddr, struct disassemble_info* info, uint8_t byte)
-{
-  size_t i;
-  uint8_t sb;
-  int status = read_memory (memaddr, &sb, 1, info);
-  if (status < 0)
-    return status;
-
-  enum SB_DIR  dir = (sb & 0x40) ? SB_LEFT : SB_RIGHT;
-  enum SB_TYPE type = (sb & 0x80) ? SB_ARITHMETIC : SB_LOGICAL;
-  enum SB_MODE mode = -1;
-  for (i = 0; i < sizeof (sb_table) / sizeof (sb_table[0]); ++i)
-    {
-      const struct sb *sbe = sb_table + i;
-      if ((sb & sbe->mask) == sbe->value)
-	mode = sbe->mode;
-    }
-
-  char mnemonic[6];
-  int x = 0;
-  if (mode == SB_ROT)
-    {
-      mnemonic[x++] = 'r';
-      mnemonic[x++] = 'o';
-    }
-  else
-    {
-      mnemonic[x++] = (type == SB_LOGICAL) ? 'l' : 'a';
-      mnemonic[x++] = 's';
-    }
-
-  mnemonic[x++] = (dir == SB_LEFT) ? 'l' : 'r';
-
-  switch (mode)
-    {
-    case SB_REG_OPR_EFF:
-    case SB_ROT:
-    case SB_REG_OPR_OPR:
-      mnemonic[x++] = '.';
-      mnemonic[x++] = shift_size_table[sb & 0x03];
-      break;
-    case SB_OPR_N:
-      {
-	uint8_t xb;
-	read_memory (memaddr + 1, &xb, 1, info);
-	/* The size suffix is not printed if the OPR operand refers
-	   directly to a register, because the size is implied by the
-	   size of that register. */
-	if ((xb & 0xF8) != 0xB8)
-	  {
-	    mnemonic[x++] = '.';
-	    mnemonic[x++] = shift_size_table[sb & 0x03];
-	  }
-      }
-      break;
-    default:
-      break;
-    };
-
-  mnemonic[x++] = '\0';
-
-  (*info->fprintf_func) (info->stream, "%s", mnemonic);
-
-  /* Destination register */
-  switch (mode)
-    {
-    case SB_REG_REG_N_EFF:
-    case SB_REG_REG_N:
-    case SB_REG_OPR_EFF:
-    case SB_REG_OPR_OPR:
-      operand_separator (info);
-      (*info->fprintf_func) (info->stream, "%s", registers[byte & 0x7].name);
-      break;
-
-    case SB_ROT:
-      opr_decode (memaddr + 1, info);
-      break;
-
-    default:
-      break;
-    }
-
-  /* Source register */
-  switch (mode)
-    {
-    case SB_REG_REG_N_EFF:
-    case SB_REG_REG_N:
-      operand_separator (info);
-      (*info->fprintf_func) (info->stream, "%s", registers[sb & 0x7].name);
-      break;
-
-    case SB_REG_OPR_OPR:
-      opr_decode (memaddr + 1, info);
-      break;
-
-    default:
-      break;
-    }
-
-  /* 3rd arg */
-  switch (mode)
-    {
-    case SB_REG_OPR_EFF:
-    case SB_OPR_N:
-      opr_decode (memaddr + 1, info);
-      break;
-
-    case SB_REG_REG_N:
-      {
-        uint8_t xb;
-        read_memory (memaddr + 1, &xb, 1, info);
-        /* This case is slightly unusual.
-           If XB matches the binary pattern 0111XXXX, then instead of
-           interpreting this as a general OPR postbyte in the IMMe4 mode,
-           the XB byte is interpreted in s special way.  */
-        if ((xb & 0xF0) == 0x70)
-          {
-            operand_separator (info);
-            if (byte & 0x10)
-              {
-                int shift = ((sb & 0x08) >> 3) | ((xb & 0x0f) << 1);
-                (*info->fprintf_func) (info->stream, "#%d", shift);
-              }
-            else
-              {
-                (*info->fprintf_func) (info->stream, "%s:%d", __FILE__, __LINE__);
-              }
-          }
-        else
-          {
-            opr_decode (memaddr + 1, info);
-          }
-      }
-      break;
-    case SB_REG_OPR_OPR:
-      {
-      uint8_t xb;
-      int n = opr_n_bytes (memaddr + 1, info);
-      read_memory (memaddr + 1 + n, &xb, 1, info);
-
-      if ((xb & 0xF0) == 0x70)
-	{
-	  int imm = xb & 0x0F;
-	  imm <<= 1;
-	  imm |= (sb & 0x08) >> 3;
-	  operand_separator (info);
-	  (*info->fprintf_func) (info->stream, "#%d", imm);
-	}
-      else
-	{
-	  opr_decode (memaddr + 1 + n, info);
-	}
-      }
-      break;
-    default:
-      break;
-    }
-
-  switch (mode)
-    {
-    case SB_REG_REG_N_EFF:
-    case SB_REG_OPR_EFF:
-    case SB_OPR_N:
-      operand_separator (info);
-      (*info->fprintf_func) (info->stream, "#%d",
-			     (sb & 0x08) ? 2 : 1);
-      break;
-
-    default:
-      break;
-    }
-
-  return 0;
-}
-
-int
-print_insn_s12z (bfd_vma memaddr, struct disassemble_info* info)
-{
-  bfd_byte byte;
-  int status = read_memory (memaddr++, &byte, 1, info);
-  if (status != 0)
-    return status;
-
-  const struct opcode *opc2 = NULL;
-  const struct opcode *opc = page1 + byte;
-  if (opc->mnemonic)
-    {
-      (*info->fprintf_func) (info->stream, "%s", opc->mnemonic);
-    }
-  else
-    {
-      /* The special cases ... */
-      switch (byte)
-	{
-	case PAGE2_PREBYTE:
-	  {
-	    bfd_byte byte2;
-	    read_memory (memaddr++, &byte2, 1, info);
-	    opc2 = page2 + byte2;
-	    if (opc2->mnemonic)
-	      {
-		(*info->fprintf_func) (info->stream, "%s", opc2->mnemonic);
-
-		if (opc2->operands)
-		  {
-		    opc2->operands (memaddr, info);
-		  }
-
-		if (opc2->operands2)
-		  {
-		    opc2->operands2 (memaddr, info);
-		  }
-	      }
-	    else if (byte2 >= 0x08 && byte2 <= 0x1F)
-	      {
-		bfd_byte bb;
-		read_memory (memaddr, &bb, 1, info);
-		if (bb & 0x80)
-		  (*info->fprintf_func) (info->stream, "bfins");
-		else
-		  (*info->fprintf_func) (info->stream, "bfext");
-
-		enum BB_MODE mode = -1;
-		size_t i;
-		const struct opr_bb *bbs = 0;
-		for (i = 0; i < sizeof (bb_modes) / sizeof (bb_modes[0]); ++i)
-		  {
-		    bbs = bb_modes + i;
-		    if ((bb & bbs->mask) == bbs->value)
-		      {
-			mode = bbs->mode;
-			break;
-		      }
-		  }
-
-		switch (mode)
-		  {
-		  case BB_REG_OPR_REG:
-		  case BB_REG_OPR_IMM:
-		  case BB_OPR_REG_REG:
-		  case BB_OPR_REG_IMM:
-		    {
-		      int size = (bb >> 2) & 0x03;
-		      (*info->fprintf_func) (info->stream, ".%c",
-					     shift_size_table [size]);
-		    }
-		    break;
-		  default:
-		    break;
-		  }
-
-		int reg1 = byte2 & 0x07;
-		/* First operand */
-		switch (mode)
-		  {
-		  case BB_REG_REG_REG:
-		  case BB_REG_REG_IMM:
-		  case BB_REG_OPR_REG:
-		  case BB_REG_OPR_IMM:
-		    operand_separator (info);
-		    (*info->fprintf_func) (info->stream, "%s",
-					   registers[reg1].name);
-		    break;
-		  case BB_OPR_REG_REG:
-		    opr_decode (memaddr + 1, info);
-		    break;
-		  case BB_OPR_REG_IMM:
-		    opr_decode (memaddr + 2, info);
-		    break;
-		  }
-
-		/* Second operand */
-		switch (mode)
-		  {
-		  case BB_REG_REG_REG:
-		  case BB_REG_REG_IMM:
-		    {
-		      int reg_src = (bb >> 2) & 0x07;
-		      operand_separator (info);
-		      (*info->fprintf_func) (info->stream, "%s",
-					     registers[reg_src].name);
-		    }
-		    break;
-		  case BB_OPR_REG_REG:
-		  case BB_OPR_REG_IMM:
-		    {
-		      int reg_src = (byte2 & 0x07);
-		      operand_separator (info);
-		      (*info->fprintf_func) (info->stream, "%s",
-					     registers[reg_src].name);
-		    }
-		    break;
-		  case BB_REG_OPR_REG:
-		    opr_decode (memaddr + 1, info);
-		    break;
-		  case BB_REG_OPR_IMM:
-		    opr_decode (memaddr + 2, info);
-		    break;
-		  }
-
-		/* Third operand */
-		operand_separator (info);
-		switch (mode)
-		  {
-		  case BB_REG_REG_REG:
-		  case BB_OPR_REG_REG:
-		  case BB_REG_OPR_REG:
-		    {
-		      int reg_parm = bb & 0x03;
-		      (*info->fprintf_func) (info->stream, "%s",
-					     registers[reg_parm].name);
-		    }
-		    break;
-		  case BB_REG_REG_IMM:
-		  case BB_OPR_REG_IMM:
-		  case BB_REG_OPR_IMM:
-		    {
-		      bfd_byte i1;
-		      read_memory (memaddr + 1, &i1, 1, info);
-		      int offset = i1 & 0x1f;
-		      int width = bb & 0x03;
-		      width <<= 3;
-		      width |= i1 >> 5;
-		      (*info->fprintf_func) (info->stream, "#%d:%d", width,  offset);
-		    }
-		    break;
-		  }
-	      }
-	  }
-	  break;
-	case 0xae: /* EXG / SEX */
-	  status = print_insn_exg_sex (memaddr, info);
-	  break;
-	case 0x0b:  /* Loop Primitives TBcc and DBcc */
-	  status = print_insn_loop_primitive (memaddr, info);
-	  break;
-	case 0x10:  	    /* shift */
-	case 0x11:  	    /* shift */
-	case 0x12:  	    /* shift */
-	case 0x13:  	    /* shift */
-	case 0x14:  	    /* shift */
-	case 0x15:  	    /* shift */
-	case 0x16:  	    /* shift */
-	case 0x17:  	    /* shift */
-	  status = print_insn_shift (memaddr, info, byte);
-	  break;
-	case 0x04:  	    /* psh / pul */
-	  {
-	    read_memory (memaddr, &byte, 1, info);
-	    (*info->fprintf_func) (info->stream, (byte & 0x80) ? "pul" : "psh");
-	    int bit;
-	    if (byte & 0x40)
-	      {
-		if ((byte & 0x3F) == 0)
-		  {
-		    operand_separator (info);
-		    (*info->fprintf_func) (info->stream, "%s", "ALL16b");
-		  }
-		else
-		  for (bit = 5; bit >= 0; --bit)
-		    {
-		      if (byte & (0x1 << bit))
-			{
-			  operand_separator (info);
-			  (*info->fprintf_func) (info->stream, "%s", oprregs2[bit]);
-			}
-		    }
-	      }
-	    else
-	      {
-		if ((byte & 0x3F) == 0)
-		  {
-		    operand_separator (info);
-		    (*info->fprintf_func) (info->stream, "%s", "ALL");
-		  }
-		else
-		  for (bit = 5; bit >= 0; --bit)
-		    {
-		      if (byte & (0x1 << bit))
-			{
-			  operand_separator (info);
-			  (*info->fprintf_func) (info->stream, "%s", oprregs1[bit]);
-			}
-		    }
-	      }
-	  }
-	  break;
-	default:
-	  operand_separator (info);
-	  (*info->fprintf_func) (info->stream, "???");
-	  break;
-	}
-    }
-
-  if (opc2 == NULL)
+  /* Ship out the operands.  */
+  for (int o = 0; o < n_operands; ++o)
     {
-      if (opc->operands)
-	{
-	  opc->operands (memaddr, info);
-	}
-
-      if (opc->operands2)
-	{
-	  opc->operands2 (memaddr, info);
-	}
+      opr_emit_disassembly (operands[o], mra.info);
+      free (operands[o]);
     }
 
-  int n = 0;
-
-  /* Opcodes in page2 have an additional byte */
-  if (opc2)
-    n++;
-
-  if (opc2 && opc2->insn_bytes == 0)
-    return n;
-
-  if (!opc2 && opc->insn_bytes == 0)
-    return n;
-
-  if (opc2)
-    n += opc2->insn_bytes (memaddr, info);
-  else
-    n += opc->insn_bytes (memaddr, info);
-
-  return n;
+  return n_bytes;
 }
diff --git a/opcodes/s12z-opc.c b/opcodes/s12z-opc.c
new file mode 100644
index 0000000000..36509b58dc
--- /dev/null
+++ b/opcodes/s12z-opc.c
@@ -0,0 +1,2701 @@
+/* s12z-decode.c -- Freescale S12Z disassembly
+   Copyright (C) 2018 Free Software Foundation, Inc.
+
+   This file is part of the GNU opcodes library.
+
+   This library 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 3, or (at your option)
+   any later version.
+
+   It 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.
+
+   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.  */
+
+#include "sysdep.h"
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include "opcode/s12z.h"
+
+#include "bfd.h"
+
+#include "s12z-opc.h"
+
+
+typedef int (* insn_bytes_f) (struct mem_read_abstraction_base *);
+
+typedef void (*operands_f) (struct mem_read_abstraction_base *,
+			    int *n_operands, struct operand **operand);
+
+typedef enum operator (*discriminator_f) (struct mem_read_abstraction_base *,
+					  enum operator hint);
+
+enum OPR_MODE
+  {
+    OPR_IMMe4,
+    OPR_REG,
+    OPR_OFXYS,
+    OPR_XY_PRE_INC,
+    OPR_XY_POST_INC,
+    OPR_XY_PRE_DEC,
+    OPR_XY_POST_DEC,
+    OPR_S_PRE_DEC,
+    OPR_S_POST_INC,
+    OPR_REG_DIRECT,
+    OPR_REG_INDIRECT,
+    OPR_IDX_DIRECT,
+    OPR_IDX_INDIRECT,
+    OPR_EXT1,
+    OPR_IDX2_REG,
+    OPR_IDX3_DIRECT,
+    OPR_IDX3_INDIRECT,
+
+    OPR_EXT18,
+    OPR_IDX3_DIRECT_REG,
+    OPR_EXT3_DIRECT,
+    OPR_EXT3_INDIRECT
+  };
+
+struct opr_pb
+{
+  uint8_t mask;
+  uint8_t value;
+  int n_operands;
+  enum OPR_MODE mode;
+};
+
+static const  struct opr_pb opr_pb[] = {
+  {0xF0, 0x70, 1, OPR_IMMe4},
+  {0xF8, 0xB8, 1, OPR_REG},
+  {0xC0, 0x40, 1, OPR_OFXYS},
+  {0xEF, 0xE3, 1, OPR_XY_PRE_INC},
+  {0xEF, 0xE7, 1, OPR_XY_POST_INC},
+  {0xEF, 0xC3, 1, OPR_XY_PRE_DEC},
+  {0xEF, 0xC7, 1, OPR_XY_POST_DEC},
+  {0xFF, 0xFB, 1, OPR_S_PRE_DEC},
+  {0xFF, 0xFF, 1, OPR_S_POST_INC},
+  {0xC8, 0x88, 1, OPR_REG_DIRECT},
+  {0xE8, 0xC8, 1, OPR_REG_INDIRECT},
+
+  {0xCE, 0xC0, 2, OPR_IDX_DIRECT},
+  {0xCE, 0xC4, 2, OPR_IDX_INDIRECT},
+  {0xC0, 0x00, 2, OPR_EXT1},
+
+  {0xC8, 0x80, 3, OPR_IDX2_REG},
+  {0xFA, 0xF8, 3, OPR_EXT18},
+
+  {0xCF, 0xC2, 4, OPR_IDX3_DIRECT},
+  {0xCF, 0xC6, 4, OPR_IDX3_INDIRECT},
+
+  {0xF8, 0xE8, 4, OPR_IDX3_DIRECT_REG},
+  {0xFF, 0xFA, 4, OPR_EXT3_DIRECT},
+  {0xFF, 0xFE, 4, OPR_EXT3_INDIRECT},
+};
+
+/* Return the number of bytes in a OPR operand, including the XB postbyte.
+   It does not include any preceeding opcodes. */
+static int
+x_opr_n_bytes (struct mem_read_abstraction_base *mra, int offset)
+{
+  bfd_byte xb;
+  int status = mra->read (mra, offset, 1, &xb);
+  if (status < 0)
+    return status;
+
+  size_t i;
+  for (i = 0; i < sizeof (opr_pb) / sizeof (opr_pb[0]); ++i)
+    {
+      const struct opr_pb *pb = opr_pb + i;
+      if ((xb & pb->mask) == pb->value)
+	{
+	  return pb->n_operands;
+	}
+    }
+
+  return 1;
+}
+
+static int
+opr_n_bytes_p1 (struct mem_read_abstraction_base *mra)
+{
+  return 1 + x_opr_n_bytes (mra, 0);
+}
+
+static int
+opr_n_bytes2 (struct mem_read_abstraction_base *mra)
+{
+  int s = x_opr_n_bytes (mra, 0);
+  s += x_opr_n_bytes (mra, s);
+  return s + 1;
+}
+
+enum BB_MODE
+  {
+    BB_REG_REG_REG,
+    BB_REG_REG_IMM,
+    BB_REG_OPR_REG,
+    BB_OPR_REG_REG,
+    BB_REG_OPR_IMM,
+    BB_OPR_REG_IMM
+  };
+
+struct opr_bb
+{
+  uint8_t mask;
+  uint8_t value;
+  int n_operands;
+  bool opr;
+  enum BB_MODE mode;
+};
+
+static const struct opr_bb bb_modes[] =
+  {
+    {0x60, 0x00, 2, false, BB_REG_REG_REG},
+    {0x60, 0x20, 3, false, BB_REG_REG_IMM},
+    {0x70, 0x40, 2, true,  BB_REG_OPR_REG},
+    {0x70, 0x50, 2, true,  BB_OPR_REG_REG},
+    {0x70, 0x60, 3, true,  BB_REG_OPR_IMM},
+    {0x70, 0x70, 3, true,  BB_OPR_REG_IMM}
+  };
+
+static int
+bfextins_n_bytes (struct mem_read_abstraction_base *mra)
+{
+  bfd_byte bb;
+  int status = mra->read (mra, 0, 1, &bb);
+  if (status < 0)
+    return status;
+
+  size_t i;
+  const struct opr_bb *bbs = 0;
+  for (i = 0; i < sizeof (bb_modes) / sizeof (bb_modes[0]); ++i)
+    {
+      bbs = bb_modes + i;
+      if ((bb & bbs->mask) == bbs->value)
+	{
+	  break;
+	}
+    }
+
+  int n = bbs->n_operands;
+  if (bbs->opr)
+    n += x_opr_n_bytes (mra, n - 1);
+
+  return n;
+}
+
+static int
+single (struct mem_read_abstraction_base *mra ATTRIBUTE_UNUSED)
+{
+  return 1;
+}
+
+static int
+two (struct mem_read_abstraction_base *mra ATTRIBUTE_UNUSED)
+{
+  return 2;
+}
+
+static int
+three (struct mem_read_abstraction_base *mra ATTRIBUTE_UNUSED)
+{
+  return 3;
+}
+
+static int
+four (struct mem_read_abstraction_base *mra ATTRIBUTE_UNUSED)
+{
+  return 4;
+}
+
+static int
+five (struct mem_read_abstraction_base *mra ATTRIBUTE_UNUSED)
+{
+  return 5;
+}
+
+static int
+pcrel_15bit (struct mem_read_abstraction_base *mra)
+{
+  bfd_byte byte;
+  int status = mra->read (mra, 0, 1, &byte);
+  if (status < 0)
+    return status;
+  return (byte & 0x80) ? 3 : 2;
+}
+
+
+
+static int
+xysp_reg_from_postbyte (uint8_t postbyte)
+{
+  int reg = -1;
+  switch ((postbyte & 0x30) >> 4)
+    {
+    case 0:
+      reg = REG_X;
+      break;
+    case 1:
+      reg = REG_Y;
+      break;
+    case 2:
+      reg = REG_S;
+      break;
+    default:
+      reg = REG_P;
+    }
+  return reg;
+}
+
+static struct operand * create_immediate_operand (int value)
+{
+  struct immediate_operand *op = malloc (sizeof (*op));
+
+  ((struct operand *)op)->cl = OPND_CL_IMMEDIATE;
+  op->value = value;
+  ((struct operand *)op)->osize = -1;
+
+  return (struct operand *) op;
+}
+
+static struct operand * create_bitfield_operand (int width, int offset)
+{
+  struct bitfield_operand *op = malloc (sizeof (*op));
+
+  ((struct operand *)op)->cl = OPND_CL_BIT_FIELD;
+  op->width = width;
+  op->offset = offset;
+  ((struct operand *)op)->osize = -1;
+
+  return (struct operand *) op;
+}
+
+static struct operand *
+create_register_operand_with_size (int reg, short osize)
+{
+  struct register_operand *op = malloc (sizeof (*op));
+
+  ((struct operand *)op)->cl = OPND_CL_REGISTER;
+  op->reg = reg;
+  ((struct operand *)op)->osize = osize;
+
+  return (struct operand *) op;
+}
+
+static struct operand *
+create_register_operand (int reg)
+{
+  return create_register_operand_with_size (reg, -1);
+}
+
+static struct operand * create_register_all_operand (void)
+{
+  struct register_operand *op = malloc (sizeof (*op));
+
+  ((struct operand *)op)->cl = OPND_CL_REGISTER_ALL;
+  ((struct operand *)op)->osize = -1;
+
+  return (struct operand *) op;
+}
+
+static struct operand * create_register_all16_operand (void)
+{
+  struct register_operand *op = malloc (sizeof (*op));
+
+  ((struct operand *)op)->cl = OPND_CL_REGISTER_ALL16;
+  ((struct operand *)op)->osize = -1;
+
+  return (struct operand *) op;
+}
+
+
+static struct operand *
+create_simple_memory_operand (bfd_vma addr, bfd_vma base, bool relative)
+{
+  struct simple_memory_operand *op = malloc (sizeof (*op));
+
+  ((struct operand *)op)->cl = OPND_CL_SIMPLE_MEMORY;
+  op->addr = addr;
+  op->base = base;
+  op->relative = relative;
+  ((struct operand *)op)->osize = -1;
+
+  assert (relative || base == 0);
+
+  return (struct operand *) op;
+}
+
+static struct operand *
+create_memory_operand (bool indirect, int base, int n_regs, int reg0, int reg1)
+{
+  struct memory_operand *op = malloc (sizeof (*op));
+
+  ((struct operand *)op)->cl = OPND_CL_MEMORY;
+  op->indirect = indirect;
+  op->base_offset = base;
+  op->mutation = OPND_RM_NONE;
+  op->n_regs = n_regs;
+  op->regs[0] = reg0;
+  op->regs[1] = reg1;
+  ((struct operand *)op)->osize = -1;
+
+  return (struct operand *) op;
+}
+
+static struct operand *
+create_memory_auto_operand (enum op_reg_mutation mutation, int reg)
+{
+  struct memory_operand *op = malloc (sizeof (*op));
+
+  ((struct operand *)op)->cl = OPND_CL_MEMORY;
+  op->indirect = false;
+  op->base_offset = 0;
+  op->mutation = mutation;
+  op->n_regs = 1;
+  op->regs[0] = reg;
+  op->regs[1] = -1;
+  ((struct operand *)op)->osize = -1;
+
+  return (struct operand *) op;
+}
+
+
+
+static void
+z_ext24_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operand)
+{
+  uint8_t buffer[3];
+  int status = mra->read (mra, 0, 3, buffer);
+  if (status < 0)
+    return;
+
+  int i;
+  uint32_t addr = 0;
+  for (i = 0; i < 3; ++i)
+    {
+      addr <<= 8;
+      addr |= buffer[i];
+    }
+
+  operand[(*n_operands)++] = create_simple_memory_operand (addr, 0, false);
+}
+
+
+static uint32_t
+z_decode_signed_value (struct mem_read_abstraction_base *mra, int offset, short size)
+{
+  assert (size >0);
+  assert (size <= 4);
+  bfd_byte buffer[4];
+  if (0 > mra->read (mra, offset, size, buffer))
+    {
+      return 0;
+    }
+
+  int i;
+  uint32_t value = 0;
+  for (i = 0; i < size; ++i)
+    {
+      value |= buffer[i] << (8 * (size - i - 1));
+    }
+
+  if (buffer[0] & 0x80)
+    {
+      /* Deal with negative values */
+      value -= 0x1UL << (size * 8);
+    }
+  return value;
+}
+
+static uint32_t
+decode_signed_value (struct mem_read_abstraction_base *mra, short size)
+{
+  return z_decode_signed_value (mra, 0, size);
+}
+
+static void
+x_imm1 (struct mem_read_abstraction_base *mra,
+	int offset,
+	int *n_operands, struct operand **operand)
+{
+  bfd_byte byte;
+  int status = mra->read (mra, offset, 1, &byte);
+  if (status < 0)
+    return;
+
+  operand[(*n_operands)++] = create_immediate_operand (byte);
+}
+
+/* An eight bit immediate operand.  */
+static void
+imm1_decode (struct mem_read_abstraction_base *mra,
+	int *n_operands, struct operand **operand)
+{
+  x_imm1 (mra, 0, n_operands, operand);
+}
+
+static void
+trap_decode (struct mem_read_abstraction_base *mra,
+	     int *n_operands, struct operand **operand)
+{
+  x_imm1 (mra, -1, n_operands, operand);
+}
+
+
+static struct operand *
+x_opr_decode_with_size (struct mem_read_abstraction_base *mra, int offset,
+			short osize)
+{
+  bfd_byte postbyte;
+  int status = mra->read (mra, offset, 1, &postbyte);
+  if (status < 0)
+    return NULL;
+  offset++;
+
+  enum OPR_MODE mode = -1;
+  size_t i;
+  for (i = 0; i < sizeof (opr_pb) / sizeof (opr_pb[0]); ++i)
+    {
+      const struct opr_pb *pb = opr_pb + i;
+      if ((postbyte & pb->mask) == pb->value)
+	{
+	  mode = pb->mode;
+	  break;
+	}
+    }
+
+  struct operand *operand = NULL;
+  switch (mode)
+    {
+    case OPR_IMMe4:
+      {
+	int n;
+	uint8_t x = (postbyte & 0x0F);
+	if (x == 0)
+	  n = -1;
+	else
+	  n = x;
+
+        operand = create_immediate_operand (n);
+	break;
+      }
+    case OPR_REG:
+      {
+	uint8_t x = (postbyte & 0x07);
+        operand = create_register_operand (x);
+	break;
+      }
+    case OPR_OFXYS:
+      {
+        operand = create_memory_operand (false, postbyte & 0x0F, 1,
+					 xysp_reg_from_postbyte (postbyte), -1);
+	break;
+      }
+    case OPR_REG_DIRECT:
+      {
+        operand = create_memory_operand (false, 0, 2, postbyte & 0x07,
+					 xysp_reg_from_postbyte (postbyte));
+	break;
+      }
+    case OPR_REG_INDIRECT:
+      {
+        operand = create_memory_operand (true, 0, 2, postbyte & 0x07,
+					 (postbyte & 0x10) ? REG_Y : REG_X);
+	break;
+      }
+
+    case OPR_IDX_INDIRECT:
+      {
+	uint8_t x1;
+	mra->read (mra, offset, 1, &x1);
+	int idx = x1;
+
+	if (postbyte & 0x01)
+	  {
+	    /* Deal with negative values */
+	    idx -= 0x1UL << 8;
+	  }
+
+        operand = create_memory_operand (true, idx, 1,
+					 xysp_reg_from_postbyte (postbyte), -1);
+	break;
+      }
+
+    case OPR_IDX3_DIRECT:
+      {
+	uint8_t x[3];
+	mra->read (mra, offset, 3, x);
+	int idx = x[0] << 16 | x[1] << 8 | x[2];
+
+	if (x[0] & 0x80)
+	  {
+	    /* Deal with negative values */
+	    idx -= 0x1UL << 24;
+	  }
+
+        operand = create_memory_operand (false, idx, 1,
+					 xysp_reg_from_postbyte (postbyte), -1);
+	break;
+      }
+
+    case OPR_IDX3_DIRECT_REG:
+      {
+	uint8_t x[3];
+	mra->read (mra, offset, 3, x);
+	int idx = x[0] << 16 | x[1] << 8 | x[2];
+
+	if (x[0] & 0x80)
+	  {
+	    /* Deal with negative values */
+	    idx -= 0x1UL << 24;
+	  }
+
+        operand = create_memory_operand (false, idx, 1, postbyte & 0x07, -1);
+	break;
+      }
+
+    case OPR_IDX3_INDIRECT:
+      {
+	uint8_t x[3];
+	mra->read (mra, offset, 3, x);
+	int idx = x[0] << 16 | x[1] << 8 | x[2];
+
+	if (x[0] & 0x80)
+	  {
+	    /* Deal with negative values */
+	    idx -= 0x1UL << 24;
+	  }
+
+	operand = create_memory_operand (true, idx, 1,
+					 xysp_reg_from_postbyte (postbyte), -1);
+	break;
+      }
+
+    case OPR_IDX_DIRECT:
+      {
+	uint8_t x1;
+	mra->read (mra, offset, 1, &x1);
+	int idx = x1;
+
+	if (postbyte & 0x01)
+	  {
+	    /* Deal with negative values */
+	    idx -= 0x1UL << 8;
+	  }
+
+        operand = create_memory_operand (false, idx, 1,
+					 xysp_reg_from_postbyte (postbyte), -1);
+	break;
+      }
+
+    case OPR_IDX2_REG:
+      {
+	uint8_t x[2];
+	mra->read (mra, offset, 2, x);
+	uint32_t idx = x[1] | x[0] << 8 ;
+	idx |= (postbyte & 0x30) << 12;
+
+        operand = create_memory_operand (false, idx, 1, postbyte & 0x07, -1);
+	break;
+      }
+
+    case OPR_XY_PRE_INC:
+      {
+	operand = create_memory_auto_operand (OPND_RM_PRE_INC,
+					      (postbyte & 0x10) ? REG_Y: REG_X);
+	break;
+      }
+    case OPR_XY_POST_INC:
+      {
+	operand = create_memory_auto_operand (OPND_RM_POST_INC,
+					      (postbyte & 0x10) ? REG_Y: REG_X);
+	break;
+      }
+    case OPR_XY_PRE_DEC:
+      {
+	operand = create_memory_auto_operand (OPND_RM_PRE_DEC,
+					      (postbyte & 0x10) ? REG_Y: REG_X);
+	break;
+      }
+    case OPR_XY_POST_DEC:
+      {
+	operand = create_memory_auto_operand (OPND_RM_POST_DEC,
+					      (postbyte & 0x10) ? REG_Y: REG_X);
+	break;
+      }
+    case OPR_S_PRE_DEC:
+      {
+	operand = create_memory_auto_operand (OPND_RM_PRE_DEC, REG_S);
+	break;
+      }
+    case OPR_S_POST_INC:
+      {
+	operand = create_memory_auto_operand (OPND_RM_POST_INC, REG_S);
+	break;
+      }
+
+    case OPR_EXT18:
+      {
+	const size_t size = 2;
+	bfd_byte buffer[4];
+	status = mra->read (mra, offset, size, buffer);
+	if (status < 0)
+	  operand = NULL;
+
+	uint32_t ext18 = 0;
+	for (i = 0; i < size; ++i)
+	  {
+	    ext18 <<= 8;
+	    ext18 |= buffer[i];
+	  }
+
+	ext18 |= (postbyte & 0x01) << 16;
+	ext18 |= (postbyte & 0x04) << 15;
+
+	operand = create_simple_memory_operand (ext18, 0, false);
+	break;
+      }
+
+    case OPR_EXT1:
+      {
+	uint8_t x1 = 0;
+	mra->read (mra, offset, 1, &x1);
+	int16_t addr;
+	addr = x1;
+	addr |= (postbyte & 0x3f) << 8;
+
+	operand = create_simple_memory_operand (addr, 0, false);
+	break;
+      }
+
+    case OPR_EXT3_DIRECT:
+      {
+	const size_t size = 3;
+	bfd_byte buffer[4];
+	status = mra->read (mra, offset, size, buffer);
+	if (status < 0)
+	  operand = NULL;
+
+	uint32_t ext24 = 0;
+	for (i = 0; i < size; ++i)
+	  {
+	    ext24 |= buffer[i] << (8 * (size - i - 1));
+	  }
+
+	operand = create_simple_memory_operand (ext24, 0, false);
+	break;
+      }
+
+    case OPR_EXT3_INDIRECT:
+      {
+	const size_t size = 3;
+	bfd_byte buffer[4];
+	status = mra->read (mra, offset, size, buffer);
+	if (status < 0)
+	  operand = NULL;
+
+	uint32_t ext24 = 0;
+	for (i = 0; i < size; ++i)
+	  {
+	    ext24 |= buffer[i] << (8 * (size - i - 1));
+	  }
+
+        operand = create_memory_operand (true, ext24, 0, -1, -1);
+	break;
+      }
+
+    default:
+      printf ("Unknown OPR mode #0x%x (%d)", postbyte, mode);
+      abort ();
+    }
+
+  operand->osize = osize;
+
+  return operand;
+}
+
+static struct operand *
+x_opr_decode (struct mem_read_abstraction_base *mra, int offset)
+{
+  return x_opr_decode_with_size (mra, offset, -1);
+}
+
+static void
+z_opr_decode (struct mem_read_abstraction_base *mra,
+	      int *n_operands, struct operand **operand)
+{
+  operand[(*n_operands)++] = x_opr_decode (mra, 0);
+}
+
+static void
+z_opr_decode2 (struct mem_read_abstraction_base *mra,
+	       int *n_operands, struct operand **operand)
+{
+  int n = x_opr_n_bytes (mra, 0);
+
+  operand[(*n_operands)++] = x_opr_decode (mra, 0);
+  operand[(*n_operands)++] = x_opr_decode (mra, n);
+}
+
+static void
+imm1234 (struct mem_read_abstraction_base *mra, int base,
+	 int *n_operands, struct operand **operand)
+{
+  bfd_byte opcode;
+  int status = mra->read (mra, -1, 1, &opcode);
+  if (status < 0)
+    return;
+
+  opcode -= base;
+
+  int size = registers[opcode & 0xF].bytes;
+
+  uint32_t imm = decode_signed_value (mra, size);
+
+  operand[(*n_operands)++] = create_immediate_operand (imm);
+}
+
+
+/* Special case of LD and CMP with register S and IMM operand */
+static void
+reg_s_imm (struct mem_read_abstraction_base *mra, int *n_operands,
+	   struct operand **operand)
+{
+  operand[(*n_operands)++] = create_register_operand (REG_S);
+
+  uint32_t imm = decode_signed_value (mra, 3);
+  operand[(*n_operands)++] = create_immediate_operand (imm);
+}
+
+/* Special case of LD, CMP and ST with register S and OPR operand */
+static void
+reg_s_opr (struct mem_read_abstraction_base *mra, int *n_operands,
+	   struct operand **operand)
+{
+  operand[(*n_operands)++] = create_register_operand (REG_S);
+  operand[(*n_operands)++] = x_opr_decode (mra, 0);
+}
+
+static void
+z_imm1234_8base (struct mem_read_abstraction_base *mra, int *n_operands,
+		 struct operand **operand)
+{
+  imm1234 (mra, 8, n_operands, operand);
+}
+
+static void
+z_imm1234_0base (struct mem_read_abstraction_base *mra, int *n_operands,
+		 struct operand **operand)
+{
+  imm1234 (mra, 0, n_operands, operand);
+}
+
+
+static void
+z_tfr (struct mem_read_abstraction_base *mra, int *n_operands,
+       struct operand **operand)
+{
+  bfd_byte byte;
+  int status = mra->read (mra, 0, 1, &byte);
+  if (status < 0)
+    return;
+
+  operand[(*n_operands)++] = create_register_operand (byte >> 4);
+  operand[(*n_operands)++] = create_register_operand (byte & 0x0F);
+}
+
+static void
+z_reg (struct mem_read_abstraction_base *mra, int *n_operands,
+       struct operand **operand)
+{
+  bfd_byte byte;
+  int status = mra->read (mra, -1, 1, &byte);
+  if (status < 0)
+    return;
+
+  operand[(*n_operands)++] = create_register_operand (byte & 0x07);
+}
+
+
+static void
+reg_xy (struct mem_read_abstraction_base *mra,
+	int *n_operands, struct operand **operand)
+{
+  bfd_byte byte;
+  int status = mra->read (mra, -1, 1, &byte);
+  if (status < 0)
+    return;
+
+  operand[(*n_operands)++] =
+    create_register_operand ((byte & 0x01) ? REG_Y : REG_X);
+}
+
+static void
+lea_reg_xys_opr (struct mem_read_abstraction_base *mra,
+		 int *n_operands, struct operand **operand)
+{
+  bfd_byte byte;
+  int status = mra->read (mra, -1, 1, &byte);
+  if (status < 0)
+    return;
+
+  int reg_xys = -1;
+  switch (byte & 0x03)
+    {
+    case 0x00:
+      reg_xys = REG_X;
+      break;
+    case 0x01:
+      reg_xys = REG_Y;
+      break;
+    case 0x02:
+      reg_xys = REG_S;
+      break;
+    }
+
+  operand[(*n_operands)++] = create_register_operand (reg_xys);
+  operand[(*n_operands)++] = x_opr_decode (mra, 0);
+}
+
+static void
+lea_reg_xys (struct mem_read_abstraction_base *mra,
+	     int *n_operands, struct operand **operand)
+{
+  bfd_byte byte;
+  int status = mra->read (mra, -1, 1, &byte);
+  if (status < 0)
+    return;
+
+  int reg_n = -1;
+  switch (byte & 0x03)
+    {
+    case 0x00:
+      reg_n = REG_X;
+      break;
+    case 0x01:
+      reg_n = REG_Y;
+      break;
+    case 0x02:
+      reg_n = REG_S;
+      break;
+    }
+
+  status = mra->read (mra, 0, 1, &byte);
+  if (status < 0)
+    return;
+
+  operand[(*n_operands)++] = create_register_operand (reg_n);
+  operand[(*n_operands)++] = create_memory_operand (false, (int8_t) byte,
+						    1, reg_n, -1);
+}
+
+
+/* PC Relative offsets of size 15 or 7 bits */
+static void
+rel_15_7 (struct mem_read_abstraction_base *mra, int offset,
+	  int *n_operands, struct operand **operands)
+{
+  bfd_byte upper;
+  int status = mra->read (mra, offset - 1, 1, &upper);
+  if (status < 0)
+    return;
+
+  bool rel_size = (upper & 0x80);
+
+  int16_t addr = upper;
+  if (rel_size)
+    {
+      /* 15 bits.  Get the next byte */
+      bfd_byte lower;
+      status = mra->read (mra, offset, 1, &lower);
+      if (status < 0)
+	return;
+
+      addr <<= 8;
+      addr |= lower;
+      addr &= 0x7FFF;
+
+      bool negative = (addr & 0x4000);
+      addr &= 0x3FFF;
+      if (negative)
+	addr = addr - 0x4000;
+    }
+  else
+    {
+      /* 7 bits. */
+      bool negative = (addr & 0x40);
+      addr &= 0x3F;
+      if (negative)
+	addr = addr - 0x40;
+    }
+
+  operands[(*n_operands)++] =
+    create_simple_memory_operand (addr, mra->posn (mra) - 1, true);
+}
+
+
+/* PC Relative offsets of size 15 or 7 bits */
+static void
+decode_rel_15_7 (struct mem_read_abstraction_base *mra,
+		 int *n_operands, struct operand **operand)
+{
+  rel_15_7 (mra, 1, n_operands, operand);
+}
+
+static int shift_n_bytes (struct mem_read_abstraction_base *);
+static int mov_imm_opr_n_bytes (struct mem_read_abstraction_base *);
+static int loop_prim_n_bytes (struct mem_read_abstraction_base *);
+static int bm_rel_n_bytes (struct mem_read_abstraction_base *);
+static int mul_n_bytes (struct mem_read_abstraction_base *);
+static int bm_n_bytes (struct mem_read_abstraction_base *);
+
+static void psh_pul_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operand);
+static void shift_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operand);
+static void mul_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operand);
+static void bm_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operand);
+static void bm_rel_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operand);
+static void mov_imm_opr (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operand);
+static void loop_primitive_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operands);
+static void bit_field_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operands);
+static void exg_sex_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operands);
+
+
+static enum operator shift_discrim (struct mem_read_abstraction_base *mra, enum operator hint);
+static enum operator psh_pul_discrim (struct mem_read_abstraction_base *mra, enum operator hint);
+static enum operator mul_discrim (struct mem_read_abstraction_base *mra, enum operator hint);
+static enum operator loop_primitive_discrim (struct mem_read_abstraction_base *mra, enum operator hint);
+static enum operator bit_field_discrim (struct mem_read_abstraction_base *mra, enum operator hint);
+static enum operator exg_sex_discrim (struct mem_read_abstraction_base *mra, enum operator hint);
+
+
+static void
+cmp_xy (struct mem_read_abstraction_base *mra ATTRIBUTE_UNUSED,
+	int *n_operands, struct operand **operand)
+{
+  operand[(*n_operands)++] = create_register_operand (REG_X);
+  operand[(*n_operands)++] = create_register_operand (REG_Y);
+}
+
+static void
+sub_d6_x_y (struct mem_read_abstraction_base *mra ATTRIBUTE_UNUSED,
+	    int *n_operands, struct operand **operand)
+{
+  operand[(*n_operands)++] = create_register_operand (REG_D6);
+  operand[(*n_operands)++] = create_register_operand (REG_X);
+  operand[(*n_operands)++] = create_register_operand (REG_Y);
+}
+
+static void
+sub_d6_y_x (struct mem_read_abstraction_base *mra ATTRIBUTE_UNUSED,
+	    int *n_operands, struct operand **operand)
+{
+  operand[(*n_operands)++] = create_register_operand (REG_D6);
+  operand[(*n_operands)++] = create_register_operand (REG_Y);
+  operand[(*n_operands)++] = create_register_operand (REG_X);
+}
+
+static void ld_18bit_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operand);
+
+static enum operator
+mul_discrim (struct mem_read_abstraction_base *mra, enum operator hint)
+{
+  uint8_t mb;
+  int status = mra->read (mra, 0, 1, &mb);
+  if (status < 0)
+    return OP_INVALID;
+
+  bool signed_op = (mb & 0x80);
+
+  switch (hint)
+    {
+    case OPBASE_mul:
+      return signed_op ? OP_muls : OP_mulu;
+      break;
+    case OPBASE_div:
+      return signed_op ? OP_divs : OP_divu;
+      break;
+    case OPBASE_mod:
+      return signed_op ? OP_mods : OP_modu;
+      break;
+    case OPBASE_mac:
+      return signed_op ? OP_macs : OP_macu;
+      break;
+    case OPBASE_qmul:
+      return signed_op ? OP_qmuls : OP_qmulu;
+      break;
+    default:
+      abort ();
+    }
+
+  return OP_INVALID;
+}
+
+struct opcode
+{
+  /* The operation that this opcode performs.  */
+  enum operator operator;
+
+  /* The size of this operation.  May be -1 if it is implied
+     in the operands or if size is not applicable.  */
+  short osize;
+
+  /* Some operations need this function to work out which operation
+   is intended.  */
+  discriminator_f discriminator;
+
+  /* A function returning the number of bytes in this instruction.  */
+  insn_bytes_f insn_bytes;
+
+  operands_f operands;
+  operands_f operands2;
+};
+
+static const struct opcode page2[] =
+  {
+    [0x00] = {OP_ld, -1, 0,  opr_n_bytes_p1, reg_s_opr, 0},
+    [0x01] = {OP_st, -1, 0,  opr_n_bytes_p1, reg_s_opr, 0},
+    [0x02] = {OP_cmp, -1, 0, opr_n_bytes_p1, reg_s_opr, 0},
+    [0x03] = {OP_ld, -1, 0,  four, reg_s_imm, 0},
+    [0x04] = {OP_cmp, -1, 0, four, reg_s_imm, 0},
+    [0x05] = {OP_stop, -1, 0, single, 0, 0},
+    [0x06] = {OP_wai, -1, 0,  single, 0, 0},
+    [0x07] = {OP_sys, -1, 0,  single, 0, 0},
+    [0x08] = {0xFFFF, -1, bit_field_discrim,  bfextins_n_bytes, bit_field_decode, 0},  /* BFEXT / BFINS */
+    [0x09] = {0xFFFF, -1, bit_field_discrim,  bfextins_n_bytes, bit_field_decode, 0},
+    [0x0a] = {0xFFFF, -1, bit_field_discrim,  bfextins_n_bytes, bit_field_decode, 0},
+    [0x0b] = {0xFFFF, -1, bit_field_discrim,  bfextins_n_bytes, bit_field_decode, 0},
+    [0x0c] = {0xFFFF, -1, bit_field_discrim,  bfextins_n_bytes, bit_field_decode, 0},
+    [0x0d] = {0xFFFF, -1, bit_field_discrim,  bfextins_n_bytes, bit_field_decode, 0},
+    [0x0e] = {0xFFFF, -1, bit_field_discrim,  bfextins_n_bytes, bit_field_decode, 0},
+    [0x0f] = {0xFFFF, -1, bit_field_discrim,  bfextins_n_bytes, bit_field_decode, 0},
+    [0x10] = {OP_minu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x11] = {OP_minu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x12] = {OP_minu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x13] = {OP_minu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x14] = {OP_minu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x15] = {OP_minu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x16] = {OP_minu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x17] = {OP_minu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x18] = {OP_maxu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x19] = {OP_maxu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x1a] = {OP_maxu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x1b] = {OP_maxu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x1c] = {OP_maxu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x1d] = {OP_maxu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x1e] = {OP_maxu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x1f] = {OP_maxu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x20] = {OP_mins, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x21] = {OP_mins, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x22] = {OP_mins, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x23] = {OP_mins, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x24] = {OP_mins, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x25] = {OP_mins, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x26] = {OP_mins, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x27] = {OP_mins, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x28] = {OP_maxs, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x29] = {OP_maxs, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x2a] = {OP_maxs, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x2b] = {OP_maxs, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x2c] = {OP_maxs, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x2d] = {OP_maxs, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x2e] = {OP_maxs, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x2f] = {OP_maxs, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x30] = {OPBASE_div, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x31] = {OPBASE_div, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x32] = {OPBASE_div, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x33] = {OPBASE_div, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x34] = {OPBASE_div, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x35] = {OPBASE_div, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x36] = {OPBASE_div, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x37] = {OPBASE_div, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x38] = {OPBASE_mod, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x39] = {OPBASE_mod, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x3a] = {OPBASE_mod, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x3b] = {OPBASE_mod, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x3c] = {OPBASE_mod, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x3d] = {OPBASE_mod, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x3e] = {OPBASE_mod, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x3f] = {OPBASE_mod, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x40] = {OP_abs, -1, 0, single, z_reg, 0},
+    [0x41] = {OP_abs, -1, 0, single, z_reg, 0},
+    [0x42] = {OP_abs, -1, 0, single, z_reg, 0},
+    [0x43] = {OP_abs, -1, 0, single, z_reg, 0},
+    [0x44] = {OP_abs, -1, 0, single, z_reg, 0},
+    [0x45] = {OP_abs, -1, 0, single, z_reg, 0},
+    [0x46] = {OP_abs, -1, 0, single, z_reg, 0},
+    [0x47] = {OP_abs, -1, 0, single, z_reg, 0},
+    [0x48] = {OPBASE_mac, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x49] = {OPBASE_mac, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x4a] = {OPBASE_mac, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x4b] = {OPBASE_mac, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x4c] = {OPBASE_mac, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x4d] = {OPBASE_mac, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x4e] = {OPBASE_mac, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x4f] = {OPBASE_mac, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x50] = {OP_adc, -1, 0, three, z_reg, z_imm1234_0base},
+    [0x51] = {OP_adc, -1, 0, three, z_reg, z_imm1234_0base},
+    [0x52] = {OP_adc, -1, 0, three, z_reg, z_imm1234_0base},
+    [0x53] = {OP_adc, -1, 0, three, z_reg, z_imm1234_0base},
+    [0x54] = {OP_adc, -1, 0, two,   z_reg, z_imm1234_0base},
+    [0x55] = {OP_adc, -1, 0, two,   z_reg, z_imm1234_0base},
+    [0x56] = {OP_adc, -1, 0, five,  z_reg, z_imm1234_0base},
+    [0x57] = {OP_adc, -1, 0, five,  z_reg, z_imm1234_0base},
+    [0x58] = {OP_bit, -1, 0, three, z_reg, z_imm1234_8base},
+    [0x59] = {OP_bit, -1, 0, three, z_reg, z_imm1234_8base},
+    [0x5a] = {OP_bit, -1, 0, three, z_reg, z_imm1234_8base},
+    [0x5b] = {OP_bit, -1, 0, three, z_reg, z_imm1234_8base},
+    [0x5c] = {OP_bit, -1, 0, two,   z_reg, z_imm1234_8base},
+    [0x5d] = {OP_bit, -1, 0, two,   z_reg, z_imm1234_8base},
+    [0x5e] = {OP_bit, -1, 0, five,  z_reg, z_imm1234_8base},
+    [0x5f] = {OP_bit, -1, 0, five,  z_reg, z_imm1234_8base},
+    [0x60] = {OP_adc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x61] = {OP_adc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x62] = {OP_adc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x63] = {OP_adc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x64] = {OP_adc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x65] = {OP_adc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x66] = {OP_adc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x67] = {OP_adc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x68] = {OP_bit, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x69] = {OP_bit, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x6a] = {OP_bit, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x6b] = {OP_bit, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x6c] = {OP_bit, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x6d] = {OP_bit, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x6e] = {OP_bit, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x6f] = {OP_bit, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x70] = {OP_sbc, -1, 0, three, z_reg, z_imm1234_0base},
+    [0x71] = {OP_sbc, -1, 0, three, z_reg, z_imm1234_0base},
+    [0x72] = {OP_sbc, -1, 0, three, z_reg, z_imm1234_0base},
+    [0x73] = {OP_sbc, -1, 0, three, z_reg, z_imm1234_0base},
+    [0x74] = {OP_sbc, -1, 0, two,   z_reg, z_imm1234_0base},
+    [0x75] = {OP_sbc, -1, 0, two,   z_reg, z_imm1234_0base},
+    [0x76] = {OP_sbc, -1, 0, five,  z_reg, z_imm1234_0base},
+    [0x77] = {OP_sbc, -1, 0, five,  z_reg, z_imm1234_0base},
+    [0x78] = {OP_eor, -1, 0, three, z_reg, z_imm1234_8base},
+    [0x79] = {OP_eor, -1, 0, three, z_reg, z_imm1234_8base},
+    [0x7a] = {OP_eor, -1, 0, three, z_reg, z_imm1234_8base},
+    [0x7b] = {OP_eor, -1, 0, three, z_reg, z_imm1234_8base},
+    [0x7c] = {OP_eor, -1, 0, two,   z_reg, z_imm1234_8base},
+    [0x7d] = {OP_eor, -1, 0, two,   z_reg, z_imm1234_8base},
+    [0x7e] = {OP_eor, -1, 0, five,  z_reg, z_imm1234_8base},
+    [0x7f] = {OP_eor, -1, 0, five,  z_reg, z_imm1234_8base},
+    [0x80] = {OP_sbc, -1, 0,  opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x81] = {OP_sbc, -1, 0,  opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x82] = {OP_sbc, -1, 0,  opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x83] = {OP_sbc, -1, 0,  opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x84] = {OP_sbc, -1, 0,  opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x85] = {OP_sbc, -1, 0,  opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x86] = {OP_sbc, -1, 0,  opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x87] = {OP_sbc, -1, 0,  opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x88] = {OP_eor, -1, 0,  opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x89] = {OP_eor, -1, 0,  opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x8a] = {OP_eor, -1, 0,  opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x8b] = {OP_eor, -1, 0,  opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x8c] = {OP_eor, -1, 0,  opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x8d] = {OP_eor, -1, 0,  opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x8e] = {OP_eor, -1, 0,  opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x8f] = {OP_eor, -1, 0,  opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x90] = {OP_rti, -1, 0,  single, 0, 0},
+    [0x91] = {OP_clb, -1, 0,   two, z_tfr, 0},
+    [0x92] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0x93] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0x94] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0x95] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0x96] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0x97] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0x98] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0x99] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0x9a] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0x9b] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0x9c] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0x9d] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0x9e] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0x9f] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xa0] = {OP_sat, -1, 0, single, z_reg, 0},
+    [0xa1] = {OP_sat, -1, 0, single, z_reg, 0},
+    [0xa2] = {OP_sat, -1, 0, single, z_reg, 0},
+    [0xa3] = {OP_sat, -1, 0, single, z_reg, 0},
+    [0xa4] = {OP_sat, -1, 0, single, z_reg, 0},
+    [0xa5] = {OP_sat, -1, 0, single, z_reg, 0},
+    [0xa6] = {OP_sat, -1, 0, single, z_reg, 0},
+    [0xa7] = {OP_sat, -1, 0, single, z_reg, 0},
+    [0xa8] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xa9] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xaa] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xab] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xac] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xad] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xae] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xaf] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xb0] = {OPBASE_qmul, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0xb1] = {OPBASE_qmul, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0xb2] = {OPBASE_qmul, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0xb3] = {OPBASE_qmul, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0xb4] = {OPBASE_qmul, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0xb5] = {OPBASE_qmul, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0xb6] = {OPBASE_qmul, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0xb7] = {OPBASE_qmul, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0xb8] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xb9] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xba] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xbb] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xbc] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xbd] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xbe] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xbf] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xc0] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xc1] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xc2] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xc3] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xc4] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xc5] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xc6] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xc7] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xc8] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xc9] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xca] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xcb] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xcc] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xcd] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xce] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xcf] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xd0] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xd1] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xd2] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xd3] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xd4] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xd5] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xd6] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xd7] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xd8] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xd9] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xda] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xdb] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xdc] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xdd] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xde] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xdf] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xe0] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xe1] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xe2] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xe3] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xe4] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xe5] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xe6] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xe7] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xe8] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xe9] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xea] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xeb] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xec] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xed] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xee] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xef] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xf0] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xf1] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xf2] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xf3] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xf4] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xf5] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xf6] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xf7] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xf8] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xf9] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xfa] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xfb] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xfc] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xfd] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xfe] = {OP_trap, -1, 0,  single, trap_decode, 0},
+    [0xff] = {OP_trap, -1, 0,  single, trap_decode, 0},
+  };
+
+static const struct opcode page1[] =
+  {
+    [0x00] = {OP_bgnd, -1, 0, single, 0, 0},
+    [0x01] = {OP_nop, -1, 0,  single, 0, 0},
+    [0x02] = {OP_brclr, -1, 0, bm_rel_n_bytes, bm_rel_decode, 0},
+    [0x03] = {OP_brset, -1, 0, bm_rel_n_bytes, bm_rel_decode, 0},
+    [0x04] = {0xFFFF, -1, psh_pul_discrim,   two, psh_pul_decode, 0}, /* psh/pul */
+    [0x05] = {OP_rts, -1, 0,  single, 0, 0},
+    [0x06] = {OP_lea, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x07] = {OP_lea, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x08] = {OP_lea, -1, 0, opr_n_bytes_p1, lea_reg_xys_opr, 0},
+    [0x09] = {OP_lea, -1, 0, opr_n_bytes_p1, lea_reg_xys_opr, 0},
+    [0x0a] = {OP_lea, -1, 0, opr_n_bytes_p1, lea_reg_xys_opr, 0},
+    [0x0b] = {0xFFFF, -1, loop_primitive_discrim, loop_prim_n_bytes, loop_primitive_decode, 0}, /* Loop primitives TBcc / DBcc */
+    [0x0c] = {OP_mov, 0, 0, mov_imm_opr_n_bytes, mov_imm_opr, 0},
+    [0x0d] = {OP_mov, 1, 0, mov_imm_opr_n_bytes, mov_imm_opr, 0},
+    [0x0e] = {OP_mov, 2, 0, mov_imm_opr_n_bytes, mov_imm_opr, 0},
+    [0x0f] = {OP_mov, 3, 0, mov_imm_opr_n_bytes, mov_imm_opr, 0},
+    [0x10] = {0xFFFF, -1, shift_discrim,  shift_n_bytes, shift_decode, 0},  /* lsr/lsl/asl/asr/rol/ror */
+    [0x11] = {0xFFFF, -1, shift_discrim,  shift_n_bytes, shift_decode, 0},
+    [0x12] = {0xFFFF, -1, shift_discrim,  shift_n_bytes, shift_decode, 0},
+    [0x13] = {0xFFFF, -1, shift_discrim,  shift_n_bytes, shift_decode, 0},
+    [0x14] = {0xFFFF, -1, shift_discrim,  shift_n_bytes, shift_decode, 0},
+    [0x15] = {0xFFFF, -1, shift_discrim,  shift_n_bytes, shift_decode, 0},
+    [0x16] = {0xFFFF, -1, shift_discrim,  shift_n_bytes, shift_decode, 0},
+    [0x17] = {0xFFFF, -1, shift_discrim,  shift_n_bytes, shift_decode, 0},
+    [0x18] = {OP_lea, -1, 0,  two, lea_reg_xys, NULL},
+    [0x19] = {OP_lea, -1, 0,  two, lea_reg_xys, NULL},
+    [0x1a] = {OP_lea, -1, 0,  two, lea_reg_xys, NULL},
+    /* 0x1b PG2 */
+    [0x1c] = {OP_mov, 0, 0, opr_n_bytes2, z_opr_decode2, 0},
+    [0x1d] = {OP_mov, 1, 0, opr_n_bytes2, z_opr_decode2, 0},
+    [0x1e] = {OP_mov, 2, 0, opr_n_bytes2, z_opr_decode2, 0},
+    [0x1f] = {OP_mov, 3, 0, opr_n_bytes2, z_opr_decode2, 0},
+    [0x20] = {OP_bra, -1, 0,  pcrel_15bit, decode_rel_15_7, 0},
+    [0x21] = {OP_bsr, -1, 0,  pcrel_15bit, decode_rel_15_7, 0},
+    [0x22] = {OP_bhi, -1, 0,  pcrel_15bit, decode_rel_15_7, 0},
+    [0x23] = {OP_bls, -1, 0,  pcrel_15bit, decode_rel_15_7, 0},
+    [0x24] = {OP_bcc, -1, 0,  pcrel_15bit, decode_rel_15_7, 0},
+    [0x25] = {OP_bcs, -1, 0,  pcrel_15bit, decode_rel_15_7, 0},
+    [0x26] = {OP_bne, -1, 0,  pcrel_15bit, decode_rel_15_7, 0},
+    [0x27] = {OP_beq, -1, 0,  pcrel_15bit, decode_rel_15_7, 0},
+    [0x28] = {OP_bvc, -1, 0,  pcrel_15bit, decode_rel_15_7, 0},
+    [0x29] = {OP_bvs, -1, 0,  pcrel_15bit, decode_rel_15_7, 0},
+    [0x2a] = {OP_bpl, -1, 0,  pcrel_15bit, decode_rel_15_7, 0},
+    [0x2b] = {OP_bmi, -1, 0,  pcrel_15bit, decode_rel_15_7, 0},
+    [0x2c] = {OP_bge, -1, 0,  pcrel_15bit, decode_rel_15_7, 0},
+    [0x2d] = {OP_blt, -1, 0,  pcrel_15bit, decode_rel_15_7, 0},
+    [0x2e] = {OP_bgt, -1, 0,  pcrel_15bit, decode_rel_15_7, 0},
+    [0x2f] = {OP_ble, -1, 0,  pcrel_15bit, decode_rel_15_7, 0},
+    [0x30] = {OP_inc, -1, 0, single, z_reg, 0},
+    [0x31] = {OP_inc, -1, 0, single, z_reg, 0},
+    [0x32] = {OP_inc, -1, 0, single, z_reg, 0},
+    [0x33] = {OP_inc, -1, 0, single, z_reg, 0},
+    [0x34] = {OP_inc, -1, 0, single, z_reg, 0},
+    [0x35] = {OP_inc, -1, 0, single, z_reg, 0},
+    [0x36] = {OP_inc, -1, 0, single, z_reg, 0},
+    [0x37] = {OP_inc, -1, 0, single, z_reg, 0},
+    [0x38] = {OP_clr, -1, 0, single, z_reg, 0},
+    [0x39] = {OP_clr, -1, 0, single, z_reg, 0},
+    [0x3a] = {OP_clr, -1, 0, single, z_reg, 0},
+    [0x3b] = {OP_clr, -1, 0, single, z_reg, 0},
+    [0x3c] = {OP_clr, -1, 0, single, z_reg, 0},
+    [0x3d] = {OP_clr, -1, 0, single, z_reg, 0},
+    [0x3e] = {OP_clr, -1, 0, single, z_reg, 0},
+    [0x3f] = {OP_clr, -1, 0, single, z_reg, 0},
+    [0x40] = {OP_dec, -1, 0, single, z_reg, 0},
+    [0x41] = {OP_dec, -1, 0, single, z_reg, 0},
+    [0x42] = {OP_dec, -1, 0, single, z_reg, 0},
+    [0x43] = {OP_dec, -1, 0, single, z_reg, 0},
+    [0x44] = {OP_dec, -1, 0, single, z_reg, 0},
+    [0x45] = {OP_dec, -1, 0, single, z_reg, 0},
+    [0x46] = {OP_dec, -1, 0, single, z_reg, 0},
+    [0x47] = {OP_dec, -1, 0, single, z_reg, 0},
+    [0x48] = {OPBASE_mul, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x49] = {OPBASE_mul, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x4a] = {OPBASE_mul, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x4b] = {OPBASE_mul, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x4c] = {OPBASE_mul, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x4d] = {OPBASE_mul, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x4e] = {OPBASE_mul, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x4f] = {OPBASE_mul, -1, mul_discrim, mul_n_bytes, mul_decode, 0},
+    [0x50] = {OP_add, -1, 0, three, z_reg, z_imm1234_0base},
+    [0x51] = {OP_add, -1, 0, three, z_reg, z_imm1234_0base},
+    [0x52] = {OP_add, -1, 0, three, z_reg, z_imm1234_0base},
+    [0x53] = {OP_add, -1, 0, three, z_reg, z_imm1234_0base},
+    [0x54] = {OP_add, -1, 0, two,   z_reg, z_imm1234_0base},
+    [0x55] = {OP_add, -1, 0, two,   z_reg, z_imm1234_0base},
+    [0x56] = {OP_add, -1, 0, five,  z_reg, z_imm1234_0base},
+    [0x57] = {OP_add, -1, 0, five,  z_reg, z_imm1234_0base},
+    [0x58] = {OP_and, -1, 0, three, z_reg, z_imm1234_8base},
+    [0x59] = {OP_and, -1, 0, three, z_reg, z_imm1234_8base},
+    [0x5a] = {OP_and, -1, 0, three, z_reg, z_imm1234_8base},
+    [0x5b] = {OP_and, -1, 0, three, z_reg, z_imm1234_8base},
+    [0x5c] = {OP_and, -1, 0, two,   z_reg, z_imm1234_8base},
+    [0x5d] = {OP_and, -1, 0, two,   z_reg, z_imm1234_8base},
+    [0x5e] = {OP_and, -1, 0, five,  z_reg, z_imm1234_8base},
+    [0x5f] = {OP_and, -1, 0, five,  z_reg, z_imm1234_8base},
+    [0x60] = {OP_add, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x61] = {OP_add, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x62] = {OP_add, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x63] = {OP_add, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x64] = {OP_add, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x65] = {OP_add, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x66] = {OP_add, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x67] = {OP_add, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x68] = {OP_and, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x69] = {OP_and, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x6a] = {OP_and, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x6b] = {OP_and, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x6c] = {OP_and, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x6d] = {OP_and, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x6e] = {OP_and, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x6f] = {OP_and, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode},
+    [0x70] = {OP_sub, -1, 0, three, z_reg, z_imm1234_0base},
+    [0x71] = {OP_sub, -1, 0, three, z_reg, z_imm1234_0base},
+    [0x72] = {OP_sub, -1, 0, three, z_reg, z_imm1234_0base},
+    [0x73] = {OP_sub, -1, 0, three, z_reg, z_imm1234_0base},
+    [0x74] = {OP_sub, -1, 0, two,   z_reg, z_imm1234_0base},
+    [0x75] = {OP_sub, -1, 0, two,   z_reg, z_imm1234_0base},
+    [0x76] = {OP_sub, -1, 0, five,  z_reg, z_imm1234_0base},
+    [0x77] = {OP_sub, -1, 0, five,  z_reg, z_imm1234_0base},
+    [0x78] = {OP_or, -1, 0, three, z_reg, z_imm1234_8base},
+    [0x79] = {OP_or, -1, 0, three, z_reg, z_imm1234_8base},
+    [0x7a] = {OP_or, -1, 0, three, z_reg, z_imm1234_8base},
+    [0x7b] = {OP_or, -1, 0, three, z_reg, z_imm1234_8base},
+    [0x7c] = {OP_or, -1, 0, two,   z_reg, z_imm1234_8base},
+    [0x7d] = {OP_or, -1, 0, two,   z_reg, z_imm1234_8base},
+    [0x7e] = {OP_or, -1, 0, five,  z_reg, z_imm1234_8base},
+    [0x7f] = {OP_or, -1, 0, five,  z_reg, z_imm1234_8base},
+    [0x80] = {OP_sub, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0x81] = {OP_sub, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0x82] = {OP_sub, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0x83] = {OP_sub, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0x84] = {OP_sub, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0x85] = {OP_sub, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0x86] = {OP_sub, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0x87] = {OP_sub, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0x88] = {OP_or, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0x89] = {OP_or, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0x8a] = {OP_or, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0x8b] = {OP_or, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0x8c] = {OP_or, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0x8d] = {OP_or, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0x8e] = {OP_or, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0x8f] = {OP_or, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0x90] = {OP_ld, -1, 0, three,  z_reg, z_imm1234_0base},
+    [0x91] = {OP_ld, -1, 0, three,  z_reg, z_imm1234_0base},
+    [0x92] = {OP_ld, -1, 0, three,  z_reg, z_imm1234_0base},
+    [0x93] = {OP_ld, -1, 0, three,  z_reg, z_imm1234_0base},
+    [0x94] = {OP_ld, -1, 0, two,    z_reg, z_imm1234_0base},
+    [0x95] = {OP_ld, -1, 0, two,    z_reg, z_imm1234_0base},
+    [0x96] = {OP_ld, -1, 0, five,   z_reg, z_imm1234_0base},
+    [0x97] = {OP_ld, -1, 0, five,   z_reg, z_imm1234_0base},
+    [0x98] = {OP_ld, -1, 0, four,   reg_xy, z_imm1234_0base},
+    [0x99] = {OP_ld, -1, 0, four,   reg_xy, z_imm1234_0base},
+    [0x9a] = {OP_clr, -1, 0, single, reg_xy, 0},
+    [0x9b] = {OP_clr, -1, 0, single, reg_xy, 0},
+    [0x9c] = {OP_inc, 0, 0, opr_n_bytes_p1, z_opr_decode, 0},
+    [0x9d] = {OP_inc, 1, 0, opr_n_bytes_p1, z_opr_decode, 0},
+    [0x9e] = {OP_tfr, -1, 0, two, z_tfr, NULL},
+    [0x9f] = {OP_inc, 3, 0, opr_n_bytes_p1, z_opr_decode, 0},
+    [0xa0] = {OP_ld, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xa1] = {OP_ld, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xa2] = {OP_ld, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xa3] = {OP_ld, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xa4] = {OP_ld, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xa5] = {OP_ld, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xa6] = {OP_ld, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xa7] = {OP_ld, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xa8] = {OP_ld, -1, 0, opr_n_bytes_p1, reg_xy, z_opr_decode},
+    [0xa9] = {OP_ld, -1, 0, opr_n_bytes_p1, reg_xy, z_opr_decode},
+    [0xaa] = {OP_jmp, -1, 0, opr_n_bytes_p1, z_opr_decode, 0},
+    [0xab] = {OP_jsr, -1, 0, opr_n_bytes_p1, z_opr_decode, 0},
+    [0xac] = {OP_dec, 0, 0, opr_n_bytes_p1, z_opr_decode, 0},
+    [0xad] = {OP_dec, 1, 0, opr_n_bytes_p1, z_opr_decode, 0},
+    [0xae] = {0xFFFF, -1, exg_sex_discrim,   two, exg_sex_decode, 0},  /* EXG / SEX */
+    [0xaf] = {OP_dec, 3, 0, opr_n_bytes_p1, 0, z_opr_decode},
+    [0xb0] = {OP_ld, -1, 0, four,  z_reg, z_ext24_decode},
+    [0xb1] = {OP_ld, -1, 0, four,  z_reg, z_ext24_decode},
+    [0xb2] = {OP_ld, -1, 0, four,  z_reg, z_ext24_decode},
+    [0xb3] = {OP_ld, -1, 0, four,  z_reg, z_ext24_decode},
+    [0xb4] = {OP_ld, -1, 0, four,  z_reg, z_ext24_decode},
+    [0xb5] = {OP_ld, -1, 0, four,  z_reg, z_ext24_decode},
+    [0xb6] = {OP_ld, -1, 0, four,  z_reg, z_ext24_decode},
+    [0xb7] = {OP_ld, -1, 0, four,  z_reg, z_ext24_decode},
+    [0xb8] = {OP_ld, -1, 0, four,  reg_xy, z_ext24_decode},
+    [0xb9] = {OP_ld, -1, 0, four,  reg_xy, z_ext24_decode},
+    [0xba] = {OP_jmp, -1, 0, four, z_ext24_decode, 0},
+    [0xbb] = {OP_jsr, -1, 0, four, z_ext24_decode, 0},
+    [0xbc] = {OP_clr, 0, 0, opr_n_bytes_p1, z_opr_decode, 0},
+    [0xbd] = {OP_clr, 1, 0, opr_n_bytes_p1, z_opr_decode, 0},
+    [0xbe] = {OP_clr, 2, 0, opr_n_bytes_p1, z_opr_decode, 0},
+    [0xbf] = {OP_clr, 3, 0, opr_n_bytes_p1, z_opr_decode, 0},
+    [0xc0] = {OP_st, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xc1] = {OP_st, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xc2] = {OP_st, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xc3] = {OP_st, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xc4] = {OP_st, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xc5] = {OP_st, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xc6] = {OP_st, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xc7] = {OP_st, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xc8] = {OP_st, -1, 0, opr_n_bytes_p1, reg_xy, z_opr_decode},
+    [0xc9] = {OP_st, -1, 0, opr_n_bytes_p1, reg_xy, z_opr_decode},
+    [0xca] = {OP_ld, -1, 0, three, reg_xy, ld_18bit_decode},
+    [0xcb] = {OP_ld, -1, 0, three, reg_xy, ld_18bit_decode},
+    [0xcc] = {OP_com, 0, 0, opr_n_bytes_p1, NULL, z_opr_decode},
+    [0xcd] = {OP_com, 1, 0, opr_n_bytes_p1, NULL, z_opr_decode},
+    [0xce] = {OP_andcc, -1, 0, two, imm1_decode, 0},
+    [0xcf] = {OP_com, 3, 0, opr_n_bytes_p1, NULL, z_opr_decode},
+    [0xd0] = {OP_st, -1, 0, four,  z_reg, z_ext24_decode},
+    [0xd1] = {OP_st, -1, 0, four,  z_reg, z_ext24_decode},
+    [0xd2] = {OP_st, -1, 0, four,  z_reg, z_ext24_decode},
+    [0xd3] = {OP_st, -1, 0, four,  z_reg, z_ext24_decode},
+    [0xd4] = {OP_st, -1, 0, four,  z_reg, z_ext24_decode},
+    [0xd5] = {OP_st, -1, 0, four,  z_reg, z_ext24_decode},
+    [0xd6] = {OP_st, -1, 0, four,  z_reg, z_ext24_decode},
+    [0xd7] = {OP_st, -1, 0, four,  z_reg, z_ext24_decode},
+    [0xd8] = {OP_st, -1, 0, four,  reg_xy, z_ext24_decode},
+    [0xd9] = {OP_st, -1, 0, four,  reg_xy, z_ext24_decode},
+    [0xda] = {OP_ld, -1, 0, three, reg_xy, ld_18bit_decode},
+    [0xdb] = {OP_ld, -1, 0, three, reg_xy, ld_18bit_decode},
+    [0xdc] = {OP_neg, 0, 0, opr_n_bytes_p1, NULL, z_opr_decode},
+    [0xdd] = {OP_neg, 1, 0, opr_n_bytes_p1, NULL, z_opr_decode},
+    [0xde] = {OP_orcc, -1, 0,  two,  imm1_decode, 0},
+    [0xdf] = {OP_neg,  3, 0, opr_n_bytes_p1, NULL, z_opr_decode},
+    [0xe0] = {OP_cmp, -1, 0, three,  z_reg, z_imm1234_0base},
+    [0xe1] = {OP_cmp, -1, 0, three,  z_reg, z_imm1234_0base},
+    [0xe2] = {OP_cmp, -1, 0, three,  z_reg, z_imm1234_0base},
+    [0xe3] = {OP_cmp, -1, 0, three,  z_reg, z_imm1234_0base},
+    [0xe4] = {OP_cmp, -1, 0, two,    z_reg, z_imm1234_0base},
+    [0xe5] = {OP_cmp, -1, 0, two,    z_reg, z_imm1234_0base},
+    [0xe6] = {OP_cmp, -1, 0, five,   z_reg, z_imm1234_0base},
+    [0xe7] = {OP_cmp, -1, 0, five,   z_reg, z_imm1234_0base},
+    [0xe8] = {OP_cmp, -1, 0, four,   reg_xy, z_imm1234_0base},
+    [0xe9] = {OP_cmp, -1, 0, four,   reg_xy, z_imm1234_0base},
+    [0xea] = {OP_ld, -1, 0, three, reg_xy, ld_18bit_decode},
+    [0xeb] = {OP_ld, -1, 0, three, reg_xy, ld_18bit_decode},
+    [0xec] = {OP_bclr, -1, 0, bm_n_bytes, bm_decode, 0},
+    [0xed] = {OP_bset, -1, 0, bm_n_bytes, bm_decode, 0},
+    [0xee] = {OP_btgl, -1, 0, bm_n_bytes, bm_decode, 0},
+    [0xef] = {OP_INVALID, -1, 0, NULL, NULL, NULL}, /* SPARE */
+    [0xf0] = {OP_cmp, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xf1] = {OP_cmp, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xf2] = {OP_cmp, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xf3] = {OP_cmp, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xf4] = {OP_cmp, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xf5] = {OP_cmp, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xf6] = {OP_cmp, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xf7] = {OP_cmp, -1, 0, opr_n_bytes_p1, z_reg,    z_opr_decode},
+    [0xf8] = {OP_cmp, -1, 0, opr_n_bytes_p1, reg_xy, z_opr_decode},
+    [0xf9] = {OP_cmp, -1, 0, opr_n_bytes_p1, reg_xy, z_opr_decode},
+    [0xfa] = {OP_ld, -1, 0,  three, reg_xy, ld_18bit_decode},
+    [0xfb] = {OP_ld, -1, 0,  three, reg_xy, ld_18bit_decode},
+    [0xfc] = {OP_cmp, -1, 0, single, cmp_xy, 0},
+    [0xfd] = {OP_sub, -1, 0, single, sub_d6_x_y, 0},
+    [0xfe] = {OP_sub, -1, 0, single, sub_d6_y_x, 0},
+    [0xff] = {OP_swi, -1, 0, single, 0, 0}
+  };
+
+static const int oprregs1[] =
+  {
+    REG_D3, REG_D2, REG_D1, REG_D0, REG_CCL, REG_CCH
+  };
+
+static const int oprregs2[] =
+  {
+    REG_Y,  REG_X,  REG_D7, REG_D6, REG_D5,  REG_D4
+  };
+
+
+
+
+enum MUL_MODE
+  {
+    MUL_REG_REG,
+    MUL_REG_OPR,
+    MUL_REG_IMM,
+    MUL_OPR_OPR
+  };
+
+struct mb
+{
+  uint8_t mask;
+  uint8_t value;
+  enum MUL_MODE mode;
+};
+
+static const struct mb mul_table[] = {
+  {0x40, 0x00, MUL_REG_REG},
+
+  {0x47, 0x40, MUL_REG_OPR},
+  {0x47, 0x41, MUL_REG_OPR},
+  {0x47, 0x43, MUL_REG_OPR},
+
+  {0x47, 0x44, MUL_REG_IMM},
+  {0x47, 0x45, MUL_REG_IMM},
+  {0x47, 0x47, MUL_REG_IMM},
+
+  {0x43, 0x42, MUL_OPR_OPR},
+};
+
+
+static void
+mul_decode (struct mem_read_abstraction_base *mra,
+	    int *n_operands, struct operand **operand)
+{
+  uint8_t mb;
+  int status = mra->read (mra, 0, 1, &mb);
+  if (status < 0)
+    return;
+
+  uint8_t byte;
+  status = mra->read (mra, -1, 1, &byte);
+  if (status < 0)
+    return;
+
+  enum MUL_MODE mode = -1;
+  size_t i;
+  for (i = 0; i < sizeof (mul_table) / sizeof (mul_table[0]); ++i)
+    {
+      const struct mb *mm = mul_table + i;
+      if ((mb & mm->mask) == mm->value)
+	{
+	  mode = mm->mode;
+	  break;
+	}
+    }
+  operand[(*n_operands)++] = create_register_operand (byte & 0x07);
+
+  switch (mode)
+    {
+    case MUL_REG_IMM:
+      {
+	int size = (mb & 0x3);
+	operand[(*n_operands)++] =
+	  create_register_operand_with_size ((mb & 0x38) >> 3, size);
+	uint32_t imm = z_decode_signed_value (mra, 1, size + 1);
+	operand[(*n_operands)++] = create_immediate_operand (imm);
+      }
+      break;
+    case MUL_REG_REG:
+      operand[(*n_operands)++] = create_register_operand ((mb & 0x38) >> 3);
+      operand[(*n_operands)++] = create_register_operand (mb & 0x07);
+      break;
+    case MUL_REG_OPR:
+      operand[(*n_operands)++] = create_register_operand ((mb & 0x38) >> 3);
+      operand[(*n_operands)++] = x_opr_decode_with_size (mra, 1, mb & 0x3);
+      break;
+    case MUL_OPR_OPR:
+      {
+	int first = x_opr_n_bytes (mra, 1);
+	operand[(*n_operands)++] = x_opr_decode_with_size (mra, 1,
+							   (mb & 0x30) >> 4);
+	operand[(*n_operands)++] = x_opr_decode_with_size (mra, first + 1,
+							   (mb & 0x0c) >> 2);
+	break;
+      }
+    }
+}
+
+
+static int
+mul_n_bytes (struct mem_read_abstraction_base *mra)
+{
+  int nx = 2;
+  uint8_t mb;
+  int status = mra->read (mra, 0, 1, &mb);
+  if (status < 0)
+    return 0;
+
+  enum MUL_MODE mode = -1;
+  size_t i;
+  for (i = 0; i < sizeof (mul_table) / sizeof (mul_table[0]); ++i)
+    {
+      const struct mb *mm = mul_table + i;
+      if ((mb & mm->mask) == mm->value)
+	{
+	  mode = mm->mode;
+	  break;
+	}
+    }
+
+  int size = (mb & 0x3) + 1;
+
+  switch (mode)
+    {
+    case MUL_REG_IMM:
+      nx += size;
+      break;
+    case MUL_REG_REG:
+      break;
+    case MUL_REG_OPR:
+      nx += x_opr_n_bytes (mra, 1);
+      break;
+    case MUL_OPR_OPR:
+      {
+	int first = x_opr_n_bytes (mra, nx - 1);
+	nx += first;
+	int second = x_opr_n_bytes (mra, nx - 1);
+	nx += second;
+      }
+      break;
+    }
+
+  return nx;
+}
+
+
+/* The NXP documentation is vague about BM_RESERVED0 and BM_RESERVED1,
+   and contains obvious typos.
+   However the Freescale tools and experiments with the chip itself
+   seem to indicate that they behave like BM_REG_IMM and BM_OPR_REG
+   respectively.  */
+
+enum BM_MODE
+{
+  BM_REG_IMM,
+  BM_RESERVED0,
+  BM_OPR_B,
+  BM_OPR_W,
+  BM_OPR_L,
+  BM_OPR_REG,
+  BM_RESERVED1
+};
+
+struct bm
+{
+  uint8_t mask;
+  uint8_t value;
+  enum BM_MODE mode;
+};
+
+static const  struct bm bm_table[] = {
+  { 0xC6, 0x04,     BM_REG_IMM},
+  { 0x84, 0x00,     BM_REG_IMM},
+  { 0x06, 0x06,     BM_REG_IMM},
+  { 0xC6, 0x44,     BM_RESERVED0},
+  // 00
+  { 0x8F, 0x80,     BM_OPR_B},
+  { 0x8E, 0x82,     BM_OPR_W},
+  { 0x8C, 0x88,     BM_OPR_L},
+
+  { 0x83, 0x81,     BM_OPR_REG},
+  { 0x87, 0x84,     BM_RESERVED1},
+};
+
+static void
+bm_decode (struct mem_read_abstraction_base *mra,
+	   int *n_operands, struct operand **operand)
+{
+  uint8_t bm;
+  int status = mra->read (mra, 0, 1, &bm);
+  if (status < 0)
+    return;
+
+  size_t i;
+  enum BM_MODE mode = -1;
+  for (i = 0; i < sizeof (bm_table) / sizeof (bm_table[0]); ++i)
+    {
+      const struct bm *bme = bm_table + i;
+      if ((bm & bme->mask) == bme->value)
+	{
+	  mode = bme->mode;
+	  break;
+	}
+    }
+
+  switch (mode)
+    {
+    case BM_REG_IMM:
+    case BM_RESERVED0:
+      operand[(*n_operands)++] = create_register_operand (bm & 0x07);
+      break;
+    case BM_OPR_B:
+      operand[(*n_operands)++] = x_opr_decode_with_size (mra, 1, 0);
+      break;
+    case BM_OPR_W:
+      operand[(*n_operands)++] = x_opr_decode_with_size (mra, 1, 1);
+      break;
+    case BM_OPR_L:
+      operand[(*n_operands)++] = x_opr_decode_with_size (mra, 1, 3);
+      break;
+    case BM_OPR_REG:
+    case BM_RESERVED1:
+      {
+	uint8_t xb;
+	mra->read (mra, 1, 1, &xb);
+	/* Don't emit a size suffix for register operands */
+	if ((xb & 0xF8) != 0xB8)
+	  operand[(*n_operands)++] =
+	    x_opr_decode_with_size (mra, 1, (bm & 0x0c) >> 2);
+	else
+	  operand[(*n_operands)++] = x_opr_decode (mra, 1);
+      }
+      break;
+    }
+
+  uint8_t imm = 0;
+  switch (mode)
+    {
+    case BM_REG_IMM:
+      imm = (bm & 0x38) >> 3;
+      operand[(*n_operands)++] = create_immediate_operand (imm);
+      break;
+    case BM_OPR_L:
+      imm |= (bm & 0x03) << 3;
+      /* fallthrough */
+    case BM_OPR_W:
+      imm |= (bm & 0x01) << 3;
+      /* fallthrough */
+    case BM_OPR_B:
+      imm |= (bm & 0x70) >> 4;
+      operand[(*n_operands)++] = create_immediate_operand (imm);
+      break;
+    case BM_OPR_REG:
+    case BM_RESERVED1:
+      operand[(*n_operands)++] = create_register_operand ((bm & 0x70) >> 4);
+      break;
+    case BM_RESERVED0:
+      assert (0);
+      break;
+    }
+}
+
+
+static void
+bm_rel_decode (struct mem_read_abstraction_base *mra,
+	       int *n_operands, struct operand **operand)
+{
+  uint8_t bm;
+  int status = mra->read (mra, 0, 1, &bm);
+  if (status < 0)
+    return;
+
+  size_t i;
+  enum BM_MODE mode = -1;
+  for (i = 0; i < sizeof (bm_table) / sizeof (bm_table[0]); ++i)
+    {
+      const struct bm *bme = bm_table + i;
+      if ((bm & bme->mask) == bme->value)
+	{
+	  mode = bme->mode;
+	  break;
+	}
+    }
+
+  int n = 1;
+  switch (mode)
+    {
+    case BM_REG_IMM:
+    case BM_RESERVED0:
+      operand[(*n_operands)++] = create_register_operand (bm & 0x07);
+      break;
+    case BM_OPR_B:
+      operand[(*n_operands)++] = x_opr_decode_with_size (mra, 1, 0);
+      n = 1 + x_opr_n_bytes (mra, 1);
+      break;
+    case BM_OPR_W:
+      operand[(*n_operands)++] = x_opr_decode_with_size (mra, 1, 1);
+      n = 1 + x_opr_n_bytes (mra, 1);
+      break;
+    case BM_OPR_L:
+      operand[(*n_operands)++] = x_opr_decode_with_size (mra, 1, 3);
+      n = 1 + x_opr_n_bytes (mra, 1);
+      break;
+    case BM_OPR_REG:
+    case BM_RESERVED1:
+      {
+	uint8_t xb;
+	mra->read (mra, +1, 1, &xb);
+	/* Don't emit a size suffix for register operands */
+	if ((xb & 0xF8) != 0xB8)
+	  {
+	    short os = (bm & 0x0c) >> 2;
+	    operand[(*n_operands)++] = x_opr_decode_with_size (mra, 1, os);
+	  }
+	else
+	  operand[(*n_operands)++] = x_opr_decode (mra, 1);
+
+      }
+      break;
+    }
+
+  int imm = 0;
+  switch (mode)
+    {
+    case BM_OPR_L:
+      imm |= (bm & 0x02) << 3;
+      /* fall through */
+    case BM_OPR_W:
+      imm |= (bm & 0x01) << 3;
+      /* fall through */
+    case BM_OPR_B:
+      imm |= (bm & 0x70) >> 4;
+      operand[(*n_operands)++] = create_immediate_operand (imm);
+      break;
+    case BM_RESERVED0:
+      imm = (bm & 0x38) >> 3;
+      operand[(*n_operands)++] = create_immediate_operand (imm);
+      break;
+    case BM_REG_IMM:
+      imm = (bm & 0xF8) >> 3;
+      operand[(*n_operands)++] = create_immediate_operand (imm);
+      break;
+    case BM_OPR_REG:
+    case BM_RESERVED1:
+      operand[(*n_operands)++] = create_register_operand ((bm & 0x70) >> 4);
+      n += x_opr_n_bytes (mra, 1);
+      break;
+    }
+
+  rel_15_7 (mra, n + 1, n_operands, operand);
+}
+
+static int
+bm_n_bytes (struct mem_read_abstraction_base *mra)
+{
+  uint8_t bm;
+  int status = mra->read (mra, 0, 1, &bm);
+  if (status < 0)
+    return status;
+
+  size_t i;
+  enum BM_MODE mode = -1;
+  for (i = 0; i < sizeof (bm_table) / sizeof (bm_table[0]); ++i)
+    {
+      const struct bm *bme = bm_table + i;
+      if ((bm & bme->mask) == bme->value)
+	{
+	  mode = bme->mode;
+	  break;
+	}
+    }
+
+  int n = 2;
+  switch (mode)
+    {
+    case BM_REG_IMM:
+    case BM_RESERVED0:
+      break;
+
+    case BM_OPR_B:
+    case BM_OPR_W:
+    case BM_OPR_L:
+      n += x_opr_n_bytes (mra, 1);
+      break;
+    case BM_OPR_REG:
+    case BM_RESERVED1:
+      n += x_opr_n_bytes (mra, 1);
+      break;
+    }
+
+  return n;
+}
+
+static int
+bm_rel_n_bytes (struct mem_read_abstraction_base *mra)
+{
+  int n = 1 + bm_n_bytes (mra);
+
+  bfd_byte rb;
+  int status = mra->read (mra, n - 2, 1, &rb);
+  if (status != 0)
+    return status;
+
+  if (rb & 0x80)
+    n++;
+
+  return n;
+}
+
+
+
+
+
+/* shift direction */
+enum SB_DIR
+  {
+    SB_LEFT,
+    SB_RIGHT
+  };
+
+enum SB_TYPE
+  {
+    SB_ARITHMETIC,
+    SB_LOGICAL
+  };
+
+
+enum SB_MODE
+  {
+    SB_REG_REG_N_EFF,
+    SB_REG_REG_N,
+    SB_REG_OPR_EFF,
+    SB_ROT,
+    SB_REG_OPR_OPR,
+    SB_OPR_N
+  };
+
+struct sb
+{
+  uint8_t mask;
+  uint8_t value;
+  enum SB_MODE mode;
+};
+
+static const  struct sb sb_table[] = {
+  {0x30, 0x00,     SB_REG_REG_N_EFF},
+  {0x30, 0x10,     SB_REG_REG_N},
+  {0x34, 0x20,     SB_REG_OPR_EFF},
+  {0x34, 0x24,     SB_ROT},
+  {0x34, 0x30,     SB_REG_OPR_OPR},
+  {0x34, 0x34,     SB_OPR_N},
+};
+
+static int
+shift_n_bytes (struct mem_read_abstraction_base *mra)
+{
+  bfd_byte sb;
+  int status = mra->read (mra, 0, 1, &sb);
+  if (status != 0)
+    return status;
+
+  size_t i;
+  enum SB_MODE mode = -1;
+  for (i = 0; i < sizeof (sb_table) / sizeof (sb_table[0]); ++i)
+    {
+      const struct sb *sbe = sb_table + i;
+      if ((sb & sbe->mask) == sbe->value)
+	mode = sbe->mode;
+    }
+
+  switch (mode)
+    {
+    case SB_REG_REG_N_EFF:
+      return 2;
+      break;
+    case SB_REG_OPR_EFF:
+    case SB_ROT:
+      return 2 + x_opr_n_bytes (mra, 1);
+      break;
+    case SB_REG_OPR_OPR:
+      {
+	int opr1 = x_opr_n_bytes (mra, 1);
+	int opr2 = 0;
+	if ((sb & 0x30) != 0x20)
+	  opr2 = x_opr_n_bytes (mra, opr1 + 1);
+	return 2 + opr1 + opr2;
+      }
+      break;
+    default:
+      return 3;
+    }
+
+  /* not reached */
+  return -1;
+}
+
+
+static int
+
+mov_imm_opr_n_bytes (struct mem_read_abstraction_base *mra)
+{
+  bfd_byte byte;
+  int status = mra->read (mra, -1, 1,  &byte);
+  if (status < 0)
+    return status;
+
+  int size = byte - 0x0c + 1;
+
+  return size + x_opr_n_bytes (mra, size) + 1;
+}
+
+static void
+mov_imm_opr (struct mem_read_abstraction_base *mra,
+	     int *n_operands, struct operand **operand)
+{
+  bfd_byte byte;
+  int status = mra->read (mra, -1, 1, &byte);
+  if (status < 0)
+    return ;
+
+  int size = byte - 0x0c + 1;
+  uint32_t imm = decode_signed_value (mra, size);
+
+  operand[(*n_operands)++] = create_immediate_operand (imm);
+  operand[(*n_operands)++] = x_opr_decode (mra, size);
+}
+
+
+
+static void
+ld_18bit_decode (struct mem_read_abstraction_base *mra,
+		 int *n_operands, struct operand **operand)
+{
+  size_t size = 3;
+  bfd_byte buffer[3];
+  int status = mra->read (mra, 0, 2, buffer + 1);
+  if (status < 0)
+    return ;
+
+  status = mra->read (mra, -1, 1, buffer);
+  if (status < 0)
+    return ;
+
+  buffer[0] = (buffer[0] & 0x30) >> 4;
+
+  size_t i;
+  uint32_t imm = 0;
+  for (i = 0; i < size; ++i)
+    {
+      imm |= buffer[i] << (8 * (size - i - 1));
+    }
+
+  operand[(*n_operands)++] = create_immediate_operand (imm);
+}
+
+
+
+/* Loop Primitives */
+
+enum LP_MODE {
+  LP_REG,
+  LP_XY,
+  LP_OPR
+};
+
+struct lp
+{
+  uint8_t mask;
+  uint8_t value;
+  enum LP_MODE mode;
+};
+
+static const struct lp lp_mode[] = {
+  {0x08, 0x00, LP_REG},
+  {0x0C, 0x08, LP_XY},
+  {0x0C, 0x0C, LP_OPR},
+};
+
+
+static int
+loop_prim_n_bytes (struct mem_read_abstraction_base *mra)
+{
+  int mx = 0;
+  uint8_t lb;
+  mra->read (mra, mx++, 1, &lb);
+
+  enum LP_MODE mode = -1;
+  size_t i;
+  for (i = 0; i < sizeof (lp_mode) / sizeof (lp_mode[0]); ++i)
+    {
+      const struct lp *pb = lp_mode + i;
+      if ((lb & pb->mask) == pb->value)
+	{
+	  mode = pb->mode;
+	  break;
+	}
+    }
+
+  if (mode == LP_OPR)
+    {
+      mx += x_opr_n_bytes (mra, mx) ;
+    }
+
+  uint8_t rb;
+  mra->read (mra, mx++, 1, &rb);
+  if (rb & 0x80)
+    mx++;
+
+  return mx + 1;
+}
+
+
+
+
+static enum operator
+exg_sex_discrim (struct mem_read_abstraction_base *mra, enum operator hint ATTRIBUTE_UNUSED)
+{
+  uint8_t eb;
+  int status = mra->read (mra, 0, 1, &eb);
+  if (status < 0)
+    return OP_INVALID;
+
+  struct operand *op0 = create_register_operand ((eb & 0xf0) >> 4);
+  struct operand *op1 = create_register_operand (eb & 0xf);
+
+  const struct reg *r0 = registers + ((struct register_operand *) op0)->reg;
+  const struct reg *r1 = registers + ((struct register_operand *) op1)->reg;
+
+  enum operator operator = (r0->bytes < r1->bytes) ? OP_sex : OP_exg;
+
+  free (op0);
+  free (op1);
+  
+  return operator;
+}
+
+
+static void
+exg_sex_decode (struct mem_read_abstraction_base *mra,
+		int *n_operands, struct operand **operands)
+{
+  uint8_t eb;
+  int status = mra->read (mra, 0, 1, &eb);
+  if (status < 0)
+    return;
+
+  /* Ship out the operands.  */
+  operands[(*n_operands)++] =  create_register_operand ((eb & 0xf0) >> 4);
+  operands[(*n_operands)++] =  create_register_operand (eb & 0xf);
+}
+
+static enum operator
+loop_primitive_discrim (struct mem_read_abstraction_base *mra,
+			enum operator hint ATTRIBUTE_UNUSED)
+{
+  uint8_t lb;
+  int status = mra->read (mra, 0, 1, &lb);
+  if (status < 0)
+    return OP_INVALID;
+
+  enum operator opbase = (lb & 0x80) ? OP_dbNE : OP_tbNE;
+  return opbase + ((lb & 0x70) >> 4);
+}
+
+static void
+loop_primitive_decode (struct mem_read_abstraction_base *mra,
+		  int *n_operands, struct operand **operands)
+{
+  int offs = 1;
+  uint8_t lb;
+  int status = mra->read (mra, 0, 1, &lb);
+  if (status < 0)
+    return ;
+
+  enum LP_MODE mode = -1;
+  size_t i;
+  for (i = 0; i < sizeof (lp_mode) / sizeof (lp_mode[0]); ++i)
+    {
+      const struct lp *pb = lp_mode + i;
+      if ((lb & pb->mask) == pb->value)
+	{
+	  mode = pb->mode;
+	  break;
+	}
+    }
+
+  switch (mode)
+    {
+    case LP_REG:
+      operands[(*n_operands)++] = create_register_operand (lb & 0x07);
+      break;
+    case LP_XY:
+      operands[(*n_operands)++] =
+	create_register_operand ((lb & 0x01) + REG_X);
+      break;
+    case LP_OPR:
+      offs += x_opr_n_bytes (mra, 1);
+      operands[(*n_operands)++] = x_opr_decode_with_size (mra, 1, lb & 0x03);
+      break;
+    }
+
+  rel_15_7 (mra, offs + 1, n_operands, operands);
+}
+
+
+static enum operator
+shift_discrim (struct mem_read_abstraction_base *mra,  enum operator hint ATTRIBUTE_UNUSED)
+{
+  size_t i;
+  uint8_t sb;
+  int status = mra->read (mra, 0, 1, &sb);
+  if (status < 0)
+    return status;
+
+  enum SB_DIR  dir = (sb & 0x40) ? SB_LEFT : SB_RIGHT;
+  enum SB_TYPE type = (sb & 0x80) ? SB_ARITHMETIC : SB_LOGICAL;
+  enum SB_MODE mode = -1;
+  for (i = 0; i < sizeof (sb_table) / sizeof (sb_table[0]); ++i)
+    {
+      const struct sb *sbe = sb_table + i;
+      if ((sb & sbe->mask) == sbe->value)
+	mode = sbe->mode;
+    }
+
+  if (mode == SB_ROT)
+    return (dir == SB_LEFT) ? OP_rol : OP_ror;
+
+  if (type == SB_LOGICAL)
+    return (dir == SB_LEFT) ? OP_lsl : OP_lsr;
+
+  return (dir == SB_LEFT) ? OP_asl : OP_asr;
+}
+
+
+static void
+shift_decode (struct mem_read_abstraction_base *mra,  int *n_operands, struct operand **operands)
+{
+  size_t i;
+
+  uint8_t byte;
+  int status = mra->read (mra, -1, 1, &byte);
+  if (status < 0)
+    return ;
+
+  uint8_t sb;
+  status = mra->read (mra, 0, 1, &sb);
+  if (status < 0)
+    return ;
+
+  enum SB_MODE mode = -1;
+  for (i = 0; i < sizeof (sb_table) / sizeof (sb_table[0]); ++i)
+    {
+      const struct sb *sbe = sb_table + i;
+      if ((sb & sbe->mask) == sbe->value)
+	mode = sbe->mode;
+    }
+
+  short osize = -1;
+  switch (mode)
+    {
+    case SB_REG_OPR_EFF:
+    case SB_ROT:
+    case SB_REG_OPR_OPR:
+      osize = sb & 0x03;
+      break;
+    case SB_OPR_N:
+      {
+	uint8_t xb;
+	mra->read (mra, 1, 1, &xb);
+	/* The size suffix is not printed if the OPR operand refers
+	   directly to a register, because the size is implied by the
+	   size of that register. */
+	if ((xb & 0xF8) != 0xB8)
+	  osize = sb & 0x03;
+      }
+      break;
+    default:
+      break;
+    };
+
+  /* Destination register */
+  switch (mode)
+    {
+    case SB_REG_REG_N_EFF:
+    case SB_REG_REG_N:
+      operands[(*n_operands)++] = create_register_operand (byte & 0x07);
+      break;
+    case SB_REG_OPR_EFF:
+    case SB_REG_OPR_OPR:
+      operands[(*n_operands)++] = create_register_operand (byte & 0x07);
+      break;
+
+    case SB_ROT:
+      operands[(*n_operands)++] = x_opr_decode_with_size (mra, 1, osize);
+      break;
+
+    default:
+      break;
+    }
+
+  /* Source register */
+  switch (mode)
+    {
+    case SB_REG_REG_N_EFF:
+    case SB_REG_REG_N:
+      operands[(*n_operands)++] =
+	create_register_operand_with_size (sb & 0x07, osize);
+      break;
+
+    case SB_REG_OPR_OPR:
+      operands[(*n_operands)++] = x_opr_decode_with_size (mra, 1, osize);
+      break;
+
+    default:
+      break;
+    }
+
+  /* 3rd arg */
+  switch (mode)
+    {
+    case SB_REG_OPR_EFF:
+    case SB_OPR_N:
+      operands[(*n_operands)++] = x_opr_decode_with_size (mra, 1, osize);
+      break;
+
+    case SB_REG_REG_N:
+      {
+        uint8_t xb;
+        mra->read (mra, 1, 1, &xb);
+
+        /* This case is slightly unusual.
+           If XB matches the binary pattern 0111XXXX, then instead of
+           interpreting this as a general OPR postbyte in the IMMe4 mode,
+           the XB byte is interpreted in s special way.  */
+        if ((xb & 0xF0) == 0x70)
+          {
+            if (byte & 0x10)
+              {
+                int shift = ((sb & 0x08) >> 3) | ((xb & 0x0f) << 1);
+                operands[(*n_operands)++] = create_immediate_operand (shift);
+              }
+            else
+              {
+                /* This should not happen.  */
+                abort ();
+              }
+          }
+        else
+          {
+            operands[(*n_operands)++] = x_opr_decode (mra, 1);
+          }
+      }
+      break;
+    case SB_REG_OPR_OPR:
+      {
+	uint8_t xb;
+	int n = x_opr_n_bytes (mra, 1);
+	mra->read (mra, 1 + n, 1, &xb);
+
+	if ((xb & 0xF0) == 0x70)
+	  {
+	    int imm = xb & 0x0F;
+	    imm <<= 1;
+	    imm |= (sb & 0x08) >> 3;
+	    operands[(*n_operands)++] = create_immediate_operand (imm);
+	  }
+	else
+	  {
+	    operands[(*n_operands)++] = x_opr_decode (mra, 1 + n);
+	  }
+      }
+      break;
+    default:
+      break;
+    }
+
+  switch (mode)
+    {
+    case SB_REG_REG_N_EFF:
+    case SB_REG_OPR_EFF:
+    case SB_OPR_N:
+      {
+        int imm = (sb & 0x08) ? 2 : 1;
+        operands[(*n_operands)++] = create_immediate_operand (imm);
+      }
+      break;
+
+    default:
+      break;
+    }
+}
+
+static enum operator
+psh_pul_discrim (struct mem_read_abstraction_base *mra,
+		 enum operator hint ATTRIBUTE_UNUSED)
+{
+  uint8_t byte;
+  int status = mra->read (mra, 0, 1, &byte);
+  if (status != 0)
+    return OP_INVALID;
+
+  return (byte & 0x80) ? OP_pull: OP_push;
+}
+
+
+static void
+psh_pul_decode (struct mem_read_abstraction_base *mra,
+		int *n_operands, struct operand **operand)
+{
+  uint8_t byte;
+  int status = mra->read (mra, 0, 1, &byte);
+  if (status != 0)
+    return;
+  int bit;
+  if (byte & 0x40)
+    {
+      if ((byte & 0x3F) == 0)
+        {
+	  operand[(*n_operands)++] = create_register_all16_operand ();
+        }
+      else
+	for (bit = 5; bit >= 0; --bit)
+	  {
+	    if (byte & (0x1 << bit))
+	      {
+		operand[(*n_operands)++] = create_register_operand (oprregs2[bit]);
+	      }
+	  }
+    }
+  else
+    {
+      if ((byte & 0x3F) == 0)
+        {
+	  operand[(*n_operands)++] = create_register_all_operand ();
+        }
+      else
+	for (bit = 5; bit >= 0; --bit)
+	  {
+	    if (byte & (0x1 << bit))
+	      {
+		operand[(*n_operands)++] = create_register_operand (oprregs1[bit]);
+	      }
+	  }
+    }
+}
+
+static enum operator
+bit_field_discrim (struct mem_read_abstraction_base *mra, enum operator hint ATTRIBUTE_UNUSED)
+{
+  int status;
+  bfd_byte bb;
+  status = mra->read (mra, 0, 1, &bb);
+  if (status != 0)
+    return OP_INVALID;
+
+  return  (bb & 0x80) ? OP_bfins : OP_bfext;
+}
+
+static void
+bit_field_decode (struct mem_read_abstraction_base *mra,
+		  int *n_operands, struct operand **operands)
+{
+  int status;
+
+  bfd_byte byte2;
+  status = mra->read (mra, -1, 1, &byte2);
+  if (status != 0)
+    return;
+
+  bfd_byte bb;
+  status = mra->read (mra, 0, 1, &bb);
+  if (status != 0)
+    return;
+
+  enum BB_MODE mode = -1;
+  size_t i;
+  const struct opr_bb *bbs = 0;
+  for (i = 0; i < sizeof (bb_modes) / sizeof (bb_modes[0]); ++i)
+    {
+      bbs = bb_modes + i;
+      if ((bb & bbs->mask) == bbs->value)
+        {
+          mode = bbs->mode;
+          break;
+        }
+    }
+  int reg1 = byte2 & 0x07;
+  /* First operand */
+  switch (mode)
+    {
+    case BB_REG_REG_REG:
+    case BB_REG_REG_IMM:
+    case BB_REG_OPR_REG:
+    case BB_REG_OPR_IMM:
+      operands[(*n_operands)++] = create_register_operand (reg1);
+      break;
+    case BB_OPR_REG_REG:
+      operands[(*n_operands)++] = x_opr_decode_with_size (mra, 1,
+							  (bb >> 2) & 0x03);
+      break;
+    case BB_OPR_REG_IMM:
+      operands[(*n_operands)++] = x_opr_decode_with_size (mra, 2,
+							  (bb >> 2) & 0x03);
+      break;
+    }
+
+  /* Second operand */
+  switch (mode)
+    {
+    case BB_REG_REG_REG:
+    case BB_REG_REG_IMM:
+      {
+        int reg_src = (bb >> 2) & 0x07;
+        operands[(*n_operands)++] = create_register_operand (reg_src);
+      }
+      break;
+    case BB_OPR_REG_REG:
+    case BB_OPR_REG_IMM:
+      {
+        int reg_src = (byte2 & 0x07);
+        operands[(*n_operands)++] = create_register_operand (reg_src);
+      }
+      break;
+    case BB_REG_OPR_REG:
+      operands[(*n_operands)++] = x_opr_decode_with_size (mra, 1,
+							  (bb >> 2) & 0x03);
+      break;
+    case BB_REG_OPR_IMM:
+      operands[(*n_operands)++] = x_opr_decode_with_size (mra, 2,
+							  (bb >> 2) & 0x03);
+      break;
+    }
+
+  /* Third operand */
+  switch (mode)
+    {
+    case BB_REG_REG_REG:
+    case BB_OPR_REG_REG:
+    case BB_REG_OPR_REG:
+      {
+        int reg_parm = bb & 0x03;
+	operands[(*n_operands)++] = create_register_operand (reg_parm);
+      }
+      break;
+    case BB_REG_REG_IMM:
+    case BB_OPR_REG_IMM:
+    case BB_REG_OPR_IMM:
+      {
+        bfd_byte i1;
+        mra->read (mra, 1, 1, &i1);
+        int offset = i1 & 0x1f;
+        int width = bb & 0x03;
+        width <<= 3;
+        width |= i1 >> 5;
+        operands[(*n_operands)++] = create_bitfield_operand (width, offset);
+      }
+      break;
+    }
+}
+
+
+/* Decode the next instruction at MRA, according to OPC.
+   The operation to be performed is returned.
+   The number of operands, will be placed in N_OPERANDS.
+   The operands themselved into OPERANDS.  */
+static enum operator
+decode_operation (const struct opcode *opc,
+		  struct mem_read_abstraction_base *mra,
+		  int *n_operands, struct operand **operands)
+{
+  enum operator op = opc->operator;
+  if (opc->discriminator)
+    op = opc->discriminator (mra, opc->operator);
+
+  if (opc->operands)
+    opc->operands (mra, n_operands, operands);
+
+  if (opc->operands2)
+    opc->operands2 (mra, n_operands, operands);
+
+  return op;
+}
+
+int
+decode_s12z (enum operator *myoperator, short *osize,
+	     int *n_operands, struct operand **operands,
+	     struct mem_read_abstraction_base *mra)
+{
+  int n_bytes = 0;
+  bfd_byte byte;
+
+  int status = mra->read (mra, 0, 1, &byte);
+  if (status != 0)
+    return status;
+
+  mra->advance (mra);
+
+  const struct opcode *opc = page1 + byte;
+  if (byte == PAGE2_PREBYTE)
+    {
+      /* Opcodes in page2 have an additional byte */
+      n_bytes++;
+
+      bfd_byte byte2;
+      mra->read (mra, 0, 1, &byte2);
+      mra->advance (mra);
+      opc = page2 + byte2;
+    }
+  *myoperator = decode_operation (opc, mra, n_operands, operands);
+  *osize = opc->osize;
+
+  /* Return the number of bytes in the instruction.  */
+  n_bytes += (opc && opc->insn_bytes) ? opc->insn_bytes (mra) : 0;
+
+  return n_bytes;
+}
+
diff --git a/opcodes/s12z-opc.h b/opcodes/s12z-opc.h
new file mode 100644
index 0000000000..186a7f29c3
--- /dev/null
+++ b/opcodes/s12z-opc.h
@@ -0,0 +1,267 @@
+/* s12z-dis.h -- Header file for s12z-dis.c and s12z-decode.c
+   Copyright (C) 2019 Free Software Foundation, Inc.
+
+   This file is part of the GNU opcodes library.
+
+   This library 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 3, or (at your option)
+   any later version.
+
+   It 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.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING3. If not,
+   see <http://www.gnu.org/licenses/>.  */
+
+#ifndef S12Z_OPC_H
+#define S12Z_OPC_H
+
+#include <stdbool.h>
+
+/* An abstraction used to read machine code from a source.  */
+struct mem_read_abstraction_base
+{
+  int (*read) (struct mem_read_abstraction_base *, int, size_t, bfd_byte *);
+  void (*advance) (struct mem_read_abstraction_base *);
+  bfd_vma (*posn) (struct mem_read_abstraction_base *);
+};
+
+
+/* Machine code operators.
+   These *roughly* correspond to opcodes.
+   But describe their purpose rather than their form.  */
+enum operator
+  {
+    OP_INVALID = 0,
+
+    OP_push,
+    OP_pull,
+    /* Test and branch.  */
+    OP_tbNE, OP_tbEQ, OP_tbPL, OP_tbMI, OP_tbGT, OP_tbLE,
+    /* Decrement and branch.  */
+    OP_dbNE, OP_dbEQ, OP_dbPL, OP_dbMI, OP_dbGT, OP_dbLE,
+
+    /* Note: sex and exg are the same opcode.
+       They are mnemonic changes according to the operands.  */
+    OP_sex,
+    OP_exg,
+
+    /* Shifters.  */
+    OP_lsl, OP_lsr,
+    OP_asl, OP_asr,
+    OP_rol, OP_ror,
+    /* Bit field operations.  */
+    OP_bfins, OP_bfext,
+    OP_trap,
+
+    OP_ld,
+    OP_st,
+    OP_cmp,
+
+    OP_stop,
+    OP_wai,
+    OP_sys,
+
+    OP_minu,
+    OP_mins,
+    OP_maxu,
+    OP_maxs,
+
+    OP_abs,
+    OP_adc,
+    OP_bit,
+    OP_sbc,
+    OP_rti,
+    OP_clb,
+    OP_eor,
+
+    OP_sat,
+
+    OP_nop,
+    OP_bgnd,
+    OP_brclr,
+    OP_brset,
+    OP_rts,
+    OP_lea,
+    OP_mov,
+
+    OP_bra,
+    OP_bsr,
+    OP_bhi,
+    OP_bls,
+    OP_bcc,
+    OP_bcs,
+    OP_bne,
+    OP_beq,
+    OP_bvc,
+    OP_bvs,
+    OP_bpl,
+    OP_bmi,
+    OP_bge,
+    OP_blt,
+    OP_bgt,
+    OP_ble,
+    OP_inc,
+    OP_clr,
+    OP_dec,
+
+    OP_add,
+    OP_sub,
+    OP_and,
+    OP_or,
+
+    OP_tfr,
+    OP_jmp,
+    OP_jsr,
+    OP_com,
+    OP_andcc,
+    OP_neg,
+    OP_orcc,
+    OP_bclr,
+    OP_bset,
+    OP_btgl,
+    OP_swi,
+
+    OP_mulu,
+    OP_divu,
+    OP_modu,
+    OP_macu,
+    OP_qmulu,
+
+    OP_muls,
+    OP_divs,
+    OP_mods,
+    OP_macs,
+    OP_qmuls,
+
+    OPBASE_mul = 0x4000,
+    OPBASE_div,
+    OPBASE_mod,
+    OPBASE_mac,
+    OPBASE_qmul,
+
+    n_OPS
+  };
+
+
+/* Used for operands which mutate their index/base registers.
+   Eg  ld d0, (s+).  */
+enum op_reg_mutation
+  {
+    OPND_RM_NONE,
+    OPND_RM_PRE_DEC,
+    OPND_RM_PRE_INC,
+    OPND_RM_POST_DEC,
+    OPND_RM_POST_INC
+  };
+
+/* The class of an operand.  */
+enum opnd_class
+  {
+    OPND_CL_IMMEDIATE,
+    OPND_CL_MEMORY,
+    OPND_CL_REGISTER,
+    OPND_CL_REGISTER_ALL,   /* Used only for psh/pul.  */
+    OPND_CL_REGISTER_ALL16, /* Used only for psh/pul.  */
+    OPND_CL_SIMPLE_MEMORY,
+    OPND_CL_BIT_FIELD
+  };
+
+
+/* Base structure of all operands.  */
+struct operand
+{
+  enum opnd_class cl;
+
+  /* OSIZE determines the size of memory access for
+     the  operation in which the operand participates.
+     It may be -1 which indicates either unknown
+     (must be determined by other operands) or if
+     it is not applicable for this operation.  */
+  int osize;
+};
+
+/* Immediate operands.  Eg: #23  */
+struct immediate_operand
+{
+  struct operand parent;
+  int value;
+};
+
+/* Bitfield operands.   Used only in bfext and bfins
+   instructions.  */
+struct bitfield_operand
+{
+  struct operand parent;
+  int width;
+  int offset;
+};
+
+/* Register operands.  */
+struct register_operand
+{
+  struct operand parent;
+  int reg;
+};
+
+
+/* Simple memory operands.  ie, direct memory,
+   no index, no pre/post inc/dec.  May be either relative or absolute.
+   Eg st d0, 0x123456  */
+struct simple_memory_operand
+{
+  struct operand parent;
+
+  bfd_vma addr;
+  bfd_vma base;
+  bool relative;
+};
+
+
+/* Memory operands.    Should be able to represent all memory
+   operands in the S12Z instruction set which are not simple
+   memory operands.  */
+struct memory_operand
+{
+  struct operand parent;
+
+  /* True for indirect operands: eg [0x123456]   */
+  bool indirect;
+
+  /* The value of any offset.  eg 45 in (45,d7) */
+    int base_offset;
+
+  /* Does this operand increment or decrement
+     its participating registers.  Eg (-s) */
+  enum op_reg_mutation mutation;
+
+  /* The number of registers participating in this operand.
+     For S12Z this is always in the range [0, 6] (but for most
+     instructions it's <= 2).  */
+  int n_regs;
+
+  /* The participating registers.  */
+  int regs[6];
+};
+
+
+/* Decode a single instruction.
+   OPERATOR, OSIZE, N_OPERANDS and OPERANDS are pointers to
+   variables which must be provided by the caller.
+   N_OPERANDS will be incremented by the number of operands read, so
+   you should assign it to something before calling this function.
+   OPERANDS must be large enough to contain all operands read
+   (which may be up to 6).
+   It is the responsibility of the caller to free all operands
+   when they are no longer needed.
+   Returns the number of bytes read.  */
+int decode_s12z (enum operator *myoperator, short *osize,
+		 int *n_operands, struct operand **operands,
+		 struct mem_read_abstraction_base *);
+
+
+#endif /* S12Z_OPC_H  */
-- 
2.11.0


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]