1 /* Print Z80, Z180, EZ80 and R800 instructions
2 Copyright (C) 2005-2024 Free Software Foundation, Inc.
3 Contributed by Arnold Metselaar <arnold_m@operamail.com>
5 This file is part of the GNU opcodes library.
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)
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.
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. */
23 #include "disassemble.h"
32 long inss
; /* instruction set bit mask, taken from bfd_mach */
33 int nn_len
; /* address length: 2 - Z80 mode, 3 - ADL mode*/
36 typedef int (*func
)(struct buffer
*, disassemble_info
*, const char *);
44 unsigned inss
; /* bit mask of supported bfd_mach_* or 0 for all mach */
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 #define INSS_Z80N (1 << bfd_mach_z80n)
58 /* Names of 16-bit registers. */
59 static const char * rr_str
[] = { "bc", "de", "hl", "sp" };
60 /* Names of 8-bit registers. */
61 static const char * r_str
[] = { "b", "c", "d", "e", "h", "l", "(hl)", "a" };
62 /* Texts for condition codes. */
63 static const char * cc_str
[] = { "nz", "z", "nc", "c", "po", "pe", "p", "m" };
64 /* Instruction names for 8-bit arithmetic, operand "a" is often implicit */
65 static const char * arit_str
[] =
67 "add a,", "adc a,", "sub ", "sbc a,", "and ", "xor ", "or ", "cp "
69 static const char * arit_str_gbz80
[] =
71 "add a,", "adc a,", "sub a,", "sbc a,", "and ", "xor ", "or ", "cp "
73 static const char * arit_str_ez80
[] =
75 "add a,", "adc a,", "sub a,", "sbc a,", "and a,", "xor a,", "or a,", "cp a,"
80 mach_inst (struct buffer
*buf
, const struct tab_elt
*p
)
82 return !p
->inss
|| (p
->inss
& buf
->inss
);
86 fetch_data (struct buffer
*buf
, disassemble_info
* info
, int n
)
90 if (buf
->n_fetch
+ n
> (int)sizeof (buf
->data
))
93 r
= info
->read_memory_func (buf
->base
+ buf
->n_fetch
,
94 (unsigned char*) buf
->data
+ buf
->n_fetch
,
99 info
->memory_error_func (r
, buf
->base
+ buf
->n_fetch
, info
);
104 prt (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
106 info
->fprintf_func (info
->stream
, "%s", txt
);
107 buf
->n_used
= buf
->n_fetch
;
112 prt_e (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
117 if (fetch_data (buf
, info
, 1))
120 target_addr
= (buf
->base
+ 2 + e
) & 0xffff;
121 buf
->n_used
= buf
->n_fetch
;
122 info
->fprintf_func (info
->stream
, "%s0x%04x", txt
, target_addr
);
131 jr_cc (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
135 snprintf (mytxt
, TXTSIZ
, txt
, cc_str
[(buf
->data
[0] >> 3) & 3]);
136 return prt_e (buf
, info
, mytxt
);
140 prt_nn (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
146 p
= (unsigned char*) buf
->data
+ buf
->n_fetch
;
147 if (fetch_data (buf
, info
, buf
->nn_len
))
152 nn
= nn
* 0x100 + p
[i
];
153 info
->fprintf_func (info
->stream
, txt
, nn
);
154 buf
->n_used
= buf
->n_fetch
;
162 prt_rr_nn (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
167 rr
= (buf
->data
[buf
->n_fetch
- 1] >> 4) & 3;
168 snprintf (mytxt
, TXTSIZ
, txt
, rr_str
[rr
]);
169 return prt_nn (buf
, info
, mytxt
);
173 prt_rr (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
175 info
->fprintf_func (info
->stream
, "%s%s", txt
,
176 rr_str
[(buf
->data
[buf
->n_fetch
- 1] >> 4) & 3]);
177 buf
->n_used
= buf
->n_fetch
;
182 prt_n (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
187 p
= (unsigned char*) buf
->data
+ buf
->n_fetch
;
189 if (fetch_data (buf
, info
, 1))
192 info
->fprintf_func (info
->stream
, txt
, n
);
193 buf
->n_used
= buf
->n_fetch
;
202 prt_n_n (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
208 p
= (unsigned char*) buf
->data
+ buf
->n_fetch
;
210 if (fetch_data (buf
, info
, 1))
213 snprintf (mytxt
, TXTSIZ
, txt
, n
);
214 buf
->n_used
= buf
->n_fetch
;
219 return prt_n (buf
, info
, mytxt
);
223 prt_r_n (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
228 r
= (buf
->data
[buf
->n_fetch
- 1] >> 3) & 7;
229 snprintf (mytxt
, TXTSIZ
, txt
, r_str
[r
]);
230 return prt_n (buf
, info
, mytxt
);
234 ld_r_n (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
238 snprintf (mytxt
, TXTSIZ
, txt
, r_str
[(buf
->data
[buf
->n_fetch
- 1] >> 3) & 7]);
239 return prt_n (buf
, info
, mytxt
);
243 prt_r (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
245 info
->fprintf_func (info
->stream
, txt
,
246 r_str
[(buf
->data
[buf
->n_fetch
- 1] >> 3) & 7]);
247 buf
->n_used
= buf
->n_fetch
;
252 ld_r_r (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
254 info
->fprintf_func (info
->stream
, txt
,
255 r_str
[(buf
->data
[buf
->n_fetch
- 1] >> 3) & 7],
256 r_str
[buf
->data
[buf
->n_fetch
- 1] & 7]);
257 buf
->n_used
= buf
->n_fetch
;
262 prt_d (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
267 p
= buf
->data
+ buf
->n_fetch
;
269 if (fetch_data (buf
, info
, 1))
272 info
->fprintf_func (info
->stream
, txt
, d
);
273 buf
->n_used
= buf
->n_fetch
;
282 prt_rr_d (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
287 rr
= (buf
->data
[buf
->n_fetch
- 1] >> 4) & 3;
288 if (rr
== 3) /* SP is not supported */
291 snprintf (mytxt
, TXTSIZ
, txt
, rr_str
[rr
]);
292 return prt_d (buf
, info
, mytxt
);
296 arit_r (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
298 const char * const *arit
;
300 if (buf
->inss
& INSS_EZ80
)
301 arit
= arit_str_ez80
;
302 else if (buf
->inss
& INSS_GBZ80
)
303 arit
= arit_str_gbz80
;
307 info
->fprintf_func (info
->stream
, txt
,
308 arit
[(buf
->data
[buf
->n_fetch
- 1] >> 3) & 7],
309 r_str
[buf
->data
[buf
->n_fetch
- 1] & 7]);
310 buf
->n_used
= buf
->n_fetch
;
315 prt_cc (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
317 info
->fprintf_func (info
->stream
, "%s%s", txt
,
318 cc_str
[(buf
->data
[0] >> 3) & 7]);
319 buf
->n_used
= buf
->n_fetch
;
324 pop_rr (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
326 static char *rr_stack
[] = { "bc","de","hl","af"};
328 info
->fprintf_func (info
->stream
, "%s %s", txt
,
329 rr_stack
[(buf
->data
[0] >> 4) & 3]);
330 buf
->n_used
= buf
->n_fetch
;
336 jp_cc_nn (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
340 snprintf (mytxt
,TXTSIZ
,
341 "%s%s,0x%%04x", txt
, cc_str
[(buf
->data
[0] >> 3) & 7]);
342 return prt_nn (buf
, info
, mytxt
);
346 arit_n (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
349 const char * const *arit
;
351 if (buf
->inss
& INSS_EZ80
)
352 arit
= arit_str_ez80
;
353 else if (buf
->inss
& INSS_GBZ80
)
354 arit
= arit_str_gbz80
;
358 snprintf (mytxt
,TXTSIZ
, txt
, arit
[(buf
->data
[0] >> 3) & 7]);
359 return prt_n (buf
, info
, mytxt
);
363 rst (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
365 info
->fprintf_func (info
->stream
, txt
, buf
->data
[0] & 0x38);
366 buf
->n_used
= buf
->n_fetch
;
372 cis (struct buffer
*buf
, disassemble_info
* info
, const char *txt ATTRIBUTE_UNUSED
)
374 static char * opar
[] = { "ld", "cp", "in", "out" };
379 op
= ((0x13 & c
) == 0x13) ? "ot" : (opar
[c
& 3]);
380 info
->fprintf_func (info
->stream
,
382 (c
& 0x08) ? 'd' : 'i',
383 (c
& 0x10) ? "r" : "");
389 cism (struct buffer
*buf
, disassemble_info
* info
, const char *txt ATTRIBUTE_UNUSED
)
391 static char * opar
[] = { "in%cm%s", "ot%cm%s" };
397 info
->fprintf_func (info
->stream
,
399 (c
& 0x08) ? 'd' : 'i',
400 (c
& 0x10) ? "r" : "");
406 dump (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
410 info
->fprintf_func (info
->stream
, "defb ");
411 for (i
= 0; txt
[i
]; ++i
)
412 info
->fprintf_func (info
->stream
, i
? ", 0x%02x" : "0x%02x",
413 (unsigned char) buf
->data
[i
]);
418 /* Table to disassemble machine codes with prefix 0xED. */
419 static const struct tab_elt opc_ed
[] =
421 { 0x30, 0xFF, prt
, "mul d,e", INSS_Z80N
},
422 { 0x31, 0xFF, prt
, "add hl,a", INSS_Z80N
},
423 { 0x31, 0xFF, prt
, "ld iy,(hl)", INSS_EZ80
},
424 { 0x30, 0xFE, dump
, "xx", INSS_ALL
}, /* do not move this line */
425 { 0x00, 0xC7, prt_r_n
, "in0 %s,(0x%%02x)", INSS_Z180
|INSS_EZ80
},
426 { 0x01, 0xC7, prt_r_n
, "out0 (0x%%02x),%s", INSS_Z180
|INSS_EZ80
},
427 { 0x32, 0xFF, prt_d
, "lea ix,ix%+d", INSS_EZ80
},
428 { 0x33, 0xFF, prt_d
, "lea iy,iy%+d", INSS_EZ80
},
429 { 0x02, 0xCF, prt_rr_d
, "lea %s,ix%%+d", INSS_EZ80
},
430 { 0x03, 0xCF, prt_rr_d
, "lea %s,iy%%+d", INSS_EZ80
},
431 { 0x04, 0xC7, prt_r
, "tst %s", INSS_Z180
},
432 { 0x04, 0xC7, prt_r
, "tst a,%s", INSS_EZ80
},
433 { 0x07, 0xFF, prt
, "ld bc,(hl)", INSS_EZ80
},
434 { 0x3F, 0xFF, prt
, "ld (hl),ix", INSS_EZ80
},
435 { 0x0F, 0xCF, prt_rr
, "ld (hl),", INSS_EZ80
},
436 { 0x17, 0xFF, prt
, "ld de,(hl)", INSS_EZ80
},
437 { 0x23, 0xFF, prt
, "swapnib", INSS_Z80N
},
438 { 0x24, 0xFF, prt
, "mirror", INSS_Z80N
},
439 { 0x27, 0xFF, prt
, "ld hl,(hl)", INSS_EZ80
},
440 { 0x27, 0xFF, prt_n
, "test 0x%02x", INSS_Z80N
},
441 { 0x28, 0xFF, prt
, "bsla de,b", INSS_Z80N
},
442 { 0x29, 0xFF, prt
, "bsra de,b", INSS_Z80N
},
443 { 0x2A, 0xFF, prt
, "bsrl de,b", INSS_Z80N
},
444 { 0x2B, 0xFF, prt
, "bsrf de,b", INSS_Z80N
},
445 { 0x2C, 0xFF, prt
, "bslc de,b", INSS_Z80N
},
446 { 0x32, 0xFF, prt
, "add de,a", INSS_Z80N
},
447 { 0x33, 0xFF, prt
, "add bc,a", INSS_Z80N
},
448 { 0x34, 0xFF, prt_nn
, "add hl,0x%04x", INSS_Z80N
},
449 { 0x35, 0xFF, prt_nn
, "add de,0x%04x", INSS_Z80N
},
450 { 0x36, 0xFF, prt_nn
, "add bc,0x%04x", INSS_Z80N
},
451 { 0x37, 0xFF, prt
, "ld ix,(hl)", INSS_EZ80
},
452 { 0x3E, 0xFF, prt
, "ld (hl),iy", INSS_EZ80
},
453 { 0x70, 0xFF, prt
, "in f,(c)", INSS_Z80
| INSS_R800
| INSS_Z80N
},
454 { 0x70, 0xFF, dump
, "xx", INSS_ALL
},
455 { 0x40, 0xC7, prt_r
, "in %s,(bc)", INSS_EZ80
},
456 { 0x40, 0xC7, prt_r
, "in %s,(c)", INSS_ALL
},
457 { 0x71, 0xFF, prt
, "out (c),0", INSS_Z80
| INSS_Z80N
},
458 { 0x71, 0xFF, dump
, "xx", INSS_ALL
},
459 { 0x41, 0xC7, prt_r
, "out (bc),%s", INSS_EZ80
},
460 { 0x41, 0xC7, prt_r
, "out (c),%s", INSS_ALL
},
461 { 0x42, 0xCF, prt_rr
, "sbc hl,", INSS_ALL
},
462 { 0x43, 0xCF, prt_rr_nn
, "ld (0x%%04x),%s", INSS_ALL
},
463 { 0x44, 0xFF, prt
, "neg", INSS_ALL
},
464 { 0x45, 0xFF, prt
, "retn", INSS_ALL
},
465 { 0x46, 0xFF, prt
, "im 0", INSS_ALL
},
466 { 0x47, 0xFF, prt
, "ld i,a", INSS_ALL
},
467 { 0x4A, 0xCF, prt_rr
, "adc hl,", INSS_ALL
},
468 { 0x4B, 0xCF, prt_rr_nn
, "ld %s,(0x%%04x)", INSS_ALL
},
469 { 0x4C, 0xCF, prt_rr
, "mlt ", INSS_Z180
|INSS_EZ80
},
470 { 0x4D, 0xFF, prt
, "reti", INSS_ALL
},
471 { 0x4F, 0xFF, prt
, "ld r,a", INSS_ALL
},
472 { 0x54, 0xFF, prt_d
, "lea ix,iy%+d", INSS_EZ80
},
473 { 0x55, 0xFF, prt_d
, "lea iy,ix%+d", INSS_EZ80
},
474 { 0x56, 0xFF, prt
, "im 1", INSS_ALL
},
475 { 0x57, 0xFF, prt
, "ld a,i", INSS_ALL
},
476 { 0x5E, 0xFF, prt
, "im 2", INSS_ALL
},
477 { 0x5F, 0xFF, prt
, "ld a,r", INSS_ALL
},
478 { 0x64, 0xFF, prt_n
, "tst 0x%02x", INSS_Z180
},
479 { 0x64, 0xFF, prt_n
, "tst a,0x%02x", INSS_EZ80
},
480 { 0x65, 0xFF, prt_d
, "pea ix%+d", INSS_EZ80
},
481 { 0x66, 0xFF, prt_d
, "pea iy%+d", INSS_EZ80
},
482 { 0x67, 0xFF, prt
, "rrd", INSS_ALL
},
483 { 0x6D, 0xFF, prt
, "ld mb,a", INSS_EZ80
},
484 { 0x6E, 0xFF, prt
, "ld a,mb", INSS_EZ80
},
485 { 0x6F, 0xFF, prt
, "rld", INSS_ALL
},
486 { 0x74, 0xFF, prt_n
, "tstio 0x%02x", INSS_Z180
|INSS_EZ80
},
487 { 0x76, 0xFF, prt
, "slp", INSS_Z180
|INSS_EZ80
},
488 { 0x7D, 0xFF, prt
, "stmix", INSS_EZ80
},
489 { 0x7E, 0xFF, prt
, "rsmix", INSS_EZ80
},
490 { 0x82, 0xE6, cism
, "", INSS_Z180
|INSS_EZ80
},
491 { 0x84, 0xFF, prt
, "ini2", INSS_EZ80
},
492 { 0x8A, 0xFF, prt_n_n
, "push 0x%02x%%02x", INSS_Z80N
},
493 { 0x8C, 0xFF, prt
, "ind2", INSS_EZ80
},
494 { 0x90, 0xFF, prt
, "outinb", INSS_Z80N
},
495 { 0x91, 0xFF, prt_n_n
, "nextreg 0x%02x,0x%%02x", INSS_Z80N
},
496 { 0x92, 0xFF, prt_n
, "nextreg 0x%02x,a", INSS_Z80N
},
497 { 0x93, 0xFF, prt
, "pixeldn", INSS_Z80N
},
498 { 0x94, 0xFF, prt
, "ini2r", INSS_EZ80
},
499 { 0x94, 0xFF, prt
, "pixelad", INSS_Z80N
},
500 { 0x95, 0xFF, prt
, "setae", INSS_Z80N
},
501 { 0x98, 0xFF, prt
, "jp (c)", INSS_Z80N
},
502 { 0x9c, 0xFF, prt
, "ind2r", INSS_EZ80
},
503 { 0xA0, 0xE4, cis
, "", INSS_ALL
},
504 { 0xA4, 0xFF, prt
, "outi2", INSS_EZ80
},
505 { 0xA4, 0xFF, prt
, "ldix", INSS_Z80N
},
506 { 0xAC, 0xFF, prt
, "outd2", INSS_EZ80
},
507 { 0xAC, 0xFF, prt
, "lddx", INSS_Z80N
},
508 { 0xA5, 0xFF, prt
, "ldws", INSS_Z80N
},
509 { 0xB4, 0xFF, prt
, "oti2r", INSS_EZ80
},
510 { 0xB4, 0xFF, prt
, "ldirx", INSS_Z80N
},
511 { 0xB7, 0xFF, prt
, "ldpirx", INSS_Z80N
},
512 { 0xBC, 0xFF, prt
, "otd2r", INSS_EZ80
},
513 { 0xBC, 0xFF, prt
, "lddrx", INSS_Z80N
},
514 { 0xC2, 0xFF, prt
, "inirx", INSS_EZ80
},
515 { 0xC3, 0xFF, prt
, "otirx", INSS_EZ80
},
516 { 0xC7, 0xFF, prt
, "ld i,hl", INSS_EZ80
},
517 { 0xCA, 0xFF, prt
, "indrx", INSS_EZ80
},
518 { 0xCB, 0xFF, prt
, "otdrx", INSS_EZ80
},
519 { 0xC3, 0xFF, prt
, "muluw hl,bc", INSS_R800
},
520 { 0xC5, 0xE7, prt_r
, "mulub a,%s", INSS_R800
},
521 { 0xD7, 0xFF, prt
, "ld hl,i", INSS_EZ80
},
522 { 0xF3, 0xFF, prt
, "muluw hl,sp", INSS_R800
},
523 { 0x00, 0x00, dump
, "xx", INSS_ALL
}
527 pref_ed (struct buffer
*buf
, disassemble_info
*info
,
528 const char *txt ATTRIBUTE_UNUSED
)
530 const struct tab_elt
*p
;
532 if (fetch_data (buf
, info
, 1))
534 for (p
= opc_ed
; p
->val
!= (buf
->data
[1] & p
->mask
) || !mach_inst (buf
, p
); ++p
)
536 p
->fp (buf
, info
, p
->text
);
544 /* Instruction names for the instructions addressing single bits. */
545 static char *cb1_str
[] = { "", "bit", "res", "set"};
546 /* Instruction names for shifts and rotates. */
547 static char *cb2_str
[] =
549 "rlc", "rrc", "rl", "rr", "sla", "sra", "sli", "srl"
553 pref_cb (struct buffer
*buf
, disassemble_info
*info
,
554 const char *txt ATTRIBUTE_UNUSED
)
558 if (fetch_data (buf
, info
, 1))
561 if ((buf
->data
[1] & 0xc0) == 0)
563 idx
= (buf
->data
[1] >> 3) & 7;
564 if ((buf
->inss
& INSS_GBZ80
) && (idx
== 6))
567 op_txt
= cb2_str
[idx
];
568 info
->fprintf_func (info
->stream
, "%s %s",
570 r_str
[buf
->data
[1] & 7]);
573 info
->fprintf_func (info
->stream
, "%s %d,%s",
574 cb1_str
[(buf
->data
[1] >> 6) & 3],
575 (buf
->data
[1] >> 3) & 7,
576 r_str
[buf
->data
[1] & 7]);
585 addvv (struct buffer
* buf
, disassemble_info
* info
, const char *txt
)
587 info
->fprintf_func (info
->stream
, "add %s,%s", txt
, txt
);
589 return buf
->n_used
= buf
->n_fetch
;
593 ld_v_v (struct buffer
* buf
, disassemble_info
* info
, const char *txt
)
597 snprintf (mytxt
, TXTSIZ
, "ld %s%%s,%s%%s", txt
, txt
);
598 return ld_r_r (buf
, info
, mytxt
);
602 prt_d_n (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
608 p
= buf
->data
+ buf
->n_fetch
;
610 if (fetch_data (buf
, info
, 1))
613 snprintf (mytxt
, TXTSIZ
, txt
, d
);
614 return prt_n (buf
, info
, mytxt
);
623 arit_d (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
627 const char * const *arit
;
629 arit
= (buf
->inss
& INSS_EZ80
) ? arit_str_ez80
: arit_str
;
630 c
= buf
->data
[buf
->n_fetch
- 1];
631 snprintf (mytxt
, TXTSIZ
, txt
, arit
[(c
>> 3) & 7]);
632 return prt_d (buf
, info
, mytxt
);
636 ld_r_d (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
641 c
= buf
->data
[buf
->n_fetch
- 1];
642 snprintf (mytxt
, TXTSIZ
, txt
, r_str
[(c
>> 3) & 7]);
643 return prt_d (buf
, info
, mytxt
);
647 ld_d_r (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
652 c
= buf
->data
[buf
->n_fetch
- 1];
653 snprintf (mytxt
, TXTSIZ
, txt
, r_str
[c
& 7]);
654 return prt_d (buf
, info
, mytxt
);
658 ld_ii_ii (struct buffer
*buf
, disassemble_info
* info
, const char *txt
)
663 static const char *ii
[2] = { "ix", "iy" };
665 p
= (buf
->data
[buf
->n_fetch
- 2] == (signed char) 0xdd) ? 0 : 1;
666 c
= buf
->data
[buf
->n_fetch
- 1];
667 if ((c
& 0x07) != 0x07)
668 p
= 1 - p
; /* 0 -> 1, 1 -> 0 */
669 snprintf (mytxt
, TXTSIZ
, txt
, ii
[p
]);
670 return prt_d (buf
, info
, mytxt
);
674 pref_xd_cb (struct buffer
* buf
, disassemble_info
* info
, const char *txt
)
676 if (fetch_data (buf
, info
, 2))
686 if (((p
[3] & 0xC0) == 0x40) || ((p
[3] & 7) == 0x06))
687 snprintf (arg
, TXTSIZ
, "(%s%+d)", txt
, d
);
689 snprintf (arg
, TXTSIZ
, "(%s%+d),%s", txt
, d
, r_str
[p
[3] & 7]);
691 if ((p
[3] & 0xc0) == 0)
692 info
->fprintf_func (info
->stream
, "%s %s",
693 cb2_str
[(buf
->data
[3] >> 3) & 7],
696 info
->fprintf_func (info
->stream
, "%s %d,%s",
697 cb1_str
[(buf
->data
[3] >> 6) & 3],
698 (buf
->data
[3] >> 3) & 7,
707 /* Table to disassemble machine codes with prefix 0xDD or 0xFD. */
708 static struct tab_elt opc_ind
[] =
710 { 0x07, 0xFF, prt_d
, "ld bc,(%s%%+d)", INSS_EZ80
},
711 { 0x0F, 0xFF, prt_d
, "ld (%s%%+d),bc", INSS_EZ80
},
712 { 0x17, 0xFF, prt_d
, "ld de,(%s%%+d)", INSS_EZ80
},
713 { 0x1F, 0xFF, prt_d
, "ld (%s%%+d),de", INSS_EZ80
},
714 { 0x24, 0xF7, prt_r
, "inc %s%%s", INSS_ALL
},
715 { 0x25, 0xF7, prt_r
, "dec %s%%s", INSS_ALL
},
716 { 0x26, 0xF7, ld_r_n
, "ld %s%%s,0x%%%%02x", INSS_ALL
},
717 { 0x27, 0xFF, prt_d
, "ld hl,(%s%%+d)", INSS_EZ80
},
718 { 0x2F, 0xFF, prt_d
, "ld (%s%%+d),hl", INSS_EZ80
},
719 { 0x21, 0xFF, prt_nn
, "ld %s,0x%%04x", INSS_ALL
},
720 { 0x22, 0xFF, prt_nn
, "ld (0x%%04x),%s", INSS_ALL
},
721 { 0x2A, 0xFF, prt_nn
, "ld %s,(0x%%04x)", INSS_ALL
},
722 { 0x23, 0xFF, prt
, "inc %s", INSS_ALL
},
723 { 0x2B, 0xFF, prt
, "dec %s", INSS_ALL
},
724 { 0x29, 0xFF, addvv
, "%s", INSS_ALL
},
725 { 0x31, 0xFF, ld_ii_ii
, "ld %%s,(%s%%%%+d)", INSS_EZ80
},
726 { 0x37, 0xFF, ld_ii_ii
, "ld %%s,(%s%%%%+d)", INSS_EZ80
},
727 { 0x3E, 0xFE, ld_ii_ii
, "ld (%s%%%%+d),%%s", INSS_EZ80
},
728 { 0x09, 0xCF, prt_rr
, "add %s,", INSS_ALL
},
729 { 0x34, 0xFF, prt_d
, "inc (%s%%+d)", INSS_ALL
},
730 { 0x35, 0xFF, prt_d
, "dec (%s%%+d)", INSS_ALL
},
731 { 0x36, 0xFF, prt_d_n
, "ld (%s%%+d),0x%%%%02x", INSS_ALL
},
733 { 0x76, 0xFF, dump
, "h", INSS_ALL
},
734 { 0x46, 0xC7, ld_r_d
, "ld %%s,(%s%%%%+d)", INSS_ALL
},
735 { 0x70, 0xF8, ld_d_r
, "ld (%s%%%%+d),%%s", INSS_ALL
},
736 { 0x64, 0xF6, ld_v_v
, "%s", INSS_ALL
},
737 { 0x60, 0xF0, ld_r_r
, "ld %s%%s,%%s", INSS_ALL
},
738 { 0x44, 0xC6, ld_r_r
, "ld %%s,%s%%s", INSS_ALL
},
740 { 0x86, 0xC7, arit_d
, "%%s(%s%%%%+d)", INSS_ALL
},
741 { 0x84, 0xC6, arit_r
, "%%s%s%%s", INSS_ALL
},
743 { 0xE1, 0xFF, prt
, "pop %s", INSS_ALL
},
744 { 0xE5, 0xFF, prt
, "push %s", INSS_ALL
},
745 { 0xCB, 0xFF, pref_xd_cb
, "%s", INSS_ALL
},
746 { 0xE3, 0xFF, prt
, "ex (sp),%s", INSS_ALL
},
747 { 0xE9, 0xFF, prt
, "jp (%s)", INSS_ALL
},
748 { 0xF9, 0xFF, prt
, "ld sp,%s", INSS_ALL
},
749 { 0x00, 0x00, dump
, "?", INSS_ALL
},
753 pref_ind (struct buffer
*buf
, disassemble_info
*info
, const char *txt
)
755 if (fetch_data (buf
, info
, 1))
760 for (p
= opc_ind
; p
->val
!= (buf
->data
[1] & p
->mask
) || !mach_inst (buf
, p
); ++p
)
762 snprintf (mytxt
, TXTSIZ
, p
->text
, txt
);
763 p
->fp (buf
, info
, mytxt
);
772 print_insn_z80_buf (struct buffer
*buf
, disassemble_info
*info
);
775 suffix (struct buffer
*buf
, disassemble_info
*info
, const char *txt
)
777 char mybuf
[TXTSIZ
*4];
778 fprintf_ftype old_fprintf
;
784 case 'l': /* SIL or LIL */
787 case 's': /* SIS or LIS */
793 if (!fetch_data (buf
, info
, 1)
794 || buf
->data
[1] == 0x40
795 || buf
->data
[1] == 0x49
796 || buf
->data
[1] == 0x52
797 || buf
->data
[1] == 0x5b)
799 /* Double prefix, or end of data. */
800 info
->fprintf_func (info
->stream
, ".db 0x%02x ; %s", (unsigned)buf
->data
[0], txt
);
805 old_fprintf
= info
->fprintf_func
;
806 old_stream
= info
->stream
;
807 info
->fprintf_func
= (fprintf_ftype
) &sprintf
;
808 info
->stream
= mybuf
;
811 if (print_insn_z80_buf (buf
, info
) >= 0)
813 info
->fprintf_func
= old_fprintf
;
814 info
->stream
= old_stream
;
816 for (p
= mybuf
; *p
; ++p
)
822 info
->fprintf_func (info
->stream
, "%s.%s %s", mybuf
, txt
, p
);
825 info
->fprintf_func (info
->stream
, "%s.%s", mybuf
, txt
);
829 /* Table to disassemble machine codes without prefix. */
830 static const struct tab_elt
833 { 0x00, 0xFF, prt
, "nop", INSS_ALL
},
834 { 0x01, 0xCF, prt_rr_nn
, "ld %s,0x%%04x", INSS_ALL
},
835 { 0x02, 0xFF, prt
, "ld (bc),a", INSS_ALL
},
836 { 0x03, 0xCF, prt_rr
, "inc ", INSS_ALL
},
837 { 0x04, 0xC7, prt_r
, "inc %s", INSS_ALL
},
838 { 0x05, 0xC7, prt_r
, "dec %s", INSS_ALL
},
839 { 0x06, 0xC7, ld_r_n
, "ld %s,0x%%02x", INSS_ALL
},
840 { 0x07, 0xFF, prt
, "rlca", INSS_ALL
},
841 { 0x08, 0xFF, prt
, "ex af,af'", ~INSS_GBZ80
},
842 { 0x09, 0xCF, prt_rr
, "add hl,", INSS_ALL
},
843 { 0x0A, 0xFF, prt
, "ld a,(bc)", INSS_ALL
},
844 { 0x0B, 0xCF, prt_rr
, "dec ", INSS_ALL
},
845 { 0x0F, 0xFF, prt
, "rrca", INSS_ALL
},
846 { 0x10, 0xFF, prt_e
, "djnz ", ~INSS_GBZ80
},
847 { 0x12, 0xFF, prt
, "ld (de),a", INSS_ALL
},
848 { 0x17, 0xFF, prt
, "rla", INSS_ALL
},
849 { 0x18, 0xFF, prt_e
, "jr ", INSS_ALL
},
850 { 0x1A, 0xFF, prt
, "ld a,(de)", INSS_ALL
},
851 { 0x1F, 0xFF, prt
, "rra", INSS_ALL
},
852 { 0x20, 0xE7, jr_cc
, "jr %s,", INSS_ALL
},
853 { 0x22, 0xFF, prt_nn
, "ld (0x%04x),hl", ~INSS_GBZ80
},
854 { 0x27, 0xFF, prt
, "daa", INSS_ALL
},
855 { 0x2A, 0xFF, prt_nn
, "ld hl,(0x%04x)", ~INSS_GBZ80
},
856 { 0x2F, 0xFF, prt
, "cpl", INSS_ALL
},
857 { 0x32, 0xFF, prt_nn
, "ld (0x%04x),a", INSS_ALL
},
858 { 0x37, 0xFF, prt
, "scf", INSS_ALL
},
859 { 0x3A, 0xFF, prt_nn
, "ld a,(0x%04x)", INSS_ALL
},
860 { 0x3F, 0xFF, prt
, "ccf", INSS_ALL
},
862 { 0x76, 0xFF, prt
, "halt", INSS_ALL
},
864 { 0x40, 0xFF, suffix
, "sis", INSS_EZ80
},
865 { 0x49, 0xFF, suffix
, "lis", INSS_EZ80
},
866 { 0x52, 0xFF, suffix
, "sil", INSS_EZ80
},
867 { 0x5B, 0xFF, suffix
, "lil", INSS_EZ80
},
869 { 0x40, 0xC0, ld_r_r
, "ld %s,%s", INSS_ALL
},
871 { 0x80, 0xC0, arit_r
, "%s%s", INSS_ALL
},
873 { 0xC0, 0xC7, prt_cc
, "ret ", INSS_ALL
},
874 { 0xC1, 0xCF, pop_rr
, "pop", INSS_ALL
},
875 { 0xC2, 0xC7, jp_cc_nn
, "jp ", INSS_ALL
},
876 { 0xC3, 0xFF, prt_nn
, "jp 0x%04x", INSS_ALL
},
877 { 0xC4, 0xC7, jp_cc_nn
, "call ", INSS_ALL
},
878 { 0xC5, 0xCF, pop_rr
, "push", INSS_ALL
},
879 { 0xC6, 0xC7, arit_n
, "%s0x%%02x", INSS_ALL
},
880 { 0xC7, 0xC7, rst
, "rst 0x%02x", INSS_ALL
},
881 { 0xC9, 0xFF, prt
, "ret", INSS_ALL
},
882 { 0xCB, 0xFF, pref_cb
, "", INSS_ALL
},
883 { 0xCD, 0xFF, prt_nn
, "call 0x%04x", INSS_ALL
},
884 { 0xD3, 0xFF, prt_n
, "out (0x%02x),a", ~INSS_GBZ80
},
885 { 0xD9, 0xFF, prt
, "exx", ~INSS_GBZ80
},
886 { 0xDB, 0xFF, prt_n
, "in a,(0x%02x)", ~INSS_GBZ80
},
887 { 0xDD, 0xFF, pref_ind
, "ix", ~INSS_GBZ80
},
888 { 0xE3, 0xFF, prt
, "ex (sp),hl", ~INSS_GBZ80
},
889 { 0xE9, 0xFF, prt
, "jp (hl)", INSS_ALL
},
890 { 0xEB, 0xFF, prt
, "ex de,hl", ~INSS_GBZ80
},
891 { 0xED, 0xFF, pref_ed
, "", ~INSS_GBZ80
},
892 { 0xF3, 0xFF, prt
, "di", INSS_ALL
},
893 { 0xF9, 0xFF, prt
, "ld sp,hl", INSS_ALL
},
894 { 0xFB, 0xFF, prt
, "ei", INSS_ALL
},
895 { 0xFD, 0xFF, pref_ind
, "iy", ~INSS_GBZ80
},
896 { 0x00, 0x00, prt
, "????", INSS_ALL
},
899 /* Separate GBZ80 main opcode table due to many differences */
900 static const struct tab_elt
903 { 0x00, 0xFF, prt
,"nop", INSS_ALL
},
904 { 0x01, 0xCF, prt_rr_nn
, "ld %s,0x%%04x", INSS_ALL
},
905 { 0x02, 0xFF, prt
, "ld (bc),a", INSS_ALL
},
906 { 0x03, 0xCF, prt_rr
, "inc ", INSS_ALL
},
907 { 0x04, 0xC7, prt_r
, "inc %s", INSS_ALL
},
908 { 0x05, 0xC7, prt_r
, "dec %s", INSS_ALL
},
909 { 0x06, 0xC7, ld_r_n
, "ld %s,0x%%02x", INSS_ALL
},
910 { 0x07, 0xFF, prt
, "rlca", INSS_ALL
},
911 { 0x08, 0xFF, prt_nn
, "ld (0x%04x),sp", INSS_GBZ80
},
912 { 0x09, 0xCF, prt_rr
, "add hl,", INSS_ALL
},
913 { 0x0A, 0xFF, prt
, "ld a,(bc)", INSS_ALL
},
914 { 0x0B, 0xCF, prt_rr
, "dec ", INSS_ALL
},
915 { 0x0F, 0xFF, prt
, "rrca", INSS_ALL
},
916 { 0x10, 0xFF, prt
, "stop", INSS_GBZ80
},
917 { 0x12, 0xFF, prt
, "ld (de),a", INSS_ALL
},
918 { 0x17, 0xFF, prt
, "rla", INSS_ALL
},
919 { 0x18, 0xFF, prt_e
, "jr ", INSS_ALL
},
920 { 0x1A, 0xFF, prt
, "ld a,(de)", INSS_ALL
},
921 { 0x1F, 0xFF, prt
, "rra", INSS_ALL
},
922 { 0x20, 0xE7, jr_cc
, "jr %s,", INSS_ALL
},
923 { 0x22, 0xFF, prt
, "ld (hl+),a", INSS_GBZ80
},
924 { 0x27, 0xFF, prt
, "daa", INSS_ALL
},
925 { 0x2A, 0xFF, prt
, "ld a,(hl+)", INSS_GBZ80
},
926 { 0x2F, 0xFF, prt
, "cpl", INSS_ALL
},
927 { 0x32, 0xFF, prt
, "ld (hl-),a", INSS_GBZ80
},
928 { 0x37, 0xFF, prt
, "scf", INSS_ALL
},
929 { 0x3A, 0xFF, prt
, "ld a,(hl-)", INSS_GBZ80
},
930 { 0x3F, 0xFF, prt
, "ccf", INSS_ALL
},
931 { 0x76, 0xFF, prt
, "halt", INSS_ALL
},
932 { 0x40, 0xC0, ld_r_r
, "ld %s,%s", INSS_ALL
},
933 { 0x80, 0xC0, arit_r
, "%s%s", INSS_ALL
},
934 { 0xC0, 0xE7, prt_cc
, "ret ", INSS_ALL
},
935 { 0xC1, 0xCF, pop_rr
, "pop", INSS_ALL
},
936 { 0xC2, 0xE7, jp_cc_nn
, "jp ", INSS_ALL
},
937 { 0xC3, 0xFF, prt_nn
, "jp 0x%04x", INSS_ALL
},
938 { 0xC4, 0xE7, jp_cc_nn
, "call ", INSS_ALL
},
939 { 0xC5, 0xCF, pop_rr
, "push", INSS_ALL
},
940 { 0xC6, 0xC7, arit_n
, "%s0x%%02x", INSS_ALL
},
941 { 0xC7, 0xC7, rst
, "rst 0x%02x", INSS_ALL
},
942 { 0xC9, 0xFF, prt
, "ret", INSS_ALL
},
943 { 0xCB, 0xFF, pref_cb
, "", INSS_ALL
},
944 { 0xCD, 0xFF, prt_nn
, "call 0x%04x", INSS_ALL
},
945 { 0xD9, 0xFF, prt
, "reti", INSS_GBZ80
},
946 { 0xE0, 0xFF, prt_n
, "ldh (0x%02x),a", INSS_GBZ80
},
947 { 0xE2, 0xFF, prt
, "ldh (c),a", INSS_GBZ80
},
948 { 0xE8, 0xFF, prt_d
, "add sp,%d", INSS_GBZ80
},
949 { 0xE9, 0xFF, prt
, "jp (hl)", INSS_ALL
},
950 { 0xEA, 0xFF, prt_nn
, "ld (0x%04x),a", INSS_GBZ80
},
951 { 0xF0, 0xFF, prt_n
, "ldh a,(0x%02x)", INSS_GBZ80
},
952 { 0xF2, 0xFF, prt
, "ldh a,(c)", INSS_GBZ80
},
953 { 0xF3, 0xFF, prt
, "di", INSS_ALL
},
954 { 0xF8, 0xFF, prt_d
, "ldhl sp,%d", INSS_GBZ80
},
955 { 0xF9, 0xFF, prt
, "ld sp,hl", INSS_ALL
},
956 { 0xFA, 0xFF, prt_nn
, "ld a,(0x%04x)", INSS_GBZ80
},
957 { 0xFB, 0xFF, prt
, "ei", INSS_ALL
},
958 { 0x00, 0x00, dump
, "?", INSS_ALL
},
962 print_insn_z80 (bfd_vma addr
, disassemble_info
* info
)
967 buf
.inss
= 1 << info
->mach
;
968 buf
.nn_len
= info
->mach
== bfd_mach_ez80_adl
? 3 : 2;
969 info
->bytes_per_line
= (buf
.inss
& INSS_EZ80
) ? 6 : 4; /* <ss pp oo nn mm MM> OR <pp oo nn mm> */
971 return print_insn_z80_buf (&buf
, info
);
975 print_insn_z80_buf (struct buffer
*buf
, disassemble_info
*info
)
977 const struct tab_elt
*p
;
981 if (! fetch_data (buf
, info
, 1))
984 p
= (buf
->inss
& INSS_GBZ80
) ? opc_main_gbz80
: opc_main
;
986 for (; p
->val
!= (buf
->data
[0] & p
->mask
) || !mach_inst (buf
, p
); ++p
)
988 p
->fp (buf
, info
, p
->text
);