daily update
[deliverable/binutils-gdb.git] / opcodes / z80-dis.c
CommitLineData
3c9b82ba 1/* Print Z80 and R800 instructions
aa820537 2 Copyright 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
3c9b82ba
NC
3 Contributed by Arnold Metselaar <arnold_m@operamail.com>
4
9b201bb5
NC
5 This file is part of the GNU opcodes library.
6
7 This library is free software; you can redistribute it and/or modify
3c9b82ba 8 it under the terms of the GNU General Public License as published by
9b201bb5
NC
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
3c9b82ba 11
9b201bb5
NC
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.
3c9b82ba
NC
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 "dis-asm.h"
24#include <stdio.h>
25
26struct buffer
27{
28 bfd_vma base;
29 int n_fetch;
30 int n_used;
9e919b5f 31 signed char data[4];
3c9b82ba
NC
32} ;
33
34typedef int (*func)(struct buffer *, disassemble_info *, char *);
35
36struct tab_elt
37{
38 unsigned char val;
39 unsigned char mask;
40 func fp;
41 char * text;
42} ;
43
9e919b5f 44#define TXTSIZ 24
3c9b82ba
NC
45/* Names of 16-bit registers. */
46static char * rr_str[] = { "bc", "de", "hl", "sp" };
47/* Names of 8-bit registers. */
48static char * r_str[] = { "b", "c", "d", "e", "h", "l", "(hl)", "a" };
49/* Texts for condition codes. */
50static char * cc_str[] = { "nz", "z", "nc", "c", "po", "pe", "p", "m" };
51/* Instruction names for 8-bit arithmetic, operand "a" is often implicit */
52static char * arit_str[] =
53{
54 "add a,", "adc a,", "sub ", "sbc a,", "and ", "xor ", "or ", "cp "
55} ;
56\f
57static int
58fetch_data (struct buffer *buf, disassemble_info * info, int n)
59{
60 int r;
61
62 if (buf->n_fetch + n > 4)
63 abort ();
64
65 r = info->read_memory_func (buf->base + buf->n_fetch,
9e919b5f 66 (unsigned char*) buf->data + buf->n_fetch,
3c9b82ba
NC
67 n, info);
68 if (r == 0)
69 buf->n_fetch += n;
70 return !r;
71}
72
73static int
74prt (struct buffer *buf, disassemble_info * info, char *txt)
75{
76 info->fprintf_func (info->stream, "%s", txt);
77 buf->n_used = buf->n_fetch;
78 return 1;
79}
80
81static int
82prt_e (struct buffer *buf, disassemble_info * info, char *txt)
83{
84 char e;
85 int target_addr;
86
87 if (fetch_data (buf, info, 1))
88 {
89 e = buf->data[1];
90 target_addr = (buf->base + 2 + e) & 0xffff;
91 buf->n_used = buf->n_fetch;
92 info->fprintf_func (info->stream, "%s0x%04x", txt, target_addr);
93 }
94 else
95 buf->n_used = -1;
96
97 return buf->n_used;
98}
99
100static int
101jr_cc (struct buffer *buf, disassemble_info * info, char *txt)
102{
103 char mytxt[TXTSIZ];
104
105 snprintf (mytxt, TXTSIZ, txt, cc_str[(buf->data[0] >> 3) & 3]);
106 return prt_e (buf, info, mytxt);
107}
108
109static int
110prt_nn (struct buffer *buf, disassemble_info * info, char *txt)
111{
112 int nn;
113 unsigned char *p;
114
115 p = (unsigned char*) buf->data + buf->n_fetch;
116 if (fetch_data (buf, info, 2))
117 {
118 nn = p[0] + (p[1] << 8);
119 info->fprintf_func (info->stream, txt, nn);
120 buf->n_used = buf->n_fetch;
121 }
122 else
123 buf->n_used = -1;
124 return buf->n_used;
125}
126
127static int
128prt_rr_nn (struct buffer *buf, disassemble_info * info, char *txt)
129{
130 char mytxt[TXTSIZ];
d0411736 131 int rr;
3c9b82ba 132
d0411736
AM
133 rr = (buf->data[buf->n_fetch - 1] >> 4) & 3;
134 snprintf (mytxt, TXTSIZ, txt, rr_str[rr]);
3c9b82ba
NC
135 return prt_nn (buf, info, mytxt);
136}
137
138static int
139prt_rr (struct buffer *buf, disassemble_info * info, char *txt)
140{
141 info->fprintf_func (info->stream, "%s%s", txt,
142 rr_str[(buf->data[buf->n_fetch - 1] >> 4) & 3]);
143 buf->n_used = buf->n_fetch;
144 return buf->n_used;
145}
146
147static int
148prt_n (struct buffer *buf, disassemble_info * info, char *txt)
149{
150 int n;
151 unsigned char *p;
152
153 p = (unsigned char*) buf->data + buf->n_fetch;
154
155 if (fetch_data (buf, info, 1))
156 {
157 n = p[0];
158 info->fprintf_func (info->stream, txt, n);
159 buf->n_used = buf->n_fetch;
160 }
161 else
162 buf->n_used = -1;
163
164 return buf->n_used;
165}
166
167static int
168ld_r_n (struct buffer *buf, disassemble_info * info, char *txt)
169{
170 char mytxt[TXTSIZ];
171
172 snprintf (mytxt, TXTSIZ, txt, r_str[(buf->data[0] >> 3) & 7]);
173 return prt_n (buf, info, mytxt);
174}
175
176static int
177prt_r (struct buffer *buf, disassemble_info * info, char *txt)
178{
179 info->fprintf_func (info->stream, txt,
180 r_str[(buf->data[buf->n_fetch - 1] >> 3) & 7]);
181 buf->n_used = buf->n_fetch;
182 return buf->n_used;
183}
184
185static int
186ld_r_r (struct buffer *buf, disassemble_info * info, char *txt)
187{
188 info->fprintf_func (info->stream, txt,
189 r_str[(buf->data[buf->n_fetch - 1] >> 3) & 7],
190 r_str[buf->data[buf->n_fetch - 1] & 7]);
191 buf->n_used = buf->n_fetch;
192 return buf->n_used;
193}
194
195static int
196arit_r (struct buffer *buf, disassemble_info * info, char *txt)
197{
198 info->fprintf_func (info->stream, txt,
199 arit_str[(buf->data[buf->n_fetch - 1] >> 3) & 7],
200 r_str[buf->data[buf->n_fetch - 1] & 7]);
201 buf->n_used = buf->n_fetch;
202 return buf->n_used;
203}
204
205static int
206prt_cc (struct buffer *buf, disassemble_info * info, char *txt)
207{
208 info->fprintf_func (info->stream, "%s%s", txt,
209 cc_str[(buf->data[0] >> 3) & 7]);
210 buf->n_used = buf->n_fetch;
211 return buf->n_used;
212}
213
214static int
215pop_rr (struct buffer *buf, disassemble_info * info, char *txt)
216{
217 static char *rr_stack[] = { "bc","de","hl","af"};
218
219 info->fprintf_func (info->stream, "%s %s", txt,
220 rr_stack[(buf->data[0] >> 4) & 3]);
221 buf->n_used = buf->n_fetch;
222 return buf->n_used;
223}
224
225
226static int
227jp_cc_nn (struct buffer *buf, disassemble_info * info, char *txt)
228{
229 char mytxt[TXTSIZ];
230
231 snprintf (mytxt,TXTSIZ,
232 "%s%s,0x%%04x", txt, cc_str[(buf->data[0] >> 3) & 7]);
233 return prt_nn (buf, info, mytxt);
234}
235
236static int
237arit_n (struct buffer *buf, disassemble_info * info, char *txt)
238{
239 char mytxt[TXTSIZ];
240
241 snprintf (mytxt,TXTSIZ, txt, arit_str[(buf->data[0] >> 3) & 7]);
242 return prt_n (buf, info, mytxt);
243}
244
245static int
246rst (struct buffer *buf, disassemble_info * info, char *txt)
247{
248 info->fprintf_func (info->stream, txt, buf->data[0] & 0x38);
249 buf->n_used = buf->n_fetch;
250 return buf->n_used;
251}
252
253\f
254static int
255cis (struct buffer *buf, disassemble_info * info, char *txt ATTRIBUTE_UNUSED)
256{
257 static char * opar[] = { "ld", "cp", "in", "out" };
258 char * op;
259 char c;
260
261 c = buf->data[1];
262 op = ((0x13 & c) == 0x13) ? "ot" : (opar[c & 3]);
263 info->fprintf_func (info->stream,
264 "%s%c%s", op,
265 (c & 0x08) ? 'd' : 'i',
266 (c & 0x10) ? "r" : "");
267 buf->n_used = 2;
268 return buf->n_used;
269}
270
271static int
272dump (struct buffer *buf, disassemble_info * info, char *txt)
273{
274 int i;
275
276 info->fprintf_func (info->stream, "defb ");
277 for (i = 0; txt[i]; ++i)
278 info->fprintf_func (info->stream, i ? ", 0x%02x" : "0x%02x",
279 (unsigned char) buf->data[i]);
280 buf->n_used = i;
281 return buf->n_used;
282}
283\f
284/* Table to disassemble machine codes with prefix 0xED. */
285struct tab_elt opc_ed[] =
286{
287 { 0x70, 0xFF, prt, "in f,(c)" },
288 { 0x70, 0xFF, dump, "xx" },
289 { 0x40, 0xC7, prt_r, "in %s,(c)" },
290 { 0x71, 0xFF, prt, "out (c),0" },
291 { 0x70, 0xFF, dump, "xx" },
292 { 0x41, 0xC7, prt_r, "out (c),%s" },
293 { 0x42, 0xCF, prt_rr, "sbc hl," },
294 { 0x43, 0xCF, prt_rr_nn, "ld (0x%%04x),%s" },
295 { 0x44, 0xFF, prt, "neg" },
296 { 0x45, 0xFF, prt, "retn" },
297 { 0x46, 0xFF, prt, "im 0" },
298 { 0x47, 0xFF, prt, "ld i,a" },
299 { 0x4A, 0xCF, prt_rr, "adc hl," },
300 { 0x4B, 0xCF, prt_rr_nn, "ld %s,(0x%%04x)" },
301 { 0x4D, 0xFF, prt, "reti" },
d0411736 302 { 0x4F, 0xFF, prt, "ld r,a" },
3c9b82ba
NC
303 { 0x56, 0xFF, prt, "im 1" },
304 { 0x57, 0xFF, prt, "ld a,i" },
305 { 0x5E, 0xFF, prt, "im 2" },
d0411736 306 { 0x5F, 0xFF, prt, "ld a,r" },
3c9b82ba
NC
307 { 0x67, 0xFF, prt, "rrd" },
308 { 0x6F, 0xFF, prt, "rld" },
309 { 0xA0, 0xE4, cis, "" },
310 { 0xC3, 0xFF, prt, "muluw hl,bc" },
311 { 0xC5, 0xE7, prt_r, "mulub a,%s" },
312 { 0xF3, 0xFF, prt, "muluw hl,sp" },
313 { 0x00, 0x00, dump, "xx" }
314};
315
316static int
317pref_ed (struct buffer * buf, disassemble_info * info,
318 char* txt ATTRIBUTE_UNUSED)
319{
320 struct tab_elt *p;
321
322 if (fetch_data(buf, info, 1))
323 {
324 for (p = opc_ed; p->val != (buf->data[1] & p->mask); ++p)
325 ;
326 p->fp (buf, info, p->text);
327 }
328 else
329 buf->n_used = -1;
330
331 return buf->n_used;
332}
333\f
334/* Instruction names for the instructions addressing single bits. */
335static char *cb1_str[] = { "", "bit", "res", "set"};
336/* Instruction names for shifts and rotates. */
337static char *cb2_str[] =
338{
339 "rlc", "rrc", "rl", "rr", "sla", "sra", "sli", "srl"
340};
341
342static int
343pref_cb (struct buffer * buf, disassemble_info * info,
344 char* txt ATTRIBUTE_UNUSED)
345{
346 if (fetch_data (buf, info, 1))
347 {
348 buf->n_used = 2;
349 if ((buf->data[1] & 0xc0) == 0)
350 info->fprintf_func (info->stream, "%s %s",
351 cb2_str[(buf->data[1] >> 3) & 7],
352 r_str[buf->data[1] & 7]);
353 else
354 info->fprintf_func (info->stream, "%s %d,%s",
355 cb1_str[(buf->data[1] >> 6) & 3],
356 (buf->data[1] >> 3) & 7,
357 r_str[buf->data[1] & 7]);
358 }
359 else
360 buf->n_used = -1;
361
362 return buf->n_used;
363}
364\f
365static int
366addvv (struct buffer * buf, disassemble_info * info, char* txt)
367{
368 info->fprintf_func (info->stream, "add %s,%s", txt, txt);
369
370 return buf->n_used = buf->n_fetch;
371}
372
373static int
374ld_v_v (struct buffer * buf, disassemble_info * info, char* txt)
375{
376 char mytxt[TXTSIZ];
377
378 snprintf (mytxt, TXTSIZ, "ld %s%%s,%s%%s", txt, txt);
379 return ld_r_r (buf, info, mytxt);
380}
381
382static int
383prt_d (struct buffer *buf, disassemble_info * info, char *txt)
384{
385 int d;
9e919b5f 386 signed char *p;
3c9b82ba 387
c9021189 388 p = buf->data + buf->n_fetch;
3c9b82ba
NC
389
390 if (fetch_data (buf, info, 1))
391 {
392 d = p[0];
393 info->fprintf_func (info->stream, txt, d);
394 buf->n_used = buf->n_fetch;
395 }
396 else
397 buf->n_used = -1;
398
399 return buf->n_used;
400}
401
402static int
403prt_d_n (struct buffer *buf, disassemble_info * info, char *txt)
404{
405 char mytxt[TXTSIZ];
406 int d;
9e919b5f 407 signed char *p;
3c9b82ba 408
c9021189 409 p = buf->data + buf->n_fetch;
3c9b82ba
NC
410
411 if (fetch_data (buf, info, 1))
412 {
413 d = p[0];
414 snprintf (mytxt, TXTSIZ, txt, d);
415 return prt_n (buf, info, mytxt);
416 }
417 else
418 buf->n_used = -1;
419
420 return buf->n_used;
421}
422
423static int
424arit_d (struct buffer *buf, disassemble_info * info, char *txt)
425{
426 char mytxt[TXTSIZ];
9e919b5f 427 signed char c;
3c9b82ba
NC
428
429 c = buf->data[buf->n_fetch - 1];
430 snprintf (mytxt, TXTSIZ, txt, arit_str[(c >> 3) & 7]);
431 return prt_d (buf, info, mytxt);
432}
433
434static int
435ld_r_d (struct buffer *buf, disassemble_info * info, char *txt)
436{
437 char mytxt[TXTSIZ];
9e919b5f 438 signed char c;
3c9b82ba
NC
439
440 c = buf->data[buf->n_fetch - 1];
441 snprintf (mytxt, TXTSIZ, txt, r_str[(c >> 3) & 7]);
442 return prt_d (buf, info, mytxt);
443}
444
445static int
446ld_d_r(struct buffer *buf, disassemble_info * info, char *txt)
447{
448 char mytxt[TXTSIZ];
9e919b5f 449 signed char c;
3c9b82ba
NC
450
451 c = buf->data[buf->n_fetch - 1];
452 snprintf (mytxt, TXTSIZ, txt, r_str[c & 7]);
453 return prt_d (buf, info, mytxt);
454}
455
456static int
457pref_xd_cb (struct buffer * buf, disassemble_info * info, char* txt)
458{
459 if (fetch_data (buf, info, 2))
460 {
461 int d;
462 char arg[TXTSIZ];
9e919b5f 463 signed char *p;
3c9b82ba
NC
464
465 buf->n_used = 4;
466 p = buf->data;
467 d = p[2];
468
469 if (((p[3] & 0xC0) == 0x40) || ((p[3] & 7) == 0x06))
9e919b5f 470 snprintf (arg, TXTSIZ, "(%s%+d)", txt, d);
3c9b82ba 471 else
9e919b5f 472 snprintf (arg, TXTSIZ, "(%s%+d),%s", txt, d, r_str[p[3] & 7]);
3c9b82ba
NC
473
474 if ((p[3] & 0xc0) == 0)
475 info->fprintf_func (info->stream, "%s %s",
476 cb2_str[(buf->data[3] >> 3) & 7],
477 arg);
478 else
479 info->fprintf_func (info->stream, "%s %d,%s",
480 cb1_str[(buf->data[3] >> 6) & 3],
481 (buf->data[3] >> 3) & 7,
482 arg);
483 }
484 else
485 buf->n_used = -1;
486
487 return buf->n_used;
488}
489\f
490/* Table to disassemble machine codes with prefix 0xDD or 0xFD. */
491static struct tab_elt opc_ind[] =
492{
493 { 0x24, 0xF7, prt_r, "inc %s%%s" },
494 { 0x25, 0xF7, prt_r, "dec %s%%s" },
495 { 0x26, 0xF7, ld_r_n, "ld %s%%s,0x%%%%02x" },
496 { 0x21, 0xFF, prt_nn, "ld %s,0x%%04x" },
497 { 0x22, 0xFF, prt_nn, "ld (0x%%04x),%s" },
498 { 0x2A, 0xFF, prt_nn, "ld %s,(0x%%04x)" },
499 { 0x23, 0xFF, prt, "inc %s" },
500 { 0x2B, 0xFF, prt, "dec %s" },
501 { 0x29, 0xFF, addvv, "%s" },
502 { 0x09, 0xCF, prt_rr, "add %s," },
9e919b5f
AM
503 { 0x34, 0xFF, prt_d, "inc (%s%%+d)" },
504 { 0x35, 0xFF, prt_d, "dec (%s%%+d)" },
505 { 0x36, 0xFF, prt_d_n, "ld (%s%%+d),0x%%%%02x" },
3c9b82ba
NC
506
507 { 0x76, 0xFF, dump, "h" },
9e919b5f
AM
508 { 0x46, 0xC7, ld_r_d, "ld %%s,(%s%%%%+d)" },
509 { 0x70, 0xF8, ld_d_r, "ld (%s%%%%+d),%%s" },
3c9b82ba
NC
510 { 0x64, 0xF6, ld_v_v, "%s" },
511 { 0x60, 0xF0, ld_r_r, "ld %s%%s,%%s" },
512 { 0x44, 0xC6, ld_r_r, "ld %%s,%s%%s" },
513
9e919b5f 514 { 0x86, 0xC7, arit_d, "%%s(%s%%%%+d)" },
3c9b82ba
NC
515 { 0x84, 0xC6, arit_r, "%%s%s%%s" },
516
517 { 0xE1, 0xFF, prt, "pop %s" },
518 { 0xE5, 0xFF, prt, "push %s" },
519 { 0xCB, 0xFF, pref_xd_cb, "%s" },
520 { 0xE3, 0xFF, prt, "ex (sp),%s" },
521 { 0xE9, 0xFF, prt, "jp (%s)" },
522 { 0xF9, 0xFF, prt, "ld sp,%s" },
523 { 0x00, 0x00, dump, "?" },
524} ;
525
526static int
527pref_ind (struct buffer * buf, disassemble_info * info, char* txt)
528{
529 if (fetch_data (buf, info, 1))
530 {
531 char mytxt[TXTSIZ];
532 struct tab_elt *p;
533
534 for (p = opc_ind; p->val != (buf->data[1] & p->mask); ++p)
535 ;
536 snprintf (mytxt, TXTSIZ, p->text, txt);
537 p->fp (buf, info, mytxt);
538 }
539 else
540 buf->n_used = -1;
541
542 return buf->n_used;
543}
544
545/* Table to disassemble machine codes without prefix. */
546static struct tab_elt opc_main[] =
547{
548 { 0x00, 0xFF, prt, "nop" },
549 { 0x01, 0xCF, prt_rr_nn, "ld %s,0x%%04x" },
550 { 0x02, 0xFF, prt, "ld (bc),a" },
551 { 0x03, 0xCF, prt_rr, "inc " },
552 { 0x04, 0xC7, prt_r, "inc %s" },
553 { 0x05, 0xC7, prt_r, "dec %s" },
554 { 0x06, 0xC7, ld_r_n, "ld %s,0x%%02x" },
555 { 0x07, 0xFF, prt, "rlca" },
556 { 0x08, 0xFF, prt, "ex af,af'" },
557 { 0x09, 0xCF, prt_rr, "add hl," },
558 { 0x0A, 0xFF, prt, "ld a,(bc)" },
559 { 0x0B, 0xCF, prt_rr, "dec " },
560 { 0x0F, 0xFF, prt, "rrca" },
561 { 0x10, 0xFF, prt_e, "djnz " },
562 { 0x12, 0xFF, prt, "ld (de),a" },
563 { 0x17, 0xFF, prt, "rla" },
564 { 0x18, 0xFF, prt_e, "jr "},
565 { 0x1A, 0xFF, prt, "ld a,(de)" },
566 { 0x1F, 0xFF, prt, "rra" },
567 { 0x20, 0xE7, jr_cc, "jr %s,"},
568 { 0x22, 0xFF, prt_nn, "ld (0x%04x),hl" },
569 { 0x27, 0xFF, prt, "daa"},
570 { 0x2A, 0xFF, prt_nn, "ld hl,(0x%04x)" },
571 { 0x2F, 0xFF, prt, "cpl" },
572 { 0x32, 0xFF, prt_nn, "ld (0x%04x),a" },
573 { 0x37, 0xFF, prt, "scf" },
574 { 0x3A, 0xFF, prt_nn, "ld a,(0x%04x)" },
575 { 0x3F, 0xFF, prt, "ccf" },
576
577 { 0x76, 0xFF, prt, "halt" },
578 { 0x40, 0xC0, ld_r_r, "ld %s,%s"},
579
580 { 0x80, 0xC0, arit_r, "%s%s" },
581
582 { 0xC0, 0xC7, prt_cc, "ret " },
583 { 0xC1, 0xCF, pop_rr, "pop" },
584 { 0xC2, 0xC7, jp_cc_nn, "jp " },
585 { 0xC3, 0xFF, prt_nn, "jp 0x%04x" },
586 { 0xC4, 0xC7, jp_cc_nn, "call " },
587 { 0xC5, 0xCF, pop_rr, "push" },
588 { 0xC6, 0xC7, arit_n, "%s0x%%02x" },
589 { 0xC7, 0xC7, rst, "rst 0x%02x" },
590 { 0xC9, 0xFF, prt, "ret" },
591 { 0xCB, 0xFF, pref_cb, "" },
592 { 0xCD, 0xFF, prt_nn, "call 0x%04x" },
593 { 0xD3, 0xFF, prt_n, "out (0x%02x),a" },
594 { 0xD9, 0xFF, prt, "exx" },
595 { 0xDB, 0xFF, prt_n, "in a,(0x%02x)" },
596 { 0xDD, 0xFF, pref_ind, "ix" },
597 { 0xE3, 0xFF, prt, "ex (sp),hl" },
598 { 0xE9, 0xFF, prt, "jp (hl)" },
599 { 0xEB, 0xFF, prt, "ex de,hl" },
600 { 0xED, 0xFF, pref_ed, ""},
601 { 0xF3, 0xFF, prt, "di" },
602 { 0xF9, 0xFF, prt, "ld sp,hl" },
603 { 0xFB, 0xFF, prt, "ei" },
604 { 0xFD, 0xFF, pref_ind, "iy" },
605 { 0x00, 0x00, prt, "????" },
606} ;
607
608int
609print_insn_z80 (bfd_vma addr, disassemble_info * info)
610{
611 struct buffer buf;
612 struct tab_elt *p;
613
614 buf.base = addr;
615 buf.n_fetch = 0;
616 buf.n_used = 0;
617
618 if (! fetch_data (& buf, info, 1))
619 return -1;
620
621 for (p = opc_main; p->val != (buf.data[0] & p->mask); ++p)
622 ;
623 p->fp (& buf, info, p->text);
624
625 return buf.n_used;
626}
This page took 0.259027 seconds and 4 git commands to generate.