]> cloudbase.mooo.com Git - z180-stamp.git/blob - avr/disas_z180.c
new command: dissassemle - Disassemble Z180 code from memory
[z180-stamp.git] / avr / disas_z180.c
1 /*
2 * (C) Copyright 2014,2018 Leo C. <erbl259-lmu@yahoo.de>
3 *
4 */
5
6 #include "common.h"
7 #include "z80-if.h"
8 #include "disas_z180.h"
9
10 /*
11 * t_MNEMONICS
12 */
13 enum {
14 /* 1-byte other */
15 i_, iNOP, iLD, iINC, iDEC, iDJNZ, iJR, iHALT, /* 0 .. 7 */
16 iRET, iPOP, iJP, iCALL, iPUSH, iRST, iOUT, iEXX, /* 8 .. 15 */
17 iIN, iEX, iDI, iEI, /* 16 .. 19 */
18 /* CB bit */
19 iBIT, iRES, iSET, /* 20 .. 22 */
20 /* ED */
21 iNEG, iRETN, iRETI, iIM, iRRD, iRLD, /* 23 .. 28 */
22 /* ED Z180 */
23 iIN0, iOUT0, iTST, iMLT, iTSTIO,
24 iSLP, iOTIM, iOTDM, iOTIMR, iOTDMR, /* 29 .. 38 */
25
26 //i_opc_alu equ opc_index
27 /* 1-byte "alu" */
28 iADD, iADC, iSUB, iSBC, iAND, iXOR, iOR, iCP, /* 39 .. 46 */
29 /* 1-byte no arguments */
30 iRLCA, iRRCA, iRLA, iRRA, iDAA, iCPL, iSCF, iCCF, /* 47 .. 54 */
31 /* CB rot */
32 iRLC, iRRC, iRL, iRR, iSLA, iSRA, iSLL, iSRL, /* 55 .. 62 */
33
34 //i_opc_bli equ opc_index
35 /* ED Block instr (bli) */
36 iLDI, iCPI, iINI, iOUTI, iLDD, iCPD, iIND, iOUTD, /* 63 .. 70 */
37 iLDIR,iCPIR,iINIR,iOTIR, iLDDR,iCPDR,iINDR,iOTDR /* 71 .. 78 */
38 } mnemo_index;
39
40 #define i_opc_alu 39
41 #define i_opc_bli 63
42
43 //t_MNEMONICS:
44 const FLASH uint8_t mnemonics[] = {
45 '?' + 0x80, /* 1-byte other */
46 'N','O','P', + 0x80,
47 'L','D' + 0x80,
48 'I','N','C' + 0x80,
49 'D','E','C' + 0x80,
50 'D','J','N','Z' + 0x80,
51 'J','R' + 0x80,
52 'H','A','L','T' + 0x80,
53 'R','E','T' + 0x80,
54 'P','O','P' + 0x80,
55 'J','P' + 0x80,
56 'C','A','L','L' + 0x80,
57 'P','U','S','H' + 0x80,
58 'R','S','T' + 0x80,
59 'O','U','T' + 0x80,
60 'E','X','X' + 0x80,
61 'I','N' + 0x80,
62 'E','X' + 0x80,
63 'D','I' + 0x80,
64 'E','I' + 0x80,
65 'B','I','T' + 0x80, /* CB bit */
66 'R','E','S' + 0x80,
67 'S','E','T' + 0x80,
68 'N','E','G' + 0x80,
69 'R','E','T','N' + 0x80,
70 'R','E','T','I' + 0x80,
71 'I','M' + 0x80,
72 'R','R','D' + 0x80,
73 'R','L','D' + 0x80,
74 'I','N','0' + 0x80, /* Z180 */
75 'O','U','T','0' + 0x80,
76 'T','S','T' + 0x80,
77 'M','L','T' + 0x80,
78 'T','S','T','I','O' + 0x80,
79 'S','L','P' + 0x80,
80 'O','T','I','M' + 0x80,
81 'O','T','D','M' + 0x80,
82 'O','T','I','M','R' + 0x80,
83 'O','T','D','M','R' + 0x80,
84 'A','D','D' + 0x80, /* 1-byte "alu" */
85 'A','D','C' + 0x80,
86 'S','U','B' + 0x80,
87 'S','B','C' + 0x80,
88 'A','N','D' + 0x80,
89 'X','O','R' + 0x80,
90 'O','R' + 0x80,
91 'C','P' + 0x80,
92 'R','L','C','A' + 0x80, /* 1-byte no arguments */
93 'R','R','C','A' + 0x80,
94 'R','L','A' + 0x80,
95 'R','R','A' + 0x80,
96 'D','A','A' + 0x80,
97 'C','P','L' + 0x80,
98 'S','C','F' + 0x80,
99 'C','C','F' + 0x80,
100 'R','L','C' + 0x80, /* CB rot */
101 'R','R','C' + 0x80,
102 'R','L' + 0x80,
103 'R','R' + 0x80,
104 'S','L','A' + 0x80,
105 'S','R','A' + 0x80,
106 'S','L','L' + 0x80,
107 'S','R','L' + 0x80,
108 'L','D','I' + 0x80, /* ED Block instr (bli) */
109 'C','P','I' + 0x80,
110 'I','N','I' + 0x80,
111 'O','U','T','I' + 0x80,
112 'L','D','D' + 0x80,
113 'C','P','D' + 0x80,
114 'I','N','D' + 0x80,
115 'O','U','T','D' + 0x80,
116 'L','D','I','R' + 0x80,
117 'C','P','I','R' + 0x80,
118 'I','N','I','R' + 0x80,
119 'O','T','I','R' + 0x80,
120 'L','D','D','R' + 0x80,
121 'C','P','D','R' + 0x80,
122 'I','N','D','R' + 0x80,
123 'O','T','D','R' + 0x80,
124 };
125
126 //-------------------------------------------------------------------------------
127 //
128 // GROUP2, GROUP1 and GROUP3 are instruction decoding tables and have
129 // the following structure:
130 //
131 // [ mask { mode ( match , index ) } 0FFH ] 0.
132 //
133 // The repeating group ( match , index ) terminates when the MSB of the
134 // index byte is set. The interpretation of the "mode" byte is
135 // explained in the documentation to datasheet OPRNDZ.
136 //
137
138 //
139
140 //const FLASH uint8_t dec_tab2
141
142 struct dec_tab {
143 uint8_t group2[18]; /* GROUP2: CB group */
144 uint8_t group1[123]; /* GROUP1: Main group */
145 uint8_t group3[92]; /* GROUP3, ED group */
146 } __attribute__((__packed__));
147
148 const FLASH struct dec_tab dec_tab = {
149 .group2 = {
150 0xC0,0x36, //mask, mode
151 0x40,iBIT, // bit b,g
152 0x80,iRES, // res b,g
153 0xC0,iSET+0x80, // set b,g
154 0xFF, //
155 0xF8,0x00, //mask, mode
156 0x30,i_+0x80, // (sll g)
157 0xFF, //
158 0xC0,0x06, //mask, mode
159 0x00,iRLC+0x80, // rlc g ... srl g
160 },
161 .group1 = {
162 0xFF,0x00, //mask, mode
163 0x00,iNOP, // NOP
164 0x76,iHALT, // HALT
165 0xC9,iRET, // RET
166 0xD9,iEXX, // EXX
167 0xF3,iDI, // DI
168 0xFB,iEI+0x80, // EI //14
169 0x04, //mode
170 0x08,iEX+0x80, //
171 0x01,
172 0x10,iDJNZ,
173 0x18,iJR+0x80,
174 0xAF,
175 0x22,iLD+0x80,
176 0xFA,
177 0x2A,iLD+0x80,
178 0xA7,
179 0x32,iLD+0x80,
180 0x7A,
181 0x3A,iLD+0x80,
182 0x03,
183 0xC3,iJP,
184 0xCD,iCALL+0x80,
185 0x97,
186 0xD3,iOUT+0x80,
187 0x79,
188 0xDB,iIN+0x80,
189 0x5F,
190 0xE3,iEX+0x80,
191 0x0E,
192 0xE9,iJP+0x80,
193 0x05,
194 0xEB,iEX+0x80, //
195 0xDF,
196 0xF9,iLD+0x80,
197 0xFF, //44
198
199 0xC0, //mask
200 0xB6, //mode r[y],r[z]
201 0x40,iLD+0x80,
202 0x06, //mode alu[y],r[z]
203 0x80,iADD+0x80,
204 0xFF, //8
205
206 0xC7, //mask
207 0x0B,
208 0x04,iINC, // inc r[y]
209 0x05,iDEC+0x80, // dec r[y]
210 0xB2,
211 0x06,iLD+0x80, // ld r[y],nn
212 0x00, //mode
213 0x07,iRLCA+0x80, // rlca ...
214 0x20,
215 0xC0,iRET+0x80, // ret cc
216 0x23,
217 0xC2,iJP, // jp cc,mn
218 0xC4,iCALL+0x80, // call cc,mn
219 0x10,
220 0xC7,iRST+0x80, // rst
221 0x02, //mode alu[y] n
222 0xC6,iADD+0x80, // add ...
223 0xFF, //27
224
225 0xCF,
226 0xD3,
227 0x01,iLD+0x80, // ld ww,mn
228 0x0D,
229 0x03,iINC, // inc rp
230 0x0B,iDEC+0x80, // dec rp
231 0xFD,
232 0x09,iADD+0x80, // add hl,rp
233 0x60,
234 0xC1,iPOP, // pop rp2
235 0xC5,iPUSH+0x80, // push rp2
236 0xFF, //18
237
238 0xE7,
239 0x21,
240 0x20,iJR+0x80, //jr cc,
241 0xFF,
242
243 0xEF,
244 0xE7,
245 0x02,iLD+0x80, // ld (rp),a //rp=bc,de
246 0x7E,
247 0x0A,iLD+0x80, // ld a,(rp) //rp=bc,de //12
248 },
249 .group3 = {
250 0xFF,0x00, //
251 0x44,iNEG, // NEG
252 0x45,iRETN, // RETN
253 0x4D,iRETI, // RETI
254 0x4E,i_, // (IM 0)
255 0x67,iRRD, // RRD
256 0x6F,iRLD, // RLD
257 0x76,iSLP, // slp
258 0x83,iOTIM, // otim
259 0x93,iOTIMR, // otimr
260 0x8B,iOTDM, // otdm
261 0x9B,iOTDMR, // otdmr
262 0x31,i_, // (OUT0 (m),0)
263 0x71,i_+0x80, // (OUT (C),0)
264 0x09,
265 0x30,iIN0+0x80, // in0 (m)
266 0x02,
267 0x64,iTST, // tst m
268 0x74,iTSTIO+0x80, // tstio m
269 0x80,
270 0x70,iIN+0x80, // IN (C)
271 0xFF, //40
272
273 0xC7,
274 0x0b,
275 0x04,iTST+0x80, // tst r
276 0xB8,
277 0x40,iIN+0x80, // IN r,(C)
278 0xB9,
279 0x00,iIN0+0x80, // IN0 r,(m)
280 0x8B, //
281 0x41,iOUT+0x80, // OUT (C),r
282 0x9B, //
283 0x01,iOUT0+0x80, // UT0 (m),r
284 0xFF, // //17
285
286 0xCF, //
287 0xFD, //
288 0x42,iSBC, // sbc hl,rp
289 0x4A,iADC+0x80, // adc hl,rp
290 0xAD, //
291 0x43,iLD+0x80, // LD (nn),rp
292 0xDA, //
293 0x4B,iLD+0x80, // LD rp,(nn)
294 0x0D,
295 0x4C,iMLT+0x80, //mlt rp
296 0xFF, // //16
297
298 0xE7, //
299 0x40, //
300 0x46,iIM+0x80, // IM x
301 0xFF, //
302
303 0xF7, //
304 0xC7, //
305 0x47,iLD+0x80, // LD i|r,A
306 0x7C, //
307 0x57,iLD+0x80, // LD A,i|r
308 0xFF,
309
310 0xE4, //
311 0x00, //
312 0xA0,iLDI+0x80, // LDI ...
313 0xFF, //
314
315 0x00 //19
316 }
317 };
318
319
320 //-------------------------------------------------------------------------------
321 //
322 // Disassemble and output Z80 machine code operand
323 //
324 // Index OPRND1 OPRND2
325 // -----------------------------------------------------------
326 // 1 RST address Relative address
327 // 2 Condition Immediate byte
328 // 3 Bit number Immediate word
329 // 4 Interrupt mode AF,AF'
330 // 5 (SP) DE,HL
331 // 6 Register pair 8-bit source
332 // -----------------------------------------------------------
333 // 7 A
334 // 8 (C)
335 // 9 (port number)
336 // A (Absolute address)
337 // B 8-bit destination
338 // C I or R
339 // D 16-bit register
340 // E Address in 16-bit register
341 // F Index register
342 //
343 // Input:
344 // A: opcode
345 // B: operand index
346 // DE: Address of next instruction byte
347 // HL: Address of next free byte in output buffer
348 // (iy+0): Bit = 1: Print opcodes
349 // (iy+1): index register flag (1=IX, 2=IY, else 0)
350 // (iy+2): displacement for any indexed instruction
351 // (iy+3): no. of instraction bytes fetched
352 //
353 // Output:
354 // Operand in output buffer
355 // DE, HL updated
356 // AF, BC destroyed
357 //
358 //
359 //-------------------------------------------------------------------------------
360
361 enum {
362 irR8 = 0, irPA = 6, irRA = 7, irIR = 8,
363 irAFAF= 10, irDEHL = 11, irR16 = 12, irINDX = 16,
364 irSP = 19, irCOND = 20, irINTMOD= 28
365 } reg_index;
366
367 const FLASH uint8_t op_register[] = {
368 'B' + 0x80, // 0
369 'C' + 0x80, //
370 'D' + 0x80, //
371 'E' + 0x80, //
372 'H' + 0x80, //
373 'L' + 0x80, //
374 '(','C',')' + 0x80, // 6
375 'A' + 0x80, //
376 'I' + 0x80, // 8
377 'R' + 0x80, //
378 'A','F',',','A','F','\'' + 0x80, //10
379 'D','E',',','H','L' + 0x80, //
380 'B','C' + 0x80, //12
381 'D','E' + 0x80, //
382 'A','F' + 0x80, //
383 'S','P' + 0x80, //
384 'H','L' + 0x80, //16
385 'I','X' + 0x80, //
386 'I','Y' + 0x80, //
387 '(','S','P',')' + 0x80, //19
388 'N','Z' + 0x80, //20
389 'Z' + 0x80, //
390 'N','C' + 0x80, //
391 'C' + 0x80, //
392 'P','O' + 0x80, //
393 'P','E' + 0x80, //
394 'P' + 0x80, //
395 'M' + 0x80, //
396 '0' + 0x80, //28
397 '?' + 0x80, //
398 '1' + 0x80, //
399 '2' + 0x80, //
400 };
401
402 //-------------------------------------------------------------------------------
403
404 typedef struct disas_data_s disas_data_t;
405 struct disas_data_s {
406 uint32_t address;
407 uint8_t opcode;
408 int8_t opc_displacement;
409 uint8_t indexflag;
410 uint8_t bytes_fetched;
411 int8_t outbufpos;
412 char outbuf[18];
413 };
414
415 static
416 void xtract(uint8_t index, const FLASH uint8_t *strlist, disas_data_t *dat)
417 {
418 uint8_t ch;
419
420 while (index != 0) {
421 while ((*strlist++ & 0x80) == 0)
422 ;
423 --index;
424 }
425 do {
426 ch = *strlist++;
427 dat->outbuf[dat->outbufpos++] = ch & 0x7f;
428 } while ((ch & 0x80) == 0);
429 }
430
431 static
432 uint8_t op_fetch(uint32_t addr)
433 {
434 uint8_t op = z80_read(addr);
435
436 return op;
437 }
438
439 static
440 uint8_t op_fetch_print(disas_data_t *dat)
441 {
442 uint8_t opc = op_fetch(dat->address);
443 ++dat->address;
444 ++dat->bytes_fetched;
445 printf_P(PSTR("%02X "), opc);
446
447 return opc;
448 }
449
450
451 static
452 void put_char(uint8_t ch, disas_data_t *dat)
453 {
454 dat->outbuf[dat->outbufpos++] = ch;
455 }
456
457 static
458 void put_digit(uint8_t digit, disas_data_t *dat)
459 {
460 digit &= 0xf;
461 if (digit > 9)
462 digit += (-10 + 'A'-'0');
463 digit += '0';
464
465 put_char(digit, dat);
466 }
467
468
469
470 static
471 void put_hex(uint8_t byte, disas_data_t *dat)
472 {
473 put_digit(byte >> 4, dat);
474 put_digit(byte, dat);
475 }
476
477 static
478 void put_hex_16(uint16_t word, disas_data_t *dat)
479 {
480 put_hex(word >> 8, dat);
481 put_hex(word, dat);
482 }
483
484 static
485 void do_op_reg16(disas_data_t *dat)
486 {
487 uint8_t op = dat->opcode >> 3;
488 op = ((op >> 1) & 0x3) + irR16;
489 if (op == 2 + irR16)
490 op = dat->indexflag + irINDX;
491 xtract(op, op_register, dat);
492 }
493
494 static
495 void do_op_8bit_src_dst(uint8_t op, disas_data_t *dat)
496 {
497 op = op & 0x07;
498 if (op == 6) {
499 put_char('(', dat);
500 xtract(dat->indexflag + irINDX, op_register, dat);
501 if (dat->indexflag != 0) {
502 char c = '+';
503 int d = dat->opc_displacement;
504 if (d < 0) {
505 c = '-';
506 d = -d;
507 }
508 put_char(c, dat);
509 put_hex (d & 0xff, dat);
510 }
511 put_char(')', dat);
512 } else
513 xtract(op, op_register, dat);
514 }
515
516 static
517 void do_operand(uint8_t mode, disas_data_t *dat)
518 {
519 uint8_t op1;
520
521 switch(mode) {
522 case 0:
523 break;
524 case 1: /* RST address */
525 put_hex (dat->opcode & 0x38, dat);
526 break;
527 case 2: /* Op1 i2: Condition */
528 op1 = dat->opcode >> 3;
529 if ((op1 & 0x10) == 0) op1 &= 3;
530 op1 = (op1 & 7) + irCOND;
531 xtract(op1, op_register, dat);
532 break;
533 case 3: /* Bit number */
534 op1 = dat->opcode >> 3;
535 op1 &= 0x7;
536 put_digit (op1, dat);
537 break;
538 case 4: /* Int mode */
539 op1 = dat->opcode >> 3;
540 op1 = (op1 & 0x03) + irINTMOD;
541 xtract(op1, op_register, dat);
542 break;
543 case 5: /* (SP) */
544 xtract(irSP, op_register, dat);
545 break;
546 case 6: /* Register pair */
547 op1 = dat->opcode >> 3;
548 op1 = (op1 >> 1) & 0x03;
549 if (op1 == 2) {
550 op1 = dat->indexflag + irINDX;
551 } else {
552 if (op1 == 3) --op1;
553 op1 += irR16;
554 }
555 xtract(op1, op_register, dat);
556 break;
557 case 7: /* A */
558 xtract(irRA, op_register, dat);
559 break;
560 case 8: /* (C) */
561 xtract(irPA, op_register, dat);
562 break;
563 case 9: /* (port number) */
564 put_char('(', dat);
565 op1 = op_fetch_print(dat);
566 put_hex(op1, dat);
567 put_char(')', dat);
568 break;
569 case 0xA: /* (Absolute address) */
570 put_char('(', dat);
571 uint16_t arg16 = op_fetch_print(dat)
572 + (op_fetch_print(dat) << 8);
573 put_hex_16(arg16, dat);
574 put_char(')', dat);
575 break;
576 case 0xB: /* 8-bit destination */
577 op1 = dat->opcode >> 3;
578 do_op_8bit_src_dst(op1,dat);
579 break;
580 case 0xC: /* I or R */
581 op1 = dat->opcode >> 3;
582 op1 = op1 & 0x9;
583 xtract(op1, op_register, dat);
584 break;
585 case 0xD: /* 16-bit register */
586 do_op_reg16(dat);
587 break;
588 case 0xE: /* Address in 16-bit register */
589 put_char('(', dat);
590 do_op_reg16(dat);
591 put_char(')', dat);
592 break;
593 case 0xF: /* Index register */
594 op1 = dat->indexflag + irINDX;
595 xtract(op1, op_register, dat);
596 break;
597 case 0x10:
598 break;
599 case 0x11: /* Relative address */
600 op1 = op_fetch_print(dat);
601 uint16_t dst = dat->address + (int8_t) op1;
602 put_hex_16(dst, dat);
603 break;
604 case 0x12: /* Immediate byte */
605 op1 = op_fetch_print(dat);
606 put_hex(op1, dat);
607 break;
608 case 0x13: ; /* Immediate word */
609 uint16_t imm16 = op_fetch_print(dat)
610 + (op_fetch_print(dat) << 8);
611 put_hex_16(imm16, dat);
612 break;
613 case 0x14: /* AF,AF' */
614 xtract(irAFAF, op_register, dat);
615 break;
616 case 0x15: /* DE,HL */
617 xtract(irDEHL, op_register, dat);
618 break;
619 case 0x16: /* 8-bit source */
620 do_op_8bit_src_dst(dat->opcode,dat);
621 break;
622 }
623 }
624
625 uint32_t dis_decode(uint32_t addr)
626 {
627 disas_data_t data;
628
629 memset(&data, 0, sizeof(data));
630 data.address = addr;
631
632 uint8_t op;
633 uint8_t iflag;
634 uint8_t mnemi;
635 uint8_t mask;
636 uint8_t mode;
637
638 printf_P(PSTR("%04X "), data.address);
639
640 const FLASH uint8_t *decodep = dec_tab.group3;
641
642 do {
643 iflag = 0;
644 op = op_fetch_print(&data);
645 if (op == 0xed) {
646 } else if (op == 0xdd) {
647 iflag = 1;
648 } else if (op == 0xfd) {
649 iflag = 2;
650 } else {
651 break;
652 }
653 data.indexflag = iflag;
654 } while (iflag != 0);
655
656 if (op != 0xed) {
657 if (data.indexflag != 0) {
658 if ((op == 0xcb) || ((op & 0x44) == 0x04) || ((op & 0xc0) == 0x40)) {
659 data.opc_displacement = op_fetch_print(&data);
660 }
661 }
662 if (op != 0xcb) {
663 decodep = dec_tab.group1;
664 } else {
665 decodep = dec_tab.group2;
666 op = op_fetch_print(&data);
667 }
668 } else {
669 op = op_fetch_print(&data);
670 }
671
672 data.opcode = op;
673
674 mnemi = 0;
675 while ((mask = *decodep++) != 0) { //NEWMSK
676
677 uint8_t opmask = op & mask;
678
679 while ((mode = *decodep++) != 0xff) { //NEWMOD
680
681 uint8_t opmatch;
682 uint8_t imatch;
683 do {
684 opmatch = *decodep++;
685 imatch = *decodep++;
686 if (opmatch == opmask) {
687 mnemi = imatch & 0x7f;
688 goto matchfound;
689 }
690 } while ((imatch & 0x80) == 0);
691 }
692 } //TABEND
693 matchfound:
694
695 /* block instruction? */
696 if (mnemi >= iLDI) {
697 mnemi = mnemi + (op & 0x03) + ((op >> 1) & 0x0c);
698 } else
699 /* Alu op? */
700 if ((mnemi >= iADD) && ((mode & 0x80) == 0)) {
701 mnemi = mnemi + ((op >> 3) & 0x07);
702 }
703
704 xtract(mnemi, mnemonics, &data);
705 while (data.outbufpos < 6)
706 put_char(' ', &data);
707
708 uint8_t w = (mode & 0xf0) >> 4;
709 if (w != 0) {
710 do_operand(w, &data);
711 if (mode & 0x0f)
712 put_char(',', &data);
713 }
714 w = mode & 0x0f;
715 if (w != 0) {
716 if (w < 7)
717 w += 0x10;
718 do_operand(w, &data);
719 }
720 for (uint8_t i = data.bytes_fetched; i < 4; i++)
721 printf_P(PSTR(" "));
722 printf_P(PSTR("%s\n"), data.outbuf);
723
724 return data.address;
725 }