/src/binutils-gdb/opcodes/ns32k-dis.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Print National Semiconductor 32000 instructions. |
2 | | Copyright (C) 1986-2025 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 "disassemble.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 | 8.64k | #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 | 143k | { |
38 | 143k | long val; |
39 | 143k | int i; |
40 | | |
41 | 431k | for (val = 0, i = nr - 1; i >= 0; i--) |
42 | 287k | { |
43 | 287k | val = (val << 8); |
44 | 287k | val |= (0xff & *(addr + i)); |
45 | 287k | } |
46 | 143k | return val; |
47 | 143k | } |
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 | 10.8M | ((addr) <= ((struct private *)(info->private_data))->max_fetched \ |
69 | 10.8M | ? 1 : fetch_data ((info), (addr))) |
70 | | |
71 | | static int |
72 | | fetch_data (struct disassemble_info *info, bfd_byte *addr) |
73 | 1.38M | { |
74 | 1.38M | int status; |
75 | 1.38M | struct private *priv = (struct private *) info->private_data; |
76 | 1.38M | bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); |
77 | | |
78 | 1.38M | status = (*info->read_memory_func) (start, |
79 | 1.38M | priv->max_fetched, |
80 | 1.38M | addr - priv->max_fetched, |
81 | 1.38M | info); |
82 | 1.38M | if (status != 0) |
83 | 498 | { |
84 | 498 | (*info->memory_error_func) (status, start, info); |
85 | 498 | OPCODES_SIGLONGJMP (priv->bailout, 1); |
86 | 498 | } |
87 | 1.38M | else |
88 | 1.38M | priv->max_fetched = addr; |
89 | 1.38M | return 1; |
90 | 1.38M | } |
91 | | |
92 | | /* Number of elements in the opcode table. */ |
93 | 119M | #define NOPCODES (sizeof ns32k_opcodes / sizeof ns32k_opcodes[0]) |
94 | | |
95 | 3.34M | #define NEXT_IS_ADDR '|' |
96 | | |
97 | | |
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 | | |
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 | 8.87k | { |
220 | 8.87k | if (options == 0) |
221 | 389 | { |
222 | 389 | sprintf (result, "[]"); |
223 | 389 | return; |
224 | 389 | } |
225 | | |
226 | 8.48k | sprintf (result, "["); |
227 | | |
228 | 62.6k | for (; (options != 0) && optionP->pattern; optionP++) |
229 | 54.1k | { |
230 | 54.1k | if ((options & optionP->match) == optionP->value) |
231 | 27.1k | { |
232 | | /* We found a match, update result and options. */ |
233 | 27.1k | strcat (result, optionP->pattern); |
234 | 27.1k | options &= ~optionP->value; |
235 | 27.1k | if (options != 0) /* More options to come. */ |
236 | 19.5k | strcat (result, ","); |
237 | 27.1k | } |
238 | 54.1k | } |
239 | | |
240 | 8.48k | if (options != 0) |
241 | 928 | strcat (result, "undefined"); |
242 | | |
243 | 8.48k | strcat (result, "]"); |
244 | 8.48k | } |
245 | | |
246 | | static void |
247 | | list_search (int reg_value, const struct ns32k_option *optionP, char *result) |
248 | 18.4k | { |
249 | 121k | for (; optionP->pattern; optionP++) |
250 | 120k | { |
251 | 120k | if ((reg_value & optionP->match) == optionP->value) |
252 | 17.0k | { |
253 | 17.0k | sprintf (result, "%s", optionP->pattern); |
254 | 17.0k | return; |
255 | 17.0k | } |
256 | 120k | } |
257 | 1.40k | sprintf (result, "undefined"); |
258 | 1.40k | } |
259 | | |
260 | | /* Extract "count" bits starting "offset" bits into buffer. */ |
261 | | |
262 | | static int |
263 | | bit_extract (bfd_byte *buffer, int offset, int count) |
264 | 1.62M | { |
265 | 1.62M | unsigned int result; |
266 | 1.62M | unsigned int bit; |
267 | | |
268 | 1.62M | if (offset < 0 || count < 0) |
269 | 25.6k | return 0; |
270 | 1.59M | buffer += offset >> 3; |
271 | 1.59M | offset &= 7; |
272 | 1.59M | bit = 1; |
273 | 1.59M | result = 0; |
274 | 11.8M | while (count--) |
275 | 10.2M | { |
276 | 10.2M | FETCH_DATA (dis_info, buffer + 1); |
277 | 10.2M | if ((*buffer & (1 << offset))) |
278 | 3.67M | result |= bit; |
279 | 10.2M | if (++offset == 8) |
280 | 1.71M | { |
281 | 1.71M | offset = 0; |
282 | 1.71M | buffer++; |
283 | 1.71M | } |
284 | 10.2M | bit <<= 1; |
285 | 10.2M | } |
286 | 1.59M | return result; |
287 | 1.62M | } |
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 | 24.4k | { |
294 | 24.4k | unsigned int result; |
295 | 24.4k | unsigned int bit; |
296 | | |
297 | 24.4k | if (offset < 0 || count < 0) |
298 | 0 | return 0; |
299 | 24.4k | buffer += offset >> 3; |
300 | 24.4k | offset &= 7; |
301 | 24.4k | bit = 1; |
302 | 24.4k | result = 0; |
303 | 395k | while (count--) |
304 | 371k | { |
305 | 371k | if ((*buffer & (1 << offset))) |
306 | 55.6k | result |= bit; |
307 | 371k | if (++offset == 8) |
308 | 39.4k | { |
309 | 39.4k | offset = 0; |
310 | 39.4k | buffer++; |
311 | 39.4k | } |
312 | 371k | bit <<= 1; |
313 | 371k | } |
314 | 24.4k | return result; |
315 | 24.4k | } |
316 | | |
317 | | static void |
318 | | bit_copy (bfd_byte *buffer, int offset, int count, char *to) |
319 | 8.64k | { |
320 | 8.64k | if (offset < 0 || count < 0) |
321 | 0 | return; |
322 | 57.5k | for (; count > 8; count -= 8, to++, offset += 8) |
323 | 48.9k | *to = bit_extract (buffer, offset, 8); |
324 | 8.64k | *to = bit_extract (buffer, offset, count); |
325 | 8.64k | } |
326 | | |
327 | | static int |
328 | | sign_extend (unsigned int value, unsigned int bits) |
329 | 244k | { |
330 | 244k | unsigned int sign = 1u << (bits - 1); |
331 | 244k | return ((value & (sign + sign - 1)) ^ sign) - sign; |
332 | 244k | } |
333 | | |
334 | | static void |
335 | | flip_bytes (char *ptr, int count) |
336 | 87.4k | { |
337 | 87.4k | char tmp; |
338 | | |
339 | 237k | while (count > 0) |
340 | 149k | { |
341 | 149k | tmp = ptr[0]; |
342 | 149k | ptr[0] = ptr[count - 1]; |
343 | 149k | ptr[count - 1] = tmp; |
344 | 149k | ptr++; |
345 | 149k | count -= 2; |
346 | 149k | } |
347 | 87.4k | } |
348 | | |
349 | | /* Given a character C, does it represent a general addressing mode? */ |
350 | 613k | #define Is_gen(c) (strchr ("FLBWDAIZf", (c)) != NULL) |
351 | | |
352 | | /* Adressing modes. */ |
353 | 1.09M | #define Adrmod_index_byte 0x1c |
354 | 1.08M | #define Adrmod_index_word 0x1d |
355 | 1.07M | #define Adrmod_index_doubleword 0x1e |
356 | 1.06M | #define Adrmod_index_quadword 0x1f |
357 | | |
358 | | /* Is MODE an indexed addressing mode? */ |
359 | | #define Adrmod_is_index(mode) \ |
360 | 548k | ( mode == Adrmod_index_byte \ |
361 | 548k | || mode == Adrmod_index_word \ |
362 | 548k | || mode == Adrmod_index_doubleword \ |
363 | 548k | || mode == Adrmod_index_quadword) |
364 | | |
365 | | |
366 | | static int |
367 | | get_displacement (bfd_byte *buffer, int *aoffsetp) |
368 | 225k | { |
369 | 225k | int Ivalue; |
370 | 225k | short Ivalue2; |
371 | | |
372 | 225k | Ivalue = bit_extract (buffer, *aoffsetp, 8); |
373 | 225k | switch (Ivalue & 0xc0) |
374 | 225k | { |
375 | 87.7k | case 0x00: |
376 | 150k | case 0x40: |
377 | 150k | Ivalue = sign_extend (Ivalue, 7); |
378 | 150k | *aoffsetp += 8; |
379 | 150k | break; |
380 | 35.1k | case 0x80: |
381 | 35.1k | Ivalue2 = bit_extract (buffer, *aoffsetp, 16); |
382 | 35.1k | flip_bytes ((char *) & Ivalue2, 2); |
383 | 35.1k | Ivalue = sign_extend (Ivalue2, 14); |
384 | 35.1k | *aoffsetp += 16; |
385 | 35.1k | break; |
386 | 40.0k | case 0xc0: |
387 | 40.0k | Ivalue = bit_extract (buffer, *aoffsetp, 32); |
388 | 40.0k | flip_bytes ((char *) & Ivalue, 4); |
389 | 40.0k | Ivalue = sign_extend (Ivalue, 30); |
390 | 40.0k | *aoffsetp += 32; |
391 | 40.0k | break; |
392 | 225k | } |
393 | 225k | return Ivalue; |
394 | 225k | } |
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 | 8.61k | { |
400 | 8.61k | int val; |
401 | | |
402 | 8.61k | if (len == 4) |
403 | 2.87k | val = (bit_extract_simple (p, 23, 8)/*exponent*/ == 0xff |
404 | 2.87k | || (bit_extract_simple (p, 23, 8)/*exponent*/ == 0 |
405 | 2.51k | && bit_extract_simple (p, 0, 23)/*mantisa*/ != 0)); |
406 | 5.73k | else if (len == 8) |
407 | 5.73k | val = (bit_extract_simple (p, 52, 11)/*exponent*/ == 0x7ff |
408 | 5.73k | || (bit_extract_simple (p, 52, 11)/*exponent*/ == 0 |
409 | 5.61k | && (bit_extract_simple (p, 0, 32)/*low mantisa*/ != 0 |
410 | 3.67k | || bit_extract_simple (p, 32, 20)/*high mantisa*/ != 0))); |
411 | 0 | else |
412 | 0 | val = 1; |
413 | 8.61k | return (val); |
414 | 8.61k | } |
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 -1 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 | 681k | { |
461 | 681k | union |
462 | 681k | { |
463 | 681k | float f; |
464 | 681k | double d; |
465 | 681k | int i[2]; |
466 | 681k | } value; |
467 | 681k | int Ivalue; |
468 | 681k | int addr_mode; |
469 | 681k | int disp1, disp2; |
470 | 681k | int size; |
471 | | |
472 | 681k | switch (d) |
473 | 681k | { |
474 | 55 | case 'f': |
475 | | /* A "gen" operand but 5 bits from the end of instruction. */ |
476 | 55 | ioffset -= 5; |
477 | | /* Fall through. */ |
478 | 1.18k | case 'Z': |
479 | 5.68k | case 'F': |
480 | 12.0k | case 'L': |
481 | 270k | case 'I': |
482 | 454k | case 'B': |
483 | 522k | case 'W': |
484 | 582k | case 'D': |
485 | 606k | case 'A': |
486 | 606k | addr_mode = bit_extract (buffer, ioffset - 5, 5); |
487 | 606k | ioffset -= 5; |
488 | 606k | switch (addr_mode) |
489 | 606k | { |
490 | 284k | case 0x0: case 0x1: case 0x2: case 0x3: |
491 | 348k | case 0x4: case 0x5: case 0x6: case 0x7: |
492 | | /* Register mode R0 -- R7. */ |
493 | 348k | switch (d) |
494 | 348k | { |
495 | 790 | case 'F': |
496 | 1.17k | case 'L': |
497 | 2.08k | case 'Z': |
498 | 2.08k | sprintf (result, "f%d", addr_mode); |
499 | 2.08k | break; |
500 | 346k | default: |
501 | 346k | sprintf (result, "r%d", addr_mode); |
502 | 348k | } |
503 | 348k | break; |
504 | 348k | case 0x8: case 0x9: case 0xa: case 0xb: |
505 | 92.9k | case 0xc: case 0xd: case 0xe: case 0xf: |
506 | | /* Register relative disp(R0 -- R7). */ |
507 | 92.9k | disp1 = get_displacement (buffer, aoffsetp); |
508 | 92.9k | sprintf (result, "%d(r%d)", disp1, addr_mode & 7); |
509 | 92.9k | break; |
510 | 15.4k | case 0x10: |
511 | 22.8k | case 0x11: |
512 | 27.1k | case 0x12: |
513 | | /* Memory relative disp2(disp1(FP, SP, SB)). */ |
514 | 27.1k | disp1 = get_displacement (buffer, aoffsetp); |
515 | 27.1k | disp2 = get_displacement (buffer, aoffsetp); |
516 | 27.1k | sprintf (result, "%d(%d(%s))", disp2, disp1, |
517 | 27.1k | addr_mode == 0x10 ? "fp" : addr_mode == 0x11 ? "sp" : "sb"); |
518 | 27.1k | break; |
519 | 6.34k | case 0x13: |
520 | | /* Reserved. */ |
521 | 6.34k | sprintf (result, "reserved"); |
522 | 6.34k | break; |
523 | 22.2k | case 0x14: |
524 | | /* Immediate. */ |
525 | 22.2k | switch (d) |
526 | 22.2k | { |
527 | 8.05k | default: |
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 | 8.05k | sprintf (result, _("$<undefined>")); |
534 | 8.05k | break; |
535 | 1.86k | case 'B': |
536 | 1.86k | Ivalue = bit_extract (buffer, *aoffsetp, 8); |
537 | 1.86k | Ivalue = sign_extend (Ivalue, 8); |
538 | 1.86k | *aoffsetp += 8; |
539 | 1.86k | sprintf (result, "$%d", Ivalue); |
540 | 1.86k | break; |
541 | 1.60k | case 'W': |
542 | 1.60k | Ivalue = bit_extract (buffer, *aoffsetp, 16); |
543 | 1.60k | flip_bytes ((char *) & Ivalue, 2); |
544 | 1.60k | *aoffsetp += 16; |
545 | 1.60k | Ivalue = sign_extend (Ivalue, 16); |
546 | 1.60k | sprintf (result, "$%d", Ivalue); |
547 | 1.60k | break; |
548 | 2.10k | case 'D': |
549 | 2.10k | Ivalue = bit_extract (buffer, *aoffsetp, 32); |
550 | 2.10k | flip_bytes ((char *) & Ivalue, 4); |
551 | 2.10k | *aoffsetp += 32; |
552 | 2.10k | sprintf (result, "$%d", Ivalue); |
553 | 2.10k | break; |
554 | 2.89k | case 'F': |
555 | 2.89k | bit_copy (buffer, *aoffsetp, 32, (char *) &value.f); |
556 | 2.89k | flip_bytes ((char *) &value.f, 4); |
557 | 2.89k | *aoffsetp += 32; |
558 | 2.89k | if (INVALID_FLOAT (&value.f, 4)) |
559 | 1.38k | sprintf (result, "<<invalid float 0x%.8x>>", value.i[0]); |
560 | 1.50k | else /* Assume host has ieee float. */ |
561 | 1.50k | sprintf (result, "$%g", value.f); |
562 | 2.89k | break; |
563 | 5.75k | case 'L': |
564 | 5.75k | bit_copy (buffer, *aoffsetp, 64, (char *) &value.d); |
565 | 5.75k | flip_bytes ((char *) &value.d, 8); |
566 | 5.75k | *aoffsetp += 64; |
567 | 5.75k | if (INVALID_FLOAT (&value.d, 8)) |
568 | 2.96k | sprintf (result, "<<invalid double 0x%.8x%.8x>>", |
569 | 2.96k | value.i[1], value.i[0]); |
570 | 2.79k | else /* Assume host has ieee float. */ |
571 | 2.79k | sprintf (result, "$%g", value.d); |
572 | 5.75k | break; |
573 | 22.2k | } |
574 | 22.2k | break; |
575 | 22.2k | case 0x15: |
576 | | /* Absolute @disp. */ |
577 | 10.9k | disp1 = get_displacement (buffer, aoffsetp); |
578 | 10.9k | sprintf (result, "@|%d|", disp1); |
579 | 10.9k | break; |
580 | 5.99k | case 0x16: |
581 | | /* External EXT(disp1) + disp2 (Mod table stuff). */ |
582 | 5.99k | disp1 = get_displacement (buffer, aoffsetp); |
583 | 5.99k | disp2 = get_displacement (buffer, aoffsetp); |
584 | 5.99k | sprintf (result, "EXT(%d) + %d", disp1, disp2); |
585 | 5.99k | break; |
586 | 6.63k | case 0x17: |
587 | | /* Top of stack tos. */ |
588 | 6.63k | sprintf (result, "tos"); |
589 | 6.63k | break; |
590 | 12.9k | case 0x18: |
591 | | /* Memory space disp(FP). */ |
592 | 12.9k | disp1 = get_displacement (buffer, aoffsetp); |
593 | 12.9k | sprintf (result, "%d(fp)", disp1); |
594 | 12.9k | break; |
595 | 4.93k | case 0x19: |
596 | | /* Memory space disp(SP). */ |
597 | 4.93k | disp1 = get_displacement (buffer, aoffsetp); |
598 | 4.93k | sprintf (result, "%d(sp)", disp1); |
599 | 4.93k | break; |
600 | 4.25k | case 0x1a: |
601 | | /* Memory space disp(SB). */ |
602 | 4.25k | disp1 = get_displacement (buffer, aoffsetp); |
603 | 4.25k | sprintf (result, "%d(sb)", disp1); |
604 | 4.25k | break; |
605 | 5.31k | case 0x1b: |
606 | | /* Memory space disp(PC). */ |
607 | 5.31k | disp1 = get_displacement (buffer, aoffsetp); |
608 | 5.31k | *result++ = NEXT_IS_ADDR; |
609 | 5.31k | sprintf (result, "%" PRIx64, (uint64_t) (addr + disp1)); |
610 | 5.31k | result += strlen (result); |
611 | 5.31k | *result++ = NEXT_IS_ADDR; |
612 | 5.31k | *result = '\0'; |
613 | 5.31k | break; |
614 | 15.5k | case 0x1c: |
615 | 25.7k | case 0x1d: |
616 | 35.3k | case 0x1e: |
617 | 58.2k | case 0x1f: |
618 | 58.2k | { |
619 | 58.2k | int bit_index; |
620 | 58.2k | static const char *ind = "bwdq"; |
621 | 58.2k | char *off; |
622 | | |
623 | | /* Scaled index basemode[R0 -- R7:B,W,D,Q]. */ |
624 | 58.2k | bit_index = bit_extract (buffer, index_offset - 8, 3); |
625 | 58.2k | print_insn_arg (d, index_offset, aoffsetp, buffer, addr, |
626 | 58.2k | result, 0); |
627 | 58.2k | off = result + strlen (result); |
628 | 58.2k | sprintf (off, "[r%d:%c]", bit_index, ind[addr_mode & 3]); |
629 | 58.2k | } |
630 | 58.2k | break; |
631 | 606k | } |
632 | 606k | break; |
633 | 606k | case 'H': |
634 | 15.5k | case 'q': |
635 | 15.5k | Ivalue = bit_extract (buffer, ioffset-4, 4); |
636 | 15.5k | Ivalue = sign_extend (Ivalue, 4); |
637 | 15.5k | sprintf (result, "%d", Ivalue); |
638 | 15.5k | ioffset -= 4; |
639 | 15.5k | break; |
640 | 1.83k | case 'r': |
641 | 1.83k | Ivalue = bit_extract (buffer, ioffset-3, 3); |
642 | 1.83k | sprintf (result, "r%d", Ivalue&7); |
643 | 1.83k | ioffset -= 3; |
644 | 1.83k | break; |
645 | 5.88k | case 'd': |
646 | 5.88k | sprintf (result, "%d", get_displacement (buffer, aoffsetp)); |
647 | 5.88k | break; |
648 | 1.10k | case 'b': |
649 | 1.10k | 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 | 1.10k | size = bit_extract(buffer, ioffset-6, 2); |
657 | 1.10k | if (size == 0) /* 00 => b. */ |
658 | 291 | size = 1; |
659 | 812 | else if (size == 1) /* 01 => w. */ |
660 | 383 | size = 2; |
661 | 429 | else |
662 | 429 | size = 4; /* 11 => d. */ |
663 | | |
664 | 1.10k | sprintf (result, "%d", (Ivalue / size) + 1); |
665 | 1.10k | break; |
666 | 21.0k | case 'p': |
667 | 21.0k | *result++ = NEXT_IS_ADDR; |
668 | 21.0k | sprintf (result, "%" PRIx64, |
669 | 21.0k | (uint64_t) (addr + get_displacement (buffer, aoffsetp))); |
670 | 21.0k | result += strlen (result); |
671 | 21.0k | *result++ = NEXT_IS_ADDR; |
672 | 21.0k | *result = '\0'; |
673 | 21.0k | break; |
674 | 0 | case 'i': |
675 | 0 | Ivalue = bit_extract (buffer, *aoffsetp, 8); |
676 | 0 | *aoffsetp += 8; |
677 | 0 | sprintf (result, "0x%x", Ivalue); |
678 | 0 | break; |
679 | 5.27k | case 'u': |
680 | 5.27k | Ivalue = bit_extract (buffer, *aoffsetp, 8); |
681 | 5.27k | optlist (Ivalue, opt_u, result); |
682 | 5.27k | *aoffsetp += 8; |
683 | 5.27k | break; |
684 | 2.08k | case 'U': |
685 | 2.08k | Ivalue = bit_extract (buffer, *aoffsetp, 8); |
686 | 2.08k | optlist (Ivalue, opt_U, result); |
687 | 2.08k | *aoffsetp += 8; |
688 | 2.08k | break; |
689 | 701 | case 'O': |
690 | 701 | Ivalue = bit_extract (buffer, ioffset - 9, 9); |
691 | 701 | optlist (Ivalue, opt_O, result); |
692 | 701 | ioffset -= 9; |
693 | 701 | break; |
694 | 364 | case 'C': |
695 | 364 | Ivalue = bit_extract (buffer, ioffset - 4, 4); |
696 | 364 | optlist (Ivalue, opt_C, result); |
697 | 364 | ioffset -= 4; |
698 | 364 | break; |
699 | 464 | case 'S': |
700 | 464 | Ivalue = bit_extract (buffer, ioffset - 8, 8); |
701 | 464 | optlist (Ivalue, opt_S, result); |
702 | 464 | ioffset -= 8; |
703 | 464 | break; |
704 | 1.22k | case 'M': |
705 | 1.22k | Ivalue = bit_extract (buffer, ioffset - 4, 4); |
706 | 1.22k | list_search (Ivalue, 0 ? list_M032 : list_M532, result); |
707 | 1.22k | ioffset -= 4; |
708 | 1.22k | break; |
709 | 17.1k | case 'P': |
710 | 17.1k | Ivalue = bit_extract (buffer, ioffset - 4, 4); |
711 | 17.1k | list_search (Ivalue, 0 ? list_P032 : list_P532, result); |
712 | 17.1k | ioffset -= 4; |
713 | 17.1k | break; |
714 | 728 | case 'g': |
715 | 728 | Ivalue = bit_extract (buffer, *aoffsetp, 3); |
716 | 728 | sprintf (result, "%d", Ivalue); |
717 | 728 | *aoffsetp += 3; |
718 | 728 | break; |
719 | 729 | case 'G': |
720 | 729 | Ivalue = bit_extract(buffer, *aoffsetp, 5); |
721 | 729 | sprintf (result, "%d", Ivalue + 1); |
722 | 729 | *aoffsetp += 5; |
723 | 729 | break; |
724 | 681k | } |
725 | 680k | return ioffset; |
726 | 681k | } |
727 | | |
728 | | |
729 | | /* Print the 32000 instruction at address MEMADDR in debugged memory, |
730 | | on STREAM. Returns length of the instruction, in bytes. */ |
731 | | |
732 | | int |
733 | | print_insn_ns32k (bfd_vma memaddr, disassemble_info *info) |
734 | 458k | { |
735 | 458k | unsigned int i; |
736 | 458k | const char *d; |
737 | 458k | unsigned short first_word; |
738 | 458k | int ioffset; /* Bits into instruction. */ |
739 | 458k | int aoffset; /* Bits into arguments. */ |
740 | 458k | char arg_bufs[MAX_ARGS+1][ARG_LEN]; |
741 | 458k | int argnum; |
742 | 458k | int maxarg; |
743 | 458k | struct private priv; |
744 | 458k | bfd_byte *buffer = priv.the_buffer; |
745 | 458k | dis_info = info; |
746 | | |
747 | 458k | info->private_data = & priv; |
748 | 458k | priv.max_fetched = priv.the_buffer; |
749 | 458k | priv.insn_start = memaddr; |
750 | 458k | if (OPCODES_SIGSETJMP (priv.bailout) != 0) |
751 | | /* Error return. */ |
752 | 498 | return -1; |
753 | | |
754 | | /* Look for 8bit opcodes first. Other wise, fetching two bytes could take |
755 | | us over the end of accessible data unnecessarilly. */ |
756 | 458k | FETCH_DATA (info, buffer + 1); |
757 | 75.4M | for (i = 0; i < NOPCODES; i++) |
758 | 75.3M | if (ns32k_opcodes[i].opcode_id_size <= 8 |
759 | 75.3M | && ((buffer[0] |
760 | 21.8M | & (((unsigned long) 1 << ns32k_opcodes[i].opcode_id_size) - 1)) |
761 | 21.8M | == ns32k_opcodes[i].opcode_seed)) |
762 | 314k | break; |
763 | 458k | if (i == NOPCODES) |
764 | 143k | { |
765 | | /* Maybe it is 9 to 16 bits big. */ |
766 | 143k | FETCH_DATA (info, buffer + 2); |
767 | 143k | first_word = read_memory_integer(buffer, 2); |
768 | | |
769 | 43.7M | for (i = 0; i < NOPCODES; i++) |
770 | 43.6M | if ((first_word |
771 | 43.6M | & (((unsigned long) 1 << ns32k_opcodes[i].opcode_id_size) - 1)) |
772 | 43.6M | == ns32k_opcodes[i].opcode_seed) |
773 | 19.2k | break; |
774 | | |
775 | | /* Handle undefined instructions. */ |
776 | 143k | if (i == NOPCODES) |
777 | 124k | { |
778 | 124k | (*dis_info->fprintf_func)(dis_info->stream, "0%o", buffer[0]); |
779 | 124k | return 1; |
780 | 124k | } |
781 | 143k | } |
782 | | |
783 | 333k | (*dis_info->fprintf_func)(dis_info->stream, "%s", ns32k_opcodes[i].name); |
784 | | |
785 | 333k | ioffset = ns32k_opcodes[i].opcode_size; |
786 | 333k | aoffset = ns32k_opcodes[i].opcode_size; |
787 | 333k | d = ns32k_opcodes[i].operands; |
788 | | |
789 | 333k | if (*d) |
790 | 324k | { |
791 | | /* Offset in bits of the first thing beyond each index byte. |
792 | | Element 0 is for operand A and element 1 is for operand B. */ |
793 | 324k | int index_offset[2]; |
794 | | |
795 | | /* 0 for operand A, 1 for operand B, greater for other args. */ |
796 | 324k | int whicharg = 0; |
797 | | |
798 | 324k | (*dis_info->fprintf_func)(dis_info->stream, "\t"); |
799 | | |
800 | 324k | maxarg = 0; |
801 | | |
802 | | /* First we have to find and keep track of the index bytes, |
803 | | if we are using scaled indexed addressing mode, since the index |
804 | | bytes occur right after the basic instruction, not as part |
805 | | of the addressing extension. */ |
806 | 324k | index_offset[0] = -1; |
807 | 324k | index_offset[1] = -1; |
808 | 324k | if (Is_gen (d[1])) |
809 | 294k | { |
810 | 294k | int bitoff = d[1] == 'f' ? 10 : 5; |
811 | 294k | int addr_mode = bit_extract (buffer, ioffset - bitoff, 5); |
812 | | |
813 | 294k | if (Adrmod_is_index (addr_mode)) |
814 | 25.5k | { |
815 | 25.5k | aoffset += 8; |
816 | 25.5k | index_offset[0] = aoffset; |
817 | 25.5k | } |
818 | 294k | } |
819 | | |
820 | 324k | if (d[2] && Is_gen (d[3])) |
821 | 254k | { |
822 | 254k | int addr_mode = bit_extract (buffer, ioffset - 10, 5); |
823 | | |
824 | 254k | if (Adrmod_is_index (addr_mode)) |
825 | 19.9k | { |
826 | 19.9k | aoffset += 8; |
827 | 19.9k | index_offset[1] = aoffset; |
828 | 19.9k | } |
829 | 254k | } |
830 | | |
831 | 947k | while (*d) |
832 | 622k | { |
833 | 622k | argnum = *d - '1'; |
834 | 622k | if (argnum >= MAX_ARGS) |
835 | 0 | abort (); |
836 | 622k | d++; |
837 | 622k | if (argnum > maxarg) |
838 | 297k | maxarg = argnum; |
839 | 622k | ioffset = print_insn_arg (*d, ioffset, &aoffset, buffer, |
840 | 622k | memaddr, arg_bufs[argnum], |
841 | 622k | whicharg > 1 ? -1 : index_offset[whicharg]); |
842 | 622k | d++; |
843 | 622k | whicharg++; |
844 | 622k | } |
845 | | |
846 | 946k | for (argnum = 0; argnum <= maxarg; argnum++) |
847 | 622k | { |
848 | 622k | bfd_vma addr; |
849 | 622k | char *ch; |
850 | | |
851 | 3.64M | for (ch = arg_bufs[argnum]; *ch;) |
852 | 3.02M | { |
853 | 3.02M | if (*ch == NEXT_IS_ADDR) |
854 | 37.3k | { |
855 | 37.3k | ++ch; |
856 | 37.3k | addr = bfd_scan_vma (ch, NULL, 16); |
857 | 37.3k | (*dis_info->print_address_func) (addr, dis_info); |
858 | 264k | while (*ch && *ch != NEXT_IS_ADDR) |
859 | 227k | ++ch; |
860 | 37.3k | if (*ch) |
861 | 37.3k | ++ch; |
862 | 37.3k | } |
863 | 2.98M | else |
864 | 2.98M | (*dis_info->fprintf_func)(dis_info->stream, "%c", *ch++); |
865 | 3.02M | } |
866 | 622k | if (argnum < maxarg) |
867 | 298k | (*dis_info->fprintf_func)(dis_info->stream, ", "); |
868 | 622k | } |
869 | 324k | } |
870 | 333k | return aoffset / 8; |
871 | 333k | } |