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