source: branches/libc-0.6/src/binutils/opcodes/z8k-dis.c

Last change on this file was 610, checked in by bird, 22 years ago

This commit was generated by cvs2svn to compensate for changes in r609,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 15.3 KB
Line 
1/* Disassemble z8000 code.
2 Copyright 1992, 1993, 1998, 2000, 2001, 2002
3 Free Software Foundation, Inc.
4
5 This file is part of GNU Binutils.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 USA. */
21
22#include "sysdep.h"
23#include "dis-asm.h"
24
25#define DEFINE_TABLE
26#include "z8k-opc.h"
27
28
29#include <setjmp.h>
30
31
32typedef struct
33{
34 /* These are all indexed by nibble number (i.e only every other entry
35 of bytes is used, and every 4th entry of words). */
36 unsigned char nibbles[24];
37 unsigned char bytes[24];
38 unsigned short words[24];
39
40 /* Nibble number of first word not yet fetched. */
41 int max_fetched;
42 bfd_vma insn_start;
43 jmp_buf bailout;
44
45 long tabl_index;
46 char instr_asmsrc[80];
47 unsigned long arg_reg[0x0f];
48 unsigned long immediate;
49 unsigned long displacement;
50 unsigned long address;
51 unsigned long cond_code;
52 unsigned long ctrl_code;
53 unsigned long flags;
54 unsigned long interrupts;
55}
56instr_data_s;
57
58static int fetch_data PARAMS ((struct disassemble_info *, int));
59
60
61/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
62 to ADDR (exclusive) are valid. Returns 1 for success, longjmps
63 on error. */
64#define FETCH_DATA(info, nibble) \
65 ((nibble) < ((instr_data_s *) (info->private_data))->max_fetched \
66 ? 1 : fetch_data ((info), (nibble)))
67
68static int
69fetch_data (info, nibble)
70 struct disassemble_info *info;
71 int nibble;
72{
73 unsigned char mybuf[20];
74 int status;
75 instr_data_s *priv = (instr_data_s *) info->private_data;
76
77 if ((nibble % 4) != 0)
78 abort ();
79
80 status = (*info->read_memory_func) (priv->insn_start,
81 (bfd_byte *) mybuf,
82 nibble / 2,
83 info);
84 if (status != 0)
85 {
86 (*info->memory_error_func) (status, priv->insn_start, info);
87 longjmp (priv->bailout, 1);
88 }
89
90 {
91 int i;
92 unsigned char *p = mybuf;
93
94 for (i = 0; i < nibble;)
95 {
96 priv->words[i] = (p[0] << 8) | p[1];
97
98 priv->bytes[i] = *p;
99 priv->nibbles[i++] = *p >> 4;
100 priv->nibbles[i++] = *p & 0xf;
101
102 ++p;
103 priv->bytes[i] = *p;
104 priv->nibbles[i++] = *p >> 4;
105 priv->nibbles[i++] = *p & 0xf;
106
107 ++p;
108 }
109 }
110 priv->max_fetched = nibble;
111 return 1;
112}
113
114static char *codes[16] =
115 {
116 "f",
117 "lt",
118 "le",
119 "ule",
120 "ov/pe",
121 "mi",
122 "eq",
123 "c/ult",
124 "t",
125 "ge",
126 "gt",
127 "ugt",
128 "nov/po",
129 "pl",
130 "ne",
131 "nc/uge"
132 };
133
134static char *ctrl_names[8] =
135 {
136 "<invld>",
137 "flags",
138 "fcw",
139 "refresh",
140 "psapseg",
141 "psapoff",
142 "nspseg",
143 "nspoff"
144 };
145
146static int seg_length;
147static int print_insn_z8k PARAMS ((bfd_vma, disassemble_info *, int));
148int z8k_lookup_instr PARAMS ((unsigned char *, disassemble_info *));
149static void output_instr
150 PARAMS ((instr_data_s *, unsigned long, disassemble_info *));
151static void unpack_instr PARAMS ((instr_data_s *, int, disassemble_info *));
152static void unparse_instr PARAMS ((instr_data_s *, int));
153
154static int
155print_insn_z8k (addr, info, is_segmented)
156 bfd_vma addr;
157 disassemble_info *info;
158 int is_segmented;
159{
160 instr_data_s instr_data;
161
162 info->private_data = (PTR) &instr_data;
163 instr_data.max_fetched = 0;
164 instr_data.insn_start = addr;
165 if (setjmp (instr_data.bailout) != 0)
166 /* Error return. */
167 return -1;
168
169 info->bytes_per_chunk = 2;
170 info->bytes_per_line = 6;
171 info->display_endian = BFD_ENDIAN_BIG;
172
173 instr_data.tabl_index = z8k_lookup_instr (instr_data.nibbles, info);
174 if (instr_data.tabl_index > 0)
175 {
176 unpack_instr (&instr_data, is_segmented, info);
177 unparse_instr (&instr_data, is_segmented);
178 output_instr (&instr_data, addr, info);
179 return z8k_table[instr_data.tabl_index].length + seg_length;
180 }
181 else
182 {
183 FETCH_DATA (info, 4);
184 (*info->fprintf_func) (info->stream, ".word %02x%02x",
185 instr_data.bytes[0], instr_data.bytes[2]);
186 return 2;
187 }
188}
189
190int
191print_insn_z8001 (addr, info)
192 bfd_vma addr;
193 disassemble_info *info;
194{
195 return print_insn_z8k (addr, info, 1);
196}
197
198int
199print_insn_z8002 (addr, info)
200 bfd_vma addr;
201 disassemble_info *info;
202{
203 return print_insn_z8k (addr, info, 0);
204}
205
206int
207z8k_lookup_instr (nibbles, info)
208 unsigned char *nibbles;
209 disassemble_info *info;
210{
211
212 int nibl_index, tabl_index;
213 int nibl_matched;
214 int need_fetch = 0;
215 unsigned short instr_nibl;
216 unsigned short tabl_datum, datum_class, datum_value;
217
218 nibl_matched = 0;
219 tabl_index = 0;
220 FETCH_DATA (info, 4);
221 while (!nibl_matched && z8k_table[tabl_index].name)
222 {
223 nibl_matched = 1;
224 for (nibl_index = 0;
225 nibl_index < z8k_table[tabl_index].length * 2 && nibl_matched;
226 nibl_index++)
227 {
228 if ((nibl_index % 4) == 0)
229 {
230 /* Fetch data only if it isn't already there. */
231 if (nibl_index >= 4 || (nibl_index < 4 && need_fetch))
232 FETCH_DATA (info, nibl_index + 4); /* Fetch one word at a time. */
233 if (nibl_index < 4)
234 need_fetch = 0;
235 else
236 need_fetch = 1;
237 }
238 instr_nibl = nibbles[nibl_index];
239
240 tabl_datum = z8k_table[tabl_index].byte_info[nibl_index];
241 datum_class = tabl_datum & CLASS_MASK;
242 datum_value = ~CLASS_MASK & tabl_datum;
243
244 switch (datum_class)
245 {
246 case CLASS_BIT:
247 if (datum_value != instr_nibl)
248 nibl_matched = 0;
249 break;
250 case CLASS_IGNORE:
251 break;
252 case CLASS_00II:
253 if (!((~instr_nibl) & 0x4))
254 nibl_matched = 0;
255 break;
256 case CLASS_01II:
257 if (!(instr_nibl & 0x4))
258 nibl_matched = 0;
259 break;
260 case CLASS_0CCC:
261 if (!((~instr_nibl) & 0x8))
262 nibl_matched = 0;
263 break;
264 case CLASS_1CCC:
265 if (!(instr_nibl & 0x8))
266 nibl_matched = 0;
267 break;
268 case CLASS_0DISP7:
269 if (!((~instr_nibl) & 0x8))
270 nibl_matched = 0;
271 nibl_index += 1;
272 break;
273 case CLASS_1DISP7:
274 if (!(instr_nibl & 0x8))
275 nibl_matched = 0;
276 nibl_index += 1;
277 break;
278 case CLASS_REGN0:
279 if (instr_nibl == 0)
280 nibl_matched = 0;
281 break;
282 case CLASS_BIT_1OR2:
283 if ((instr_nibl | 0x2) != (datum_value | 0x2))
284 nibl_matched = 0;
285 break;
286 default:
287 break;
288 }
289 }
290
291 if (nibl_matched)
292 return tabl_index;
293
294 tabl_index++;
295 }
296 return -1;
297}
298
299static void
300output_instr (instr_data, addr, info)
301 instr_data_s *instr_data;
302 unsigned long addr ATTRIBUTE_UNUSED;
303 disassemble_info *info;
304{
305 int num_bytes;
306 char out_str[100];
307
308 out_str[0] = 0;
309
310 num_bytes = (z8k_table[instr_data->tabl_index].length + seg_length) * 2;
311 FETCH_DATA (info, num_bytes);
312
313 strcat (out_str, instr_data->instr_asmsrc);
314
315 (*info->fprintf_func) (info->stream, "%s", out_str);
316}
317
318static void
319unpack_instr (instr_data, is_segmented, info)
320 instr_data_s *instr_data;
321 int is_segmented;
322 disassemble_info *info;
323{
324 int nibl_count, loop;
325 unsigned short instr_nibl, instr_byte, instr_word;
326 long instr_long;
327 unsigned int tabl_datum, datum_class;
328 unsigned short datum_value;
329
330 nibl_count = 0;
331 loop = 0;
332 seg_length = 0;
333
334 while (z8k_table[instr_data->tabl_index].byte_info[loop] != 0)
335 {
336 FETCH_DATA (info, nibl_count + 4 - (nibl_count % 4));
337 instr_nibl = instr_data->nibbles[nibl_count];
338 instr_byte = instr_data->bytes[nibl_count & ~1];
339 instr_word = instr_data->words[nibl_count & ~3];
340
341 tabl_datum = z8k_table[instr_data->tabl_index].byte_info[loop];
342 datum_class = tabl_datum & CLASS_MASK;
343 datum_value = tabl_datum & ~CLASS_MASK;
344
345 switch (datum_class)
346 {
347 case CLASS_DISP:
348 switch (datum_value)
349 {
350 case ARG_DISP16:
351 instr_data->displacement = instr_data->insn_start + 4
352 + (signed short) (instr_word & 0xffff);
353 nibl_count += 3;
354 break;
355 case ARG_DISP12:
356 if (instr_word & 0x800)
357 /* Negative 12 bit displacement. */
358 instr_data->displacement = instr_data->insn_start + 2
359 - (signed short) ((instr_word & 0xfff) | 0xf000) * 2;
360 else
361 instr_data->displacement = instr_data->insn_start + 2
362 - (instr_word & 0x0fff) * 2;
363
364 nibl_count += 2;
365 break;
366 default:
367 break;
368 }
369 break;
370 case CLASS_IMM:
371 switch (datum_value)
372 {
373 case ARG_IMM4:
374 instr_data->immediate = instr_nibl;
375 break;
376 case ARG_NIM4:
377 instr_data->immediate = (- instr_nibl) & 0xf;
378 break;
379 case ARG_NIM8:
380 instr_data->immediate = (- instr_byte) & 0xff;
381 nibl_count += 1;
382 break;
383 case ARG_IMM8:
384 instr_data->immediate = instr_byte;
385 nibl_count += 1;
386 break;
387 case ARG_IMM16:
388 instr_data->immediate = instr_word;
389 nibl_count += 3;
390 break;
391 case ARG_IMM32:
392 FETCH_DATA (info, nibl_count + 8);
393 instr_long = (instr_data->words[nibl_count] << 16)
394 | (instr_data->words[nibl_count + 4]);
395 instr_data->immediate = instr_long;
396 nibl_count += 7;
397 break;
398 case ARG_IMMN:
399 instr_data->immediate = instr_nibl - 1;
400 break;
401 case ARG_IMM4M1:
402 instr_data->immediate = instr_nibl + 1;
403 break;
404 case ARG_IMM_1:
405 instr_data->immediate = 1;
406 break;
407 case ARG_IMM_2:
408 instr_data->immediate = 2;
409 break;
410 case ARG_IMM2:
411 instr_data->immediate = instr_nibl & 0x3;
412 break;
413 default:
414 break;
415 }
416 break;
417 case CLASS_CC:
418 instr_data->cond_code = instr_nibl;
419 break;
420 case CLASS_ADDRESS:
421 if (is_segmented)
422 {
423 if (instr_nibl & 0x8)
424 {
425 FETCH_DATA (info, nibl_count + 8);
426 instr_long = (instr_data->words[nibl_count] << 16)
427 | (instr_data->words[nibl_count + 4]);
428 instr_data->address = ((instr_word & 0x7f00) << 16)
429 + (instr_long & 0xffff);
430 nibl_count += 7;
431 seg_length = 2;
432 }
433 else
434 {
435 instr_data->address = ((instr_word & 0x7f00) << 16)
436 + (instr_word & 0x00ff);
437 nibl_count += 3;
438 }
439 }
440 else
441 {
442 instr_data->address = instr_word;
443 nibl_count += 3;
444 }
445 break;
446 case CLASS_0CCC:
447 case CLASS_1CCC:
448 instr_data->ctrl_code = instr_nibl & 0x7;
449 break;
450 case CLASS_0DISP7:
451 instr_data->displacement =
452 instr_data->insn_start + 2 - (instr_byte & 0x7f) * 2;
453 nibl_count += 1;
454 break;
455 case CLASS_1DISP7:
456 instr_data->displacement =
457 instr_data->insn_start + 2 - (instr_byte & 0x7f) * 2;
458 nibl_count += 1;
459 break;
460 case CLASS_01II:
461 instr_data->interrupts = instr_nibl & 0x3;
462 break;
463 case CLASS_00II:
464 instr_data->interrupts = instr_nibl & 0x3;
465 break;
466 case CLASS_IGNORE:
467 case CLASS_BIT:
468 instr_data->ctrl_code = instr_nibl & 0x7;
469 break;
470 case CLASS_FLAGS:
471 instr_data->flags = instr_nibl;
472 break;
473 case CLASS_REG:
474 instr_data->arg_reg[datum_value] = instr_nibl;
475 break;
476 case CLASS_REGN0:
477 instr_data->arg_reg[datum_value] = instr_nibl;
478 break;
479 case CLASS_DISP8:
480 instr_data->displacement =
481 instr_data->insn_start + 2 + (signed char) instr_byte * 2;
482 nibl_count += 1;
483 break;
484 case CLASS_BIT_1OR2:
485 instr_data->immediate = ((instr_nibl >> 1) & 0x1) + 1;
486 nibl_count += 1;
487 break;
488 default:
489 abort ();
490 break;
491 }
492
493 loop += 1;
494 nibl_count += 1;
495 }
496}
497
498static char *intr_names[] = {
499 "all", /* 0 */
500 "vi", /* 1 */
501 "nvi", /* 2 */
502 "none" /* 3 */
503};
504
505static void
506unparse_instr (instr_data, is_segmented)
507 instr_data_s *instr_data;
508 int is_segmented;
509{
510 unsigned short datum_value;
511 unsigned int tabl_datum, datum_class;
512 int loop, loop_limit;
513 char out_str[80], tmp_str[25];
514
515 sprintf (out_str, "%s\t", z8k_table[instr_data->tabl_index].name);
516
517 loop_limit = z8k_table[instr_data->tabl_index].noperands;
518 for (loop = 0; loop < loop_limit; loop++)
519 {
520 if (loop)
521 strcat (out_str, ",");
522
523 tabl_datum = z8k_table[instr_data->tabl_index].arg_info[loop];
524 datum_class = tabl_datum & CLASS_MASK;
525 datum_value = tabl_datum & ~CLASS_MASK;
526
527 switch (datum_class)
528 {
529 case CLASS_X:
530 sprintf (tmp_str, "0x%0lx(r%ld)", instr_data->address,
531 instr_data->arg_reg[datum_value]);
532 strcat (out_str, tmp_str);
533 break;
534 case CLASS_BA:
535 if (is_segmented)
536 sprintf (tmp_str, "rr%ld(#0x%lx)", instr_data->arg_reg[datum_value],
537 instr_data->immediate);
538 else
539 sprintf (tmp_str, "r%ld(#0x%lx)", instr_data->arg_reg[datum_value],
540 instr_data->immediate);
541 strcat (out_str, tmp_str);
542 break;
543 case CLASS_BX:
544 if (is_segmented)
545 sprintf (tmp_str, "rr%ld(r%ld)", instr_data->arg_reg[datum_value],
546 instr_data->arg_reg[ARG_RX]);
547 else
548 sprintf (tmp_str, "r%ld(r%ld)", instr_data->arg_reg[datum_value],
549 instr_data->arg_reg[ARG_RX]);
550 strcat (out_str, tmp_str);
551 break;
552 case CLASS_DISP:
553 sprintf (tmp_str, "0x%0lx", instr_data->displacement);
554 strcat (out_str, tmp_str);
555 break;
556 case CLASS_IMM:
557 if (datum_value == ARG_IMM2) /* True with EI/DI instructions only. */
558 {
559 sprintf (tmp_str, "%s", intr_names[instr_data->interrupts]);
560 strcat (out_str, tmp_str);
561 break;
562 }
563 sprintf (tmp_str, "#0x%0lx", instr_data->immediate);
564 strcat (out_str, tmp_str);
565 break;
566 case CLASS_CC:
567 sprintf (tmp_str, "%s", codes[instr_data->cond_code]);
568 strcat (out_str, tmp_str);
569 break;
570 case CLASS_CTRL:
571 sprintf (tmp_str, "%s", ctrl_names[instr_data->ctrl_code]);
572 strcat (out_str, tmp_str);
573 break;
574 case CLASS_DA:
575 case CLASS_ADDRESS:
576 sprintf (tmp_str, "0x%0lx", instr_data->address);
577 strcat (out_str, tmp_str);
578 break;
579 case CLASS_IR:
580 if (is_segmented)
581 sprintf (tmp_str, "@rr%ld", instr_data->arg_reg[datum_value]);
582 else
583 sprintf (tmp_str, "@r%ld", instr_data->arg_reg[datum_value]);
584 strcat (out_str, tmp_str);
585 break;
586 case CLASS_FLAGS:
587 sprintf (tmp_str, "0x%0lx", instr_data->flags);
588 strcat (out_str, tmp_str);
589 break;
590 case CLASS_REG_BYTE:
591 if (instr_data->arg_reg[datum_value] >= 0x8)
592 sprintf (tmp_str, "rl%ld",
593 instr_data->arg_reg[datum_value] - 0x8);
594 else
595 sprintf (tmp_str, "rh%ld", instr_data->arg_reg[datum_value]);
596 strcat (out_str, tmp_str);
597 break;
598 case CLASS_REG_WORD:
599 sprintf (tmp_str, "r%ld", instr_data->arg_reg[datum_value]);
600 strcat (out_str, tmp_str);
601 break;
602 case CLASS_REG_QUAD:
603 sprintf (tmp_str, "rq%ld", instr_data->arg_reg[datum_value]);
604 strcat (out_str, tmp_str);
605 break;
606 case CLASS_REG_LONG:
607 sprintf (tmp_str, "rr%ld", instr_data->arg_reg[datum_value]);
608 strcat (out_str, tmp_str);
609 break;
610 case CLASS_PR:
611 if (is_segmented)
612 sprintf (tmp_str, "rr%ld", instr_data->arg_reg[datum_value]);
613 else
614 sprintf (tmp_str, "r%ld", instr_data->arg_reg[datum_value]);
615 strcat (out_str, tmp_str);
616 break;
617 default:
618 abort ();
619 break;
620 }
621 }
622
623 strcpy (instr_data->instr_asmsrc, out_str);
624}
Note: See TracBrowser for help on using the repository browser.