Wed Jul 13 18:01:58 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
authorKen Raeburn <raeburn@cygnus>
Wed, 13 Jul 1994 22:05:52 +0000 (22:05 +0000)
committerKen Raeburn <raeburn@cygnus>
Wed, 13 Jul 1994 22:05:52 +0000 (22:05 +0000)
* ns32k-dis.c: Deleted all code in "#ifdef GDB".
(invalid_float): Enabled general version, doesn't require running
on ns32k host.

Sun Jul 10 00:27:47 1994  Ian Dall  (dall@hfrd.dsto.gov.au)

* opcodes/ns32k-dis.c: Semi-new file.  Had apparently been dropped
from distribution. A ns32k-dis.c from a previous distribution has
been brought up to date and supports the new interface.

* disaaemble.c: define ARCH_ns32k and add case bfd_arch_ns32k.

* configure.in: add bfd_ns32k_arch target support.

* Makefile.in: add ns32k-dis.o to ALL_MACHINES.
Add ns32k-dis.c to CFILES. Add dependencies for ns32k-dis.o.

opcodes/ChangeLog
opcodes/ns32k-dis.c [new file with mode: 0644]

index 62894c98ceb50351931d45a9582baee0de05aadd..0cb8a6d7ac2a417dbac9f69017574ff9e2f9188f 100644 (file)
@@ -1,3 +1,27 @@
+Wed Jul 13 18:01:58 1994  Ken Raeburn  (raeburn@cujo.cygnus.com)
+
+       * ns32k-dis.c: Deleted all code in "#ifdef GDB".
+       (invalid_float): Enabled general version, doesn't require running
+       on ns32k host.
+
+Sun Jul 10 00:27:47 1994  Ian Dall  (dall@hfrd.dsto.gov.au)
+
+       * opcodes/ns32k-dis.c: Semi-new file.  Had apparently been dropped
+       from distribution. A ns32k-dis.c from a previous distribution has
+       been brought up to date and supports the new interface.
+
+       * disaaemble.c: define ARCH_ns32k and add case bfd_arch_ns32k.
+
+       * configure.in: add bfd_ns32k_arch target support.
+
+       * Makefile.in: add ns32k-dis.o to ALL_MACHINES.
+       Add ns32k-dis.c to CFILES. Add dependencies for ns32k-dis.o.
+
+Wed Jun 29 22:10:37 1994  Steve Chamberlain  (sac@cygnus.com)
+
+       * h8300-dis.c (bfd_h8_disassemble): Get 16bit branch
+       disassembly right.
+
 Tue Jun 28 13:22:06 1994  Stan Shebs  (shebs@andros.cygnus.com)
 
        * h8300-dis.c, mips-dis.c: Don't use true and false.
diff --git a/opcodes/ns32k-dis.c b/opcodes/ns32k-dis.c
new file mode 100644 (file)
index 0000000..1cacee4
--- /dev/null
@@ -0,0 +1,846 @@
+/* Print National Semiconductor 32000 instructions.
+   Copyright 1986, 1988, 1991, 1992, 1994 Free Software Foundation, Inc.
+
+This file is part of opcodes library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "dis-asm.h"
+#if !defined(const) && !defined(__STDC__)
+#define const
+#endif
+#include "opcode/ns32k.h"
+
+static disassemble_info *dis_info;
+
+/*
+ * Hacks to get it to compile <= READ THESE AS FIXES NEEDED
+ */
+#define CORE_ADDR unsigned long
+#define INVALID_FLOAT(val, size) invalid_float(val, size)
+
+static long read_memory_integer(addr, nr)
+     unsigned char *addr;
+     int nr;
+{
+  long val;
+  int i;
+  for (val = 0, i = nr - 1; i >= 0; i--) {
+    val =  (val << 8);
+    val |= (0xff & *(addr + i));
+  }
+  return val;
+}
+
+/* 32000 instructions are never longer than this.  */
+#define MAXLEN 62
+
+
+#include <setjmp.h>
+
+struct private
+{
+  /* Points to first byte not fetched.  */
+  bfd_byte *max_fetched;
+  bfd_byte the_buffer[MAXLEN];
+  bfd_vma insn_start;
+  jmp_buf bailout;
+};
+
+
+/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
+   to ADDR (exclusive) are valid.  Returns 1 for success, longjmps
+   on error.  */
+#define FETCH_DATA(info, addr) \
+  ((addr) <= ((struct private *)(info->private_data))->max_fetched \
+   ? 1 : fetch_data ((info), (addr)))
+
+static int
+fetch_data (info, addr)
+     struct disassemble_info *info;
+     bfd_byte *addr;
+{
+  int status;
+  struct private *priv = (struct private *)info->private_data;
+  bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
+
+  status = (*info->read_memory_func) (start,
+                                     priv->max_fetched,
+                                     addr - priv->max_fetched,
+                                     info);
+  if (status != 0)
+    {
+      (*info->memory_error_func) (status, start, info);
+      longjmp (priv->bailout, 1);
+    }
+  else
+    priv->max_fetched = addr;
+  return 1;
+}
+/* Number of elements in the opcode table.  */
+#define NOPCODES (sizeof ns32k_opcodes / sizeof ns32k_opcodes[0])
+
+#define NEXT_IS_ADDR   '|'
+
+\f
+struct option {
+  char *pattern;               /* the option itself */
+  unsigned long value;         /* binary value of the option */
+  unsigned long match;         /* these bits must match */
+};
+
+\f
+static struct option opt_u[]= /* restore, exit */
+{
+  { "r0",      0x80,   0x80    },
+  { "r1",      0x40,   0x40    },
+  { "r2",      0x20,   0x20    },
+  { "r3",      0x10,   0x10    },
+  { "r4",      0x08,   0x08    },
+  { "r5",      0x04,   0x04    },
+  { "r6",      0x02,   0x02    },
+  { "r7",      0x01,   0x01    },
+  {  0 ,       0x00,   0x00    }
+};
+
+static struct option opt_U[]= /* save, enter */
+{
+  { "r0",      0x01,   0x01    },
+  { "r1",      0x02,   0x02    },
+  { "r2",      0x04,   0x04    },
+  { "r3",      0x08,   0x08    },
+  { "r4",      0x10,   0x10    },
+  { "r5",      0x20,   0x20    },
+  { "r6",      0x40,   0x40    },
+  { "r7",      0x80,   0x80    },
+  {  0 ,       0x00,   0x00    }
+};
+
+static struct option opt_O[]= /* setcfg */
+{
+  { "c",       0x8,    0x8     },
+  { "m",       0x4,    0x4     },
+  { "f",       0x2,    0x2     },
+  { "i",       0x1,    0x1     },
+  {  0 ,       0x0,    0x0     }
+};
+
+static struct option opt_C[]= /* cinv */
+{
+  { "a",       0x4,    0x4     },
+  { "i",       0x2,    0x2     },
+  { "d",       0x1,    0x1     },
+  {  0 ,       0x0,    0x0     }
+};
+
+static struct option opt_S[]= /* string inst */
+{
+  { "b",       0x1,    0x1     },
+  { "u",       0x6,    0x6     },
+  { "w",       0x2,    0x2     },
+  {  0 ,       0x0,    0x0     }
+};
+
+static struct option list_P532[]= /* lpr spr */
+{
+  { "us",      0x0,    0xf     },
+  { "dcr",     0x1,    0xf     },
+  { "bpc",     0x2,    0xf     },
+  { "dsr",     0x3,    0xf     },
+  { "car",     0x4,    0xf     },
+  { "fp",      0x8,    0xf     },
+  { "sp",      0x9,    0xf     },
+  { "sb",      0xa,    0xf     },
+  { "usp",     0xb,    0xf     },
+  { "cfg",     0xc,    0xf     },
+  { "psr",     0xd,    0xf     },
+  { "intbase", 0xe,    0xf     },
+  { "mod",     0xf,    0xf     },
+  {  0 ,       0x00,   0xf     }
+};
+
+static struct option list_M532[]= /* lmr smr */
+{
+  { "mcr",     0x9,    0xf     },
+  { "msr",     0xa,    0xf     },
+  { "tear",    0xb,    0xf     },
+  { "ptb0",    0xc,    0xf     },
+  { "ptb1",    0xd,    0xf     },
+  { "ivar0",   0xe,    0xf     },
+  { "ivar1",   0xf,    0xf     },
+  {  0 ,       0x0,    0xf     }
+};
+
+static struct option list_P032[]= /* lpr spr */
+{
+  { "upsr",    0x0,    0xf     },
+  { "fp",      0x8,    0xf     },
+  { "sp",      0x9,    0xf     },
+  { "sb",      0xa,    0xf     },
+  { "psr",     0xb,    0xf     },
+  { "intbase", 0xe,    0xf     },
+  { "mod",     0xf,    0xf     },
+  {  0 ,       0x0,    0xf     }
+};
+
+static struct option list_M032[]= /* lmr smr */
+{
+  { "bpr0",    0x0,    0xf     },
+  { "bpr1",    0x1,    0xf     },
+  { "pf0",     0x4,    0xf     },
+  { "pf1",     0x5,    0xf     },
+  { "sc",      0x8,    0xf     },
+  { "msr",     0xa,    0xf     },
+  { "bcnt",    0xb,    0xf     },
+  { "ptb0",    0xc,    0xf     },
+  { "ptb1",    0xd,    0xf     },
+  { "eia",     0xf,    0xf     },
+  {  0 ,       0x0,    0xf     }
+};
+
+
+/*
+ * figure out which options are present
+ */
+static void
+optlist(options, optionP, result)
+    int options;
+    struct option *optionP;
+    char *result;
+{
+    if (options == 0) {
+       sprintf(result, "[]");
+       return;
+    }
+    sprintf(result, "[");
+
+    for (; (options != 0) && optionP->pattern; optionP++) {
+       if ((options & optionP->match) == optionP->value) {
+           /* we found a match, update result and options */
+           strcat(result, optionP->pattern);
+           options &= ~optionP->value;
+           if (options != 0)   /* more options to come */
+               strcat(result, ",");
+       }
+    }
+    if (options != 0)
+       strcat(result, "undefined");
+
+    strcat(result, "]");
+}
+
+static list_search(reg_value, optionP, result)
+    int reg_value;
+    struct option *optionP;
+    char *result;
+{
+    for (; optionP->pattern; optionP++) {
+       if ((reg_value & optionP->match) == optionP->value) {
+           sprintf(result, "%s", optionP->pattern);
+           return;
+       }
+    }
+    sprintf(result, "undefined");
+}
+\f
+/*
+ * extract "count" bits starting "offset" bits
+ * into buffer
+ */
+
+static int
+bit_extract (buffer, offset, count)
+     bfd_byte *buffer;
+     int offset;
+     int count;
+{
+  int result;
+  int mask;
+  int bit;
+
+  buffer += offset >> 3;
+  offset &= 7;
+  bit = 1;
+  result = 0;
+  while (count--)
+    {
+      FETCH_DATA(dis_info, buffer + 1);
+      if ((*buffer & (1 << offset)))
+       result |= bit;
+      if (++offset == 8)
+       {
+         offset = 0;
+         buffer++;
+       }
+      bit <<= 1;
+    }
+  return result;
+}
+
+static void
+bit_copy (buffer, offset, count, to)
+     char *buffer;
+     int offset;
+     int count;
+     char *to;
+{
+  for(; count > 8; count -= 8, to++, offset += 8)
+    *to = bit_extract (buffer, offset, 8);
+  *to = bit_extract (buffer, offset, count);
+}
+
+
+static sign_extend (value, bits)
+     int value, bits;
+{
+  value = value & ((1 << bits) - 1);
+  return (value & (1 << (bits-1))
+         ? value | (~((1 << bits) - 1))
+         : value);
+}
+
+static flip_bytes (ptr, count)
+     char *ptr;
+     int count;
+{
+  char tmp;
+
+  while (count > 0)
+    {
+      tmp = ptr[0];
+      ptr[0] = ptr[count-1];
+      ptr[count-1] = tmp;
+      ptr++;
+      count -= 2;
+    }
+}
+\f
+/* Given a character C, does it represent a general addressing mode?  */
+#define Is_gen(c) \
+  ((c) == 'F' || (c) == 'L' || (c) == 'B' \
+   || (c) == 'W' || (c) == 'D' || (c) == 'A' || (c) == 'I' || (c) == 'Z')
+
+/* Adressing modes.  */
+#define Adrmod_index_byte 0x1c
+#define Adrmod_index_word 0x1d
+#define Adrmod_index_doubleword 0x1e
+#define Adrmod_index_quadword 0x1f
+
+/* Is MODE an indexed addressing mode?  */
+#define Adrmod_is_index(mode) \
+  (mode == Adrmod_index_byte \
+   || mode == Adrmod_index_word \
+   || mode == Adrmod_index_doubleword \
+   || mode == Adrmod_index_quadword)
+
+\f
+/* Print the 32000 instruction at address MEMADDR in debugged memory,
+   on STREAM.  Returns length of the instruction, in bytes.  */
+
+int
+print_insn_ns32k (memaddr, info)
+     bfd_vma memaddr;
+     disassemble_info *info;
+{
+  register int i;
+  register unsigned char *p;
+  register char *d;
+  unsigned short first_word;
+  int gen, disp;
+  int ioffset;         /* bits into instruction */
+  int aoffset;         /* bits into arguments */
+  char arg_bufs[MAX_ARGS+1][ARG_LEN];
+  int argnum;
+  int maxarg;
+  struct private priv;
+  bfd_byte *buffer = priv.the_buffer;
+  dis_info = info;
+
+  info->private_data = (PTR) &priv;
+  priv.max_fetched = priv.the_buffer;
+  priv.insn_start = memaddr;
+  if (setjmp (priv.bailout) != 0)
+    /* Error return.  */
+    return -1;
+
+  /* Look for 8bit opcodes first. Other wise, fetching two bytes could take
+   * us over the end of accessible data unnecessarilly
+   */
+  FETCH_DATA(info, buffer + 1);
+  for (i = 0; i < NOPCODES; i++)
+    if (ns32k_opcodes[i].opcode_id_size <= 8
+       && ((buffer[0] & ((1 << ns32k_opcodes[i].opcode_id_size) - 1))
+           == ns32k_opcodes[i].opcode_seed))
+      break;
+  if (i == NOPCODES) {
+    /* Maybe it is 9 to 16 bits big */
+    FETCH_DATA(info, buffer + 2);
+    first_word = read_memory_integer(buffer, 2);
+
+    for (i = 0; i < NOPCODES; i++)
+      if ((first_word & ((1 << ns32k_opcodes[i].opcode_id_size) - 1))
+         == ns32k_opcodes[i].opcode_seed)
+       break;
+
+    /* Handle undefined instructions.  */
+    if (i == NOPCODES)
+      {
+       (*dis_info->fprintf_func)(dis_info->stream, "0%o", buffer[0]);
+       return 1;
+      }
+  }
+
+  (*dis_info->fprintf_func)(dis_info->stream, "%s", ns32k_opcodes[i].name);
+
+  ioffset = ns32k_opcodes[i].opcode_size;
+  aoffset = ns32k_opcodes[i].opcode_size;
+  d = ns32k_opcodes[i].operands;
+
+  if (*d)
+    {
+      /* Offset in bits of the first thing beyond each index byte.
+        Element 0 is for operand A and element 1 is for operand B.
+        The rest are irrelevant, but we put them here so we don't
+        index outside the array.  */
+      int index_offset[MAX_ARGS];
+
+      /* 0 for operand A, 1 for operand B, greater for other args.  */
+      int whicharg = 0;
+      
+      (*dis_info->fprintf_func)(dis_info->stream, "\t");
+
+      maxarg = 0;
+
+      /* First we have to find and keep track of the index bytes,
+        if we are using scaled indexed addressing mode, since the index
+        bytes occur right after the basic instruction, not as part
+        of the addressing extension.  */
+      if (Is_gen(d[1]))
+       {
+         int addr_mode = bit_extract (buffer, ioffset - 5, 5);
+
+         if (Adrmod_is_index (addr_mode))
+           {
+             aoffset += 8;
+             index_offset[0] = aoffset;
+           }
+       }
+      if (d[2] && Is_gen(d[3]))
+       {
+         int addr_mode = bit_extract (buffer, ioffset - 10, 5);
+
+         if (Adrmod_is_index (addr_mode))
+           {
+             aoffset += 8;
+             index_offset[1] = aoffset;
+           }
+       }
+
+      while (*d)
+       {
+         argnum = *d - '1';
+         d++;
+         if (argnum > maxarg && argnum < MAX_ARGS)
+           maxarg = argnum;
+         ioffset = print_insn_arg (*d, ioffset, &aoffset, buffer,
+                                   memaddr, arg_bufs[argnum],
+                                   index_offset[whicharg]);
+         d++;
+         whicharg++;
+       }
+      for (argnum = 0; argnum <= maxarg; argnum++)
+       {
+         CORE_ADDR addr;
+         char *ch;
+         for (ch = arg_bufs[argnum]; *ch;)
+           {
+             if (*ch == NEXT_IS_ADDR)
+               {
+                 ++ch;
+                 addr = atoi (ch);
+                 (*dis_info->print_address_func) (addr, dis_info);
+                 while (*ch && *ch != NEXT_IS_ADDR)
+                   ++ch;
+                 if (*ch)
+                   ++ch;
+               }
+             else
+               (*dis_info->fprintf_func)(dis_info->stream, "%c", *ch++);
+           }
+         if (argnum < maxarg)
+           (*dis_info->fprintf_func)(dis_info->stream, ", ");
+       }
+    }
+  return aoffset / 8;
+}
+
+/* Print an instruction operand of category given by d.  IOFFSET is
+   the bit position below which small (<1 byte) parts of the operand can
+   be found (usually in the basic instruction, but for indexed
+   addressing it can be in the index byte).  AOFFSETP is a pointer to the
+   bit position of the addressing extension.  BUFFER contains the
+   instruction.  ADDR is where BUFFER was read from.  Put the disassembled
+   version of the operand in RESULT.  INDEX_OFFSET is the bit position
+   of the index byte (it contains garbage if this operand is not a
+   general operand using scaled indexed addressing mode).  */
+
+print_insn_arg (d, ioffset, aoffsetp, buffer, addr, result, index_offset)
+     char d;
+     int ioffset, *aoffsetp;
+     char *buffer;
+     CORE_ADDR addr;
+     char *result;
+     int index_offset;
+{
+  int addr_mode;
+  float Fvalue;
+  double Lvalue;
+  int Ivalue;
+  int disp1, disp2;
+  int index;
+  int size;
+
+  switch (d)
+    {
+    case 'f':
+      /* a "gen" operand but 5 bits from the end of instruction */
+      ioffset -= 5;
+    case 'Z':
+    case 'F':
+    case 'L':
+    case 'I':
+    case 'B':
+    case 'W':
+    case 'D':
+    case 'A':
+      addr_mode = bit_extract (buffer, ioffset-5, 5);
+      ioffset -= 5;
+      switch (addr_mode)
+       {
+       case 0x0: case 0x1: case 0x2: case 0x3:
+       case 0x4: case 0x5: case 0x6: case 0x7:
+         /* register mode R0 -- R7 */
+         switch (d)
+           {
+           case 'F':
+           case 'L':
+           case 'Z':
+             sprintf (result, "f%d", addr_mode);
+             break;
+           default:
+             sprintf (result, "r%d", addr_mode);
+           }
+         break;
+       case 0x8: case 0x9: case 0xa: case 0xb:
+       case 0xc: case 0xd: case 0xe: case 0xf:
+         /* Register relative disp(R0 -- R7) */
+         disp1 = get_displacement (buffer, aoffsetp);
+         sprintf (result, "%d(r%d)", disp1, addr_mode & 7);
+         break;
+       case 0x10:
+       case 0x11:
+       case 0x12:
+         /* Memory relative disp2(disp1(FP, SP, SB)) */
+         disp1 = get_displacement (buffer, aoffsetp);
+         disp2 = get_displacement (buffer, aoffsetp);
+         sprintf (result, "%d(%d(%s))", disp2, disp1,
+                  addr_mode==0x10?"fp":addr_mode==0x11?"sp":"sb");
+         break;
+       case 0x13:
+         /* reserved */
+         sprintf (result, "reserved");
+         break;
+       case 0x14:
+         /* Immediate */
+         switch (d)
+           {
+           case 'I': case 'Z': case 'A':
+             /* I and Z are output operands and can`t be immediate
+              * A is an address and we can`t have the address of
+              * an immediate either. We don't know how much to increase
+              * aoffsetp by since whatever generated this is broken
+              * anyway!
+              */
+             sprintf (result, "$<undefined>");
+             break;
+           case 'B':
+             Ivalue = bit_extract (buffer, *aoffsetp, 8);
+             Ivalue = sign_extend (Ivalue, 8);
+             *aoffsetp += 8;
+             sprintf (result, "$%d", Ivalue);
+             break;
+           case 'W':
+             Ivalue = bit_extract (buffer, *aoffsetp, 16);
+             flip_bytes (&Ivalue, 2);
+             *aoffsetp += 16;
+             Ivalue = sign_extend (Ivalue, 16);
+             sprintf (result, "$%d", Ivalue);
+             break;
+           case 'D':
+             Ivalue = bit_extract (buffer, *aoffsetp, 32);
+             flip_bytes (&Ivalue, 4);
+             *aoffsetp += 32;
+             sprintf (result, "$%d", Ivalue);
+             break;
+           case 'F':
+             bit_copy (buffer, *aoffsetp, 32, (char *) &Fvalue);
+             flip_bytes (&Fvalue, 4);
+             *aoffsetp += 32;
+             if (INVALID_FLOAT (&Fvalue, 4))
+               sprintf (result, "<<invalid float 0x%.8x>>", *(int *) &Fvalue);
+             else /* assume host has ieee float */
+               sprintf (result, "$%g", Fvalue);
+             break;
+           case 'L':
+             bit_copy (buffer, *aoffsetp, 64, (char *) &Lvalue);
+             flip_bytes (&Lvalue, 8);
+             *aoffsetp += 64;
+             if (INVALID_FLOAT (&Lvalue, 8))
+               sprintf (result, "<<invalid long 0x%.8x%.8x>>",
+                        *(((int *) &Lvalue) + 1), *(int *) &Lvalue);
+             else /* assume host has ieee float */
+               sprintf (result, "$%g", Lvalue);
+             break;
+           }
+         break;
+       case 0x15:
+         /* Absolute @disp */
+         disp1 = get_displacement (buffer, aoffsetp);
+         sprintf (result, "@|%d|", disp1);
+         break;
+       case 0x16:
+         /* External EXT(disp1) + disp2 (Mod table stuff) */
+         disp1 = get_displacement (buffer, aoffsetp);
+         disp2 = get_displacement (buffer, aoffsetp);
+         sprintf (result, "EXT(%d) + %d", disp1, disp2);
+         break;
+       case 0x17:
+         /* Top of stack tos */
+         sprintf (result, "tos");
+         break;
+       case 0x18:
+         /* Memory space disp(FP) */
+         disp1 = get_displacement (buffer, aoffsetp);
+         sprintf (result, "%d(fp)", disp1);
+         break;
+       case 0x19:
+         /* Memory space disp(SP) */
+         disp1 = get_displacement (buffer, aoffsetp);
+         sprintf (result, "%d(sp)", disp1);
+         break;
+       case 0x1a:
+         /* Memory space disp(SB) */
+         disp1 = get_displacement (buffer, aoffsetp);
+         sprintf (result, "%d(sb)", disp1);
+         break;
+       case 0x1b:
+         /* Memory space disp(PC) */
+         disp1 = get_displacement (buffer, aoffsetp);
+         sprintf (result, "|%d|", addr + disp1);
+         break;
+       case 0x1c:
+       case 0x1d:
+       case 0x1e:
+       case 0x1f:
+         /* Scaled index basemode[R0 -- R7:B,W,D,Q] */
+         index = bit_extract (buffer, index_offset - 8, 3);
+         print_insn_arg (d, index_offset, aoffsetp, buffer, addr,
+                         result, 0);
+         {
+           static char *ind[] = {"b", "w", "d", "q"};
+           char *off;
+
+           off = result + strlen (result);
+           sprintf (off, "[r%d:%s]", index,
+                    ind[addr_mode & 3]);
+         }
+         break;
+       }
+      break;
+    case 'H':
+    case 'q':
+      Ivalue = bit_extract (buffer, ioffset-4, 4);
+      Ivalue = sign_extend (Ivalue, 4);
+      sprintf (result, "%d", Ivalue);
+      ioffset -= 4;
+      break;
+    case 'r':
+      Ivalue = bit_extract (buffer, ioffset-3, 3);
+      sprintf (result, "r%d", Ivalue&7);
+      ioffset -= 3;
+      break;
+    case 'd':
+      sprintf (result, "%d", get_displacement (buffer, aoffsetp));
+      break;
+    case 'b':
+      Ivalue = get_displacement (buffer, aoffsetp);
+      /*
+       * Warning!!  HACK ALERT!
+       * Operand type 'b' is only used by the cmp{b,w,d} and
+       * movm{b,w,d} instructions; we need to know whether
+       * it's a `b' or `w' or `d' instruction; and for both
+       * cmpm and movm it's stored at the same place so we
+       * just grab two bits of the opcode and look at it...
+       * 
+       */
+      size = bit_extract(buffer, ioffset-6, 2);
+      if (size == 0)           /* 00 => b */
+       size = 1;
+      else if (size == 1)      /* 01 => w */
+       size = 2;
+      else
+       size = 4;               /* 11 => d */
+
+      sprintf (result, "%d", (Ivalue / size) + 1);
+      break;
+    case 'p':
+      sprintf (result, "%c%d%c", NEXT_IS_ADDR,
+              addr + get_displacement (buffer, aoffsetp),
+              NEXT_IS_ADDR);
+      break;
+    case 'i':
+      Ivalue = bit_extract (buffer, *aoffsetp, 8);
+      *aoffsetp += 8;
+      sprintf (result, "0x%x", Ivalue);
+      break;
+    case 'u':
+      Ivalue = bit_extract (buffer, *aoffsetp, 8);
+      optlist(Ivalue, opt_u, result);
+      *aoffsetp += 8;
+      break;
+    case 'U':
+      Ivalue = bit_extract(buffer, *aoffsetp, 8);
+      optlist(Ivalue, opt_U, result);
+      *aoffsetp += 8;
+      break;
+    case 'O':
+      Ivalue = bit_extract(buffer, ioffset-9, 9);
+      optlist(Ivalue, opt_O, result);
+      ioffset -= 9;
+      break;
+    case 'C':
+      Ivalue = bit_extract(buffer, ioffset-4, 4);
+      optlist(Ivalue, opt_C, result);
+      ioffset -= 4;
+      break;
+    case 'S':
+      Ivalue = bit_extract(buffer, ioffset - 8, 8);
+      optlist(Ivalue, opt_S, result);
+      ioffset -= 8;
+      break;
+    case 'M':
+      Ivalue = bit_extract(buffer, ioffset-4, 4);
+      list_search(Ivalue, 0 ? list_M032 : list_M532, result);
+      ioffset -= 4;
+      break;
+    case 'P':
+      Ivalue = bit_extract(buffer, ioffset-4, 4);
+      list_search(Ivalue, 0 ? list_P032 : list_P532, result);
+      ioffset -= 4;
+      break;
+    case 'g':
+      Ivalue = bit_extract(buffer, *aoffsetp, 3);
+      sprintf(result, "%d", Ivalue);
+      *aoffsetp += 3;
+      break;
+    case 'G':
+      Ivalue = bit_extract(buffer, *aoffsetp, 5);
+      sprintf(result, "%d", Ivalue + 1);
+      *aoffsetp += 5;
+      break;
+    }
+  return ioffset;
+}
+
+get_displacement (buffer, aoffsetp)
+     char *buffer;
+     int *aoffsetp;
+{
+  int Ivalue;
+  short Ivalue2;
+
+  Ivalue = bit_extract (buffer, *aoffsetp, 8);
+  switch (Ivalue & 0xc0)
+    {
+    case 0x00:
+    case 0x40:
+      Ivalue = sign_extend (Ivalue, 7);
+      *aoffsetp += 8;
+      break;
+    case 0x80:
+      Ivalue2 = bit_extract (buffer, *aoffsetp, 16);
+      flip_bytes (&Ivalue2, 2);
+      Ivalue = sign_extend (Ivalue2, 14);
+      *aoffsetp += 16;
+      break;
+    case 0xc0:
+      Ivalue = bit_extract (buffer, *aoffsetp, 32);
+      flip_bytes (&Ivalue, 4);
+      Ivalue = sign_extend (Ivalue, 30);
+      *aoffsetp += 32;
+      break;
+    }
+  return Ivalue;
+}
+\f
+
+#if 1 /* a version that should work on ns32k f's&d's on any machine */
+int invalid_float(p, len)
+     register union { double d; float f; } *p;
+     register int len;
+{
+  register val;
+
+  if ( len == sizeof (float) )
+    val = (bit_extract(&p.f, 23, 8)/*exponent*/ == 0xff
+          || (bit_extract(&p, 23, 8)/*exponent*/ == 0 &&
+              bit_extract(&p, 0, 23)/*mantisa*/ != 0));
+  else if ( len == sizeof (double) )
+    val = (bit_extract(&p.d, 52, 11)/*exponent*/ == 0x7ff
+          || (bit_extract(&p, 52, 11)/*exponent*/ == 0
+              && (bit_extract(&p, 0, 32)/*low mantisa*/ != 0
+                  || bit_extract(&p, 32, 20)/*high mantisa*/ != 0)));
+  else
+    val = 1;
+  return (val);
+}
+#else
+
+/* assumes the bytes have been swapped to local order */
+typedef union { double d;
+               float f;
+               struct { unsigned m:23, e:8, :1;} sf;
+               struct { unsigned lm; unsigned m:20, e:11, :1;} sd;
+             } float_type_u;
+
+int invalid_float(p, len)
+     register float_type_u *p;
+     register int len;
+{
+  register int val;
+  if ( len == sizeof (float) )
+    val = (p->sf.e == 0xff
+          || (p->sf.e == 0 && p->sf.m != 0));
+  else if ( len == sizeof (double) )
+    val = (p->sd.e == 0x7ff
+          || (p->sd.e == 0 && (p->sd.m != 0 || p->sd.lm != 0)));
+  else
+    val = 1;
+  return (val);
+}
+#endif