1 /* Disassemble z8000 code. 2 Copyright 1992, 1993, 1998, 2000, 2001, 2002, 2003 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 #include <setjmp.h> 29 30 typedef struct 31 { 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 int 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; 53 } 54 instr_data_s; 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) \ 60 ((nibble) < ((instr_data_s *) (info->private_data))->max_fetched \ 61 ? 1 : fetch_data ((info), (nibble))) 62 63 static int 64 fetch_data (struct disassemble_info *info, int nibble) 65 { 66 unsigned char mybuf[20]; 67 int status; 68 instr_data_s *priv = (instr_data_s *) info->private_data; 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; 85 unsigned char *p = mybuf; 86 87 for (i = 0; i < nibble;) 88 { 89 priv->words[i] = (p[0] << 8) | p[1]; 90 91 priv->bytes[i] = *p; 92 priv->nibbles[i++] = *p >> 4; 93 priv->nibbles[i++] = *p & 0xf; 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 107 static 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 127 static char *ctrl_names[8] = 128 { 129 "<invld>", 130 "flags", 131 "fcw", 132 "refresh", 133 "psapseg", 134 "psapoff", 135 "nspseg", 136 "nspoff" 137 }; 138 139 static int seg_length; 140 int z8k_lookup_instr (unsigned char *, disassemble_info *); 141 static void output_instr (instr_data_s *, unsigned long, disassemble_info *); 142 static void unpack_instr (instr_data_s *, int, disassemble_info *); 143 static void unparse_instr (instr_data_s *, int); 144 145 static int 146 print_insn_z8k (bfd_vma addr, disassemble_info *info, int is_segmented) 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 157 info->bytes_per_chunk = 2; 158 info->bytes_per_line = 6; 159 info->display_endian = BFD_ENDIAN_BIG; 160 161 instr_data.tabl_index = z8k_lookup_instr (instr_data.nibbles, info); 162 if (instr_data.tabl_index >= 0) 163 { 164 unpack_instr (&instr_data, is_segmented, info); 165 unparse_instr (&instr_data, is_segmented); 166 output_instr (&instr_data, addr, info); 167 return z8k_table[instr_data.tabl_index].length + seg_length; 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 178 int 179 print_insn_z8001 (bfd_vma addr, disassemble_info *info) 180 { 181 return print_insn_z8k (addr, info, 1); 182 } 183 184 int 185 print_insn_z8002 (bfd_vma addr, disassemble_info *info) 186 { 187 return print_insn_z8k (addr, info, 0); 188 } 189 190 int 191 z8k_lookup_instr (unsigned char *nibbles, disassemble_info *info) 192 { 193 int nibl_index, tabl_index; 194 int nibl_matched; 195 int need_fetch = 0; 196 unsigned short instr_nibl; 197 unsigned short tabl_datum, datum_class, datum_value; 198 199 nibl_matched = 0; 200 tabl_index = 0; 201 FETCH_DATA (info, 4); 202 while (!nibl_matched && z8k_table[tabl_index].name) 203 { 204 nibl_matched = 1; 205 for (nibl_index = 0; 206 nibl_index < z8k_table[tabl_index].length * 2 && nibl_matched; 207 nibl_index++) 208 { 209 if ((nibl_index % 4) == 0) 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 } 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; 231 case CLASS_IGNORE: 232 break; 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 } 271 272 if (nibl_matched) 273 return tabl_index; 274 275 tabl_index++; 276 } 277 return -1; 278 } 279 280 static void 281 output_instr (instr_data_s *instr_data, 282 unsigned long addr ATTRIBUTE_UNUSED, 283 disassemble_info *info) 284 { 285 int num_bytes; 286 char out_str[100]; 287 288 out_str[0] = 0; 289 290 num_bytes = (z8k_table[instr_data->tabl_index].length + seg_length) * 2; 291 FETCH_DATA (info, num_bytes); 292 293 strcat (out_str, instr_data->instr_asmsrc); 294 295 (*info->fprintf_func) (info->stream, "%s", out_str); 296 } 297 298 static void 299 unpack_instr (instr_data_s *instr_data, int is_segmented, disassemble_info *info) 300 { 301 int nibl_count, loop; 302 unsigned short instr_nibl, instr_byte, instr_word; 303 long instr_long; 304 unsigned int tabl_datum, datum_class; 305 unsigned short datum_value; 306 307 nibl_count = 0; 308 loop = 0; 309 seg_length = 0; 310 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]; 315 instr_byte = instr_data->bytes[nibl_count & ~1]; 316 instr_word = instr_data->words[nibl_count & ~3]; 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 { 324 case CLASS_DISP: 325 switch (datum_value) 326 { 327 case ARG_DISP16: 328 instr_data->displacement = instr_data->insn_start + 4 329 + (signed short) (instr_word & 0xffff); 330 nibl_count += 3; 331 break; 332 case ARG_DISP12: 333 if (instr_word & 0x800) 334 /* Negative 12 bit displacement. */ 335 instr_data->displacement = instr_data->insn_start + 2 336 - (signed short) ((instr_word & 0xfff) | 0xf000) * 2; 337 else 338 instr_data->displacement = instr_data->insn_start + 2 339 - (instr_word & 0x0fff) * 2; 340 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; 353 case ARG_NIM4: 354 instr_data->immediate = (- instr_nibl) & 0xf; 355 break; 356 case ARG_NIM8: 357 instr_data->immediate = (- instr_byte) & 0xff; 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; 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]); 405 instr_data->address = ((instr_word & 0x7f00) << 16) 406 + (instr_long & 0xffff); 407 nibl_count += 7; 408 seg_length = 2; 409 } 410 else 411 { 412 instr_data->address = ((instr_word & 0x7f00) << 16) 413 + (instr_word & 0x00ff); 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: 424 case CLASS_1CCC: 425 instr_data->ctrl_code = instr_nibl & 0x7; 426 break; 427 case CLASS_0DISP7: 428 instr_data->displacement = 429 instr_data->insn_start + 2 - (instr_byte & 0x7f) * 2; 430 nibl_count += 1; 431 break; 432 case CLASS_1DISP7: 433 instr_data->displacement = 434 instr_data->insn_start + 2 - (instr_byte & 0x7f) * 2; 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; 443 case CLASS_IGNORE: 444 case CLASS_BIT: 445 instr_data->ctrl_code = instr_nibl & 0x7; 446 break; 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; 453 case CLASS_REGN0: 454 instr_data->arg_reg[datum_value] = instr_nibl; 455 break; 456 case CLASS_DISP8: 457 instr_data->displacement = 458 instr_data->insn_start + 2 + (signed char) instr_byte * 2; 459 nibl_count += 1; 460 break; 461 case CLASS_BIT_1OR2: 462 instr_data->immediate = ((instr_nibl >> 1) & 0x1) + 1; 463 nibl_count += 1; 464 break; 465 default: 466 abort (); 467 break; 468 } 469 470 loop += 1; 471 nibl_count += 1; 472 } 473 } 474 475 static void 476 print_intr(char *tmp_str, unsigned long interrupts) 477 { 478 int comma = 0; 479 480 *tmp_str = 0; 481 if (! (interrupts & 2)) 482 { 483 strcat (tmp_str, "vi"); 484 comma = 1; 485 } 486 if (! (interrupts & 1)) 487 { 488 if (comma) strcat (tmp_str, ","); 489 strcat (tmp_str, "nvi"); 490 } 491 } 492 493 static void 494 print_flags(char *tmp_str, unsigned long flags) 495 { 496 int comma = 0; 497 498 *tmp_str = 0; 499 if (flags & 8) 500 { 501 strcat (tmp_str, "c"); 502 comma = 1; 503 } 504 if (flags & 4) 505 { 506 if (comma) strcat (tmp_str, ","); 507 strcat (tmp_str, "z"); 508 comma = 1; 509 } 510 if (flags & 2) 511 { 512 if (comma) strcat (tmp_str, ","); 513 strcat (tmp_str, "s"); 514 comma = 1; 515 } 516 if (flags & 1) 517 { 518 if (comma) strcat (tmp_str, ","); 519 strcat (tmp_str, "p"); 520 } 521 } 522 523 static void 524 unparse_instr (instr_data_s *instr_data, int is_segmented) 525 { 526 unsigned short datum_value; 527 unsigned int tabl_datum, datum_class; 528 int loop, loop_limit; 529 char out_str[80], tmp_str[25]; 530 531 sprintf (out_str, "%s\t", z8k_table[instr_data->tabl_index].name); 532 533 loop_limit = z8k_table[instr_data->tabl_index].noperands; 534 for (loop = 0; loop < loop_limit; loop++) 535 { 536 if (loop) 537 strcat (out_str, ","); 538 539 tabl_datum = z8k_table[instr_data->tabl_index].arg_info[loop]; 540 datum_class = tabl_datum & CLASS_MASK; 541 datum_value = tabl_datum & ~CLASS_MASK; 542 543 switch (datum_class) 544 { 545 case CLASS_X: 546 sprintf (tmp_str, "0x%0lx(r%ld)", instr_data->address, 547 instr_data->arg_reg[datum_value]); 548 strcat (out_str, tmp_str); 549 break; 550 case CLASS_BA: 551 if (is_segmented) 552 sprintf (tmp_str, "rr%ld(#0x%lx)", instr_data->arg_reg[datum_value], 553 instr_data->immediate); 554 else 555 sprintf (tmp_str, "r%ld(#0x%lx)", instr_data->arg_reg[datum_value], 556 instr_data->immediate); 557 strcat (out_str, tmp_str); 558 break; 559 case CLASS_BX: 560 if (is_segmented) 561 sprintf (tmp_str, "rr%ld(r%ld)", instr_data->arg_reg[datum_value], 562 instr_data->arg_reg[ARG_RX]); 563 else 564 sprintf (tmp_str, "r%ld(r%ld)", instr_data->arg_reg[datum_value], 565 instr_data->arg_reg[ARG_RX]); 566 strcat (out_str, tmp_str); 567 break; 568 case CLASS_DISP: 569 sprintf (tmp_str, "0x%0lx", instr_data->displacement); 570 strcat (out_str, tmp_str); 571 break; 572 case CLASS_IMM: 573 if (datum_value == ARG_IMM2) /* True with EI/DI instructions only. */ 574 { 575 print_intr (tmp_str, instr_data->interrupts); 576 strcat (out_str, tmp_str); 577 break; 578 } 579 sprintf (tmp_str, "#0x%0lx", instr_data->immediate); 580 strcat (out_str, tmp_str); 581 break; 582 case CLASS_CC: 583 sprintf (tmp_str, "%s", codes[instr_data->cond_code]); 584 strcat (out_str, tmp_str); 585 break; 586 case CLASS_CTRL: 587 sprintf (tmp_str, "%s", ctrl_names[instr_data->ctrl_code]); 588 strcat (out_str, tmp_str); 589 break; 590 case CLASS_DA: 591 case CLASS_ADDRESS: 592 sprintf (tmp_str, "0x%0lx", instr_data->address); 593 strcat (out_str, tmp_str); 594 break; 595 case CLASS_IR: 596 if (is_segmented) 597 sprintf (tmp_str, "@rr%ld", instr_data->arg_reg[datum_value]); 598 else 599 sprintf (tmp_str, "@r%ld", instr_data->arg_reg[datum_value]); 600 strcat (out_str, tmp_str); 601 break; 602 case CLASS_IRO: 603 sprintf (tmp_str, "@r%ld", instr_data->arg_reg[datum_value]); 604 strcat (out_str, tmp_str); 605 break; 606 case CLASS_FLAGS: 607 print_flags(tmp_str, instr_data->flags); 608 strcat (out_str, tmp_str); 609 break; 610 case CLASS_REG_BYTE: 611 if (instr_data->arg_reg[datum_value] >= 0x8) 612 sprintf (tmp_str, "rl%ld", 613 instr_data->arg_reg[datum_value] - 0x8); 614 else 615 sprintf (tmp_str, "rh%ld", instr_data->arg_reg[datum_value]); 616 strcat (out_str, tmp_str); 617 break; 618 case CLASS_REG_WORD: 619 sprintf (tmp_str, "r%ld", instr_data->arg_reg[datum_value]); 620 strcat (out_str, tmp_str); 621 break; 622 case CLASS_REG_QUAD: 623 sprintf (tmp_str, "rq%ld", instr_data->arg_reg[datum_value]); 624 strcat (out_str, tmp_str); 625 break; 626 case CLASS_REG_LONG: 627 sprintf (tmp_str, "rr%ld", instr_data->arg_reg[datum_value]); 628 strcat (out_str, tmp_str); 629 break; 630 case CLASS_PR: 631 if (is_segmented) 632 sprintf (tmp_str, "rr%ld", instr_data->arg_reg[datum_value]); 633 else 634 sprintf (tmp_str, "r%ld", instr_data->arg_reg[datum_value]); 635 strcat (out_str, tmp_str); 636 break; 637 default: 638 abort (); 639 break; 640 } 641 } 642 643 strcpy (instr_data->instr_asmsrc, out_str); 644 } 645