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