2 * Z80 CPU emulation engine v0.1.1
3 * coded by Ketmar // Invisible Vector (psyc://ketmar.no-ip.org/~ketmar)
4 * Understanding is not required. Only obedience.
6 * This program is free software. It comes without any warranty, to
7 * the extent permitted by applicable law. You can redistribute it
8 * and/or modify it under the terms of the Do What The Fuck You Want
9 * To Public License, Version 2, as published by Sam Hocevar. See
10 * http://www.wtfpl.net/txt/copying/ for more details.
15 #include "zymosis_utils.h"
18 # ifndef ZYMDIS_INLINE
19 /*# define ZYMDIS_INLINE __attribute__((always_inline)) inline*/
20 # define ZYMDIS_INLINE
23 # define ZYMDIS_PURE __attribute__((pure))
26 # define ZYMDIS_CONST __attribute__((const))
29 # define ZYMDIS_FUNC __attribute__((warn_unused_result))
34 # define ZYMDIS_INLINE
47 zym_disasm_getlabel_fn zym_disasm_getlabel
= NULL
;
49 const char *zym_disasm_mnemo_end
= NULL
;
50 const char *zym_disasm_num_start
= NULL
;
51 const char *zym_disasm_num_end
= NULL
;
54 /******************************************************************************/
55 /* very simple disassembler */
56 /******************************************************************************/
74 static uint8_t zym_dis_read_byte (ZymDisWorkArea
*wkp
) {
77 res
= wkp
->z80
->mem_read(wkp
->z80
, wkp
->pc
, ZYM_MEMIO_OTHER
);
79 res
= wkp
->mem
[wkp
->mempos
++];
81 wkp
->pc
= (wkp
->pc
+1)&0xffff;
86 static ZYMDIS_INLINE
uint16_t zym_dis_read_word (ZymDisWorkArea
*wkp
) {
87 uint16_t tmptmpb0
= zym_dis_read_byte(wkp
);
88 uint16_t tmptmpb1
= zym_dis_read_byte(wkp
);
89 return tmptmpb0
|(tmptmpb1
<<8);
93 static void zym_dis_put_str (ZymDisWorkArea
*wkp
, const char *s
) {
97 if (wkp
->nfo
->locase
) {
98 if (ch
>= 'A' && ch
<= 'Z') ch
+= 32;
100 if (ch
>= 'a' && ch
<= 'z') ch
-= 32;
102 if (wkp
->dbpos
+2 < sizeof(wkp
->nfo
->disbuf
)) wkp
->nfo
->disbuf
[wkp
->dbpos
++] = ch
;
107 static void zym_dis_put_str_as_is (ZymDisWorkArea
*wkp
, const char *s
) {
110 if (wkp
->dbpos
+2 < sizeof(wkp
->nfo
->disbuf
)) wkp
->nfo
->disbuf
[wkp
->dbpos
++] = s
[0];
115 static ZYMDIS_INLINE
void zym_dis_end_mnemo (ZymDisWorkArea
*wkp
) {
116 /*if (nfo->mnemo.length) assert(0, "internal error");*/
117 if (zym_disasm_mnemo_end
) zym_dis_put_str_as_is(wkp
, zym_disasm_mnemo_end
); else zym_dis_put_str_as_is(wkp
, "\t");
118 wkp
->nfo
->mnemo
= wkp
->nfo
->disbuf
;
119 wkp
->nfo
->mnemolen
= wkp
->dbpos
;
120 wkp
->dbstpos
= wkp
->dbpos
;
124 static ZYMDIS_INLINE
void zym_dis_end_arg (ZymDisWorkArea
*wkp
) {
125 /*if (curarg >= nfo->args.length) assert(0, "internal error");*/
126 wkp
->nfo
->args
[wkp
->curarg
] = wkp
->nfo
->disbuf
+wkp
->dbstpos
;
127 wkp
->nfo
->argslen
[wkp
->curarg
] = (int)(wkp
->dbpos
-wkp
->dbstpos
);
129 wkp
->dbstpos
= wkp
->dbpos
;
134 static ZYMDIS_INLINE
void zym_dis_start_arg (ZymDisWorkArea
*wkp
) {
135 if (!wkp
->argstarted
&& wkp
->curarg
) zym_dis_put_str_as_is(wkp
, ",");
140 static ZYMDIS_INLINE
void zym_dis_put_mnemo (ZymDisWorkArea
*wkp
, const char *s
) {
141 zym_dis_put_str(wkp
, s
);
142 zym_dis_end_mnemo(wkp
);
146 static ZYMDIS_INLINE
void zym_dis_put_arg_part (ZymDisWorkArea
*wkp
, const char *s
) {
148 if (!wkp
->argstarted
&& wkp
->curarg
) zym_dis_put_str_as_is(wkp
, ",");
150 zym_dis_put_str(wkp
, s
);
155 static ZYMDIS_INLINE
void zym_dis_put_arg (ZymDisWorkArea
*wkp
, const char *s
) {
156 zym_dis_put_arg_part(wkp
, s
);
157 zym_dis_end_arg(wkp
);
161 static void zym_dis_put_uint_dec (ZymDisWorkArea
*wkp
, int n
) {
162 uint32_t ntmp
= (uint32_t)(n
&0xffffU
);
164 unsigned bpos
= (unsigned)sizeof(buf
);
166 do { buf
[--bpos
] = (char)('0'+ntmp
%10); } while ((ntmp
/= 10) != 0);
167 if (zym_disasm_num_start
) zym_dis_put_str_as_is(wkp
, zym_disasm_num_start
);
168 zym_dis_put_str(wkp
, buf
+bpos
);
169 if (zym_disasm_num_end
) zym_dis_put_str_as_is(wkp
, zym_disasm_num_end
);
173 static void zym_dis_put_uint_hex_len (ZymDisWorkArea
*wkp
, int n
, int len
) {
174 uint32_t ntmp
= (uint32_t)(n
&0xffffU
);
177 unsigned bpos
= (unsigned)sizeof(buf
);
178 if (lentmp
> 12) lentmp
= 12;
180 do { buf
[--bpos
] = (char)('0'+ntmp
%16+(ntmp
%16 > 9 ? 7 : 0)); } while ((ntmp
/= 16) != 0);
181 while (sizeof(buf
)-bpos
< lentmp
+1) buf
[--bpos
] = '0';
183 if (zym_disasm_num_start
) zym_dis_put_str_as_is(wkp
, zym_disasm_num_start
);
184 zym_dis_put_str(wkp
, buf
+bpos
);
185 if (zym_disasm_num_end
) zym_dis_put_str_as_is(wkp
, zym_disasm_num_end
);
189 static ZYMDIS_INLINE
void zym_dis_put_uint_hexlen (ZymDisWorkArea
*wkp
, int n
, int len
) {
190 if (wkp
->nfo
->decimal
) zym_dis_put_uint_dec(wkp
, n
); else zym_dis_put_uint_hex_len(wkp
, n
, len
);
194 static ZYMDIS_INLINE
void zym_dis_put_uint_addr_pc (ZymDisWorkArea
*wkp
, int n
, int len
) {
195 const char *lbl
= (zym_disasm_getlabel
? zym_disasm_getlabel(n
&0xffff, ZYM_DIS_ATYPE_PC_ADDR
) : NULL
);
196 if (lbl
) zym_dis_put_str_as_is(wkp
, lbl
);
197 else if (wkp
->nfo
->decimal
) zym_dis_put_uint_dec(wkp
, n
); else zym_dis_put_uint_hex_len(wkp
, n
, len
);
201 static ZYMDIS_INLINE
void zym_dis_put_uint_addr_data (ZymDisWorkArea
*wkp
, int n
, int len
) {
202 const char *lbl
= (zym_disasm_getlabel
? zym_disasm_getlabel(n
&0xffff, ZYM_DIS_ATYPE_DATA_ADDR
) : NULL
);
203 if (lbl
) zym_dis_put_str_as_is(wkp
, lbl
);
204 else if (wkp
->nfo
->decimal
) zym_dis_put_uint_dec(wkp
, n
); else zym_dis_put_uint_hex_len(wkp
, n
, len
);
208 static ZYMDIS_INLINE
void zym_dis_put_uint_data_byte (ZymDisWorkArea
*wkp
, int n
, int len
) {
209 const char *lbl
= (zym_disasm_getlabel
? zym_disasm_getlabel(n
&0xff, ZYM_DIS_ATYPE_BYTE
) : NULL
);
210 if (lbl
) zym_dis_put_str_as_is(wkp
, lbl
);
211 else if (wkp
->nfo
->decimal
) zym_dis_put_uint_dec(wkp
, n
); else zym_dis_put_uint_hex_len(wkp
, n
, len
);
215 static ZYMDIS_INLINE
void zym_dis_put_uint_data_word (ZymDisWorkArea
*wkp
, int n
, int len
) {
216 const char *lbl
= (zym_disasm_getlabel
? zym_disasm_getlabel(n
&0xffff, ZYM_DIS_ATYPE_WORD
) : NULL
);
217 if (lbl
) zym_dis_put_str_as_is(wkp
, lbl
);
218 else if (wkp
->nfo
->decimal
) zym_dis_put_uint_dec(wkp
, n
); else zym_dis_put_uint_hex_len(wkp
, n
, len
);
222 static ZYMDIS_INLINE
void zym_dis_put_uint_port_byte (ZymDisWorkArea
*wkp
, int n
, int len
) {
223 const char *lbl
= (zym_disasm_getlabel
? zym_disasm_getlabel(n
&0xff, ZYM_DIS_ATYPE_PORT8
) : NULL
);
224 if (lbl
) zym_dis_put_str_as_is(wkp
, lbl
);
225 else if (wkp
->nfo
->decimal
) zym_dis_put_uint_dec(wkp
, n
); else zym_dis_put_uint_hex_len(wkp
, n
, len
);
229 static ZYMDIS_INLINE
void zym_dis_put_disp (ZymDisWorkArea
*wkp
, int n
) {
232 if (zym_disasm_num_start
) zym_dis_put_str_as_is(wkp
, zym_disasm_num_start
);
233 zym_dis_put_str_as_is(wkp
, "-");
234 if (zym_disasm_num_end
) zym_dis_put_str_as_is(wkp
, zym_disasm_num_end
);
235 zym_dis_put_uint_dec(wkp
, -nnn
);
236 } else if (nnn
> 0) {
237 /*if (zym_disasm_num_start) zym_dis_put_str_as_is(wkp, zym_disasm_num_start);*/
238 zym_dis_put_str_as_is(wkp
, "+");
239 /*if (zym_disasm_num_end) zym_dis_put_str_as_is(wkp, zym_disasm_num_end);*/
240 zym_dis_put_uint_dec(wkp
, nnn
);
245 static ZYMDIS_INLINE
void zym_dis_put_cc (ZymDisWorkArea
*wkp
, unsigned n
) {
246 const char *conds
[8] = {"NZ", "Z", "NC", "C", "PO", "PE", "P", "M"};
247 zym_dis_put_arg(wkp
, conds
[n
&0x07]);
251 static ZYMDIS_INLINE
void zym_dis_put_r8 (ZymDisWorkArea
*wkp
, const char *hlspec
, unsigned n
) {
253 case 0: zym_dis_put_arg(wkp
, "B"); break;
254 case 1: zym_dis_put_arg(wkp
, "C"); break;
255 case 2: zym_dis_put_arg(wkp
, "D"); break;
256 case 3: zym_dis_put_arg(wkp
, "E"); break;
257 case 4: zym_dis_put_arg(wkp
, "H"); break;
258 case 5: zym_dis_put_arg(wkp
, "L"); break;
260 if (hlspec
&& hlspec
[0]) {
261 zym_dis_put_arg(wkp
, hlspec
);
263 zym_dis_put_arg_part(wkp
, "(");
264 zym_dis_put_arg_part(wkp
, wkp
->DD
);
265 if (wkp
->gotDD
) zym_dis_put_disp(wkp
, wkp
->disp
);
266 zym_dis_put_arg(wkp
, ")");
269 case 7: zym_dis_put_arg(wkp
, "A"); break;
274 static ZYMDIS_INLINE
void zym_dis_put_r16sp (ZymDisWorkArea
*wkp
, const char *hlspec
, unsigned n
) {
276 case 0: zym_dis_put_arg(wkp
, "BC"); break;
277 case 1: zym_dis_put_arg(wkp
, "DE"); break;
278 case 2: if (hlspec
&& hlspec
[0]) zym_dis_put_arg(wkp
, hlspec
); else zym_dis_put_arg(wkp
, wkp
->DD
); break;
279 case 3: zym_dis_put_arg(wkp
, "SP"); break;
284 static ZYMDIS_INLINE
void zym_dis_put_r16af (ZymDisWorkArea
*wkp
, unsigned n
) {
286 case 0: zym_dis_put_arg(wkp
, "BC"); break;
287 case 1: zym_dis_put_arg(wkp
, "DE"); break;
288 case 2: zym_dis_put_arg(wkp
, wkp
->DD
); break;
289 case 3: zym_dis_put_arg(wkp
, "AF"); break;
294 static ZYMDIS_INLINE
void zym_finish (ZymDisWorkArea
*wkp
) {
295 wkp
->nfo
->inslen
= (wkp
->pc
< wkp
->stpc
? wkp
->pc
+0x10000-wkp
->stpc
: wkp
->pc
-wkp
->stpc
);
296 /* remove trailing blanks if we have no operands */
297 if (wkp
->dbstpos
> 0 && (unsigned)(wkp
->nfo
->disbuf
[wkp
->dbstpos
-1]&0xffU
) <= 32) --wkp
->dbstpos
;
298 wkp
->nfo
->disbuf
[wkp
->dbstpos
] = 0;
302 // ////////////////////////////////////////////////////////////////////////// //
305 void zym_disasm_init (zym_disop_t
*nfo
) {
306 memset(nfo
, 0, sizeof(*nfo
));
308 nfo
->args
[0] = nfo
->args
[1] = nfo
->args
[2] = NULL
;
312 static void zym_disasm_one_internal (zym_cpu_t
*z80
, zym_disop_t
*nfo
, uint16_t origpc
, const uint8_t mem
[8]) {
332 nfo
->args
[0] = nfo
->args
[1] = nfo
->args
[2] = NULL
;
333 nfo
->argslen
[0] = nfo
->argslen
[1] = nfo
->argslen
[2] = 0;
335 uint8_t opcode
= zym_dis_read_byte(&wk
);
337 wk
.gotDD
= 0/*false*/;
340 // check for I[XY] prefix
341 if (opcode
== 0xdd || opcode
== 0xfd) {
342 const uint32_t withIndexBmp
[8] = {0x00,0x700000,0x40404040,0x40bf4040,0x40404040,0x40404040,0x0800,0x00};
344 wk
.DD
= (opcode
== 0xdd ? "IX" : "IY");
345 // read opcode -- OCR(4)
346 opcode
= zym_dis_read_byte(&wk
);
347 // test if this instruction have (HL)
348 if (withIndexBmp
[opcode
>>5]&(1<<(opcode
&0x1f))) {
349 // 3rd byte is always DISP here
350 wk
.disp
= zym_dis_read_byte(&wk
);
351 if (wk
.disp
> 127) wk
.disp
-= 256;
352 } else if (opcode
== 0xdd && opcode
== 0xfd) {
353 // double prefix; put special NOP
354 --wk
.pc
; // rollback for correct length
355 zym_dis_put_mnemo(&wk
, "NOP");
356 if (opcode
== 0xdd) zym_dis_put_arg(&wk
, "#DD"); else zym_dis_put_arg(&wk
, "#FD");
360 wk
.gotDD
= 1/*true*/;
362 // ED-prefixed instructions
363 if (opcode
== 0xed) {
364 wk
.DD
= "HL"; // Á ÎÁÓ -- ÒÁÔØ!
365 // read opcode -- OCR(4)
366 opcode
= zym_dis_read_byte(&wk
);
368 // LDI, LDIR, LDD, LDDR
369 case 0xa0: zym_dis_put_mnemo(&wk
, "LDI"); zym_finish(&wk
); return;
370 case 0xb0: zym_dis_put_mnemo(&wk
, "LDIR"); zym_finish(&wk
); return;
371 case 0xa8: zym_dis_put_mnemo(&wk
, "LDD"); zym_finish(&wk
); return;
372 case 0xb8: zym_dis_put_mnemo(&wk
, "LDDR"); zym_finish(&wk
); return;
373 // CPI, CPIR, CPD, CPDR
374 case 0xa1: zym_dis_put_mnemo(&wk
, "CPI"); zym_finish(&wk
); return;
375 case 0xb1: zym_dis_put_mnemo(&wk
, "CPIR"); zym_finish(&wk
); return;
376 case 0xa9: zym_dis_put_mnemo(&wk
, "CPD"); zym_finish(&wk
); return;
377 case 0xb9: zym_dis_put_mnemo(&wk
, "CPDR"); zym_finish(&wk
); return;
378 // OUTI, OTIR, OUTD, OTDR
379 case 0xa3: zym_dis_put_mnemo(&wk
, "OUTI"); zym_finish(&wk
); return;
380 case 0xb3: zym_dis_put_mnemo(&wk
, "OTIR"); zym_finish(&wk
); return;
381 case 0xab: zym_dis_put_mnemo(&wk
, "OUTD"); zym_finish(&wk
); return;
382 case 0xbb: zym_dis_put_mnemo(&wk
, "OTDR"); zym_finish(&wk
); return;
383 // INI, INIR, IND, INDR
384 case 0xa2: zym_dis_put_mnemo(&wk
, "INI"); zym_finish(&wk
); return;
385 case 0xb2: zym_dis_put_mnemo(&wk
, "INIR"); zym_finish(&wk
); return;
386 case 0xaa: zym_dis_put_mnemo(&wk
, "IND"); zym_finish(&wk
); return;
387 case 0xba: zym_dis_put_mnemo(&wk
, "INDR"); zym_finish(&wk
); return;
388 // not strings, but some good instructions anyway
390 if ((opcode
&0xc0) == 0x40) {
392 switch (opcode
&0x07) {
394 case 1: // OUT (C),r8
395 if (opcode
&0x07) { zym_dis_put_mnemo(&wk
, "OUT"); zym_dis_put_arg(&wk
, "(C)"); } else zym_dis_put_mnemo(&wk
, "IN");
396 if (opcode
&0x07) zym_dis_put_r8(&wk
, "0", ((opcode
>>3)&0x07)); else zym_dis_put_r8(&wk
, "F", ((opcode
>>3)&0x07)); // 0 on NMOS, 255 on CMOS
397 if ((opcode
&0x07) == 0) zym_dis_put_arg(&wk
, "(C)");
400 // SBC HL,rr/ADC HL,rr
402 zym_dis_put_mnemo(&wk
, opcode
&0x08 ? "ADC" : "SBC");
403 zym_dis_put_arg(&wk
, "HL");
404 zym_dis_put_r16sp(&wk
, "HL", ((opcode
>>4)&0x03));
407 // LD (nn),rr/LD rr,(nn)
409 zym_dis_put_mnemo(&wk
, "LD");
410 if ((opcode
&0x08) == 0) {
412 zym_dis_put_arg_part(&wk
, "(");
413 tmpW
= zym_dis_read_word(&wk
);
414 zym_dis_put_uint_addr_data(&wk
, tmpW
, 4);
415 zym_dis_put_arg(&wk
, ")");
417 zym_dis_put_r16sp(&wk
, "HL", ((opcode
>>4)&0x03));
418 if ((opcode
&0x08) != 0) {
420 zym_dis_put_arg_part(&wk
, "(");
421 tmpW
= zym_dis_read_word(&wk
);
422 zym_dis_put_uint_addr_data(&wk
, tmpW
, 4);
423 zym_dis_put_arg(&wk
, ")");
429 zym_dis_put_mnemo(&wk
, "NEG");
434 // RETI: 0x4d, 0x5d, 0x6d, 0x7d
435 // RETN: 0x45, 0x55, 0x65, 0x75
436 if (opcode
&0x08) zym_dis_put_mnemo(&wk
, "RETI"); else zym_dis_put_mnemo(&wk
, "RETN");
441 zym_dis_put_mnemo(&wk
, "IM");
443 case 0x56: case 0x76: zym_dis_put_arg(&wk
, "1"); break;
444 case 0x5e: case 0x7e: zym_dis_put_arg(&wk
, "2"); break;
445 default: zym_dis_put_arg(&wk
, "0"); break;
453 zym_dis_put_mnemo(&wk
, "LD");
454 zym_dis_put_arg(&wk
, "I");
455 zym_dis_put_arg(&wk
, "A");
459 zym_dis_put_mnemo(&wk
, "LD");
460 zym_dis_put_arg(&wk
, "R");
461 zym_dis_put_arg(&wk
, "A");
465 zym_dis_put_mnemo(&wk
, "LD");
466 zym_dis_put_arg(&wk
, "A");
467 zym_dis_put_arg(&wk
, "I");
471 zym_dis_put_mnemo(&wk
, "LD");
472 zym_dis_put_arg(&wk
, "A");
473 zym_dis_put_arg(&wk
, "R");
477 zym_dis_put_mnemo(&wk
, "RRD");
481 zym_dis_put_mnemo(&wk
, "RLD");
487 // slt and other traps
488 if (opcode
== 0xFB) {
489 zym_dis_put_mnemo(&wk
, "TSLT");
491 zym_dis_put_mnemo(&wk
, "TRAP");
492 zym_dis_start_arg(&wk
);
493 zym_dis_put_uint_hex_len(&wk
, opcode
, 2);
494 zym_dis_end_arg(&wk
);
501 zym_dis_put_mnemo(&wk
, "NOP");
502 zym_dis_put_arg(&wk
, "#ED");
503 zym_dis_start_arg(&wk
);
504 zym_dis_put_uint_hex_len(&wk
, opcode
, 2);
505 zym_dis_end_arg(&wk
);
509 // CB-prefixed instructions
510 if (opcode
== 0xcb) {
511 // shifts and bit operations
513 opcode
= zym_dis_read_byte(&wk
);
515 switch ((opcode
>>3)&0x1f) {
516 case 0: zym_dis_put_mnemo(&wk
, "RLC"); break;
517 case 1: zym_dis_put_mnemo(&wk
, "RRC"); break;
518 case 2: zym_dis_put_mnemo(&wk
, "RL"); break;
519 case 3: zym_dis_put_mnemo(&wk
, "RR"); break;
520 case 4: zym_dis_put_mnemo(&wk
, "SLA"); break;
521 case 5: zym_dis_put_mnemo(&wk
, "SRA"); break;
522 case 6: zym_dis_put_mnemo(&wk
, "SLL"); break;
523 case 7: zym_dis_put_mnemo(&wk
, "SRL"); break;
525 switch ((opcode
>>6)&0x03) {
526 case 1: zym_dis_put_mnemo(&wk
, "BIT"); break;
527 case 2: zym_dis_put_mnemo(&wk
, "RES"); break;
528 case 3: zym_dis_put_mnemo(&wk
, "SET"); break;
530 zym_dis_start_arg(&wk
);
531 zym_dis_put_uint_dec(&wk
, (opcode
>>3)&0x07);
532 zym_dis_end_arg(&wk
);
537 zym_dis_put_arg_part(&wk
, "(");
538 zym_dis_put_arg_part(&wk
, wk
.DD
);
539 zym_dis_put_disp(&wk
, wk
.disp
);
540 zym_dis_put_arg(&wk
, ")");
541 if ((opcode
&0x07) != 6) zym_dis_put_r8(&wk
, "", (opcode
&0x07));
543 zym_dis_put_r8(&wk
, "(HL)", (opcode
&0x07));
549 switch (opcode
&0xc0) {
552 switch (opcode
&0x07) {
553 // misc,DJNZ,JR,JR cc
559 zym_dis_put_mnemo(&wk
, "JR");
560 zym_dis_put_cc(&wk
, (opcode
>>3)&0x03);
563 zym_dis_put_mnemo(&wk
, opcode
&0x08 ? "JR" : "DJNZ");
565 wk
.disp
= zym_dis_read_byte(&wk
);
566 if (wk
.disp
> 127) wk
.disp
-= 256; // convert to int8_t
567 uint16_t addr
= (uint16_t)(wk
.pc
+wk
.disp
);
568 zym_dis_start_arg(&wk
);
569 zym_dis_put_uint_addr_pc(&wk
, addr
, 4);
570 zym_dis_end_arg(&wk
);
574 zym_dis_put_mnemo(&wk
, "EX");
575 zym_dis_put_arg(&wk
, "AF");
576 zym_dis_put_arg(&wk
, "AF'");
578 zym_dis_put_mnemo(&wk
, "NOP");
583 // LD rr,nn/ADD HL,rr
587 zym_dis_put_mnemo(&wk
, "ADD");
588 zym_dis_put_arg(&wk
, wk
.DD
);
589 zym_dis_put_r16sp(&wk
, "", ((opcode
>>4)&0x03));
592 zym_dis_put_mnemo(&wk
, "LD");
593 zym_dis_put_r16sp(&wk
, "", ((opcode
>>4)&0x03));
594 tmpW
= zym_dis_read_word(&wk
);
595 zym_dis_start_arg(&wk
);
596 zym_dis_put_uint_data_word(&wk
, tmpW
, 4);
597 zym_dis_end_arg(&wk
);
603 zym_dis_put_mnemo(&wk
, "LD");
604 switch ((opcode
>>3)&0x07) {
606 case 0: zym_dis_put_arg(&wk
, "(BC)"); zym_dis_put_arg(&wk
, "A"); break;
608 case 1: zym_dis_put_arg(&wk
, "A"); zym_dis_put_arg(&wk
, "(BC)"); break;
610 case 2: zym_dis_put_arg(&wk
, "(DE)"); zym_dis_put_arg(&wk
, "A"); break;
612 case 3: zym_dis_put_arg(&wk
, "A"); zym_dis_put_arg(&wk
, "(DE)"); break;
614 case 4: zym_dis_put_arg_part(&wk
, "("); tmpW
= zym_dis_read_word(&wk
); zym_dis_put_uint_addr_data(&wk
, tmpW
, 4); zym_dis_put_arg(&wk
, ")"); zym_dis_put_arg(&wk
, wk
.DD
); break;
616 case 5: zym_dis_put_arg(&wk
, wk
.DD
); zym_dis_put_arg_part(&wk
, "("); tmpW
= zym_dis_read_word(&wk
); zym_dis_put_uint_addr_data(&wk
, tmpW
, 4); zym_dis_put_arg(&wk
, ")"); break;
618 case 6: zym_dis_put_arg_part(&wk
, "("); tmpW
= zym_dis_read_word(&wk
); zym_dis_put_uint_addr_data(&wk
, tmpW
, 4); zym_dis_put_arg(&wk
, ")"); zym_dis_put_arg(&wk
, "A"); break;
620 case 7: zym_dis_put_arg(&wk
, "A"); zym_dis_put_arg_part(&wk
, "("); tmpW
= zym_dis_read_word(&wk
); zym_dis_put_uint_addr_data(&wk
, tmpW
, 4); zym_dis_put_arg(&wk
, ")"); break;
626 zym_dis_put_mnemo(&wk
, opcode
&0x08 ? "DEC" : "INC");
627 zym_dis_put_r16sp(&wk
, "", ((opcode
>>4)&0x03));
630 // INC/DEC r8; LD r8,n
634 switch (opcode
&0x07) {
635 case 4: zym_dis_put_mnemo(&wk
, "INC"); break;
636 case 5: zym_dis_put_mnemo(&wk
, "DEC"); break;
637 case 6: zym_dis_put_mnemo(&wk
, "LD"); break;
639 switch ((opcode
>>3)&0x07) {
640 case 0: zym_dis_put_arg(&wk
, "B"); break;
641 case 1: zym_dis_put_arg(&wk
, "C"); break;
642 case 2: zym_dis_put_arg(&wk
, "D"); break;
643 case 3: zym_dis_put_arg(&wk
, "E"); break;
644 case 4: if (wk
.gotDD
) zym_dis_put_arg_part(&wk
, wk
.DD
); zym_dis_put_arg(&wk
, "H"); break;
645 case 5: if (wk
.gotDD
) zym_dis_put_arg_part(&wk
, wk
.DD
); zym_dis_put_arg(&wk
, "L"); break;
647 zym_dis_put_arg_part(&wk
, "(");
648 zym_dis_put_arg_part(&wk
, wk
.DD
);
649 if (wk
.gotDD
) zym_dis_put_disp(&wk
, wk
.disp
);
650 zym_dis_put_arg(&wk
, ")");
652 case 7: zym_dis_put_arg(&wk
, "A"); break;
655 if ((opcode
&0x07) == 6) {
656 tmpB
= zym_dis_read_byte(&wk
);
657 zym_dis_start_arg(&wk
);
658 zym_dis_put_uint_data_byte(&wk
, tmpB
, 2);
659 zym_dis_end_arg(&wk
);
665 switch ((opcode
>>3)&0x07) {
666 case 0: zym_dis_put_mnemo(&wk
, "RLCA"); break;
667 case 1: zym_dis_put_mnemo(&wk
, "RRCA"); break;
668 case 2: zym_dis_put_mnemo(&wk
, "RLA"); break;
669 case 3: zym_dis_put_mnemo(&wk
, "RRA"); break;
670 case 4: zym_dis_put_mnemo(&wk
, "DAA"); break;
671 case 5: zym_dis_put_mnemo(&wk
, "CPL"); break;
672 case 6: zym_dis_put_mnemo(&wk
, "SCF"); break;
673 case 7: zym_dis_put_mnemo(&wk
, "CCF"); break;
680 // 0x40..0x7F: LD r8,r8
682 if (opcode
== 0x76) { zym_dis_put_mnemo(&wk
, "HALT"); zym_finish(&wk
); return; }
683 zym_dis_put_mnemo(&wk
, "LD");
684 const uint8_t rsrc
= (opcode
&0x07);
685 const uint8_t rdst
= ((opcode
>>3)&0x07);
687 case 0: zym_dis_put_arg(&wk
, "B"); break;
688 case 1: zym_dis_put_arg(&wk
, "C"); break;
689 case 2: zym_dis_put_arg(&wk
, "D"); break;
690 case 3: zym_dis_put_arg(&wk
, "E"); break;
691 case 4: if (wk
.gotDD
&& rsrc
!= 6) zym_dis_put_arg_part(&wk
, wk
.DD
); zym_dis_put_arg(&wk
, "H"); break;
692 case 5: if (wk
.gotDD
&& rsrc
!= 6) zym_dis_put_arg_part(&wk
, wk
.DD
); zym_dis_put_arg(&wk
, "L"); break;
694 zym_dis_put_arg_part(&wk
, "(");
695 zym_dis_put_arg_part(&wk
, wk
.DD
);
696 if (wk
.gotDD
) zym_dis_put_disp(&wk
, wk
.disp
);
697 zym_dis_put_arg(&wk
, ")");
699 case 7: zym_dis_put_arg(&wk
, "A"); break;
702 case 0: zym_dis_put_arg(&wk
, "B"); break;
703 case 1: zym_dis_put_arg(&wk
, "C"); break;
704 case 2: zym_dis_put_arg(&wk
, "D"); break;
705 case 3: zym_dis_put_arg(&wk
, "E"); break;
706 case 4: if (wk
.gotDD
&& rdst
!= 6) zym_dis_put_arg_part(&wk
, wk
.DD
); zym_dis_put_arg(&wk
, "H"); break;
707 case 5: if (wk
.gotDD
&& rdst
!= 6) zym_dis_put_arg_part(&wk
, wk
.DD
); zym_dis_put_arg(&wk
, "L"); break;
709 zym_dis_put_arg_part(&wk
, "(");
710 zym_dis_put_arg_part(&wk
, wk
.DD
);
711 if (wk
.gotDD
) zym_dis_put_disp(&wk
, wk
.disp
);
712 zym_dis_put_arg(&wk
, ")");
714 case 7: zym_dis_put_arg(&wk
, "A"); break;
718 // 0x80..0xBF: ALU A,r8
720 switch ((opcode
>>3)&0x07) {
721 case 0: zym_dis_put_mnemo(&wk
, "ADD"); zym_dis_put_arg(&wk
, "A"); break;
722 case 1: zym_dis_put_mnemo(&wk
, "ADC"); zym_dis_put_arg(&wk
, "A"); break;
723 case 2: zym_dis_put_mnemo(&wk
, "SUB"); break;
724 case 3: zym_dis_put_mnemo(&wk
, "SBC"); zym_dis_put_arg(&wk
, "A"); break;
725 case 4: zym_dis_put_mnemo(&wk
, "AND"); break;
726 case 5: zym_dis_put_mnemo(&wk
, "XOR"); break;
727 case 6: zym_dis_put_mnemo(&wk
, "OR"); break;
728 case 7: zym_dis_put_mnemo(&wk
, "CP"); break;
730 zym_dis_put_r8(&wk
, "", (opcode
&0x07));
735 switch (opcode
&0x07) {
738 zym_dis_put_mnemo(&wk
, "RET");
739 zym_dis_put_cc(&wk
, (opcode
>>3)&0x07);
745 switch ((opcode
>>4)&0x03) {
747 case 0: zym_dis_put_mnemo(&wk
, "RET"); break;
749 case 1: zym_dis_put_mnemo(&wk
, "EXX"); break;
751 case 2: zym_dis_put_mnemo(&wk
, "JP"); zym_dis_put_arg_part(&wk
, "("); zym_dis_put_arg_part(&wk
, wk
.DD
); zym_dis_put_arg(&wk
, ")"); break;
753 case 3: zym_dis_put_mnemo(&wk
, "LD"); zym_dis_put_arg(&wk
, "SP"); zym_dis_put_arg(&wk
, wk
.DD
); break;
757 zym_dis_put_mnemo(&wk
, "POP");
758 zym_dis_put_r16af(&wk
, (opcode
>>4)&0x03);
763 zym_dis_put_mnemo(&wk
, "JP");
764 zym_dis_put_cc(&wk
, (opcode
>>3)&0x07);
765 tmpW
= zym_dis_read_word(&wk
);
766 zym_dis_start_arg(&wk
);
767 zym_dis_put_uint_addr_pc(&wk
, tmpW
, 4);
768 zym_dis_end_arg(&wk
);
772 switch ((opcode
>>3)&0x07) {
774 case 0: zym_dis_put_mnemo(&wk
, "JP"); tmpW
= zym_dis_read_word(&wk
); zym_dis_start_arg(&wk
); zym_dis_put_uint_addr_pc(&wk
, tmpW
, 4); zym_dis_end_arg(&wk
); break;
776 case 2: zym_dis_put_mnemo(&wk
, "OUT"); zym_dis_put_arg_part(&wk
, "("); tmpB
= zym_dis_read_byte(&wk
); zym_dis_put_uint_port_byte(&wk
, tmpB
, 2); zym_dis_put_arg(&wk
, ")"); zym_dis_put_arg(&wk
, "A"); break;
778 case 3: zym_dis_put_mnemo(&wk
, "IN"); zym_dis_put_arg(&wk
, "A"); zym_dis_put_arg_part(&wk
, "("); tmpB
= zym_dis_read_byte(&wk
); zym_dis_put_uint_port_byte(&wk
, tmpB
, 2); zym_dis_put_arg(&wk
, ")"); break;
780 case 4: zym_dis_put_mnemo(&wk
, "EX"); zym_dis_put_arg(&wk
, "(SP)"); zym_dis_put_arg(&wk
, wk
.DD
); break;
782 case 5: zym_dis_put_mnemo(&wk
, "EX"); zym_dis_put_arg(&wk
, "DE"); zym_dis_put_arg(&wk
, "HL"); break;
784 case 6: zym_dis_put_mnemo(&wk
, "DI"); break;
786 case 7: zym_dis_put_mnemo(&wk
, "EI"); break;
791 zym_dis_put_mnemo(&wk
, "CALL");
792 zym_dis_put_cc(&wk
, (opcode
>>3)&0x07);
793 tmpW
= zym_dis_read_word(&wk
);
794 zym_dis_start_arg(&wk
);
795 zym_dis_put_uint_addr_pc(&wk
, tmpW
, 4);
796 zym_dis_end_arg(&wk
);
801 if (((opcode
>>4)&0x03) == 0) {
803 zym_dis_put_mnemo(&wk
, "CALL");
804 tmpW
= zym_dis_read_word(&wk
);
805 zym_dis_start_arg(&wk
);
806 zym_dis_put_uint_addr_pc(&wk
, tmpW
, 4);
807 zym_dis_end_arg(&wk
);
811 zym_dis_put_mnemo(&wk
, "PUSH");
812 zym_dis_put_r16af(&wk
, (opcode
>>4)&0x03);
817 switch ((opcode
>>3)&0x07) {
818 case 0: zym_dis_put_mnemo(&wk
, "ADD"); zym_dis_put_arg(&wk
, "A"); break;
819 case 1: zym_dis_put_mnemo(&wk
, "ADC"); zym_dis_put_arg(&wk
, "A"); break;
820 case 2: zym_dis_put_mnemo(&wk
, "SUB"); break;
821 case 3: zym_dis_put_mnemo(&wk
, "SBC"); zym_dis_put_arg(&wk
, "A"); break;
822 case 4: zym_dis_put_mnemo(&wk
, "AND"); break;
823 case 5: zym_dis_put_mnemo(&wk
, "XOR"); break;
824 case 6: zym_dis_put_mnemo(&wk
, "OR"); break;
825 case 7: zym_dis_put_mnemo(&wk
, "CP"); break;
827 tmpB
= zym_dis_read_byte(&wk
);
828 zym_dis_start_arg(&wk
);
829 zym_dis_put_uint_data_byte(&wk
, tmpB
, 2);
830 zym_dis_end_arg(&wk
);
834 zym_dis_put_mnemo(&wk
, "RST");
835 zym_dis_start_arg(&wk
);
836 zym_dis_put_uint_hexlen(&wk
, opcode
&0x38, 2);
837 zym_dis_end_arg(&wk
);
846 void zym_disasm_one (zym_cpu_t
*z80
, zym_disop_t
*nfo
, uint16_t pc
) {
848 zym_disasm_one_internal(z80
, nfo
, pc
, NULL
);
852 void zym_disasm_one_ex (zym_disop_t
*nfo
, const uint8_t mem
[8], uint16_t pc
) {
854 zym_disasm_one_internal(NULL
, nfo
, pc
, mem
);