Fix various assembler testsuite failures for the Z80 target.
[deliverable/binutils-gdb.git] / opcodes / z80-dis.c
CommitLineData
6655dba2 1/* Print Z80, Z180, EZ80 and R800 instructions
b3adc24a 2 Copyright (C) 2005-2020 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"
88c1242d 23#include "disassemble.h"
3c9b82ba
NC
24#include <stdio.h>
25
26struct buffer
27{
28 bfd_vma base;
29 int n_fetch;
30 int n_used;
6655dba2
SB
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*/
3c9b82ba
NC
34} ;
35
6655dba2 36typedef int (*func)(struct buffer *, disassemble_info *, const char *);
3c9b82ba
NC
37
38struct tab_elt
39{
40 unsigned char val;
41 unsigned char mask;
42 func fp;
6655dba2
SB
43 const char * text;
44 unsigned inss; /* bit mask of supported bfd_mach_* or 0 for all mach */
3c9b82ba
NC
45} ;
46
6655dba2
SB
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
9e919b5f 56#define TXTSIZ 24
3c9b82ba 57/* Names of 16-bit registers. */
6655dba2 58static const char * rr_str[] = { "bc", "de", "hl", "sp" };
3c9b82ba 59/* Names of 8-bit registers. */
6655dba2 60static const char * r_str[] = { "b", "c", "d", "e", "h", "l", "(hl)", "a" };
3c9b82ba 61/* Texts for condition codes. */
6655dba2 62static const char * cc_str[] = { "nz", "z", "nc", "c", "po", "pe", "p", "m" };
3c9b82ba 63/* Instruction names for 8-bit arithmetic, operand "a" is often implicit */
6655dba2 64static const char * arit_str[] =
3c9b82ba
NC
65{
66 "add a,", "adc a,", "sub ", "sbc a,", "and ", "xor ", "or ", "cp "
67} ;
6655dba2
SB
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
3c9b82ba 73\f
6655dba2
SB
74static int
75mach_inst (struct buffer *buf, struct tab_elt *p)
76{
77 return !p->inss || (p->inss & buf->inss);
78}
79
3c9b82ba
NC
80static int
81fetch_data (struct buffer *buf, disassemble_info * info, int n)
82{
83 int r;
84
40c75bc8 85 if (buf->n_fetch + n > (int)sizeof (buf->data))
3c9b82ba
NC
86 abort ();
87
88 r = info->read_memory_func (buf->base + buf->n_fetch,
9e919b5f 89 (unsigned char*) buf->data + buf->n_fetch,
3c9b82ba
NC
90 n, info);
91 if (r == 0)
92 buf->n_fetch += n;
93 return !r;
94}
95
96static int
6655dba2 97prt (struct buffer *buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
98{
99 info->fprintf_func (info->stream, "%s", txt);
100 buf->n_used = buf->n_fetch;
101 return 1;
102}
103
104static int
6655dba2 105prt_e (struct buffer *buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
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
6655dba2 124jr_cc (struct buffer *buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
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
6655dba2 133prt_nn (struct buffer *buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
134{
135 int nn;
136 unsigned char *p;
6655dba2 137 int i;
3c9b82ba
NC
138
139 p = (unsigned char*) buf->data + buf->n_fetch;
6655dba2 140 if (fetch_data (buf, info, buf->nn_len))
3c9b82ba 141 {
6655dba2
SB
142 nn = 0;
143 i = buf->nn_len;
144 while (i--)
145 nn = nn * 0x100 + p[i];
3c9b82ba
NC
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
6655dba2 155prt_rr_nn (struct buffer *buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
156{
157 char mytxt[TXTSIZ];
d0411736 158 int rr;
3c9b82ba 159
43e65147 160 rr = (buf->data[buf->n_fetch - 1] >> 4) & 3;
d0411736 161 snprintf (mytxt, TXTSIZ, txt, rr_str[rr]);
3c9b82ba
NC
162 return prt_nn (buf, info, mytxt);
163}
164
165static int
6655dba2 166prt_rr (struct buffer *buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
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
6655dba2 175prt_n (struct buffer *buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
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
6655dba2
SB
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)
3c9b82ba
NC
207{
208 char mytxt[TXTSIZ];
209
6655dba2 210 snprintf (mytxt, TXTSIZ, txt, r_str[(buf->data[buf->n_fetch - 1] >> 3) & 7]);
3c9b82ba
NC
211 return prt_n (buf, info, mytxt);
212}
213
214static int
6655dba2 215prt_r (struct buffer *buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
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
6655dba2 224ld_r_r (struct buffer *buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
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
6655dba2 234prt_d (struct buffer *buf, disassemble_info * info, const char *txt)
3c9b82ba 235{
6655dba2
SB
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;
3c9b82ba 272 info->fprintf_func (info->stream, txt,
6655dba2
SB
273 arit[(buf->data[buf->n_fetch - 1] >> 3) & 7],
274 r_str[buf->data[buf->n_fetch - 1] & 7]);
3c9b82ba
NC
275 buf->n_used = buf->n_fetch;
276 return buf->n_used;
277}
278
279static int
6655dba2 280prt_cc (struct buffer *buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
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
6655dba2 289pop_rr (struct buffer *buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
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
6655dba2 301jp_cc_nn (struct buffer *buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
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
6655dba2 311arit_n (struct buffer *buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
312{
313 char mytxt[TXTSIZ];
6655dba2 314 const char * const *arit;
3c9b82ba 315
6655dba2
SB
316 arit = (buf->inss & INSS_EZ80) ? arit_str_ez80 : arit_str;
317 snprintf (mytxt,TXTSIZ, txt, arit[(buf->data[0] >> 3) & 7]);
3c9b82ba
NC
318 return prt_n (buf, info, mytxt);
319}
320
321static int
6655dba2 322rst (struct buffer *buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
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\f
330static int
6655dba2 331cis (struct buffer *buf, disassemble_info * info, const char *txt ATTRIBUTE_UNUSED)
3c9b82ba
NC
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
6655dba2
SB
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)
3c9b82ba
NC
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\f
395/* Table to disassemble machine codes with prefix 0xED. */
396struct tab_elt opc_ed[] =
397{
6655dba2
SB
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 }
3c9b82ba
NC
465};
466
467static int
6655dba2
SB
468pref_ed (struct buffer *buf, disassemble_info *info,
469 const char *txt ATTRIBUTE_UNUSED)
3c9b82ba
NC
470{
471 struct tab_elt *p;
472
40c75bc8 473 if (fetch_data (buf, info, 1))
3c9b82ba 474 {
40c75bc8 475 for (p = opc_ed; p->val != (buf->data[1] & p->mask) || !mach_inst (buf, p); ++p)
6655dba2 476 ;
3c9b82ba
NC
477 p->fp (buf, info, p->text);
478 }
479 else
480 buf->n_used = -1;
481
482 return buf->n_used;
483}
484\f
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
6655dba2
SB
494pref_cb (struct buffer *buf, disassemble_info *info,
495 const char *txt ATTRIBUTE_UNUSED)
3c9b82ba 496{
6655dba2
SB
497 const char *op_txt;
498 int idx;
3c9b82ba
NC
499 if (fetch_data (buf, info, 1))
500 {
501 buf->n_used = 2;
502 if ((buf->data[1] & 0xc0) == 0)
6655dba2
SB
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 }
3c9b82ba
NC
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\f
525static int
6655dba2 526addvv (struct buffer * buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
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
6655dba2 534ld_v_v (struct buffer * buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
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
6655dba2 543prt_d_n (struct buffer *buf, disassemble_info * info, const char *txt)
3c9b82ba 544{
6655dba2 545 char mytxt[TXTSIZ];
3c9b82ba 546 int d;
9e919b5f 547 signed char *p;
3c9b82ba 548
c9021189 549 p = buf->data + buf->n_fetch;
3c9b82ba
NC
550
551 if (fetch_data (buf, info, 1))
552 {
553 d = p[0];
6655dba2
SB
554 snprintf (mytxt, TXTSIZ, txt, d);
555 return prt_n (buf, info, mytxt);
3c9b82ba
NC
556 }
557 else
558 buf->n_used = -1;
559
560 return buf->n_used;
561}
562
563static int
6655dba2 564arit_d (struct buffer *buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
565{
566 char mytxt[TXTSIZ];
6655dba2
SB
567 signed char c;
568 const char * const *arit;
3c9b82ba 569
6655dba2
SB
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);
3c9b82ba
NC
574}
575
576static int
6655dba2 577ld_r_d (struct buffer *buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
578{
579 char mytxt[TXTSIZ];
9e919b5f 580 signed char c;
3c9b82ba
NC
581
582 c = buf->data[buf->n_fetch - 1];
6655dba2 583 snprintf (mytxt, TXTSIZ, txt, r_str[(c >> 3) & 7]);
3c9b82ba
NC
584 return prt_d (buf, info, mytxt);
585}
586
587static int
40c75bc8 588ld_d_r (struct buffer *buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
589{
590 char mytxt[TXTSIZ];
9e919b5f 591 signed char c;
3c9b82ba
NC
592
593 c = buf->data[buf->n_fetch - 1];
6655dba2 594 snprintf (mytxt, TXTSIZ, txt, r_str[c & 7]);
3c9b82ba
NC
595 return prt_d (buf, info, mytxt);
596}
597
598static int
40c75bc8 599ld_ii_ii (struct buffer *buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
600{
601 char mytxt[TXTSIZ];
9e919b5f 602 signed char c;
6655dba2
SB
603 int p;
604 static const char *ii[2] = { "ix", "iy" };
3c9b82ba 605
bce58db4 606 p = (buf->data[buf->n_fetch - 2] == (signed char) 0xdd) ? 0 : 1;
3c9b82ba 607 c = buf->data[buf->n_fetch - 1];
6655dba2
SB
608 if ((c & 0x07) != 0x07)
609 p = 1 - p; /* 0 -> 1, 1 -> 0 */
610 snprintf (mytxt, TXTSIZ, txt, ii[p]);
3c9b82ba
NC
611 return prt_d (buf, info, mytxt);
612}
613
614static int
6655dba2 615pref_xd_cb (struct buffer * buf, disassemble_info * info, const char *txt)
3c9b82ba
NC
616{
617 if (fetch_data (buf, info, 2))
618 {
619 int d;
620 char arg[TXTSIZ];
9e919b5f 621 signed char *p;
3c9b82ba
NC
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))
9e919b5f 628 snprintf (arg, TXTSIZ, "(%s%+d)", txt, d);
3c9b82ba 629 else
9e919b5f 630 snprintf (arg, TXTSIZ, "(%s%+d),%s", txt, d, r_str[p[3] & 7]);
3c9b82ba
NC
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\f
648/* Table to disassemble machine codes with prefix 0xDD or 0xFD. */
649static struct tab_elt opc_ind[] =
650{
6655dba2
SB
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 },
3c9b82ba
NC
691} ;
692
693static int
6655dba2 694pref_ind (struct buffer *buf, disassemble_info *info, const char *txt)
3c9b82ba
NC
695{
696 if (fetch_data (buf, info, 1))
697 {
698 char mytxt[TXTSIZ];
699 struct tab_elt *p;
700
6655dba2
SB
701 for (p = opc_ind; p->val != (buf->data[1] & p->mask) || !mach_inst (buf, p); ++p)
702 ;
3c9b82ba
NC
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
6655dba2
SB
712static int
713print_insn_z80_buf (struct buffer *buf, disassemble_info *info);
714
715static int
660e62b1 716suffix (struct buffer *buf, disassemble_info *info, const char *txt)
6655dba2 717{
6655dba2
SB
718 char mybuf[TXTSIZ*4];
719 fprintf_ftype old_fprintf;
720 void *old_stream;
721 char *p;
722
6655dba2
SB
723 switch (txt[2])
724 {
725 case 'l': /* SIL or LIL */
660e62b1 726 buf->nn_len = 3;
6655dba2
SB
727 break;
728 case 's': /* SIS or LIS */
660e62b1 729 buf->nn_len = 2;
6655dba2
SB
730 break;
731 default:
660e62b1
AM
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. */
7a6bf3be 741 info->fprintf_func (info->stream, ".db 0x%02x ; %s", (unsigned)buf->data[0], txt);
660e62b1
AM
742 buf->n_used = 1;
743 return buf->n_used;
6655dba2 744 }
660e62b1 745
6655dba2
SB
746 old_fprintf = info->fprintf_func;
747 old_stream = info->stream;
660e62b1 748 info->fprintf_func = (fprintf_ftype) &sprintf;
6655dba2 749 info->stream = mybuf;
660e62b1
AM
750 buf->base++;
751 if (print_insn_z80_buf (buf, info) >= 0)
752 buf->n_used++;
6655dba2
SB
753 info->fprintf_func = old_fprintf;
754 info->stream = old_stream;
755
660e62b1
AM
756 for (p = mybuf; *p; ++p)
757 if (*p == ' ')
758 break;
759 if (*p)
6655dba2 760 {
660e62b1
AM
761 *p++ = '\0';
762 info->fprintf_func (info->stream, "%s.%s %s", mybuf, txt, p);
6655dba2 763 }
660e62b1
AM
764 else
765 info->fprintf_func (info->stream, "%s.%s", mybuf, txt);
766 return buf->n_used;
6655dba2
SB
767}
768
3c9b82ba
NC
769/* Table to disassemble machine codes without prefix. */
770static struct tab_elt opc_main[] =
771{
6655dba2
SB
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 },
3c9b82ba
NC
836} ;
837
838int
839print_insn_z80 (bfd_vma addr, disassemble_info * info)
840{
841 struct buffer buf;
3c9b82ba
NC
842
843 buf.base = addr;
6655dba2
SB
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> */
3c9b82ba 847
6655dba2
SB
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
660e62b1
AM
856 buf->n_fetch = 0;
857 buf->n_used = 0;
6655dba2 858 if (! fetch_data (buf, info, 1))
3c9b82ba
NC
859 return -1;
860
40c75bc8 861 for (p = opc_main; p->val != (buf->data[0] & p->mask) || !mach_inst (buf, p); ++p)
3c9b82ba 862 ;
6655dba2 863 p->fp (buf, info, p->text);
3c9b82ba 864
6655dba2 865 return buf->n_used;
3c9b82ba 866}
This page took 0.738697 seconds and 4 git commands to generate.