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