/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-2023 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 | 13.5k | #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 | 127k | { |
38 | 127k | long val; |
39 | 127k | int i; |
40 | | |
41 | 381k | for (val = 0, i = nr - 1; i >= 0; i--) |
42 | 254k | { |
43 | 254k | val = (val << 8); |
44 | 254k | val |= (0xff & *(addr + i)); |
45 | 254k | } |
46 | 127k | return val; |
47 | 127k | } |
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 | 11.2M | ((addr) <= ((struct private *)(info->private_data))->max_fetched \ |
69 | 11.2M | ? 1 : fetch_data ((info), (addr))) |
70 | | |
71 | | static int |
72 | | fetch_data (struct disassemble_info *info, bfd_byte *addr) |
73 | 1.39M | { |
74 | 1.39M | int status; |
75 | 1.39M | struct private *priv = (struct private *) info->private_data; |
76 | 1.39M | bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); |
77 | | |
78 | 1.39M | status = (*info->read_memory_func) (start, |
79 | 1.39M | priv->max_fetched, |
80 | 1.39M | addr - priv->max_fetched, |
81 | 1.39M | info); |
82 | 1.39M | if (status != 0) |
83 | 627 | { |
84 | 627 | (*info->memory_error_func) (status, start, info); |
85 | 627 | OPCODES_SIGLONGJMP (priv->bailout, 1); |
86 | 627 | } |
87 | 1.39M | else |
88 | 1.39M | priv->max_fetched = addr; |
89 | 1.39M | return 1; |
90 | 1.39M | } |
91 | | |
92 | | /* Number of elements in the opcode table. */ |
93 | 111M | #define NOPCODES (sizeof ns32k_opcodes / sizeof ns32k_opcodes[0]) |
94 | | |
95 | 3.48M | #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 | 6.02k | { |
220 | 6.02k | if (options == 0) |
221 | 628 | { |
222 | 628 | sprintf (result, "[]"); |
223 | 628 | return; |
224 | 628 | } |
225 | | |
226 | 5.39k | sprintf (result, "["); |
227 | | |
228 | 39.5k | for (; (options != 0) && optionP->pattern; optionP++) |
229 | 34.1k | { |
230 | 34.1k | if ((options & optionP->match) == optionP->value) |
231 | 18.1k | { |
232 | | /* We found a match, update result and options. */ |
233 | 18.1k | strcat (result, optionP->pattern); |
234 | 18.1k | options &= ~optionP->value; |
235 | 18.1k | if (options != 0) /* More options to come. */ |
236 | 13.1k | strcat (result, ","); |
237 | 18.1k | } |
238 | 34.1k | } |
239 | | |
240 | 5.39k | if (options != 0) |
241 | 440 | strcat (result, "undefined"); |
242 | | |
243 | 5.39k | strcat (result, "]"); |
244 | 5.39k | } |
245 | | |
246 | | static void |
247 | | list_search (int reg_value, const struct ns32k_option *optionP, char *result) |
248 | 12.8k | { |
249 | 95.3k | for (; optionP->pattern; optionP++) |
250 | 94.4k | { |
251 | 94.4k | if ((reg_value & optionP->match) == optionP->value) |
252 | 11.9k | { |
253 | 11.9k | sprintf (result, "%s", optionP->pattern); |
254 | 11.9k | return; |
255 | 11.9k | } |
256 | 94.4k | } |
257 | 913 | sprintf (result, "undefined"); |
258 | 913 | } |
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.67M | { |
265 | 1.67M | unsigned int result; |
266 | 1.67M | unsigned int bit; |
267 | | |
268 | 1.67M | if (offset < 0 || count < 0) |
269 | 34.4k | return 0; |
270 | 1.63M | buffer += offset >> 3; |
271 | 1.63M | offset &= 7; |
272 | 1.63M | bit = 1; |
273 | 1.63M | result = 0; |
274 | 12.3M | while (count--) |
275 | 10.6M | { |
276 | 10.6M | FETCH_DATA (dis_info, buffer + 1); |
277 | 10.6M | if ((*buffer & (1 << offset))) |
278 | 3.98M | result |= bit; |
279 | 10.6M | if (++offset == 8) |
280 | 1.75M | { |
281 | 1.75M | offset = 0; |
282 | 1.75M | buffer++; |
283 | 1.75M | } |
284 | 10.6M | bit <<= 1; |
285 | 10.6M | } |
286 | 1.63M | return result; |
287 | 1.67M | } |
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 | 38.0k | { |
294 | 38.0k | unsigned int result; |
295 | 38.0k | unsigned int bit; |
296 | | |
297 | 38.0k | if (offset < 0 || count < 0) |
298 | 0 | return 0; |
299 | 38.0k | buffer += offset >> 3; |
300 | 38.0k | offset &= 7; |
301 | 38.0k | bit = 1; |
302 | 38.0k | result = 0; |
303 | 591k | while (count--) |
304 | 553k | { |
305 | 553k | if ((*buffer & (1 << offset))) |
306 | 86.9k | result |= bit; |
307 | 553k | if (++offset == 8) |
308 | 58.3k | { |
309 | 58.3k | offset = 0; |
310 | 58.3k | buffer++; |
311 | 58.3k | } |
312 | 553k | bit <<= 1; |
313 | 553k | } |
314 | 38.0k | return result; |
315 | 38.0k | } |
316 | | |
317 | | static void |
318 | | bit_copy (bfd_byte *buffer, int offset, int count, char *to) |
319 | 13.5k | { |
320 | 13.5k | if (offset < 0 || count < 0) |
321 | 0 | return; |
322 | 82.7k | for (; count > 8; count -= 8, to++, offset += 8) |
323 | 69.2k | *to = bit_extract (buffer, offset, 8); |
324 | 13.5k | *to = bit_extract (buffer, offset, count); |
325 | 13.5k | } |
326 | | |
327 | | static int |
328 | | sign_extend (unsigned int value, unsigned int bits) |
329 | 253k | { |
330 | 253k | unsigned int sign = 1u << (bits - 1); |
331 | 253k | return ((value & (sign + sign - 1)) ^ sign) - sign; |
332 | 253k | } |
333 | | |
334 | | static void |
335 | | flip_bytes (char *ptr, int count) |
336 | 100k | { |
337 | 100k | char tmp; |
338 | | |
339 | 273k | while (count > 0) |
340 | 173k | { |
341 | 173k | tmp = ptr[0]; |
342 | 173k | ptr[0] = ptr[count - 1]; |
343 | 173k | ptr[count - 1] = tmp; |
344 | 173k | ptr++; |
345 | 173k | count -= 2; |
346 | 173k | } |
347 | 100k | } |
348 | | |
349 | | /* Given a character C, does it represent a general addressing mode? */ |
350 | 603k | #define Is_gen(c) (strchr ("FLBWDAIZf", (c)) != NULL) |
351 | | |
352 | | /* Adressing modes. */ |
353 | 1.08M | #define Adrmod_index_byte 0x1c |
354 | 1.07M | #define Adrmod_index_word 0x1d |
355 | 1.06M | #define Adrmod_index_doubleword 0x1e |
356 | 1.05M | #define Adrmod_index_quadword 0x1f |
357 | | |
358 | | /* Is MODE an indexed addressing mode? */ |
359 | | #define Adrmod_is_index(mode) \ |
360 | 544k | ( mode == Adrmod_index_byte \ |
361 | 544k | || mode == Adrmod_index_word \ |
362 | 544k | || mode == Adrmod_index_doubleword \ |
363 | 544k | || mode == Adrmod_index_quadword) |
364 | | |
365 | | |
366 | | static int |
367 | | get_displacement (bfd_byte *buffer, int *aoffsetp) |
368 | 229k | { |
369 | 229k | int Ivalue; |
370 | 229k | short Ivalue2; |
371 | | |
372 | 229k | Ivalue = bit_extract (buffer, *aoffsetp, 8); |
373 | 229k | switch (Ivalue & 0xc0) |
374 | 229k | { |
375 | 80.4k | case 0x00: |
376 | 146k | case 0x40: |
377 | 146k | Ivalue = sign_extend (Ivalue, 7); |
378 | 146k | *aoffsetp += 8; |
379 | 146k | break; |
380 | 39.6k | case 0x80: |
381 | 39.6k | Ivalue2 = bit_extract (buffer, *aoffsetp, 16); |
382 | 39.6k | flip_bytes ((char *) & Ivalue2, 2); |
383 | 39.6k | Ivalue = sign_extend (Ivalue2, 14); |
384 | 39.6k | *aoffsetp += 16; |
385 | 39.6k | break; |
386 | 43.5k | case 0xc0: |
387 | 43.5k | Ivalue = bit_extract (buffer, *aoffsetp, 32); |
388 | 43.5k | flip_bytes ((char *) & Ivalue, 4); |
389 | 43.5k | Ivalue = sign_extend (Ivalue, 30); |
390 | 43.5k | *aoffsetp += 32; |
391 | 43.5k | break; |
392 | 229k | } |
393 | 229k | return Ivalue; |
394 | 229k | } |
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 | 13.4k | { |
400 | 13.4k | int val; |
401 | | |
402 | 13.4k | if (len == 4) |
403 | 6.24k | val = (bit_extract_simple (p, 23, 8)/*exponent*/ == 0xff |
404 | 6.24k | || (bit_extract_simple (p, 23, 8)/*exponent*/ == 0 |
405 | 5.81k | && bit_extract_simple (p, 0, 23)/*mantisa*/ != 0)); |
406 | 7.18k | else if (len == 8) |
407 | 7.18k | val = (bit_extract_simple (p, 52, 11)/*exponent*/ == 0x7ff |
408 | 7.18k | || (bit_extract_simple (p, 52, 11)/*exponent*/ == 0 |
409 | 7.04k | && (bit_extract_simple (p, 0, 32)/*low mantisa*/ != 0 |
410 | 4.25k | || bit_extract_simple (p, 32, 20)/*high mantisa*/ != 0))); |
411 | 0 | else |
412 | 0 | val = 1; |
413 | 13.4k | return (val); |
414 | 13.4k | } |
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 | 683k | { |
461 | 683k | union |
462 | 683k | { |
463 | 683k | float f; |
464 | 683k | double d; |
465 | 683k | int i[2]; |
466 | 683k | } value; |
467 | 683k | int Ivalue; |
468 | 683k | int addr_mode; |
469 | 683k | int disp1, disp2; |
470 | 683k | int size; |
471 | | |
472 | 683k | switch (d) |
473 | 683k | { |
474 | 198 | case 'f': |
475 | | /* A "gen" operand but 5 bits from the end of instruction. */ |
476 | 198 | ioffset -= 5; |
477 | | /* Fall through. */ |
478 | 1.47k | case 'Z': |
479 | 12.1k | case 'F': |
480 | 20.2k | case 'L': |
481 | 284k | case 'I': |
482 | 477k | case 'B': |
483 | 532k | case 'W': |
484 | 598k | case 'D': |
485 | 615k | case 'A': |
486 | 615k | addr_mode = bit_extract (buffer, ioffset - 5, 5); |
487 | 615k | ioffset -= 5; |
488 | 615k | switch (addr_mode) |
489 | 615k | { |
490 | 280k | case 0x0: case 0x1: case 0x2: case 0x3: |
491 | 334k | case 0x4: case 0x5: case 0x6: case 0x7: |
492 | | /* Register mode R0 -- R7. */ |
493 | 334k | switch (d) |
494 | 334k | { |
495 | 1.53k | case 'F': |
496 | 1.92k | case 'L': |
497 | 2.57k | case 'Z': |
498 | 2.57k | sprintf (result, "f%d", addr_mode); |
499 | 2.57k | break; |
500 | 331k | default: |
501 | 331k | sprintf (result, "r%d", addr_mode); |
502 | 334k | } |
503 | 334k | break; |
504 | 334k | case 0x8: case 0x9: case 0xa: case 0xb: |
505 | 90.9k | case 0xc: case 0xd: case 0xe: case 0xf: |
506 | | /* Register relative disp(R0 -- R7). */ |
507 | 90.9k | disp1 = get_displacement (buffer, aoffsetp); |
508 | 90.9k | sprintf (result, "%d(r%d)", disp1, addr_mode & 7); |
509 | 90.9k | break; |
510 | 13.9k | case 0x10: |
511 | 23.4k | case 0x11: |
512 | 29.3k | case 0x12: |
513 | | /* Memory relative disp2(disp1(FP, SP, SB)). */ |
514 | 29.3k | disp1 = get_displacement (buffer, aoffsetp); |
515 | 29.3k | disp2 = get_displacement (buffer, aoffsetp); |
516 | 29.3k | sprintf (result, "%d(%d(%s))", disp2, disp1, |
517 | 29.3k | addr_mode == 0x10 ? "fp" : addr_mode == 0x11 ? "sp" : "sb"); |
518 | 29.3k | break; |
519 | 7.00k | case 0x13: |
520 | | /* Reserved. */ |
521 | 7.00k | sprintf (result, "reserved"); |
522 | 7.00k | break; |
523 | 28.5k | case 0x14: |
524 | | /* Immediate. */ |
525 | 28.5k | switch (d) |
526 | 28.5k | { |
527 | 7.73k | 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 | 7.73k | sprintf (result, _("$<undefined>")); |
534 | 7.73k | break; |
535 | 3.70k | case 'B': |
536 | 3.70k | Ivalue = bit_extract (buffer, *aoffsetp, 8); |
537 | 3.70k | Ivalue = sign_extend (Ivalue, 8); |
538 | 3.70k | *aoffsetp += 8; |
539 | 3.70k | sprintf (result, "$%d", Ivalue); |
540 | 3.70k | break; |
541 | 1.80k | case 'W': |
542 | 1.80k | Ivalue = bit_extract (buffer, *aoffsetp, 16); |
543 | 1.80k | flip_bytes ((char *) & Ivalue, 2); |
544 | 1.80k | *aoffsetp += 16; |
545 | 1.80k | Ivalue = sign_extend (Ivalue, 16); |
546 | 1.80k | sprintf (result, "$%d", Ivalue); |
547 | 1.80k | break; |
548 | 1.79k | case 'D': |
549 | 1.79k | Ivalue = bit_extract (buffer, *aoffsetp, 32); |
550 | 1.79k | flip_bytes ((char *) & Ivalue, 4); |
551 | 1.79k | *aoffsetp += 32; |
552 | 1.79k | sprintf (result, "$%d", Ivalue); |
553 | 1.79k | break; |
554 | 6.33k | case 'F': |
555 | 6.33k | bit_copy (buffer, *aoffsetp, 32, (char *) &value.f); |
556 | 6.33k | flip_bytes ((char *) &value.f, 4); |
557 | 6.33k | *aoffsetp += 32; |
558 | 6.33k | if (INVALID_FLOAT (&value.f, 4)) |
559 | 3.29k | sprintf (result, "<<invalid float 0x%.8x>>", value.i[0]); |
560 | 3.03k | else /* Assume host has ieee float. */ |
561 | 3.03k | sprintf (result, "$%g", value.f); |
562 | 6.33k | break; |
563 | 7.19k | case 'L': |
564 | 7.19k | bit_copy (buffer, *aoffsetp, 64, (char *) &value.d); |
565 | 7.19k | flip_bytes ((char *) &value.d, 8); |
566 | 7.19k | *aoffsetp += 64; |
567 | 7.19k | if (INVALID_FLOAT (&value.d, 8)) |
568 | 3.74k | sprintf (result, "<<invalid double 0x%.8x%.8x>>", |
569 | 3.74k | value.i[1], value.i[0]); |
570 | 3.45k | else /* Assume host has ieee float. */ |
571 | 3.45k | sprintf (result, "$%g", value.d); |
572 | 7.19k | break; |
573 | 28.5k | } |
574 | 28.4k | break; |
575 | 28.4k | case 0x15: |
576 | | /* Absolute @disp. */ |
577 | 8.17k | disp1 = get_displacement (buffer, aoffsetp); |
578 | 8.17k | sprintf (result, "@|%d|", disp1); |
579 | 8.17k | break; |
580 | 6.60k | case 0x16: |
581 | | /* External EXT(disp1) + disp2 (Mod table stuff). */ |
582 | 6.60k | disp1 = get_displacement (buffer, aoffsetp); |
583 | 6.60k | disp2 = get_displacement (buffer, aoffsetp); |
584 | 6.60k | sprintf (result, "EXT(%d) + %d", disp1, disp2); |
585 | 6.60k | break; |
586 | 8.19k | case 0x17: |
587 | | /* Top of stack tos. */ |
588 | 8.19k | sprintf (result, "tos"); |
589 | 8.19k | break; |
590 | 13.4k | case 0x18: |
591 | | /* Memory space disp(FP). */ |
592 | 13.4k | disp1 = get_displacement (buffer, aoffsetp); |
593 | 13.4k | sprintf (result, "%d(fp)", disp1); |
594 | 13.4k | break; |
595 | 6.55k | case 0x19: |
596 | | /* Memory space disp(SP). */ |
597 | 6.55k | disp1 = get_displacement (buffer, aoffsetp); |
598 | 6.55k | sprintf (result, "%d(sp)", disp1); |
599 | 6.55k | break; |
600 | 4.33k | case 0x1a: |
601 | | /* Memory space disp(SB). */ |
602 | 4.33k | disp1 = get_displacement (buffer, aoffsetp); |
603 | 4.33k | sprintf (result, "%d(sb)", disp1); |
604 | 4.33k | break; |
605 | 6.01k | case 0x1b: |
606 | | /* Memory space disp(PC). */ |
607 | 6.01k | disp1 = get_displacement (buffer, aoffsetp); |
608 | 6.01k | *result++ = NEXT_IS_ADDR; |
609 | 6.01k | sprintf (result, "%" PRIx64, (uint64_t) (addr + disp1)); |
610 | 6.01k | result += strlen (result); |
611 | 6.01k | *result++ = NEXT_IS_ADDR; |
612 | 6.01k | *result = '\0'; |
613 | 6.01k | break; |
614 | 16.1k | case 0x1c: |
615 | 27.7k | case 0x1d: |
616 | 41.0k | case 0x1e: |
617 | 71.2k | case 0x1f: |
618 | 71.2k | { |
619 | 71.2k | int bit_index; |
620 | 71.2k | static const char *ind = "bwdq"; |
621 | 71.2k | char *off; |
622 | | |
623 | | /* Scaled index basemode[R0 -- R7:B,W,D,Q]. */ |
624 | 71.2k | bit_index = bit_extract (buffer, index_offset - 8, 3); |
625 | 71.2k | print_insn_arg (d, index_offset, aoffsetp, buffer, addr, |
626 | 71.2k | result, 0); |
627 | 71.2k | off = result + strlen (result); |
628 | 71.2k | sprintf (off, "[r%d:%c]", bit_index, ind[addr_mode & 3]); |
629 | 71.2k | } |
630 | 71.2k | break; |
631 | 615k | } |
632 | 614k | break; |
633 | 614k | case 'H': |
634 | 18.2k | case 'q': |
635 | 18.2k | Ivalue = bit_extract (buffer, ioffset-4, 4); |
636 | 18.2k | Ivalue = sign_extend (Ivalue, 4); |
637 | 18.2k | sprintf (result, "%d", Ivalue); |
638 | 18.2k | ioffset -= 4; |
639 | 18.2k | break; |
640 | 1.88k | case 'r': |
641 | 1.88k | Ivalue = bit_extract (buffer, ioffset-3, 3); |
642 | 1.88k | sprintf (result, "r%d", Ivalue&7); |
643 | 1.88k | ioffset -= 3; |
644 | 1.88k | break; |
645 | 9.30k | case 'd': |
646 | 9.30k | sprintf (result, "%d", get_displacement (buffer, aoffsetp)); |
647 | 9.30k | break; |
648 | 368 | case 'b': |
649 | 368 | 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 | 368 | size = bit_extract(buffer, ioffset-6, 2); |
657 | 368 | if (size == 0) /* 00 => b. */ |
658 | 237 | size = 1; |
659 | 131 | else if (size == 1) /* 01 => w. */ |
660 | 59 | size = 2; |
661 | 72 | else |
662 | 72 | size = 4; /* 11 => d. */ |
663 | | |
664 | 368 | sprintf (result, "%d", (Ivalue / size) + 1); |
665 | 368 | break; |
666 | 18.5k | case 'p': |
667 | 18.5k | *result++ = NEXT_IS_ADDR; |
668 | 18.5k | sprintf (result, "%" PRIx64, |
669 | 18.5k | (uint64_t) (addr + get_displacement (buffer, aoffsetp))); |
670 | 18.5k | result += strlen (result); |
671 | 18.5k | *result++ = NEXT_IS_ADDR; |
672 | 18.5k | *result = '\0'; |
673 | 18.5k | 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 | 2.99k | case 'u': |
680 | 2.99k | Ivalue = bit_extract (buffer, *aoffsetp, 8); |
681 | 2.99k | optlist (Ivalue, opt_u, result); |
682 | 2.99k | *aoffsetp += 8; |
683 | 2.99k | break; |
684 | 1.93k | case 'U': |
685 | 1.93k | Ivalue = bit_extract (buffer, *aoffsetp, 8); |
686 | 1.93k | optlist (Ivalue, opt_U, result); |
687 | 1.93k | *aoffsetp += 8; |
688 | 1.93k | break; |
689 | 166 | case 'O': |
690 | 166 | Ivalue = bit_extract (buffer, ioffset - 9, 9); |
691 | 166 | optlist (Ivalue, opt_O, result); |
692 | 166 | ioffset -= 9; |
693 | 166 | break; |
694 | 205 | case 'C': |
695 | 205 | Ivalue = bit_extract (buffer, ioffset - 4, 4); |
696 | 205 | optlist (Ivalue, opt_C, result); |
697 | 205 | ioffset -= 4; |
698 | 205 | break; |
699 | 733 | case 'S': |
700 | 733 | Ivalue = bit_extract (buffer, ioffset - 8, 8); |
701 | 733 | optlist (Ivalue, opt_S, result); |
702 | 733 | ioffset -= 8; |
703 | 733 | break; |
704 | 243 | case 'M': |
705 | 243 | Ivalue = bit_extract (buffer, ioffset - 4, 4); |
706 | 243 | list_search (Ivalue, 0 ? list_M032 : list_M532, result); |
707 | 243 | ioffset -= 4; |
708 | 243 | break; |
709 | 12.6k | case 'P': |
710 | 12.6k | Ivalue = bit_extract (buffer, ioffset - 4, 4); |
711 | 12.6k | list_search (Ivalue, 0 ? list_P032 : list_P532, result); |
712 | 12.6k | ioffset -= 4; |
713 | 12.6k | break; |
714 | 399 | case 'g': |
715 | 399 | Ivalue = bit_extract (buffer, *aoffsetp, 3); |
716 | 399 | sprintf (result, "%d", Ivalue); |
717 | 399 | *aoffsetp += 3; |
718 | 399 | break; |
719 | 400 | case 'G': |
720 | 400 | Ivalue = bit_extract(buffer, *aoffsetp, 5); |
721 | 400 | sprintf (result, "%d", Ivalue + 1); |
722 | 400 | *aoffsetp += 5; |
723 | 400 | break; |
724 | 683k | } |
725 | 682k | return ioffset; |
726 | 683k | } |
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 | 436k | { |
735 | 436k | unsigned int i; |
736 | 436k | const char *d; |
737 | 436k | unsigned short first_word; |
738 | 436k | int ioffset; /* Bits into instruction. */ |
739 | 436k | int aoffset; /* Bits into arguments. */ |
740 | 436k | char arg_bufs[MAX_ARGS+1][ARG_LEN]; |
741 | 436k | int argnum; |
742 | 436k | int maxarg; |
743 | 436k | struct private priv; |
744 | 436k | bfd_byte *buffer = priv.the_buffer; |
745 | 436k | dis_info = info; |
746 | | |
747 | 436k | info->private_data = & priv; |
748 | 436k | priv.max_fetched = priv.the_buffer; |
749 | 436k | priv.insn_start = memaddr; |
750 | 436k | if (OPCODES_SIGSETJMP (priv.bailout) != 0) |
751 | | /* Error return. */ |
752 | 627 | 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 | 436k | FETCH_DATA (info, buffer + 1); |
757 | 72.4M | for (i = 0; i < NOPCODES; i++) |
758 | 72.2M | if (ns32k_opcodes[i].opcode_id_size <= 8 |
759 | 72.2M | && ((buffer[0] |
760 | 20.8M | & (((unsigned long) 1 << ns32k_opcodes[i].opcode_id_size) - 1)) |
761 | 20.8M | == ns32k_opcodes[i].opcode_seed)) |
762 | 309k | break; |
763 | 436k | if (i == NOPCODES) |
764 | 127k | { |
765 | | /* Maybe it is 9 to 16 bits big. */ |
766 | 127k | FETCH_DATA (info, buffer + 2); |
767 | 127k | first_word = read_memory_integer(buffer, 2); |
768 | | |
769 | 38.5M | for (i = 0; i < NOPCODES; i++) |
770 | 38.4M | if ((first_word |
771 | 38.4M | & (((unsigned long) 1 << ns32k_opcodes[i].opcode_id_size) - 1)) |
772 | 38.4M | == ns32k_opcodes[i].opcode_seed) |
773 | 20.0k | break; |
774 | | |
775 | | /* Handle undefined instructions. */ |
776 | 127k | if (i == NOPCODES) |
777 | 107k | { |
778 | 107k | (*dis_info->fprintf_func)(dis_info->stream, "0%o", buffer[0]); |
779 | 107k | return 1; |
780 | 107k | } |
781 | 127k | } |
782 | | |
783 | 329k | (*dis_info->fprintf_func)(dis_info->stream, "%s", ns32k_opcodes[i].name); |
784 | | |
785 | 329k | ioffset = ns32k_opcodes[i].opcode_size; |
786 | 329k | aoffset = ns32k_opcodes[i].opcode_size; |
787 | 329k | d = ns32k_opcodes[i].operands; |
788 | | |
789 | 329k | if (*d) |
790 | 318k | { |
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 | 318k | int index_offset[2]; |
794 | | |
795 | | /* 0 for operand A, 1 for operand B, greater for other args. */ |
796 | 318k | int whicharg = 0; |
797 | | |
798 | 318k | (*dis_info->fprintf_func)(dis_info->stream, "\t"); |
799 | | |
800 | 318k | 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 | 318k | index_offset[0] = -1; |
807 | 318k | index_offset[1] = -1; |
808 | 318k | if (Is_gen (d[1])) |
809 | 290k | { |
810 | 290k | int bitoff = d[1] == 'f' ? 10 : 5; |
811 | 290k | int addr_mode = bit_extract (buffer, ioffset - bitoff, 5); |
812 | | |
813 | 290k | if (Adrmod_is_index (addr_mode)) |
814 | 32.2k | { |
815 | 32.2k | aoffset += 8; |
816 | 32.2k | index_offset[0] = aoffset; |
817 | 32.2k | } |
818 | 290k | } |
819 | | |
820 | 318k | if (d[2] && Is_gen (d[3])) |
821 | 253k | { |
822 | 253k | int addr_mode = bit_extract (buffer, ioffset - 10, 5); |
823 | | |
824 | 253k | if (Adrmod_is_index (addr_mode)) |
825 | 21.8k | { |
826 | 21.8k | aoffset += 8; |
827 | 21.8k | index_offset[1] = aoffset; |
828 | 21.8k | } |
829 | 253k | } |
830 | | |
831 | 930k | while (*d) |
832 | 611k | { |
833 | 611k | argnum = *d - '1'; |
834 | 611k | if (argnum >= MAX_ARGS) |
835 | 0 | abort (); |
836 | 611k | d++; |
837 | 611k | if (argnum > maxarg) |
838 | 293k | maxarg = argnum; |
839 | 611k | ioffset = print_insn_arg (*d, ioffset, &aoffset, buffer, |
840 | 611k | memaddr, arg_bufs[argnum], |
841 | 611k | whicharg > 1 ? -1 : index_offset[whicharg]); |
842 | 611k | d++; |
843 | 611k | whicharg++; |
844 | 611k | } |
845 | | |
846 | 929k | for (argnum = 0; argnum <= maxarg; argnum++) |
847 | 611k | { |
848 | 611k | bfd_vma addr; |
849 | 611k | char *ch; |
850 | | |
851 | 3.81M | for (ch = arg_bufs[argnum]; *ch;) |
852 | 3.20M | { |
853 | 3.20M | if (*ch == NEXT_IS_ADDR) |
854 | 32.7k | { |
855 | 32.7k | ++ch; |
856 | 32.7k | addr = bfd_scan_vma (ch, NULL, 16); |
857 | 32.7k | (*dis_info->print_address_func) (addr, dis_info); |
858 | 225k | while (*ch && *ch != NEXT_IS_ADDR) |
859 | 192k | ++ch; |
860 | 32.7k | if (*ch) |
861 | 32.7k | ++ch; |
862 | 32.7k | } |
863 | 3.17M | else |
864 | 3.17M | (*dis_info->fprintf_func)(dis_info->stream, "%c", *ch++); |
865 | 3.20M | } |
866 | 611k | if (argnum < maxarg) |
867 | 293k | (*dis_info->fprintf_func)(dis_info->stream, ", "); |
868 | 611k | } |
869 | 318k | } |
870 | 329k | return aoffset / 8; |
871 | 329k | } |