z80-dis.c revision 1.1.1.6
1/* Print Z80, Z180, EZ80 and R800 instructions 2 Copyright (C) 2005-2020 Free Software Foundation, Inc. 3 Contributed by Arnold Metselaar <arnold_m@operamail.com> 4 5 This file is part of the GNU opcodes library. 6 7 This library 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 3, or (at your option) 10 any later version. 11 12 It is distributed in the hope that it will be useful, but WITHOUT 13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 15 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., 51 Franklin Street - Fifth Floor, Boston, 20 MA 02110-1301, USA. */ 21 22#include "sysdep.h" 23#include "disassemble.h" 24#include <stdio.h> 25 26struct buffer 27{ 28 bfd_vma base; 29 int n_fetch; 30 int n_used; 31 signed char data[6]; 32 long inss; /* instruction set bit mask, taken from bfd_mach */ 33 int nn_len; /* address length: 2 - Z80 mode, 3 - ADL mode*/ 34} ; 35 36typedef int (*func)(struct buffer *, disassemble_info *, const char *); 37 38struct tab_elt 39{ 40 unsigned char val; 41 unsigned char mask; 42 func fp; 43 const char * text; 44 unsigned inss; /* bit mask of supported bfd_mach_* or 0 for all mach */ 45} ; 46 47#define INSS_ALL 0 48#define INSS_Z80 ((1 << bfd_mach_z80) | (1 << bfd_mach_z80strict) | (1 << bfd_mach_z80full)) 49#define INSS_R800 (1 << bfd_mach_r800) 50#define INSS_GBZ80 (1 << bfd_mach_gbz80) 51#define INSS_Z180 (1 << bfd_mach_z180) 52#define INSS_EZ80_Z80 (1 << bfd_mach_ez80_z80) 53#define INSS_EZ80_ADL (1 << bfd_mach_ez80_adl) 54#define INSS_EZ80 (INSS_EZ80_ADL | INSS_EZ80_Z80) 55 56#define TXTSIZ 24 57/* Names of 16-bit registers. */ 58static const char * rr_str[] = { "bc", "de", "hl", "sp" }; 59/* Names of 8-bit registers. */ 60static const char * r_str[] = { "b", "c", "d", "e", "h", "l", "(hl)", "a" }; 61/* Texts for condition codes. */ 62static const char * cc_str[] = { "nz", "z", "nc", "c", "po", "pe", "p", "m" }; 63/* Instruction names for 8-bit arithmetic, operand "a" is often implicit */ 64static const char * arit_str[] = 65{ 66 "add a,", "adc a,", "sub ", "sbc a,", "and ", "xor ", "or ", "cp " 67} ; 68static const char * arit_str_ez80[] = 69{ 70 "add a,", "adc a,", "sub a,", "sbc a,", "and a,", "xor a,", "or a,", "cp a," 71} ; 72 73 74static int 75mach_inst (struct buffer *buf, struct tab_elt *p) 76{ 77 return !p->inss || (p->inss & buf->inss); 78} 79 80static int 81fetch_data (struct buffer *buf, disassemble_info * info, int n) 82{ 83 int r; 84 85 if (buf->n_fetch + n > (int)sizeof (buf->data)) 86 abort (); 87 88 r = info->read_memory_func (buf->base + buf->n_fetch, 89 (unsigned char*) buf->data + buf->n_fetch, 90 n, info); 91 if (r == 0) 92 buf->n_fetch += n; 93 return !r; 94} 95 96static int 97prt (struct buffer *buf, disassemble_info * info, const char *txt) 98{ 99 info->fprintf_func (info->stream, "%s", txt); 100 buf->n_used = buf->n_fetch; 101 return 1; 102} 103 104static int 105prt_e (struct buffer *buf, disassemble_info * info, const char *txt) 106{ 107 char e; 108 int target_addr; 109 110 if (fetch_data (buf, info, 1)) 111 { 112 e = buf->data[1]; 113 target_addr = (buf->base + 2 + e) & 0xffff; 114 buf->n_used = buf->n_fetch; 115 info->fprintf_func (info->stream, "%s0x%04x", txt, target_addr); 116 } 117 else 118 buf->n_used = -1; 119 120 return buf->n_used; 121} 122 123static int 124jr_cc (struct buffer *buf, disassemble_info * info, const char *txt) 125{ 126 char mytxt[TXTSIZ]; 127 128 snprintf (mytxt, TXTSIZ, txt, cc_str[(buf->data[0] >> 3) & 3]); 129 return prt_e (buf, info, mytxt); 130} 131 132static int 133prt_nn (struct buffer *buf, disassemble_info * info, const char *txt) 134{ 135 int nn; 136 unsigned char *p; 137 int i; 138 139 p = (unsigned char*) buf->data + buf->n_fetch; 140 if (fetch_data (buf, info, buf->nn_len)) 141 { 142 nn = 0; 143 i = buf->nn_len; 144 while (i--) 145 nn = nn * 0x100 + p[i]; 146 info->fprintf_func (info->stream, txt, nn); 147 buf->n_used = buf->n_fetch; 148 } 149 else 150 buf->n_used = -1; 151 return buf->n_used; 152} 153 154static int 155prt_rr_nn (struct buffer *buf, disassemble_info * info, const char *txt) 156{ 157 char mytxt[TXTSIZ]; 158 int rr; 159 160 rr = (buf->data[buf->n_fetch - 1] >> 4) & 3; 161 snprintf (mytxt, TXTSIZ, txt, rr_str[rr]); 162 return prt_nn (buf, info, mytxt); 163} 164 165static int 166prt_rr (struct buffer *buf, disassemble_info * info, const char *txt) 167{ 168 info->fprintf_func (info->stream, "%s%s", txt, 169 rr_str[(buf->data[buf->n_fetch - 1] >> 4) & 3]); 170 buf->n_used = buf->n_fetch; 171 return buf->n_used; 172} 173 174static int 175prt_n (struct buffer *buf, disassemble_info * info, const char *txt) 176{ 177 int n; 178 unsigned char *p; 179 180 p = (unsigned char*) buf->data + buf->n_fetch; 181 182 if (fetch_data (buf, info, 1)) 183 { 184 n = p[0]; 185 info->fprintf_func (info->stream, txt, n); 186 buf->n_used = buf->n_fetch; 187 } 188 else 189 buf->n_used = -1; 190 191 return buf->n_used; 192} 193 194static int 195prt_r_n (struct buffer *buf, disassemble_info * info, const char *txt) 196{ 197 char mytxt[TXTSIZ]; 198 int r; 199 200 r = (buf->data[buf->n_fetch - 1] >> 3) & 7; 201 snprintf (mytxt, TXTSIZ, txt, r_str[r]); 202 return prt_n (buf, info, mytxt); 203} 204 205static int 206ld_r_n (struct buffer *buf, disassemble_info * info, const char *txt) 207{ 208 char mytxt[TXTSIZ]; 209 210 snprintf (mytxt, TXTSIZ, txt, r_str[(buf->data[buf->n_fetch - 1] >> 3) & 7]); 211 return prt_n (buf, info, mytxt); 212} 213 214static int 215prt_r (struct buffer *buf, disassemble_info * info, const char *txt) 216{ 217 info->fprintf_func (info->stream, txt, 218 r_str[(buf->data[buf->n_fetch - 1] >> 3) & 7]); 219 buf->n_used = buf->n_fetch; 220 return buf->n_used; 221} 222 223static int 224ld_r_r (struct buffer *buf, disassemble_info * info, const char *txt) 225{ 226 info->fprintf_func (info->stream, txt, 227 r_str[(buf->data[buf->n_fetch - 1] >> 3) & 7], 228 r_str[buf->data[buf->n_fetch - 1] & 7]); 229 buf->n_used = buf->n_fetch; 230 return buf->n_used; 231} 232 233static int 234prt_d (struct buffer *buf, disassemble_info * info, const char *txt) 235{ 236 int d; 237 signed char *p; 238 239 p = buf->data + buf->n_fetch; 240 241 if (fetch_data (buf, info, 1)) 242 { 243 d = p[0]; 244 info->fprintf_func (info->stream, txt, d); 245 buf->n_used = buf->n_fetch; 246 } 247 else 248 buf->n_used = -1; 249 250 return buf->n_used; 251} 252 253static int 254prt_rr_d (struct buffer *buf, disassemble_info * info, const char *txt) 255{ 256 char mytxt[TXTSIZ]; 257 int rr; 258 259 rr = (buf->data[buf->n_fetch - 1] >> 4) & 3; 260 if (rr == 3) /* SP is not supported */ 261 return 0; 262 263 snprintf (mytxt, TXTSIZ, txt, rr_str[rr]); 264 return prt_d (buf, info, mytxt); 265} 266 267static int 268arit_r (struct buffer *buf, disassemble_info * info, const char *txt) 269{ 270 const char * const *arit; 271 arit = (buf->inss & INSS_EZ80) ? arit_str_ez80 : arit_str; 272 info->fprintf_func (info->stream, txt, 273 arit[(buf->data[buf->n_fetch - 1] >> 3) & 7], 274 r_str[buf->data[buf->n_fetch - 1] & 7]); 275 buf->n_used = buf->n_fetch; 276 return buf->n_used; 277} 278 279static int 280prt_cc (struct buffer *buf, disassemble_info * info, const char *txt) 281{ 282 info->fprintf_func (info->stream, "%s%s", txt, 283 cc_str[(buf->data[0] >> 3) & 7]); 284 buf->n_used = buf->n_fetch; 285 return buf->n_used; 286} 287 288static int 289pop_rr (struct buffer *buf, disassemble_info * info, const char *txt) 290{ 291 static char *rr_stack[] = { "bc","de","hl","af"}; 292 293 info->fprintf_func (info->stream, "%s %s", txt, 294 rr_stack[(buf->data[0] >> 4) & 3]); 295 buf->n_used = buf->n_fetch; 296 return buf->n_used; 297} 298 299 300static int 301jp_cc_nn (struct buffer *buf, disassemble_info * info, const char *txt) 302{ 303 char mytxt[TXTSIZ]; 304 305 snprintf (mytxt,TXTSIZ, 306 "%s%s,0x%%04x", txt, cc_str[(buf->data[0] >> 3) & 7]); 307 return prt_nn (buf, info, mytxt); 308} 309 310static int 311arit_n (struct buffer *buf, disassemble_info * info, const char *txt) 312{ 313 char mytxt[TXTSIZ]; 314 const char * const *arit; 315 316 arit = (buf->inss & INSS_EZ80) ? arit_str_ez80 : arit_str; 317 snprintf (mytxt,TXTSIZ, txt, arit[(buf->data[0] >> 3) & 7]); 318 return prt_n (buf, info, mytxt); 319} 320 321static int 322rst (struct buffer *buf, disassemble_info * info, const char *txt) 323{ 324 info->fprintf_func (info->stream, txt, buf->data[0] & 0x38); 325 buf->n_used = buf->n_fetch; 326 return buf->n_used; 327} 328 329 330static int 331cis (struct buffer *buf, disassemble_info * info, const char *txt ATTRIBUTE_UNUSED) 332{ 333 static char * opar[] = { "ld", "cp", "in", "out" }; 334 char * op; 335 char c; 336 337 c = buf->data[1]; 338 op = ((0x13 & c) == 0x13) ? "ot" : (opar[c & 3]); 339 info->fprintf_func (info->stream, 340 "%s%c%s", op, 341 (c & 0x08) ? 'd' : 'i', 342 (c & 0x10) ? "r" : ""); 343 buf->n_used = 2; 344 return buf->n_used; 345} 346 347static int 348cism (struct buffer *buf, disassemble_info * info, const char *txt ATTRIBUTE_UNUSED) 349{ 350 static char * opar[] = { "in%cm%s", "ot%cm%s" }; 351 char * op; 352 char c; 353 354 c = buf->data[1]; 355 op = opar[c & 1]; 356 info->fprintf_func (info->stream, 357 op, 358 (c & 0x08) ? 'd' : 'i', 359 (c & 0x10) ? "r" : ""); 360 buf->n_used = 2; 361 return buf->n_used; 362} 363 364static int 365cis2 (struct buffer *buf, disassemble_info * info, const char *txt ATTRIBUTE_UNUSED) 366{ 367 static char * opar[] = { "in", "out" }; 368 char * op; 369 char c; 370 371 c = buf->data[1]; 372 op = ((0x14 & c) == 0x14) ? "ot" : (opar[c & 1]); 373 info->fprintf_func (info->stream, 374 "%s%c2%s", 375 op, 376 (c & 0x08) ? 'd' : 'i', 377 (c & 0x10) ? "r" : ""); 378 buf->n_used = 2; 379 return buf->n_used; 380} 381 382static int 383dump (struct buffer *buf, disassemble_info * info, const char *txt) 384{ 385 int i; 386 387 info->fprintf_func (info->stream, "defb "); 388 for (i = 0; txt[i]; ++i) 389 info->fprintf_func (info->stream, i ? ", 0x%02x" : "0x%02x", 390 (unsigned char) buf->data[i]); 391 buf->n_used = i; 392 return buf->n_used; 393} 394 395/* Table to disassemble machine codes with prefix 0xED. */ 396struct tab_elt opc_ed[] = 397{ 398 { 0x30, 0xFE, dump, "xx", INSS_ALL }, 399 { 0x00, 0xC7, prt_r_n, "in0 %s,(0x%%02x)", INSS_Z180|INSS_EZ80 }, 400 { 0x01, 0xC7, prt_r_n, "out0 (0x%%02x),%s", INSS_Z180|INSS_EZ80 }, 401 { 0x32, 0xFF, prt_d, "lea ix,ix%+d", INSS_EZ80 }, 402 { 0x33, 0xFF, prt_d, "lea iy,iy%+d", INSS_EZ80 }, 403 { 0x02, 0xCF, prt_rr_d, "lea %s,ix%%+d", INSS_EZ80 }, 404 { 0x03, 0xCF, prt_rr_d, "lea %s,iy%%+d", INSS_EZ80 }, 405 { 0x04, 0xC7, prt_r, "tst %s", INSS_Z180}, 406 { 0x04, 0xC7, prt_r, "tst a,%s", INSS_EZ80 }, 407 { 0x07, 0xFF, prt, "ld bc,(hl)", INSS_EZ80 }, 408 { 0x0F, 0xCF, prt_rr, "ld (hl),", INSS_EZ80 }, 409 { 0x17, 0xFF, prt, "ld de,(hl)", INSS_EZ80 }, 410 { 0x27, 0xFF, prt, "ld hl,(hl)", INSS_EZ80 }, 411 { 0x36, 0xFF, prt, "ld iy,(hl)", INSS_EZ80 }, 412 { 0x37, 0xFF, prt, "ld ix,(hl)", INSS_EZ80 }, 413 { 0x3E, 0xFF, prt, "ld (hl),iy", INSS_EZ80 }, 414 { 0x3F, 0xFF, prt, "ld (hl),ix", INSS_EZ80 }, 415 { 0x70, 0xFF, prt, "in f,(c)", INSS_Z80 | INSS_R800 }, 416 { 0x70, 0xFF, dump, "xx", INSS_ALL }, 417 { 0x40, 0xC7, prt_r, "in %s,(bc)", INSS_EZ80 }, 418 { 0x40, 0xC7, prt_r, "in %s,(c)", INSS_ALL }, 419 { 0x71, 0xFF, prt, "out (c),0", INSS_Z80 }, 420 { 0x70, 0xFF, dump, "xx", INSS_ALL }, 421 { 0x41, 0xC7, prt_r, "out (bc),%s", INSS_EZ80 }, 422 { 0x41, 0xC7, prt_r, "out (c),%s", INSS_ALL }, 423 { 0x42, 0xCF, prt_rr, "sbc hl,", INSS_ALL }, 424 { 0x43, 0xCF, prt_rr_nn, "ld (0x%%04x),%s", INSS_ALL }, 425 { 0x44, 0xFF, prt, "neg", INSS_ALL }, 426 { 0x45, 0xFF, prt, "retn", INSS_ALL }, 427 { 0x46, 0xFF, prt, "im 0", INSS_ALL }, 428 { 0x47, 0xFF, prt, "ld i,a", INSS_ALL }, 429 { 0x4A, 0xCF, prt_rr, "adc hl,", INSS_ALL }, 430 { 0x4B, 0xCF, prt_rr_nn, "ld %s,(0x%%04x)", INSS_ALL }, 431 { 0x4C, 0xCF, prt_rr, "mlt ", INSS_Z180|INSS_EZ80 }, 432 { 0x4D, 0xFF, prt, "reti", INSS_ALL }, 433 { 0x4F, 0xFF, prt, "ld r,a", INSS_ALL }, 434 { 0x54, 0xFF, prt_d, "lea ix,iy%+d", INSS_EZ80 }, 435 { 0x55, 0xFF, prt_d, "lea iy,ix%+d", INSS_EZ80 }, 436 { 0x56, 0xFF, prt, "im 1", INSS_ALL }, 437 { 0x57, 0xFF, prt, "ld a,i", INSS_ALL }, 438 { 0x5E, 0xFF, prt, "im 2", INSS_ALL }, 439 { 0x5F, 0xFF, prt, "ld a,r", INSS_ALL }, 440 { 0x64, 0xFF, prt_n, "tst 0x%02x", INSS_Z180 }, 441 { 0x64, 0xFF, prt_n, "tst a,0x%02x", INSS_EZ80 }, 442 { 0x65, 0xFF, prt_d, "pea ix%+d", INSS_EZ80 }, 443 { 0x66, 0xFF, prt_d, "pea iy%+d", INSS_EZ80 }, 444 { 0x67, 0xFF, prt, "rrd", INSS_ALL }, 445 { 0x6F, 0xFF, prt, "rld", INSS_ALL }, 446 { 0x74, 0xFF, prt_n, "tstio 0x%02x", INSS_Z180|INSS_EZ80 }, 447 { 0x76, 0xFF, prt, "slp", INSS_Z180|INSS_EZ80 }, 448 { 0x82, 0xE6, cism, "", INSS_Z180|INSS_EZ80 }, 449 { 0x84, 0xC7, cis2, "", INSS_EZ80 }, 450 { 0xA0, 0xE4, cis, "", INSS_ALL }, 451 { 0x7D, 0xFF, prt, "stmix", INSS_EZ80 }, 452 { 0x7E, 0xFF, prt, "rsmix", INSS_EZ80 }, 453 { 0x6D, 0xFF, prt, "ld mb,a", INSS_EZ80 }, 454 { 0x6E, 0xFF, prt, "ld a,mb", INSS_EZ80 }, 455 { 0xC7, 0xFF, prt, "ld i,hl", INSS_EZ80 }, 456 { 0xD7, 0xFF, prt, "ld hl,i", INSS_EZ80 }, 457 { 0xC2, 0xFF, prt, "inirx", INSS_EZ80 }, 458 { 0xC3, 0xFF, prt, "otirx", INSS_EZ80 }, 459 { 0xCA, 0xFF, prt, "indrx", INSS_EZ80 }, 460 { 0xCB, 0xFF, prt, "otdrx", INSS_EZ80 }, 461 { 0xC3, 0xFF, prt, "muluw hl,bc", INSS_R800 }, 462 { 0xC5, 0xE7, prt_r, "mulub a,%s", INSS_R800 }, 463 { 0xF3, 0xFF, prt, "muluw hl,sp", INSS_R800 }, 464 { 0x00, 0x00, dump, "xx", INSS_ALL } 465}; 466 467static int 468pref_ed (struct buffer *buf, disassemble_info *info, 469 const char *txt ATTRIBUTE_UNUSED) 470{ 471 struct tab_elt *p; 472 473 if (fetch_data (buf, info, 1)) 474 { 475 for (p = opc_ed; p->val != (buf->data[1] & p->mask) || !mach_inst (buf, p); ++p) 476 ; 477 p->fp (buf, info, p->text); 478 } 479 else 480 buf->n_used = -1; 481 482 return buf->n_used; 483} 484 485/* Instruction names for the instructions addressing single bits. */ 486static char *cb1_str[] = { "", "bit", "res", "set"}; 487/* Instruction names for shifts and rotates. */ 488static char *cb2_str[] = 489{ 490 "rlc", "rrc", "rl", "rr", "sla", "sra", "sli", "srl" 491}; 492 493static int 494pref_cb (struct buffer *buf, disassemble_info *info, 495 const char *txt ATTRIBUTE_UNUSED) 496{ 497 const char *op_txt; 498 int idx; 499 if (fetch_data (buf, info, 1)) 500 { 501 buf->n_used = 2; 502 if ((buf->data[1] & 0xc0) == 0) 503 { 504 idx = (buf->data[1] >> 3) & 7; 505 if ((buf->inss & INSS_GBZ80) && (idx == 6)) 506 op_txt = "swap"; 507 else 508 op_txt = cb2_str[idx]; 509 info->fprintf_func (info->stream, "%s %s", 510 op_txt, 511 r_str[buf->data[1] & 7]); 512 } 513 else 514 info->fprintf_func (info->stream, "%s %d,%s", 515 cb1_str[(buf->data[1] >> 6) & 3], 516 (buf->data[1] >> 3) & 7, 517 r_str[buf->data[1] & 7]); 518 } 519 else 520 buf->n_used = -1; 521 522 return buf->n_used; 523} 524 525static int 526addvv (struct buffer * buf, disassemble_info * info, const char *txt) 527{ 528 info->fprintf_func (info->stream, "add %s,%s", txt, txt); 529 530 return buf->n_used = buf->n_fetch; 531} 532 533static int 534ld_v_v (struct buffer * buf, disassemble_info * info, const char *txt) 535{ 536 char mytxt[TXTSIZ]; 537 538 snprintf (mytxt, TXTSIZ, "ld %s%%s,%s%%s", txt, txt); 539 return ld_r_r (buf, info, mytxt); 540} 541 542static int 543prt_d_n (struct buffer *buf, disassemble_info * info, const char *txt) 544{ 545 char mytxt[TXTSIZ]; 546 int d; 547 signed char *p; 548 549 p = buf->data + buf->n_fetch; 550 551 if (fetch_data (buf, info, 1)) 552 { 553 d = p[0]; 554 snprintf (mytxt, TXTSIZ, txt, d); 555 return prt_n (buf, info, mytxt); 556 } 557 else 558 buf->n_used = -1; 559 560 return buf->n_used; 561} 562 563static int 564arit_d (struct buffer *buf, disassemble_info * info, const char *txt) 565{ 566 char mytxt[TXTSIZ]; 567 signed char c; 568 const char * const *arit; 569 570 arit = (buf->inss & INSS_EZ80) ? arit_str_ez80 : arit_str; 571 c = buf->data[buf->n_fetch - 1]; 572 snprintf (mytxt, TXTSIZ, txt, arit[(c >> 3) & 7]); 573 return prt_d (buf, info, mytxt); 574} 575 576static int 577ld_r_d (struct buffer *buf, disassemble_info * info, const char *txt) 578{ 579 char mytxt[TXTSIZ]; 580 signed char c; 581 582 c = buf->data[buf->n_fetch - 1]; 583 snprintf (mytxt, TXTSIZ, txt, r_str[(c >> 3) & 7]); 584 return prt_d (buf, info, mytxt); 585} 586 587static int 588ld_d_r (struct buffer *buf, disassemble_info * info, const char *txt) 589{ 590 char mytxt[TXTSIZ]; 591 signed char c; 592 593 c = buf->data[buf->n_fetch - 1]; 594 snprintf (mytxt, TXTSIZ, txt, r_str[c & 7]); 595 return prt_d (buf, info, mytxt); 596} 597 598static int 599ld_ii_ii (struct buffer *buf, disassemble_info * info, const char *txt) 600{ 601 char mytxt[TXTSIZ]; 602 signed char c; 603 int p; 604 static const char *ii[2] = { "ix", "iy" }; 605 606 p = (buf->data[buf->n_fetch - 2] == (signed char) 0xdd) ? 0 : 1; 607 c = buf->data[buf->n_fetch - 1]; 608 if ((c & 0x07) != 0x07) 609 p = 1 - p; /* 0 -> 1, 1 -> 0 */ 610 snprintf (mytxt, TXTSIZ, txt, ii[p]); 611 return prt_d (buf, info, mytxt); 612} 613 614static int 615pref_xd_cb (struct buffer * buf, disassemble_info * info, const char *txt) 616{ 617 if (fetch_data (buf, info, 2)) 618 { 619 int d; 620 char arg[TXTSIZ]; 621 signed char *p; 622 623 buf->n_used = 4; 624 p = buf->data; 625 d = p[2]; 626 627 if (((p[3] & 0xC0) == 0x40) || ((p[3] & 7) == 0x06)) 628 snprintf (arg, TXTSIZ, "(%s%+d)", txt, d); 629 else 630 snprintf (arg, TXTSIZ, "(%s%+d),%s", txt, d, r_str[p[3] & 7]); 631 632 if ((p[3] & 0xc0) == 0) 633 info->fprintf_func (info->stream, "%s %s", 634 cb2_str[(buf->data[3] >> 3) & 7], 635 arg); 636 else 637 info->fprintf_func (info->stream, "%s %d,%s", 638 cb1_str[(buf->data[3] >> 6) & 3], 639 (buf->data[3] >> 3) & 7, 640 arg); 641 } 642 else 643 buf->n_used = -1; 644 645 return buf->n_used; 646} 647 648/* Table to disassemble machine codes with prefix 0xDD or 0xFD. */ 649static struct tab_elt opc_ind[] = 650{ 651 { 0x07, 0xFF, prt_d, "ld bc,(%s%%+d)", INSS_EZ80 }, 652 { 0x0F, 0xFF, prt_d, "ld (%s%%+d),bc", INSS_EZ80 }, 653 { 0x17, 0xFF, prt_d, "ld de,(%s%%+d)", INSS_EZ80 }, 654 { 0x1F, 0xFF, prt_d, "ld (%s%%+d),de", INSS_EZ80 }, 655 { 0x24, 0xF7, prt_r, "inc %s%%s", INSS_ALL }, 656 { 0x25, 0xF7, prt_r, "dec %s%%s", INSS_ALL }, 657 { 0x26, 0xF7, ld_r_n, "ld %s%%s,0x%%%%02x", INSS_ALL }, 658 { 0x27, 0xFF, prt_d, "ld hl,(%s%%+d)", INSS_EZ80 }, 659 { 0x2F, 0xFF, prt_d, "ld (%s%%+d),hl", INSS_EZ80 }, 660 { 0x21, 0xFF, prt_nn, "ld %s,0x%%04x", INSS_ALL }, 661 { 0x22, 0xFF, prt_nn, "ld (0x%%04x),%s", INSS_ALL }, 662 { 0x2A, 0xFF, prt_nn, "ld %s,(0x%%04x)", INSS_ALL }, 663 { 0x23, 0xFF, prt, "inc %s", INSS_ALL }, 664 { 0x2B, 0xFF, prt, "dec %s", INSS_ALL }, 665 { 0x29, 0xFF, addvv, "%s", INSS_ALL }, 666 { 0x31, 0xFF, ld_ii_ii, "ld %%s,(%s%%%%+d)", INSS_EZ80 }, 667 { 0x37, 0xFF, ld_ii_ii, "ld %%s,(%s%%%%+d)", INSS_EZ80 }, 668 { 0x3E, 0xFE, ld_ii_ii, "ld (%s%%%%+d),%%s", INSS_EZ80 }, 669 { 0x09, 0xCF, prt_rr, "add %s,", INSS_ALL }, 670 { 0x34, 0xFF, prt_d, "inc (%s%%+d)", INSS_ALL }, 671 { 0x35, 0xFF, prt_d, "dec (%s%%+d)", INSS_ALL }, 672 { 0x36, 0xFF, prt_d_n, "ld (%s%%+d),0x%%%%02x", INSS_ALL }, 673 674 { 0x76, 0xFF, dump, "h", INSS_ALL }, 675 { 0x46, 0xC7, ld_r_d, "ld %%s,(%s%%%%+d)", INSS_ALL }, 676 { 0x70, 0xF8, ld_d_r, "ld (%s%%%%+d),%%s", INSS_ALL }, 677 { 0x64, 0xF6, ld_v_v, "%s", INSS_ALL }, 678 { 0x60, 0xF0, ld_r_r, "ld %s%%s,%%s", INSS_ALL }, 679 { 0x44, 0xC6, ld_r_r, "ld %%s,%s%%s", INSS_ALL }, 680 681 { 0x86, 0xC7, arit_d, "%%s(%s%%%%+d)", INSS_ALL }, 682 { 0x84, 0xC6, arit_r, "%%s%s%%s", INSS_ALL }, 683 684 { 0xE1, 0xFF, prt, "pop %s", INSS_ALL }, 685 { 0xE5, 0xFF, prt, "push %s", INSS_ALL }, 686 { 0xCB, 0xFF, pref_xd_cb, "%s", INSS_ALL }, 687 { 0xE3, 0xFF, prt, "ex (sp),%s", INSS_ALL }, 688 { 0xE9, 0xFF, prt, "jp (%s)", INSS_ALL }, 689 { 0xF9, 0xFF, prt, "ld sp,%s", INSS_ALL }, 690 { 0x00, 0x00, dump, "?", INSS_ALL }, 691} ; 692 693static int 694pref_ind (struct buffer *buf, disassemble_info *info, const char *txt) 695{ 696 if (fetch_data (buf, info, 1)) 697 { 698 char mytxt[TXTSIZ]; 699 struct tab_elt *p; 700 701 for (p = opc_ind; p->val != (buf->data[1] & p->mask) || !mach_inst (buf, p); ++p) 702 ; 703 snprintf (mytxt, TXTSIZ, p->text, txt); 704 p->fp (buf, info, mytxt); 705 } 706 else 707 buf->n_used = -1; 708 709 return buf->n_used; 710} 711 712static int 713print_insn_z80_buf (struct buffer *buf, disassemble_info *info); 714 715static int 716suffix (struct buffer *buf, disassemble_info *info, const char *txt) 717{ 718 char mybuf[TXTSIZ*4]; 719 fprintf_ftype old_fprintf; 720 void *old_stream; 721 char *p; 722 723 switch (txt[2]) 724 { 725 case 'l': /* SIL or LIL */ 726 buf->nn_len = 3; 727 break; 728 case 's': /* SIS or LIS */ 729 buf->nn_len = 2; 730 break; 731 default: 732 abort (); 733 } 734 if (!fetch_data (buf, info, 1) 735 || buf->data[1] == 0x40 736 || buf->data[1] == 0x49 737 || buf->data[1] == 0x52 738 || buf->data[1] == 0x5b) 739 { 740 /* Double prefix, or end of data. */ 741 info->fprintf_func (info->stream, ".db 0x%02x ; %s", (unsigned)buf->data[0], txt); 742 buf->n_used = 1; 743 return buf->n_used; 744 } 745 746 old_fprintf = info->fprintf_func; 747 old_stream = info->stream; 748 info->fprintf_func = (fprintf_ftype) &sprintf; 749 info->stream = mybuf; 750 buf->base++; 751 if (print_insn_z80_buf (buf, info) >= 0) 752 buf->n_used++; 753 info->fprintf_func = old_fprintf; 754 info->stream = old_stream; 755 756 for (p = mybuf; *p; ++p) 757 if (*p == ' ') 758 break; 759 if (*p) 760 { 761 *p++ = '\0'; 762 info->fprintf_func (info->stream, "%s.%s %s", mybuf, txt, p); 763 } 764 else 765 info->fprintf_func (info->stream, "%s.%s", mybuf, txt); 766 return buf->n_used; 767} 768 769/* Table to disassemble machine codes without prefix. */ 770static struct tab_elt opc_main[] = 771{ 772 { 0x00, 0xFF, prt, "nop", INSS_ALL }, 773 { 0x01, 0xCF, prt_rr_nn, "ld %s,0x%%04x", INSS_ALL }, 774 { 0x02, 0xFF, prt, "ld (bc),a", INSS_ALL }, 775 { 0x03, 0xCF, prt_rr, "inc ", INSS_ALL }, 776 { 0x04, 0xC7, prt_r, "inc %s", INSS_ALL }, 777 { 0x05, 0xC7, prt_r, "dec %s", INSS_ALL }, 778 { 0x06, 0xC7, ld_r_n, "ld %s,0x%%02x", INSS_ALL }, 779 { 0x07, 0xFF, prt, "rlca", INSS_ALL }, 780 { 0x08, 0xFF, prt, "ex af,af'", ~INSS_GBZ80 }, 781 { 0x09, 0xCF, prt_rr, "add hl,", INSS_ALL }, 782 { 0x0A, 0xFF, prt, "ld a,(bc)", INSS_ALL }, 783 { 0x0B, 0xCF, prt_rr, "dec ", INSS_ALL }, 784 { 0x0F, 0xFF, prt, "rrca", INSS_ALL }, 785 { 0x10, 0xFF, prt_e, "djnz ", ~INSS_GBZ80 }, 786 { 0x12, 0xFF, prt, "ld (de),a", INSS_ALL }, 787 { 0x17, 0xFF, prt, "rla", INSS_ALL }, 788 { 0x18, 0xFF, prt_e, "jr ", INSS_ALL }, 789 { 0x1A, 0xFF, prt, "ld a,(de)", INSS_ALL }, 790 { 0x1F, 0xFF, prt, "rra", INSS_ALL }, 791 { 0x20, 0xE7, jr_cc, "jr %s,", INSS_ALL }, 792 { 0x22, 0xFF, prt_nn, "ld (0x%04x),hl", ~INSS_GBZ80 }, 793 { 0x27, 0xFF, prt, "daa", INSS_ALL }, 794 { 0x2A, 0xFF, prt_nn, "ld hl,(0x%04x)", ~INSS_GBZ80 }, 795 { 0x2F, 0xFF, prt, "cpl", INSS_ALL }, 796 { 0x32, 0xFF, prt_nn, "ld (0x%04x),a", INSS_ALL }, 797 { 0x37, 0xFF, prt, "scf", INSS_ALL }, 798 { 0x3A, 0xFF, prt_nn, "ld a,(0x%04x)", INSS_ALL }, 799 { 0x3F, 0xFF, prt, "ccf", INSS_ALL }, 800 801 { 0x76, 0xFF, prt, "halt", INSS_ALL }, 802 803 { 0x40, 0xFF, suffix, "sis", INSS_EZ80 }, 804 { 0x49, 0xFF, suffix, "lis", INSS_EZ80 }, 805 { 0x52, 0xFF, suffix, "sil", INSS_EZ80 }, 806 { 0x5B, 0xFF, suffix, "lil", INSS_EZ80 }, 807 808 { 0x40, 0xC0, ld_r_r, "ld %s,%s", INSS_ALL}, 809 810 { 0x80, 0xC0, arit_r, "%s%s", INSS_ALL }, 811 812 { 0xC0, 0xC7, prt_cc, "ret ", INSS_ALL }, 813 { 0xC1, 0xCF, pop_rr, "pop", INSS_ALL }, 814 { 0xC2, 0xC7, jp_cc_nn, "jp ", INSS_ALL }, 815 { 0xC3, 0xFF, prt_nn, "jp 0x%04x", INSS_ALL }, 816 { 0xC4, 0xC7, jp_cc_nn, "call ", INSS_ALL }, 817 { 0xC5, 0xCF, pop_rr, "push", INSS_ALL }, 818 { 0xC6, 0xC7, arit_n, "%s0x%%02x", INSS_ALL }, 819 { 0xC7, 0xC7, rst, "rst 0x%02x", INSS_ALL }, 820 { 0xC9, 0xFF, prt, "ret", INSS_ALL }, 821 { 0xCB, 0xFF, pref_cb, "", INSS_ALL }, 822 { 0xCD, 0xFF, prt_nn, "call 0x%04x", INSS_ALL }, 823 { 0xD3, 0xFF, prt_n, "out (0x%02x),a", ~INSS_GBZ80 }, 824 { 0xD9, 0xFF, prt, "exx", ~INSS_GBZ80 }, 825 { 0xDB, 0xFF, prt_n, "in a,(0x%02x)", ~INSS_GBZ80 }, 826 { 0xDD, 0xFF, pref_ind, "ix", ~INSS_GBZ80 }, 827 { 0xE3, 0xFF, prt, "ex (sp),hl", ~INSS_GBZ80 }, 828 { 0xE9, 0xFF, prt, "jp (hl)", INSS_ALL }, 829 { 0xEB, 0xFF, prt, "ex de,hl", ~INSS_GBZ80 }, 830 { 0xED, 0xFF, pref_ed, "", ~INSS_GBZ80 }, 831 { 0xF3, 0xFF, prt, "di", INSS_ALL }, 832 { 0xF9, 0xFF, prt, "ld sp,hl", ~INSS_GBZ80 }, 833 { 0xFB, 0xFF, prt, "ei", INSS_ALL }, 834 { 0xFD, 0xFF, pref_ind, "iy", ~INSS_GBZ80 }, 835 { 0x00, 0x00, prt, "????", INSS_ALL }, 836} ; 837 838int 839print_insn_z80 (bfd_vma addr, disassemble_info * info) 840{ 841 struct buffer buf; 842 843 buf.base = addr; 844 buf.inss = 1 << info->mach; 845 buf.nn_len = info->mach == bfd_mach_ez80_adl ? 3 : 2; 846 info->bytes_per_line = (buf.inss & INSS_EZ80) ? 6 : 4; /* <ss pp oo nn mm MM> OR <pp oo nn mm> */ 847 848 return print_insn_z80_buf (&buf, info); 849} 850 851static int 852print_insn_z80_buf (struct buffer *buf, disassemble_info *info) 853{ 854 struct tab_elt *p; 855 856 buf->n_fetch = 0; 857 buf->n_used = 0; 858 if (! fetch_data (buf, info, 1)) 859 return -1; 860 861 for (p = opc_main; p->val != (buf->data[0] & p->mask) || !mach_inst (buf, p); ++p) 862 ; 863 p->fp (buf, info, p->text); 864 865 return buf->n_used; 866} 867