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