daily update
[external/binutils.git] / opcodes / ns32k-dis.c
1 /* Print National Semiconductor 32000 instructions.
2    Copyright 1986, 1988, 1991, 1992, 1994, 1998, 2001, 2002, 2005
3    Free Software Foundation, Inc.
4
5    This file is part of opcodes library.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20    MA 02110-1301, USA.  */
21
22
23 #include "bfd.h"
24 #include "sysdep.h"
25 #include "dis-asm.h"
26 #if !defined(const) && !defined(__STDC__)
27 #define const
28 #endif
29 #include "opcode/ns32k.h"
30 #include "opintl.h"
31
32 static disassemble_info *dis_info;
33
34 /* Hacks to get it to compile <= READ THESE AS FIXES NEEDED.  */
35 #define INVALID_FLOAT(val, size) invalid_float ((bfd_byte *) val, size)
36
37 static long
38 read_memory_integer (unsigned char * addr, int nr)
39 {
40   long val;
41   int i;
42
43   for (val = 0, i = nr - 1; i >= 0; i--)
44     {
45       val =  (val << 8);
46       val |= (0xff & *(addr + i));
47     }
48   return val;
49 }
50
51 /* 32000 instructions are never longer than this.  */
52 #define MAXLEN 62
53
54 #include <setjmp.h>
55
56 struct private
57 {
58   /* Points to first byte not fetched.  */
59   bfd_byte *max_fetched;
60   bfd_byte the_buffer[MAXLEN];
61   bfd_vma insn_start;
62   jmp_buf bailout;
63 };
64
65
66 /* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
67    to ADDR (exclusive) are valid.  Returns 1 for success, longjmps
68    on error.  */
69 #define FETCH_DATA(info, addr) \
70   ((addr) <= ((struct private *)(info->private_data))->max_fetched \
71    ? 1 : fetch_data ((info), (addr)))
72
73 static int
74 fetch_data (struct disassemble_info *info, bfd_byte *addr)
75 {
76   int status;
77   struct private *priv = (struct private *) info->private_data;
78   bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
79
80   status = (*info->read_memory_func) (start,
81                                       priv->max_fetched,
82                                       addr - priv->max_fetched,
83                                       info);
84   if (status != 0)
85     {
86       (*info->memory_error_func) (status, start, info);
87       longjmp (priv->bailout, 1);
88     }
89   else
90     priv->max_fetched = addr;
91   return 1;
92 }
93
94 /* Number of elements in the opcode table.  */
95 #define NOPCODES (sizeof ns32k_opcodes / sizeof ns32k_opcodes[0])
96
97 #define NEXT_IS_ADDR    '|'
98
99 \f
100 struct ns32k_option
101 {
102   char *pattern;                /* The option itself.  */
103   unsigned long value;          /* Binary value of the option.  */
104   unsigned long match;          /* These bits must match.  */
105 };
106
107 \f
108 static const struct ns32k_option opt_u[]= /* Restore, exit.  */
109 {
110   { "r0",       0x80,   0x80    },
111   { "r1",       0x40,   0x40    },
112   { "r2",       0x20,   0x20    },
113   { "r3",       0x10,   0x10    },
114   { "r4",       0x08,   0x08    },
115   { "r5",       0x04,   0x04    },
116   { "r6",       0x02,   0x02    },
117   { "r7",       0x01,   0x01    },
118   {  0 ,        0x00,   0x00    }
119 };
120
121 static const struct ns32k_option opt_U[]= /* Save, enter.  */
122 {
123   { "r0",       0x01,   0x01    },
124   { "r1",       0x02,   0x02    },
125   { "r2",       0x04,   0x04    },
126   { "r3",       0x08,   0x08    },
127   { "r4",       0x10,   0x10    },
128   { "r5",       0x20,   0x20    },
129   { "r6",       0x40,   0x40    },
130   { "r7",       0x80,   0x80    },
131   {  0 ,        0x00,   0x00    }
132 };
133
134 static const struct ns32k_option opt_O[]= /* Setcfg.  */
135 {
136   { "c",        0x8,    0x8     },
137   { "m",        0x4,    0x4     },
138   { "f",        0x2,    0x2     },
139   { "i",        0x1,    0x1     },
140   {  0 ,        0x0,    0x0     }
141 };
142
143 static const struct ns32k_option opt_C[]= /* Cinv.  */
144 {
145   { "a",        0x4,    0x4     },
146   { "i",        0x2,    0x2     },
147   { "d",        0x1,    0x1     },
148   {  0 ,        0x0,    0x0     }
149 };
150
151 static const struct ns32k_option opt_S[]= /* String inst.  */
152 {
153   { "b",        0x1,    0x1     },
154   { "u",        0x6,    0x6     },
155   { "w",        0x2,    0x2     },
156   {  0 ,        0x0,    0x0     }
157 };
158
159 static const struct ns32k_option list_P532[]= /* Lpr spr.  */
160 {
161   { "us",       0x0,    0xf     },
162   { "dcr",      0x1,    0xf     },
163   { "bpc",      0x2,    0xf     },
164   { "dsr",      0x3,    0xf     },
165   { "car",      0x4,    0xf     },
166   { "fp",       0x8,    0xf     },
167   { "sp",       0x9,    0xf     },
168   { "sb",       0xa,    0xf     },
169   { "usp",      0xb,    0xf     },
170   { "cfg",      0xc,    0xf     },
171   { "psr",      0xd,    0xf     },
172   { "intbase",  0xe,    0xf     },
173   { "mod",      0xf,    0xf     },
174   {  0 ,        0x00,   0xf     }
175 };
176
177 static const struct ns32k_option list_M532[]= /* Lmr smr.  */
178 {
179   { "mcr",      0x9,    0xf     },
180   { "msr",      0xa,    0xf     },
181   { "tear",     0xb,    0xf     },
182   { "ptb0",     0xc,    0xf     },
183   { "ptb1",     0xd,    0xf     },
184   { "ivar0",    0xe,    0xf     },
185   { "ivar1",    0xf,    0xf     },
186   {  0 ,        0x0,    0xf     }
187 };
188
189 static const struct ns32k_option list_P032[]= /* Lpr spr.  */
190 {
191   { "upsr",     0x0,    0xf     },
192   { "fp",       0x8,    0xf     },
193   { "sp",       0x9,    0xf     },
194   { "sb",       0xa,    0xf     },
195   { "psr",      0xb,    0xf     },
196   { "intbase",  0xe,    0xf     },
197   { "mod",      0xf,    0xf     },
198   {  0 ,        0x0,    0xf     }
199 };
200
201 static const struct ns32k_option list_M032[]= /* Lmr smr.  */
202 {
203   { "bpr0",     0x0,    0xf     },
204   { "bpr1",     0x1,    0xf     },
205   { "pf0",      0x4,    0xf     },
206   { "pf1",      0x5,    0xf     },
207   { "sc",       0x8,    0xf     },
208   { "msr",      0xa,    0xf     },
209   { "bcnt",     0xb,    0xf     },
210   { "ptb0",     0xc,    0xf     },
211   { "ptb1",     0xd,    0xf     },
212   { "eia",      0xf,    0xf     },
213   {  0 ,        0x0,    0xf     }
214 };
215
216
217 /* Figure out which options are present.   */
218
219 static void
220 optlist (int options, const struct ns32k_option * optionP, char * result)
221 {
222   if (options == 0)
223     {
224       sprintf (result, "[]");
225       return;
226     }
227
228   sprintf (result, "[");
229
230   for (; (options != 0) && optionP->pattern; optionP++)
231     {
232       if ((options & optionP->match) == optionP->value)
233         {
234           /* We found a match, update result and options.  */
235           strcat (result, optionP->pattern);
236           options &= ~optionP->value;
237           if (options != 0)     /* More options to come.  */
238             strcat (result, ",");
239         }
240     }
241
242   if (options != 0)
243     strcat (result, "undefined");
244
245   strcat (result, "]");
246 }
247
248 static void
249 list_search (int reg_value, const struct ns32k_option *optionP, char *result)
250 {
251   for (; optionP->pattern; optionP++)
252     {
253       if ((reg_value & optionP->match) == optionP->value)
254         {
255           sprintf (result, "%s", optionP->pattern);
256           return;
257         }
258     }
259   sprintf (result, "undefined");
260 }
261 \f
262 /* Extract "count" bits starting "offset" bits into buffer.  */
263
264 static int
265 bit_extract (bfd_byte *buffer, int offset, int count)
266 {
267   int result;
268   int bit;
269
270   buffer += offset >> 3;
271   offset &= 7;
272   bit = 1;
273   result = 0;
274   while (count--)
275     {
276       FETCH_DATA (dis_info, buffer + 1);
277       if ((*buffer & (1 << offset)))
278         result |= bit;
279       if (++offset == 8)
280         {
281           offset = 0;
282           buffer++;
283         }
284       bit <<= 1;
285     }
286   return result;
287 }
288
289 /* Like bit extract but the buffer is valid and doen't need to be fetched.  */
290
291 static int
292 bit_extract_simple (bfd_byte *buffer, int offset, int count)
293 {
294   int result;
295   int bit;
296
297   buffer += offset >> 3;
298   offset &= 7;
299   bit = 1;
300   result = 0;
301   while (count--)
302     {
303       if ((*buffer & (1 << offset)))
304         result |= bit;
305       if (++offset == 8)
306         {
307           offset = 0;
308           buffer++;
309         }
310       bit <<= 1;
311     }
312   return result;
313 }
314
315 static void
316 bit_copy (bfd_byte *buffer, int offset, int count, char *to)
317 {
318   for (; count > 8; count -= 8, to++, offset += 8)
319     *to = bit_extract (buffer, offset, 8);
320   *to = bit_extract (buffer, offset, count);
321 }
322
323 static int
324 sign_extend (int value, int bits)
325 {
326   value = value & ((1 << bits) - 1);
327   return (value & (1 << (bits - 1))
328           ? value | (~((1 << bits) - 1))
329           : value);
330 }
331
332 static void
333 flip_bytes (char *ptr, int count)
334 {
335   char tmp;
336
337   while (count > 0)
338     {
339       tmp = ptr[0];
340       ptr[0] = ptr[count - 1];
341       ptr[count - 1] = tmp;
342       ptr++;
343       count -= 2;
344     }
345 }
346 \f
347 /* Given a character C, does it represent a general addressing mode?  */
348 #define Is_gen(c) \
349   ((c) == 'F' || (c) == 'L' || (c) == 'B' \
350    || (c) == 'W' || (c) == 'D' || (c) == 'A' || (c) == 'I' || (c) == 'Z')
351
352 /* Adressing modes.  */
353 #define Adrmod_index_byte        0x1c
354 #define Adrmod_index_word        0x1d
355 #define Adrmod_index_doubleword  0x1e
356 #define Adrmod_index_quadword    0x1f
357
358 /* Is MODE an indexed addressing mode?  */
359 #define Adrmod_is_index(mode) \
360   (   mode == Adrmod_index_byte \
361    || mode == Adrmod_index_word \
362    || mode == Adrmod_index_doubleword \
363    || mode == Adrmod_index_quadword)
364
365 \f
366 static int
367 get_displacement (bfd_byte *buffer, int *aoffsetp)
368 {
369   int Ivalue;
370   short Ivalue2;
371
372   Ivalue = bit_extract (buffer, *aoffsetp, 8);
373   switch (Ivalue & 0xc0)
374     {
375     case 0x00:
376     case 0x40:
377       Ivalue = sign_extend (Ivalue, 7);
378       *aoffsetp += 8;
379       break;
380     case 0x80:
381       Ivalue2 = bit_extract (buffer, *aoffsetp, 16);
382       flip_bytes ((char *) & Ivalue2, 2);
383       Ivalue = sign_extend (Ivalue2, 14);
384       *aoffsetp += 16;
385       break;
386     case 0xc0:
387       Ivalue = bit_extract (buffer, *aoffsetp, 32);
388       flip_bytes ((char *) & Ivalue, 4);
389       Ivalue = sign_extend (Ivalue, 30);
390       *aoffsetp += 32;
391       break;
392     }
393   return Ivalue;
394 }
395
396 #if 1 /* A version that should work on ns32k f's&d's on any machine.  */
397 static int
398 invalid_float (bfd_byte *p, int len)
399 {
400   int val;
401
402   if (len == 4)
403     val = (bit_extract_simple (p, 23, 8)/*exponent*/ == 0xff
404            || (bit_extract_simple (p, 23, 8)/*exponent*/ == 0
405                && bit_extract_simple (p, 0, 23)/*mantisa*/ != 0));
406   else if (len == 8)
407     val = (bit_extract_simple (p, 52, 11)/*exponent*/ == 0x7ff
408            || (bit_extract_simple (p, 52, 11)/*exponent*/ == 0
409                && (bit_extract_simple (p, 0, 32)/*low mantisa*/ != 0
410                    || bit_extract_simple (p, 32, 20)/*high mantisa*/ != 0)));
411   else
412     val = 1;
413   return (val);
414 }
415 #else
416 /* Assumes the bytes have been swapped to local order.  */
417 typedef union
418
419   double d;
420   float f;
421   struct { unsigned m:23, e:8, :1;} sf;
422   struct { unsigned lm; unsigned m:20, e:11, :1;} sd;
423 } float_type_u;
424
425 static int
426 invalid_float (float_type_u *p, int len)
427 {
428   int val;
429
430   if (len == sizeof (float))
431     val = (p->sf.e == 0xff
432            || (p->sf.e == 0 && p->sf.m != 0));
433   else if (len == sizeof (double))
434     val = (p->sd.e == 0x7ff
435            || (p->sd.e == 0 && (p->sd.m != 0 || p->sd.lm != 0)));
436   else
437     val = 1;
438   return val;
439 }
440 #endif
441
442 /* Print an instruction operand of category given by d.  IOFFSET is
443    the bit position below which small (<1 byte) parts of the operand can
444    be found (usually in the basic instruction, but for indexed
445    addressing it can be in the index byte).  AOFFSETP is a pointer to the
446    bit position of the addressing extension.  BUFFER contains the
447    instruction.  ADDR is where BUFFER was read from.  Put the disassembled
448    version of the operand in RESULT.  INDEX_OFFSET is the bit position
449    of the index byte (it contains garbage if this operand is not a
450    general operand using scaled indexed addressing mode).  */
451
452 static int
453 print_insn_arg (int d,
454                 int ioffset,
455                 int *aoffsetp,
456                 bfd_byte *buffer,
457                 bfd_vma addr,
458                 char *result,
459                 int index_offset)
460 {
461   union
462   {
463     float f;
464     double d;
465     int i[2];
466   } value;
467   int Ivalue;
468   int addr_mode;
469   int disp1, disp2;
470   int index;
471   int size;
472
473   switch (d)
474     {
475     case 'f':
476       /* A "gen" operand but 5 bits from the end of instruction.  */
477       ioffset -= 5;
478     case 'Z':
479     case 'F':
480     case 'L':
481     case 'I':
482     case 'B':
483     case 'W':
484     case 'D':
485     case 'A':
486       addr_mode = bit_extract (buffer, ioffset - 5, 5);
487       ioffset -= 5;
488       switch (addr_mode)
489         {
490         case 0x0: case 0x1: case 0x2: case 0x3:
491         case 0x4: case 0x5: case 0x6: case 0x7:
492           /* Register mode R0 -- R7.  */
493           switch (d)
494             {
495             case 'F':
496             case 'L':
497             case 'Z':
498               sprintf (result, "f%d", addr_mode);
499               break;
500             default:
501               sprintf (result, "r%d", addr_mode);
502             }
503           break;
504         case 0x8: case 0x9: case 0xa: case 0xb:
505         case 0xc: case 0xd: case 0xe: case 0xf:
506           /* Register relative disp(R0 -- R7).  */
507           disp1 = get_displacement (buffer, aoffsetp);
508           sprintf (result, "%d(r%d)", disp1, addr_mode & 7);
509           break;
510         case 0x10:
511         case 0x11:
512         case 0x12:
513           /* Memory relative disp2(disp1(FP, SP, SB)).  */
514           disp1 = get_displacement (buffer, aoffsetp);
515           disp2 = get_displacement (buffer, aoffsetp);
516           sprintf (result, "%d(%d(%s))", disp2, disp1,
517                    addr_mode == 0x10 ? "fp" : addr_mode == 0x11 ? "sp" : "sb");
518           break;
519         case 0x13:
520           /* Reserved.  */
521           sprintf (result, "reserved");
522           break;
523         case 0x14:
524           /* Immediate.  */
525           switch (d)
526             {
527             case 'I':
528             case 'Z':
529             case 'A':
530               /* I and Z are output operands and can`t be immediate
531                  A is an address and we can`t have the address of
532                  an immediate either. We don't know how much to increase
533                  aoffsetp by since whatever generated this is broken
534                  anyway!  */
535               sprintf (result, _("$<undefined>"));
536               break;
537             case 'B':
538               Ivalue = bit_extract (buffer, *aoffsetp, 8);
539               Ivalue = sign_extend (Ivalue, 8);
540               *aoffsetp += 8;
541               sprintf (result, "$%d", Ivalue);
542               break;
543             case 'W':
544               Ivalue = bit_extract (buffer, *aoffsetp, 16);
545               flip_bytes ((char *) & Ivalue, 2);
546               *aoffsetp += 16;
547               Ivalue = sign_extend (Ivalue, 16);
548               sprintf (result, "$%d", Ivalue);
549               break;
550             case 'D':
551               Ivalue = bit_extract (buffer, *aoffsetp, 32);
552               flip_bytes ((char *) & Ivalue, 4);
553               *aoffsetp += 32;
554               sprintf (result, "$%d", Ivalue);
555               break;
556             case 'F':
557               bit_copy (buffer, *aoffsetp, 32, (char *) &value.f);
558               flip_bytes ((char *) &value.f, 4);
559               *aoffsetp += 32;
560               if (INVALID_FLOAT (&value.f, 4))
561                 sprintf (result, "<<invalid float 0x%.8x>>", value.i[0]);
562               else /* Assume host has ieee float.  */
563                 sprintf (result, "$%g", value.f);
564               break;
565             case 'L':
566               bit_copy (buffer, *aoffsetp, 64, (char *) &value.d);
567               flip_bytes ((char *) &value.d, 8);
568               *aoffsetp += 64;
569               if (INVALID_FLOAT (&value.d, 8))
570                 sprintf (result, "<<invalid double 0x%.8x%.8x>>",
571                          value.i[1], value.i[0]);
572               else /* Assume host has ieee float.  */
573                 sprintf (result, "$%g", value.d);
574               break;
575             }
576           break;
577         case 0x15:
578           /* Absolute @disp.  */
579           disp1 = get_displacement (buffer, aoffsetp);
580           sprintf (result, "@|%d|", disp1);
581           break;
582         case 0x16:
583           /* External EXT(disp1) + disp2 (Mod table stuff).  */
584           disp1 = get_displacement (buffer, aoffsetp);
585           disp2 = get_displacement (buffer, aoffsetp);
586           sprintf (result, "EXT(%d) + %d", disp1, disp2);
587           break;
588         case 0x17:
589           /* Top of stack tos.  */
590           sprintf (result, "tos");
591           break;
592         case 0x18:
593           /* Memory space disp(FP).  */
594           disp1 = get_displacement (buffer, aoffsetp);
595           sprintf (result, "%d(fp)", disp1);
596           break;
597         case 0x19:
598           /* Memory space disp(SP).  */
599           disp1 = get_displacement (buffer, aoffsetp);
600           sprintf (result, "%d(sp)", disp1);
601           break;
602         case 0x1a:
603           /* Memory space disp(SB).  */
604           disp1 = get_displacement (buffer, aoffsetp);
605           sprintf (result, "%d(sb)", disp1);
606           break;
607         case 0x1b:
608           /* Memory space disp(PC).  */
609           disp1 = get_displacement (buffer, aoffsetp);
610           *result++ = NEXT_IS_ADDR;
611           sprintf_vma (result, addr + disp1);
612           result += strlen (result);
613           *result++ = NEXT_IS_ADDR;
614           *result = '\0';
615           break;
616         case 0x1c:
617         case 0x1d:
618         case 0x1e:
619         case 0x1f:
620           /* Scaled index basemode[R0 -- R7:B,W,D,Q].  */
621           index = bit_extract (buffer, index_offset - 8, 3);
622           print_insn_arg (d, index_offset, aoffsetp, buffer, addr,
623                           result, 0);
624           {
625             static const char *ind = "bwdq";
626             char *off;
627
628             off = result + strlen (result);
629             sprintf (off, "[r%d:%c]", index,
630                      ind[addr_mode & 3]);
631           }
632           break;
633         }
634       break;
635     case 'H':
636     case 'q':
637       Ivalue = bit_extract (buffer, ioffset-4, 4);
638       Ivalue = sign_extend (Ivalue, 4);
639       sprintf (result, "%d", Ivalue);
640       ioffset -= 4;
641       break;
642     case 'r':
643       Ivalue = bit_extract (buffer, ioffset-3, 3);
644       sprintf (result, "r%d", Ivalue&7);
645       ioffset -= 3;
646       break;
647     case 'd':
648       sprintf (result, "%d", get_displacement (buffer, aoffsetp));
649       break;
650     case 'b':
651       Ivalue = get_displacement (buffer, aoffsetp);
652       /* Warning!!  HACK ALERT!
653          Operand type 'b' is only used by the cmp{b,w,d} and
654          movm{b,w,d} instructions; we need to know whether
655          it's a `b' or `w' or `d' instruction; and for both
656          cmpm and movm it's stored at the same place so we
657          just grab two bits of the opcode and look at it...  */
658       size = bit_extract(buffer, ioffset-6, 2);
659       if (size == 0)            /* 00 => b.  */
660         size = 1;
661       else if (size == 1)       /* 01 => w.  */
662         size = 2;
663       else
664         size = 4;               /* 11 => d.  */
665
666       sprintf (result, "%d", (Ivalue / size) + 1);
667       break;
668     case 'p':
669       *result++ = NEXT_IS_ADDR;
670       sprintf_vma (result, addr + get_displacement (buffer, aoffsetp));
671       result += strlen (result);
672       *result++ = NEXT_IS_ADDR;
673       *result = '\0';
674       break;
675     case 'i':
676       Ivalue = bit_extract (buffer, *aoffsetp, 8);
677       *aoffsetp += 8;
678       sprintf (result, "0x%x", Ivalue);
679       break;
680     case 'u':
681       Ivalue = bit_extract (buffer, *aoffsetp, 8);
682       optlist (Ivalue, opt_u, result);
683       *aoffsetp += 8;
684       break;
685     case 'U':
686       Ivalue = bit_extract (buffer, *aoffsetp, 8);
687       optlist (Ivalue, opt_U, result);
688       *aoffsetp += 8;
689       break;
690     case 'O':
691       Ivalue = bit_extract (buffer, ioffset - 9, 9);
692       optlist (Ivalue, opt_O, result);
693       ioffset -= 9;
694       break;
695     case 'C':
696       Ivalue = bit_extract (buffer, ioffset - 4, 4);
697       optlist (Ivalue, opt_C, result);
698       ioffset -= 4;
699       break;
700     case 'S':
701       Ivalue = bit_extract (buffer, ioffset - 8, 8);
702       optlist (Ivalue, opt_S, result);
703       ioffset -= 8;
704       break;
705     case 'M':
706       Ivalue = bit_extract (buffer, ioffset - 4, 4);
707       list_search (Ivalue, 0 ? list_M032 : list_M532, result);
708       ioffset -= 4;
709       break;
710     case 'P':
711       Ivalue = bit_extract (buffer, ioffset - 4, 4);
712       list_search (Ivalue, 0 ? list_P032 : list_P532, result);
713       ioffset -= 4;
714       break;
715     case 'g':
716       Ivalue = bit_extract (buffer, *aoffsetp, 3);
717       sprintf (result, "%d", Ivalue);
718       *aoffsetp += 3;
719       break;
720     case 'G':
721       Ivalue = bit_extract(buffer, *aoffsetp, 5);
722       sprintf (result, "%d", Ivalue + 1);
723       *aoffsetp += 5;
724       break;
725     }
726   return ioffset;
727 }
728
729 \f
730 /* Print the 32000 instruction at address MEMADDR in debugged memory,
731    on STREAM.  Returns length of the instruction, in bytes.  */
732
733 int
734 print_insn_ns32k (bfd_vma memaddr, disassemble_info *info)
735 {
736   unsigned int i;
737   const char *d;
738   unsigned short first_word;
739   int ioffset;          /* Bits into instruction.  */
740   int aoffset;          /* Bits into arguments.  */
741   char arg_bufs[MAX_ARGS+1][ARG_LEN];
742   int argnum;
743   int maxarg;
744   struct private priv;
745   bfd_byte *buffer = priv.the_buffer;
746   dis_info = info;
747
748   info->private_data = & priv;
749   priv.max_fetched = priv.the_buffer;
750   priv.insn_start = memaddr;
751   if (setjmp (priv.bailout) != 0)
752     /* Error return.  */
753     return -1;
754
755   /* Look for 8bit opcodes first. Other wise, fetching two bytes could take
756      us over the end of accessible data unnecessarilly.  */
757   FETCH_DATA (info, buffer + 1);
758   for (i = 0; i < NOPCODES; i++)
759     if (ns32k_opcodes[i].opcode_id_size <= 8
760         && ((buffer[0]
761              & (((unsigned long) 1 << ns32k_opcodes[i].opcode_id_size) - 1))
762             == ns32k_opcodes[i].opcode_seed))
763       break;
764   if (i == NOPCODES)
765     {
766       /* Maybe it is 9 to 16 bits big.  */
767       FETCH_DATA (info, buffer + 2);
768       first_word = read_memory_integer(buffer, 2);
769
770       for (i = 0; i < NOPCODES; i++)
771         if ((first_word
772              & (((unsigned long) 1 << ns32k_opcodes[i].opcode_id_size) - 1))
773             == ns32k_opcodes[i].opcode_seed)
774           break;
775
776       /* Handle undefined instructions.  */
777       if (i == NOPCODES)
778         {
779           (*dis_info->fprintf_func)(dis_info->stream, "0%o", buffer[0]);
780           return 1;
781         }
782     }
783
784   (*dis_info->fprintf_func)(dis_info->stream, "%s", ns32k_opcodes[i].name);
785
786   ioffset = ns32k_opcodes[i].opcode_size;
787   aoffset = ns32k_opcodes[i].opcode_size;
788   d = ns32k_opcodes[i].operands;
789
790   if (*d)
791     {
792       /* Offset in bits of the first thing beyond each index byte.
793          Element 0 is for operand A and element 1 is for operand B.
794          The rest are irrelevant, but we put them here so we don't
795          index outside the array.  */
796       int index_offset[MAX_ARGS];
797
798       /* 0 for operand A, 1 for operand B, greater for other args.  */
799       int whicharg = 0;
800       
801       (*dis_info->fprintf_func)(dis_info->stream, "\t");
802
803       maxarg = 0;
804
805       /* First we have to find and keep track of the index bytes,
806          if we are using scaled indexed addressing mode, since the index
807          bytes occur right after the basic instruction, not as part
808          of the addressing extension.  */
809       if (Is_gen(d[1]))
810         {
811           int addr_mode = bit_extract (buffer, ioffset - 5, 5);
812
813           if (Adrmod_is_index (addr_mode))
814             {
815               aoffset += 8;
816               index_offset[0] = aoffset;
817             }
818         }
819
820       if (d[2] && Is_gen(d[3]))
821         {
822           int addr_mode = bit_extract (buffer, ioffset - 10, 5);
823
824           if (Adrmod_is_index (addr_mode))
825             {
826               aoffset += 8;
827               index_offset[1] = aoffset;
828             }
829         }
830
831       while (*d)
832         {
833           argnum = *d - '1';
834           d++;
835           if (argnum > maxarg && argnum < MAX_ARGS)
836             maxarg = argnum;
837           ioffset = print_insn_arg (*d, ioffset, &aoffset, buffer,
838                                     memaddr, arg_bufs[argnum],
839                                     index_offset[whicharg]);
840           d++;
841           whicharg++;
842         }
843       for (argnum = 0; argnum <= maxarg; argnum++)
844         {
845           bfd_vma addr;
846           char *ch;
847
848           for (ch = arg_bufs[argnum]; *ch;)
849             {
850               if (*ch == NEXT_IS_ADDR)
851                 {
852                   ++ch;
853                   addr = bfd_scan_vma (ch, NULL, 16);
854                   (*dis_info->print_address_func) (addr, dis_info);
855                   while (*ch && *ch != NEXT_IS_ADDR)
856                     ++ch;
857                   if (*ch)
858                     ++ch;
859                 }
860               else
861                 (*dis_info->fprintf_func)(dis_info->stream, "%c", *ch++);
862             }
863           if (argnum < maxarg)
864             (*dis_info->fprintf_func)(dis_info->stream, ", ");
865         }
866     }
867   return aoffset / 8;
868 }