Back to index

cell-binutils  2.17cvs20070401
ns32k-dis.c
Go to the documentation of this file.
00001 /* Print National Semiconductor 32000 instructions.
00002    Copyright 1986, 1988, 1991, 1992, 1994, 1998, 2001, 2002, 2005
00003    Free Software Foundation, Inc.
00004 
00005    This file is part of opcodes library.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software
00019    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
00020    MA 02110-1301, USA.  */
00021 
00022 
00023 #include "bfd.h"
00024 #include "sysdep.h"
00025 #include "dis-asm.h"
00026 #if !defined(const) && !defined(__STDC__)
00027 #define const
00028 #endif
00029 #include "opcode/ns32k.h"
00030 #include "opintl.h"
00031 
00032 static disassemble_info *dis_info;
00033 
00034 /* Hacks to get it to compile <= READ THESE AS FIXES NEEDED.  */
00035 #define INVALID_FLOAT(val, size) invalid_float ((bfd_byte *) val, size)
00036 
00037 static long
00038 read_memory_integer (unsigned char * addr, int nr)
00039 {
00040   long val;
00041   int i;
00042 
00043   for (val = 0, i = nr - 1; i >= 0; i--)
00044     {
00045       val =  (val << 8);
00046       val |= (0xff & *(addr + i));
00047     }
00048   return val;
00049 }
00050 
00051 /* 32000 instructions are never longer than this.  */
00052 #define MAXLEN 62
00053 
00054 #include <setjmp.h>
00055 
00056 struct private
00057 {
00058   /* Points to first byte not fetched.  */
00059   bfd_byte *max_fetched;
00060   bfd_byte the_buffer[MAXLEN];
00061   bfd_vma insn_start;
00062   jmp_buf bailout;
00063 };
00064 
00065 
00066 /* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
00067    to ADDR (exclusive) are valid.  Returns 1 for success, longjmps
00068    on error.  */
00069 #define FETCH_DATA(info, addr) \
00070   ((addr) <= ((struct private *)(info->private_data))->max_fetched \
00071    ? 1 : fetch_data ((info), (addr)))
00072 
00073 static int
00074 fetch_data (struct disassemble_info *info, bfd_byte *addr)
00075 {
00076   int status;
00077   struct private *priv = (struct private *) info->private_data;
00078   bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
00079 
00080   status = (*info->read_memory_func) (start,
00081                                   priv->max_fetched,
00082                                   addr - priv->max_fetched,
00083                                   info);
00084   if (status != 0)
00085     {
00086       (*info->memory_error_func) (status, start, info);
00087       longjmp (priv->bailout, 1);
00088     }
00089   else
00090     priv->max_fetched = addr;
00091   return 1;
00092 }
00093 
00094 /* Number of elements in the opcode table.  */
00095 #define NOPCODES (sizeof ns32k_opcodes / sizeof ns32k_opcodes[0])
00096 
00097 #define NEXT_IS_ADDR '|'
00098 
00099 
00100 struct ns32k_option
00101 {
00102   char *pattern;            /* The option itself.  */
00103   unsigned long value;             /* Binary value of the option.  */
00104   unsigned long match;             /* These bits must match.  */
00105 };
00106 
00107 
00108 static const struct ns32k_option opt_u[]= /* Restore, exit.  */
00109 {
00110   { "r0",     0x80,  0x80   },
00111   { "r1",     0x40,  0x40   },
00112   { "r2",     0x20,  0x20   },
00113   { "r3",     0x10,  0x10   },
00114   { "r4",     0x08,  0x08   },
00115   { "r5",     0x04,  0x04   },
00116   { "r6",     0x02,  0x02   },
00117   { "r7",     0x01,  0x01   },
00118   {  0 ,      0x00,  0x00   }
00119 };
00120 
00121 static const struct ns32k_option opt_U[]= /* Save, enter.  */
00122 {
00123   { "r0",     0x01,  0x01   },
00124   { "r1",     0x02,  0x02   },
00125   { "r2",     0x04,  0x04   },
00126   { "r3",     0x08,  0x08   },
00127   { "r4",     0x10,  0x10   },
00128   { "r5",     0x20,  0x20   },
00129   { "r6",     0x40,  0x40   },
00130   { "r7",     0x80,  0x80   },
00131   {  0 ,      0x00,  0x00   }
00132 };
00133 
00134 static const struct ns32k_option opt_O[]= /* Setcfg.  */
00135 {
00136   { "c",      0x8,   0x8    },
00137   { "m",      0x4,   0x4    },
00138   { "f",      0x2,   0x2    },
00139   { "i",      0x1,   0x1    },
00140   {  0 ,      0x0,   0x0    }
00141 };
00142 
00143 static const struct ns32k_option opt_C[]= /* Cinv.  */
00144 {
00145   { "a",      0x4,   0x4    },
00146   { "i",      0x2,   0x2    },
00147   { "d",      0x1,   0x1    },
00148   {  0 ,      0x0,   0x0    }
00149 };
00150 
00151 static const struct ns32k_option opt_S[]= /* String inst.  */
00152 {
00153   { "b",      0x1,   0x1    },
00154   { "u",      0x6,   0x6    },
00155   { "w",      0x2,   0x2    },
00156   {  0 ,      0x0,   0x0    }
00157 };
00158 
00159 static const struct ns32k_option list_P532[]= /* Lpr spr.  */
00160 {
00161   { "us",     0x0,   0xf    },
00162   { "dcr",    0x1,   0xf    },
00163   { "bpc",    0x2,   0xf    },
00164   { "dsr",    0x3,   0xf    },
00165   { "car",    0x4,   0xf    },
00166   { "fp",     0x8,   0xf    },
00167   { "sp",     0x9,   0xf    },
00168   { "sb",     0xa,   0xf    },
00169   { "usp",    0xb,   0xf    },
00170   { "cfg",    0xc,   0xf    },
00171   { "psr",    0xd,   0xf    },
00172   { "intbase",       0xe,   0xf    },
00173   { "mod",    0xf,   0xf    },
00174   {  0 ,      0x00,  0xf    }
00175 };
00176 
00177 static const struct ns32k_option list_M532[]= /* Lmr smr.  */
00178 {
00179   { "mcr",    0x9,   0xf    },
00180   { "msr",    0xa,   0xf    },
00181   { "tear",   0xb,   0xf    },
00182   { "ptb0",   0xc,   0xf    },
00183   { "ptb1",   0xd,   0xf    },
00184   { "ivar0",  0xe,   0xf    },
00185   { "ivar1",  0xf,   0xf    },
00186   {  0 ,      0x0,   0xf    }
00187 };
00188 
00189 static const struct ns32k_option list_P032[]= /* Lpr spr.  */
00190 {
00191   { "upsr",   0x0,   0xf    },
00192   { "fp",     0x8,   0xf    },
00193   { "sp",     0x9,   0xf    },
00194   { "sb",     0xa,   0xf    },
00195   { "psr",    0xb,   0xf    },
00196   { "intbase",       0xe,   0xf    },
00197   { "mod",    0xf,   0xf    },
00198   {  0 ,      0x0,   0xf    }
00199 };
00200 
00201 static const struct ns32k_option list_M032[]= /* Lmr smr.  */
00202 {
00203   { "bpr0",   0x0,   0xf    },
00204   { "bpr1",   0x1,   0xf    },
00205   { "pf0",    0x4,   0xf    },
00206   { "pf1",    0x5,   0xf    },
00207   { "sc",     0x8,   0xf    },
00208   { "msr",    0xa,   0xf    },
00209   { "bcnt",   0xb,   0xf    },
00210   { "ptb0",   0xc,   0xf    },
00211   { "ptb1",   0xd,   0xf    },
00212   { "eia",    0xf,   0xf    },
00213   {  0 ,      0x0,   0xf    }
00214 };
00215 
00216 
00217 /* Figure out which options are present.   */
00218 
00219 static void
00220 optlist (int options, const struct ns32k_option * optionP, char * result)
00221 {
00222   if (options == 0)
00223     {
00224       sprintf (result, "[]");
00225       return;
00226     }
00227 
00228   sprintf (result, "[");
00229 
00230   for (; (options != 0) && optionP->pattern; optionP++)
00231     {
00232       if ((options & optionP->match) == optionP->value)
00233        {
00234          /* We found a match, update result and options.  */
00235          strcat (result, optionP->pattern);
00236          options &= ~optionP->value;
00237          if (options != 0)  /* More options to come.  */
00238            strcat (result, ",");
00239        }
00240     }
00241 
00242   if (options != 0)
00243     strcat (result, "undefined");
00244 
00245   strcat (result, "]");
00246 }
00247 
00248 static void
00249 list_search (int reg_value, const struct ns32k_option *optionP, char *result)
00250 {
00251   for (; optionP->pattern; optionP++)
00252     {
00253       if ((reg_value & optionP->match) == optionP->value)
00254        {
00255          sprintf (result, "%s", optionP->pattern);
00256          return;
00257        }
00258     }
00259   sprintf (result, "undefined");
00260 }
00261 
00262 /* Extract "count" bits starting "offset" bits into buffer.  */
00263 
00264 static int
00265 bit_extract (bfd_byte *buffer, int offset, int count)
00266 {
00267   int result;
00268   int bit;
00269 
00270   buffer += offset >> 3;
00271   offset &= 7;
00272   bit = 1;
00273   result = 0;
00274   while (count--)
00275     {
00276       FETCH_DATA (dis_info, buffer + 1);
00277       if ((*buffer & (1 << offset)))
00278        result |= bit;
00279       if (++offset == 8)
00280        {
00281          offset = 0;
00282          buffer++;
00283        }
00284       bit <<= 1;
00285     }
00286   return result;
00287 }
00288 
00289 /* Like bit extract but the buffer is valid and doen't need to be fetched.  */
00290 
00291 static int
00292 bit_extract_simple (bfd_byte *buffer, int offset, int count)
00293 {
00294   int result;
00295   int bit;
00296 
00297   buffer += offset >> 3;
00298   offset &= 7;
00299   bit = 1;
00300   result = 0;
00301   while (count--)
00302     {
00303       if ((*buffer & (1 << offset)))
00304        result |= bit;
00305       if (++offset == 8)
00306        {
00307          offset = 0;
00308          buffer++;
00309        }
00310       bit <<= 1;
00311     }
00312   return result;
00313 }
00314 
00315 static void
00316 bit_copy (bfd_byte *buffer, int offset, int count, char *to)
00317 {
00318   for (; count > 8; count -= 8, to++, offset += 8)
00319     *to = bit_extract (buffer, offset, 8);
00320   *to = bit_extract (buffer, offset, count);
00321 }
00322 
00323 static int
00324 sign_extend (int value, int bits)
00325 {
00326   value = value & ((1 << bits) - 1);
00327   return (value & (1 << (bits - 1))
00328          ? value | (~((1 << bits) - 1))
00329          : value);
00330 }
00331 
00332 static void
00333 flip_bytes (char *ptr, int count)
00334 {
00335   char tmp;
00336 
00337   while (count > 0)
00338     {
00339       tmp = ptr[0];
00340       ptr[0] = ptr[count - 1];
00341       ptr[count - 1] = tmp;
00342       ptr++;
00343       count -= 2;
00344     }
00345 }
00346 
00347 /* Given a character C, does it represent a general addressing mode?  */
00348 #define Is_gen(c) \
00349   ((c) == 'F' || (c) == 'L' || (c) == 'B' \
00350    || (c) == 'W' || (c) == 'D' || (c) == 'A' || (c) == 'I' || (c) == 'Z')
00351 
00352 /* Adressing modes.  */
00353 #define Adrmod_index_byte        0x1c
00354 #define Adrmod_index_word        0x1d
00355 #define Adrmod_index_doubleword  0x1e
00356 #define Adrmod_index_quadword    0x1f
00357 
00358 /* Is MODE an indexed addressing mode?  */
00359 #define Adrmod_is_index(mode) \
00360   (   mode == Adrmod_index_byte \
00361    || mode == Adrmod_index_word \
00362    || mode == Adrmod_index_doubleword \
00363    || mode == Adrmod_index_quadword)
00364 
00365 
00366 static int
00367 get_displacement (bfd_byte *buffer, int *aoffsetp)
00368 {
00369   int Ivalue;
00370   short Ivalue2;
00371 
00372   Ivalue = bit_extract (buffer, *aoffsetp, 8);
00373   switch (Ivalue & 0xc0)
00374     {
00375     case 0x00:
00376     case 0x40:
00377       Ivalue = sign_extend (Ivalue, 7);
00378       *aoffsetp += 8;
00379       break;
00380     case 0x80:
00381       Ivalue2 = bit_extract (buffer, *aoffsetp, 16);
00382       flip_bytes ((char *) & Ivalue2, 2);
00383       Ivalue = sign_extend (Ivalue2, 14);
00384       *aoffsetp += 16;
00385       break;
00386     case 0xc0:
00387       Ivalue = bit_extract (buffer, *aoffsetp, 32);
00388       flip_bytes ((char *) & Ivalue, 4);
00389       Ivalue = sign_extend (Ivalue, 30);
00390       *aoffsetp += 32;
00391       break;
00392     }
00393   return Ivalue;
00394 }
00395 
00396 #if 1 /* A version that should work on ns32k f's&d's on any machine.  */
00397 static int
00398 invalid_float (bfd_byte *p, int len)
00399 {
00400   int val;
00401 
00402   if (len == 4)
00403     val = (bit_extract_simple (p, 23, 8)/*exponent*/ == 0xff
00404           || (bit_extract_simple (p, 23, 8)/*exponent*/ == 0
00405               && bit_extract_simple (p, 0, 23)/*mantisa*/ != 0));
00406   else if (len == 8)
00407     val = (bit_extract_simple (p, 52, 11)/*exponent*/ == 0x7ff
00408           || (bit_extract_simple (p, 52, 11)/*exponent*/ == 0
00409               && (bit_extract_simple (p, 0, 32)/*low mantisa*/ != 0
00410                  || bit_extract_simple (p, 32, 20)/*high mantisa*/ != 0)));
00411   else
00412     val = 1;
00413   return (val);
00414 }
00415 #else
00416 /* Assumes the bytes have been swapped to local order.  */
00417 typedef union
00418 { 
00419   double d;
00420   float f;
00421   struct { unsigned m:23, e:8, :1;} sf;
00422   struct { unsigned lm; unsigned m:20, e:11, :1;} sd;
00423 } float_type_u;
00424 
00425 static int
00426 invalid_float (float_type_u *p, int len)
00427 {
00428   int val;
00429 
00430   if (len == sizeof (float))
00431     val = (p->sf.e == 0xff
00432           || (p->sf.e == 0 && p->sf.m != 0));
00433   else if (len == sizeof (double))
00434     val = (p->sd.e == 0x7ff
00435           || (p->sd.e == 0 && (p->sd.m != 0 || p->sd.lm != 0)));
00436   else
00437     val = 1;
00438   return val;
00439 }
00440 #endif
00441 
00442 /* Print an instruction operand of category given by d.  IOFFSET is
00443    the bit position below which small (<1 byte) parts of the operand can
00444    be found (usually in the basic instruction, but for indexed
00445    addressing it can be in the index byte).  AOFFSETP is a pointer to the
00446    bit position of the addressing extension.  BUFFER contains the
00447    instruction.  ADDR is where BUFFER was read from.  Put the disassembled
00448    version of the operand in RESULT.  INDEX_OFFSET is the bit position
00449    of the index byte (it contains garbage if this operand is not a
00450    general operand using scaled indexed addressing mode).  */
00451 
00452 static int
00453 print_insn_arg (int d,
00454               int ioffset,
00455               int *aoffsetp,
00456               bfd_byte *buffer,
00457               bfd_vma addr,
00458               char *result,
00459               int index_offset)
00460 {
00461   union
00462   {
00463     float f;
00464     double d;
00465     int i[2];
00466   } value;
00467   int Ivalue;
00468   int addr_mode;
00469   int disp1, disp2;
00470   int index;
00471   int size;
00472 
00473   switch (d)
00474     {
00475     case 'f':
00476       /* A "gen" operand but 5 bits from the end of instruction.  */
00477       ioffset -= 5;
00478     case 'Z':
00479     case 'F':
00480     case 'L':
00481     case 'I':
00482     case 'B':
00483     case 'W':
00484     case 'D':
00485     case 'A':
00486       addr_mode = bit_extract (buffer, ioffset - 5, 5);
00487       ioffset -= 5;
00488       switch (addr_mode)
00489        {
00490        case 0x0: case 0x1: case 0x2: case 0x3:
00491        case 0x4: case 0x5: case 0x6: case 0x7:
00492          /* Register mode R0 -- R7.  */
00493          switch (d)
00494            {
00495            case 'F':
00496            case 'L':
00497            case 'Z':
00498              sprintf (result, "f%d", addr_mode);
00499              break;
00500            default:
00501              sprintf (result, "r%d", addr_mode);
00502            }
00503          break;
00504        case 0x8: case 0x9: case 0xa: case 0xb:
00505        case 0xc: case 0xd: case 0xe: case 0xf:
00506          /* Register relative disp(R0 -- R7).  */
00507          disp1 = get_displacement (buffer, aoffsetp);
00508          sprintf (result, "%d(r%d)", disp1, addr_mode & 7);
00509          break;
00510        case 0x10:
00511        case 0x11:
00512        case 0x12:
00513          /* Memory relative disp2(disp1(FP, SP, SB)).  */
00514          disp1 = get_displacement (buffer, aoffsetp);
00515          disp2 = get_displacement (buffer, aoffsetp);
00516          sprintf (result, "%d(%d(%s))", disp2, disp1,
00517                  addr_mode == 0x10 ? "fp" : addr_mode == 0x11 ? "sp" : "sb");
00518          break;
00519        case 0x13:
00520          /* Reserved.  */
00521          sprintf (result, "reserved");
00522          break;
00523        case 0x14:
00524          /* Immediate.  */
00525          switch (d)
00526            {
00527            case 'I':
00528            case 'Z':
00529            case 'A':
00530              /* I and Z are output operands and can`t be immediate
00531                 A is an address and we can`t have the address of
00532                 an immediate either. We don't know how much to increase
00533                 aoffsetp by since whatever generated this is broken
00534                 anyway!  */
00535              sprintf (result, _("$<undefined>"));
00536              break;
00537            case 'B':
00538              Ivalue = bit_extract (buffer, *aoffsetp, 8);
00539              Ivalue = sign_extend (Ivalue, 8);
00540              *aoffsetp += 8;
00541              sprintf (result, "$%d", Ivalue);
00542              break;
00543            case 'W':
00544              Ivalue = bit_extract (buffer, *aoffsetp, 16);
00545              flip_bytes ((char *) & Ivalue, 2);
00546              *aoffsetp += 16;
00547              Ivalue = sign_extend (Ivalue, 16);
00548              sprintf (result, "$%d", Ivalue);
00549              break;
00550            case 'D':
00551              Ivalue = bit_extract (buffer, *aoffsetp, 32);
00552              flip_bytes ((char *) & Ivalue, 4);
00553              *aoffsetp += 32;
00554              sprintf (result, "$%d", Ivalue);
00555              break;
00556            case 'F':
00557              bit_copy (buffer, *aoffsetp, 32, (char *) &value.f);
00558              flip_bytes ((char *) &value.f, 4);
00559              *aoffsetp += 32;
00560              if (INVALID_FLOAT (&value.f, 4))
00561               sprintf (result, "<<invalid float 0x%.8x>>", value.i[0]);
00562              else /* Assume host has ieee float.  */
00563               sprintf (result, "$%g", value.f);
00564              break;
00565            case 'L':
00566              bit_copy (buffer, *aoffsetp, 64, (char *) &value.d);
00567              flip_bytes ((char *) &value.d, 8);
00568              *aoffsetp += 64;
00569              if (INVALID_FLOAT (&value.d, 8))
00570               sprintf (result, "<<invalid double 0x%.8x%.8x>>",
00571                       value.i[1], value.i[0]);
00572              else /* Assume host has ieee float.  */
00573               sprintf (result, "$%g", value.d);
00574              break;
00575            }
00576          break;
00577        case 0x15:
00578          /* Absolute @disp.  */
00579          disp1 = get_displacement (buffer, aoffsetp);
00580          sprintf (result, "@|%d|", disp1);
00581          break;
00582        case 0x16:
00583          /* External EXT(disp1) + disp2 (Mod table stuff).  */
00584          disp1 = get_displacement (buffer, aoffsetp);
00585          disp2 = get_displacement (buffer, aoffsetp);
00586          sprintf (result, "EXT(%d) + %d", disp1, disp2);
00587          break;
00588        case 0x17:
00589          /* Top of stack tos.  */
00590          sprintf (result, "tos");
00591          break;
00592        case 0x18:
00593          /* Memory space disp(FP).  */
00594          disp1 = get_displacement (buffer, aoffsetp);
00595          sprintf (result, "%d(fp)", disp1);
00596          break;
00597        case 0x19:
00598          /* Memory space disp(SP).  */
00599          disp1 = get_displacement (buffer, aoffsetp);
00600          sprintf (result, "%d(sp)", disp1);
00601          break;
00602        case 0x1a:
00603          /* Memory space disp(SB).  */
00604          disp1 = get_displacement (buffer, aoffsetp);
00605          sprintf (result, "%d(sb)", disp1);
00606          break;
00607        case 0x1b:
00608          /* Memory space disp(PC).  */
00609          disp1 = get_displacement (buffer, aoffsetp);
00610          *result++ = NEXT_IS_ADDR;
00611          sprintf_vma (result, addr + disp1);
00612          result += strlen (result);
00613          *result++ = NEXT_IS_ADDR;
00614          *result = '\0';
00615          break;
00616        case 0x1c:
00617        case 0x1d:
00618        case 0x1e:
00619        case 0x1f:
00620          /* Scaled index basemode[R0 -- R7:B,W,D,Q].  */
00621          index = bit_extract (buffer, index_offset - 8, 3);
00622          print_insn_arg (d, index_offset, aoffsetp, buffer, addr,
00623                        result, 0);
00624          {
00625            static const char *ind = "bwdq";
00626            char *off;
00627 
00628            off = result + strlen (result);
00629            sprintf (off, "[r%d:%c]", index,
00630                    ind[addr_mode & 3]);
00631          }
00632          break;
00633        }
00634       break;
00635     case 'H':
00636     case 'q':
00637       Ivalue = bit_extract (buffer, ioffset-4, 4);
00638       Ivalue = sign_extend (Ivalue, 4);
00639       sprintf (result, "%d", Ivalue);
00640       ioffset -= 4;
00641       break;
00642     case 'r':
00643       Ivalue = bit_extract (buffer, ioffset-3, 3);
00644       sprintf (result, "r%d", Ivalue&7);
00645       ioffset -= 3;
00646       break;
00647     case 'd':
00648       sprintf (result, "%d", get_displacement (buffer, aoffsetp));
00649       break;
00650     case 'b':
00651       Ivalue = get_displacement (buffer, aoffsetp);
00652       /* Warning!!  HACK ALERT!
00653          Operand type 'b' is only used by the cmp{b,w,d} and
00654          movm{b,w,d} instructions; we need to know whether
00655          it's a `b' or `w' or `d' instruction; and for both
00656          cmpm and movm it's stored at the same place so we
00657          just grab two bits of the opcode and look at it...  */
00658       size = bit_extract(buffer, ioffset-6, 2);
00659       if (size == 0)        /* 00 => b.  */
00660        size = 1;
00661       else if (size == 1)   /* 01 => w.  */
00662        size = 2;
00663       else
00664        size = 4;            /* 11 => d.  */
00665 
00666       sprintf (result, "%d", (Ivalue / size) + 1);
00667       break;
00668     case 'p':
00669       *result++ = NEXT_IS_ADDR;
00670       sprintf_vma (result, addr + get_displacement (buffer, aoffsetp));
00671       result += strlen (result);
00672       *result++ = NEXT_IS_ADDR;
00673       *result = '\0';
00674       break;
00675     case 'i':
00676       Ivalue = bit_extract (buffer, *aoffsetp, 8);
00677       *aoffsetp += 8;
00678       sprintf (result, "0x%x", Ivalue);
00679       break;
00680     case 'u':
00681       Ivalue = bit_extract (buffer, *aoffsetp, 8);
00682       optlist (Ivalue, opt_u, result);
00683       *aoffsetp += 8;
00684       break;
00685     case 'U':
00686       Ivalue = bit_extract (buffer, *aoffsetp, 8);
00687       optlist (Ivalue, opt_U, result);
00688       *aoffsetp += 8;
00689       break;
00690     case 'O':
00691       Ivalue = bit_extract (buffer, ioffset - 9, 9);
00692       optlist (Ivalue, opt_O, result);
00693       ioffset -= 9;
00694       break;
00695     case 'C':
00696       Ivalue = bit_extract (buffer, ioffset - 4, 4);
00697       optlist (Ivalue, opt_C, result);
00698       ioffset -= 4;
00699       break;
00700     case 'S':
00701       Ivalue = bit_extract (buffer, ioffset - 8, 8);
00702       optlist (Ivalue, opt_S, result);
00703       ioffset -= 8;
00704       break;
00705     case 'M':
00706       Ivalue = bit_extract (buffer, ioffset - 4, 4);
00707       list_search (Ivalue, 0 ? list_M032 : list_M532, result);
00708       ioffset -= 4;
00709       break;
00710     case 'P':
00711       Ivalue = bit_extract (buffer, ioffset - 4, 4);
00712       list_search (Ivalue, 0 ? list_P032 : list_P532, result);
00713       ioffset -= 4;
00714       break;
00715     case 'g':
00716       Ivalue = bit_extract (buffer, *aoffsetp, 3);
00717       sprintf (result, "%d", Ivalue);
00718       *aoffsetp += 3;
00719       break;
00720     case 'G':
00721       Ivalue = bit_extract(buffer, *aoffsetp, 5);
00722       sprintf (result, "%d", Ivalue + 1);
00723       *aoffsetp += 5;
00724       break;
00725     }
00726   return ioffset;
00727 }
00728 
00729 
00730 /* Print the 32000 instruction at address MEMADDR in debugged memory,
00731    on STREAM.  Returns length of the instruction, in bytes.  */
00732 
00733 int
00734 print_insn_ns32k (bfd_vma memaddr, disassemble_info *info)
00735 {
00736   unsigned int i;
00737   const char *d;
00738   unsigned short first_word;
00739   int ioffset;              /* Bits into instruction.  */
00740   int aoffset;              /* Bits into arguments.  */
00741   char arg_bufs[MAX_ARGS+1][ARG_LEN];
00742   int argnum;
00743   int maxarg;
00744   struct private priv;
00745   bfd_byte *buffer = priv.the_buffer;
00746   dis_info = info;
00747 
00748   info->private_data = & priv;
00749   priv.max_fetched = priv.the_buffer;
00750   priv.insn_start = memaddr;
00751   if (setjmp (priv.bailout) != 0)
00752     /* Error return.  */
00753     return -1;
00754 
00755   /* Look for 8bit opcodes first. Other wise, fetching two bytes could take
00756      us over the end of accessible data unnecessarilly.  */
00757   FETCH_DATA (info, buffer + 1);
00758   for (i = 0; i < NOPCODES; i++)
00759     if (ns32k_opcodes[i].opcode_id_size <= 8
00760        && ((buffer[0]
00761             & (((unsigned long) 1 << ns32k_opcodes[i].opcode_id_size) - 1))
00762            == ns32k_opcodes[i].opcode_seed))
00763       break;
00764   if (i == NOPCODES)
00765     {
00766       /* Maybe it is 9 to 16 bits big.  */
00767       FETCH_DATA (info, buffer + 2);
00768       first_word = read_memory_integer(buffer, 2);
00769 
00770       for (i = 0; i < NOPCODES; i++)
00771        if ((first_word
00772             & (((unsigned long) 1 << ns32k_opcodes[i].opcode_id_size) - 1))
00773            == ns32k_opcodes[i].opcode_seed)
00774          break;
00775 
00776       /* Handle undefined instructions.  */
00777       if (i == NOPCODES)
00778        {
00779          (*dis_info->fprintf_func)(dis_info->stream, "0%o", buffer[0]);
00780          return 1;
00781        }
00782     }
00783 
00784   (*dis_info->fprintf_func)(dis_info->stream, "%s", ns32k_opcodes[i].name);
00785 
00786   ioffset = ns32k_opcodes[i].opcode_size;
00787   aoffset = ns32k_opcodes[i].opcode_size;
00788   d = ns32k_opcodes[i].operands;
00789 
00790   if (*d)
00791     {
00792       /* Offset in bits of the first thing beyond each index byte.
00793         Element 0 is for operand A and element 1 is for operand B.
00794         The rest are irrelevant, but we put them here so we don't
00795         index outside the array.  */
00796       int index_offset[MAX_ARGS];
00797 
00798       /* 0 for operand A, 1 for operand B, greater for other args.  */
00799       int whicharg = 0;
00800       
00801       (*dis_info->fprintf_func)(dis_info->stream, "\t");
00802 
00803       maxarg = 0;
00804 
00805       /* First we have to find and keep track of the index bytes,
00806         if we are using scaled indexed addressing mode, since the index
00807         bytes occur right after the basic instruction, not as part
00808         of the addressing extension.  */
00809       if (Is_gen(d[1]))
00810        {
00811          int addr_mode = bit_extract (buffer, ioffset - 5, 5);
00812 
00813          if (Adrmod_is_index (addr_mode))
00814            {
00815              aoffset += 8;
00816              index_offset[0] = aoffset;
00817            }
00818        }
00819 
00820       if (d[2] && Is_gen(d[3]))
00821        {
00822          int addr_mode = bit_extract (buffer, ioffset - 10, 5);
00823 
00824          if (Adrmod_is_index (addr_mode))
00825            {
00826              aoffset += 8;
00827              index_offset[1] = aoffset;
00828            }
00829        }
00830 
00831       while (*d)
00832        {
00833          argnum = *d - '1';
00834          d++;
00835          if (argnum > maxarg && argnum < MAX_ARGS)
00836            maxarg = argnum;
00837          ioffset = print_insn_arg (*d, ioffset, &aoffset, buffer,
00838                                 memaddr, arg_bufs[argnum],
00839                                 index_offset[whicharg]);
00840          d++;
00841          whicharg++;
00842        }
00843       for (argnum = 0; argnum <= maxarg; argnum++)
00844        {
00845          bfd_vma addr;
00846          char *ch;
00847 
00848          for (ch = arg_bufs[argnum]; *ch;)
00849            {
00850              if (*ch == NEXT_IS_ADDR)
00851               {
00852                 ++ch;
00853                 addr = bfd_scan_vma (ch, NULL, 16);
00854                 (*dis_info->print_address_func) (addr, dis_info);
00855                 while (*ch && *ch != NEXT_IS_ADDR)
00856                   ++ch;
00857                 if (*ch)
00858                   ++ch;
00859               }
00860              else
00861               (*dis_info->fprintf_func)(dis_info->stream, "%c", *ch++);
00862            }
00863          if (argnum < maxarg)
00864            (*dis_info->fprintf_func)(dis_info->stream, ", ");
00865        }
00866     }
00867   return aoffset / 8;
00868 }