1/* Disassemble z8000 code. 2 Copyright (C) 1992-2022 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 "disassemble.h" 23#include "libiberty.h" 24 25#define DEFINE_TABLE 26#include "z8k-opc.h" 27 28#include <setjmp.h> 29 30typedef 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 unsigned int max_fetched; 40 bfd_vma insn_start; 41 OPCODES_SIGJMP_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} 54instr_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 63static int 64fetch_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 OPCODES_SIGLONGJMP (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 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 }; 138 139static int seg_length; 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); 144 145static int 146print_insn_z8k (bfd_vma addr, disassemble_info *info, int is_segmented) 147{ 148 instr_data_s instr_data; 149 150 info->private_data = &instr_data; 151 instr_data.max_fetched = 0; 152 instr_data.insn_start = addr; 153 if (OPCODES_SIGSETJMP (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 178int 179print_insn_z8001 (bfd_vma addr, disassemble_info *info) 180{ 181 return print_insn_z8k (addr, info, 1); 182} 183 184int 185print_insn_z8002 (bfd_vma addr, disassemble_info *info) 186{ 187 return print_insn_z8k (addr, info, 0); 188} 189 190int 191z8k_lookup_instr (unsigned char *nibbles, disassemble_info *info) 192{ 193 unsigned 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_matched 207 && nibl_index < ARRAY_SIZE (z8k_table[0].byte_info) 208 && nibl_index < z8k_table[tabl_index].length * 2; 209 nibl_index++) 210 { 211 if ((nibl_index % 4) == 0) 212 { 213 /* Fetch data only if it isn't already there. */ 214 if (nibl_index >= 4 || (nibl_index < 4 && need_fetch)) 215 FETCH_DATA (info, nibl_index + 4); /* Fetch one word at a time. */ 216 if (nibl_index < 4) 217 need_fetch = 0; 218 else 219 need_fetch = 1; 220 } 221 instr_nibl = nibbles[nibl_index]; 222 223 tabl_datum = z8k_table[tabl_index].byte_info[nibl_index]; 224 datum_class = tabl_datum & CLASS_MASK; 225 datum_value = ~CLASS_MASK & tabl_datum; 226 227 switch (datum_class) 228 { 229 case CLASS_BIT: 230 if (datum_value != instr_nibl) 231 nibl_matched = 0; 232 break; 233 case CLASS_IGNORE: 234 break; 235 case CLASS_00II: 236 if (!((~instr_nibl) & 0x4)) 237 nibl_matched = 0; 238 break; 239 case CLASS_01II: 240 if (!(instr_nibl & 0x4)) 241 nibl_matched = 0; 242 break; 243 case CLASS_0CCC: 244 if (!((~instr_nibl) & 0x8)) 245 nibl_matched = 0; 246 break; 247 case CLASS_1CCC: 248 if (!(instr_nibl & 0x8)) 249 nibl_matched = 0; 250 break; 251 case CLASS_0DISP7: 252 if (!((~instr_nibl) & 0x8)) 253 nibl_matched = 0; 254 nibl_index += 1; 255 break; 256 case CLASS_1DISP7: 257 if (!(instr_nibl & 0x8)) 258 nibl_matched = 0; 259 nibl_index += 1; 260 break; 261 case CLASS_REGN0: 262 if (instr_nibl == 0) 263 nibl_matched = 0; 264 break; 265 case CLASS_BIT_1OR2: 266 if ((instr_nibl | 0x2) != (datum_value | 0x2)) 267 nibl_matched = 0; 268 break; 269 default: 270 break; 271 } 272 } 273 274 if (nibl_matched) 275 return tabl_index; 276 277 tabl_index++; 278 } 279 return -1; 280} 281 282static void 283output_instr (instr_data_s *instr_data, 284 unsigned long addr ATTRIBUTE_UNUSED, 285 disassemble_info *info) 286{ 287 unsigned int num_bytes; 288 char out_str[100]; 289 290 out_str[0] = 0; 291 292 num_bytes = (z8k_table[instr_data->tabl_index].length + seg_length) * 2; 293 FETCH_DATA (info, num_bytes); 294 295 strcat (out_str, instr_data->instr_asmsrc); 296 297 (*info->fprintf_func) (info->stream, "%s", out_str); 298} 299 300static void 301unpack_instr (instr_data_s *instr_data, int is_segmented, disassemble_info *info) 302{ 303 unsigned int nibl_count, loop; 304 unsigned short instr_nibl, instr_byte, instr_word; 305 long instr_long; 306 unsigned int tabl_datum, datum_class; 307 unsigned short datum_value; 308 309 nibl_count = 0; 310 loop = 0; 311 seg_length = 0; 312 313 while (z8k_table[instr_data->tabl_index].byte_info[loop] != 0) 314 { 315 FETCH_DATA (info, nibl_count + 4 - (nibl_count % 4)); 316 instr_nibl = instr_data->nibbles[nibl_count]; 317 instr_byte = instr_data->bytes[nibl_count & ~1]; 318 instr_word = instr_data->words[nibl_count & ~3]; 319 320 tabl_datum = z8k_table[instr_data->tabl_index].byte_info[loop]; 321 datum_class = tabl_datum & CLASS_MASK; 322 datum_value = tabl_datum & ~CLASS_MASK; 323 324 switch (datum_class) 325 { 326 case CLASS_DISP: 327 switch (datum_value) 328 { 329 case ARG_DISP16: 330 instr_data->displacement = instr_data->insn_start + 4 331 + (signed short) (instr_word & 0xffff); 332 nibl_count += 3; 333 break; 334 case ARG_DISP12: 335 if (instr_word & 0x800) 336 /* Negative 12 bit displacement. */ 337 instr_data->displacement = instr_data->insn_start + 2 338 - (signed short) ((instr_word & 0xfff) | 0xf000) * 2; 339 else 340 instr_data->displacement = instr_data->insn_start + 2 341 - (instr_word & 0x0fff) * 2; 342 343 nibl_count += 2; 344 break; 345 default: 346 break; 347 } 348 break; 349 case CLASS_IMM: 350 switch (datum_value) 351 { 352 case ARG_IMM4: 353 instr_data->immediate = instr_nibl; 354 break; 355 case ARG_NIM4: 356 instr_data->immediate = (- instr_nibl) & 0xf; 357 break; 358 case ARG_NIM8: 359 instr_data->immediate = (- instr_byte) & 0xff; 360 nibl_count += 1; 361 break; 362 case ARG_IMM8: 363 instr_data->immediate = instr_byte; 364 nibl_count += 1; 365 break; 366 case ARG_IMM16: 367 instr_data->immediate = instr_word; 368 nibl_count += 3; 369 break; 370 case ARG_IMM32: 371 FETCH_DATA (info, nibl_count + 8); 372 instr_long = ((unsigned) instr_data->words[nibl_count] << 16 373 | instr_data->words[nibl_count + 4]); 374 instr_data->immediate = instr_long; 375 nibl_count += 7; 376 break; 377 case ARG_IMMN: 378 instr_data->immediate = instr_nibl - 1; 379 break; 380 case ARG_IMM4M1: 381 instr_data->immediate = instr_nibl + 1; 382 break; 383 case ARG_IMM_1: 384 instr_data->immediate = 1; 385 break; 386 case ARG_IMM_2: 387 instr_data->immediate = 2; 388 break; 389 case ARG_IMM2: 390 instr_data->immediate = instr_nibl & 0x3; 391 break; 392 default: 393 break; 394 } 395 break; 396 case CLASS_CC: 397 instr_data->cond_code = instr_nibl; 398 break; 399 case CLASS_ADDRESS: 400 if (is_segmented) 401 { 402 if (instr_nibl & 0x8) 403 { 404 FETCH_DATA (info, nibl_count + 8); 405 instr_long = ((unsigned) instr_data->words[nibl_count] << 16 406 | instr_data->words[nibl_count + 4]); 407 instr_data->address = ((instr_word & 0x7f00) << 16 408 | (instr_long & 0xffff)); 409 nibl_count += 7; 410 seg_length = 2; 411 } 412 else 413 { 414 instr_data->address = ((instr_word & 0x7f00) << 16 415 | (instr_word & 0x00ff)); 416 nibl_count += 3; 417 } 418 } 419 else 420 { 421 instr_data->address = instr_word; 422 nibl_count += 3; 423 } 424 break; 425 case CLASS_0CCC: 426 case CLASS_1CCC: 427 instr_data->ctrl_code = instr_nibl & 0x7; 428 break; 429 case CLASS_0DISP7: 430 instr_data->displacement = 431 instr_data->insn_start + 2 - (instr_byte & 0x7f) * 2; 432 nibl_count += 1; 433 break; 434 case CLASS_1DISP7: 435 instr_data->displacement = 436 instr_data->insn_start + 2 - (instr_byte & 0x7f) * 2; 437 nibl_count += 1; 438 break; 439 case CLASS_01II: 440 instr_data->interrupts = instr_nibl & 0x3; 441 break; 442 case CLASS_00II: 443 instr_data->interrupts = instr_nibl & 0x3; 444 break; 445 case CLASS_IGNORE: 446 case CLASS_BIT: 447 instr_data->ctrl_code = instr_nibl & 0x7; 448 break; 449 case CLASS_FLAGS: 450 instr_data->flags = instr_nibl; 451 break; 452 case CLASS_REG: 453 instr_data->arg_reg[datum_value] = instr_nibl; 454 break; 455 case CLASS_REGN0: 456 instr_data->arg_reg[datum_value] = instr_nibl; 457 break; 458 case CLASS_DISP8: 459 instr_data->displacement = 460 instr_data->insn_start + 2 + (signed char) instr_byte * 2; 461 nibl_count += 1; 462 break; 463 case CLASS_BIT_1OR2: 464 instr_data->immediate = ((instr_nibl >> 1) & 0x1) + 1; 465 nibl_count += 1; 466 break; 467 default: 468 abort (); 469 break; 470 } 471 472 loop += 1; 473 nibl_count += 1; 474 } 475} 476 477static void 478print_intr(char *tmp_str, unsigned long interrupts) 479{ 480 int comma = 0; 481 482 *tmp_str = 0; 483 if (! (interrupts & 2)) 484 { 485 strcat (tmp_str, "vi"); 486 comma = 1; 487 } 488 if (! (interrupts & 1)) 489 { 490 if (comma) strcat (tmp_str, ","); 491 strcat (tmp_str, "nvi"); 492 } 493} 494 495static void 496print_flags(char *tmp_str, unsigned long flags) 497{ 498 int comma = 0; 499 500 *tmp_str = 0; 501 if (flags & 8) 502 { 503 strcat (tmp_str, "c"); 504 comma = 1; 505 } 506 if (flags & 4) 507 { 508 if (comma) strcat (tmp_str, ","); 509 strcat (tmp_str, "z"); 510 comma = 1; 511 } 512 if (flags & 2) 513 { 514 if (comma) strcat (tmp_str, ","); 515 strcat (tmp_str, "s"); 516 comma = 1; 517 } 518 if (flags & 1) 519 { 520 if (comma) strcat (tmp_str, ","); 521 strcat (tmp_str, "p"); 522 } 523} 524 525static void 526unparse_instr (instr_data_s *instr_data, int is_segmented) 527{ 528 unsigned short datum_value; 529 unsigned int tabl_datum, datum_class; 530 int loop, loop_limit; 531 char out_str[80], tmp_str[25]; 532 533 sprintf (out_str, "%s\t", z8k_table[instr_data->tabl_index].name); 534 535 loop_limit = z8k_table[instr_data->tabl_index].noperands; 536 for (loop = 0; loop < loop_limit; loop++) 537 { 538 if (loop) 539 strcat (out_str, ","); 540 541 tabl_datum = z8k_table[instr_data->tabl_index].arg_info[loop]; 542 datum_class = tabl_datum & CLASS_MASK; 543 datum_value = tabl_datum & ~CLASS_MASK; 544 545 switch (datum_class) 546 { 547 case CLASS_X: 548 sprintf (tmp_str, "0x%0lx(r%ld)", instr_data->address, 549 instr_data->arg_reg[datum_value]); 550 strcat (out_str, tmp_str); 551 break; 552 case CLASS_BA: 553 if (is_segmented) 554 sprintf (tmp_str, "rr%ld(#0x%lx)", instr_data->arg_reg[datum_value], 555 instr_data->immediate); 556 else 557 sprintf (tmp_str, "r%ld(#0x%lx)", instr_data->arg_reg[datum_value], 558 instr_data->immediate); 559 strcat (out_str, tmp_str); 560 break; 561 case CLASS_BX: 562 if (is_segmented) 563 sprintf (tmp_str, "rr%ld(r%ld)", instr_data->arg_reg[datum_value], 564 instr_data->arg_reg[ARG_RX]); 565 else 566 sprintf (tmp_str, "r%ld(r%ld)", instr_data->arg_reg[datum_value], 567 instr_data->arg_reg[ARG_RX]); 568 strcat (out_str, tmp_str); 569 break; 570 case CLASS_DISP: 571 sprintf (tmp_str, "0x%0lx", instr_data->displacement); 572 strcat (out_str, tmp_str); 573 break; 574 case CLASS_IMM: 575 if (datum_value == ARG_IMM2) /* True with EI/DI instructions only. */ 576 { 577 print_intr (tmp_str, instr_data->interrupts); 578 strcat (out_str, tmp_str); 579 break; 580 } 581 sprintf (tmp_str, "#0x%0lx", instr_data->immediate); 582 strcat (out_str, tmp_str); 583 break; 584 case CLASS_CC: 585 sprintf (tmp_str, "%s", codes[instr_data->cond_code]); 586 strcat (out_str, tmp_str); 587 break; 588 case CLASS_CTRL: 589 sprintf (tmp_str, "%s", ctrl_names[instr_data->ctrl_code]); 590 strcat (out_str, tmp_str); 591 break; 592 case CLASS_DA: 593 case CLASS_ADDRESS: 594 sprintf (tmp_str, "0x%0lx", instr_data->address); 595 strcat (out_str, tmp_str); 596 break; 597 case CLASS_IR: 598 if (is_segmented) 599 sprintf (tmp_str, "@rr%ld", instr_data->arg_reg[datum_value]); 600 else 601 sprintf (tmp_str, "@r%ld", instr_data->arg_reg[datum_value]); 602 strcat (out_str, tmp_str); 603 break; 604 case CLASS_IRO: 605 sprintf (tmp_str, "@r%ld", instr_data->arg_reg[datum_value]); 606 strcat (out_str, tmp_str); 607 break; 608 case CLASS_FLAGS: 609 print_flags(tmp_str, instr_data->flags); 610 strcat (out_str, tmp_str); 611 break; 612 case CLASS_REG_BYTE: 613 if (instr_data->arg_reg[datum_value] >= 0x8) 614 sprintf (tmp_str, "rl%ld", 615 instr_data->arg_reg[datum_value] - 0x8); 616 else 617 sprintf (tmp_str, "rh%ld", instr_data->arg_reg[datum_value]); 618 strcat (out_str, tmp_str); 619 break; 620 case CLASS_REG_WORD: 621 sprintf (tmp_str, "r%ld", instr_data->arg_reg[datum_value]); 622 strcat (out_str, tmp_str); 623 break; 624 case CLASS_REG_QUAD: 625 sprintf (tmp_str, "rq%ld", instr_data->arg_reg[datum_value]); 626 strcat (out_str, tmp_str); 627 break; 628 case CLASS_REG_LONG: 629 sprintf (tmp_str, "rr%ld", instr_data->arg_reg[datum_value]); 630 strcat (out_str, tmp_str); 631 break; 632 case CLASS_PR: 633 if (is_segmented) 634 sprintf (tmp_str, "rr%ld", instr_data->arg_reg[datum_value]); 635 else 636 sprintf (tmp_str, "r%ld", instr_data->arg_reg[datum_value]); 637 strcat (out_str, tmp_str); 638 break; 639 default: 640 abort (); 641 break; 642 } 643 } 644 645 strcpy (instr_data->instr_asmsrc, out_str); 646} 647