In order to make debugging easier, I thought it might to have a disassembler. It’s fairly table driven. It needs a lot of work still. I think it disassembles valid instructions, but doesn’t guarantee that invalid instructions are handled in any particular way. By valid, I mean the officially documented instructions. It is not optimized for speed. Rather, my goal was code size. Whether I met that or not is something I’m wondering. All the little special cases add code size.
Anyone needing a Z-80 disassembler is free to use what they want from this.
1 // Associate shiftMask to a StartInfo
2 struct ShiftMaskAndIndexStartInfo {
3 // upper nibble is shift amount. Bottom nibble is mask
4 uint8_t shiftMaskInfo ;
5
6 // A start index
7 uint8_t indexStart ;
8 };
9
10 // Information to create an instruction
11 struct InstructionInfo
12 {
13 // 8 bit mask of relevant bits
14 uint8_t mask ;
15
16 // expected value after anding with mask
17 uint8_t value ;
18
19 // 7-6: type 5-0: index
20 uint8_t opcodeInfo ;
21
22 // arg0 info
23 uint8_t argInfoIndex0 ;
24
25 // arg1 info
26 uint8_t argInfoIndex1 ;
27 };
28
29 // Opcode builder
30 struct OpcodeBuildInfo {
31 // 8 bit mask of relevant bits
32 uint8_t mask ;
33
34 // Expected value after anding with mask
35 uint8_t value ;
36
37 // Letter to append if (b & mask) == value
38 char letter ;
39 };
40
41
42 // Keep synched with InstructionTableArray
43 enum InstructionTableIndices
44 {
45 TABLE_MAIN_00 ,
46 TABLE_MAIN_40 ,
47 TABLE_MAIN_80 ,
48 TABLE_MAIN_C0 ,
49 TABLE_CB ,
50 TABLE_ED ,
51 TABLE_COUNT
52 };
53
54 // keep synched with LiteralStringArray
55 enum LiteralStringIndices {
56 DA_LIT_Q ,
57 DA_LIT_nop ,
58 DA_LIT_djnz ,
59 DA_LIT_jr ,
60 DA_LIT_ld ,
61 DA_LIT_add ,
62 DA_LIT_ex ,
63 DA_LIT_halt ,
64 DA_LIT_ret ,
65 DA_LIT_call ,
66 DA_LIT_jp ,
67 DA_LIT_exx ,
68 DA_LIT_rst ,
69 DA_LIT_neg ,
70 DA_LIT_reti ,
71 DA_LIT_retn ,
72 DA_LIT_im ,
73 DA_LIT_inc ,
74 DA_LIT_dec ,
75 DA_LIT_adc ,
76 DA_LIT_sub ,
77 DA_LIT_sbc ,
78 DA_LIT_and ,
79 DA_LIT_xor ,
80 DA_LIT_or ,
81 DA_LIT_cp ,
82 DA_LIT_daa ,
83 DA_LIT_cpl ,
84 DA_LIT_scf ,
85 DA_LIT_ccf ,
86 DA_LIT_pop ,
87 DA_LIT_push ,
88 DA_LIT_out ,
89 DA_LIT_in ,
90 DA_LIT_di ,
91 DA_LIT_ei ,
92 DA_LIT_bit ,
93 DA_LIT_set ,
94 DA_LIT_res ,
95 DA_LIT_nz ,
96 DA_LIT_z ,
97 DA_LIT_nc ,
98 DA_LIT_c ,
99 DA_LIT_po ,
100 DA_LIT_pe ,
101 DA_LIT_p ,
102 DA_LIT_m ,
103 DA_LIT_bc ,
104 DA_LIT_de ,
105 DA_LIT_hl ,
106 DA_LIT_ix ,
107 DA_LIT_iy ,
108 DA_LIT_sp ,
109 DA_LIT_af ,
110 DA_LIT_a ,
111 DA_LIT_b ,
112 DA_LIT_d ,
113 DA_LIT_e ,
114 DA_LIT_h ,
115 DA_LIT_l ,
116 DA_LIT_i ,
117 DA_LIT_r ,
118 DA_LIT_af_alt ,
119 DA_LIT_COUNT
120 };
121
122 // keep synced with enum DisassembleLiteralIndices
123 static const char * const LiteralStringArray [ DA_LIT_COUNT ] =
124 {
125 "?" ,
126 "nop" ,
127 "djnz" ,
128 "jr" ,
129 "ld" ,
130 "add" ,
131 "ex" ,
132 "halt" ,
133 "ret" ,
134 "call" ,
135 "jp" ,
136 "exx" ,
137 "rst" ,
138 "neg" ,
139 "reti" ,
140 "retn" ,
141 "im" ,
142 "inc" ,
143 "dec" ,
144 "adc" ,
145 "sub" ,
146 "sbc" ,
147 "and" ,
148 "xor" ,
149 "or" ,
150 "cp" ,
151 "daa" ,
152 "cpl" ,
153 "scf" ,
154 "ccf" ,
155 "pop" ,
156 "push" ,
157 "out" ,
158 "in" ,
159 "di" ,
160 "ei" ,
161 "bit" ,
162 "set" ,
163 "res" ,
164 "nz" ,
165 "z" ,
166 "nc" ,
167 "c" ,
168 "po" ,
169 "pe" ,
170 "p" ,
171 "m" ,
172 "bc" ,
173 "de" ,
174 "hl" ,
175 "ix" ,
176 "iy" ,
177 "sp" ,
178 "af" ,
179 "a" ,
180 "b" ,
181 "d" ,
182 "e" ,
183 "h" ,
184 "l" ,
185 "i" ,
186 "r" ,
187 "af'"
188 };
189
190 /*
191 0: @alu : add, adc, sub, sbc, and, xor, or, cp
192 1 : @bitsetres : -, bit, set, res
193 2 : @daacplscfccf : daa, cpl, scf, ccf
194 3 : @incdec : inc, dec
195 4 : @poppush : pop, push
196 5 : @outin : out, in
197 6 : @inout : in, out
198 7 : @diei : di, ei
199 8 : @sbcadc : sbc, adc
200 */
201
202 enum OpcodeByMaskInfoIndices
203 {
204 OPCODE_MASKABLE_ALU , // 10@@ @rrr -- 11@@ @110
205 OPCODE_MASKABLE_BIT , // @@## #rrr
206 OPCODE_MASKABLE_DAA , // 001@ @111
207 OPCODE_MASKABLE_INC_RRS , // 00rr @011
208 OPCODE_MASKABLE_INC_R , // 00rr r10@
209 OPCODE_MASKABLE_POP , // 11rr 0@01
210 OPCODE_MASKABLE_INOUT , // 01rr r00@
211 OPCODE_MASKABLE_OUTIN , // 1110 @011
212 OPCODE_MASKABLE_DIEI , // 1111 @011
213 OPCODE_MASKABLE_SBC , // 01rr @010
214 OPCODE_MASKABLE_COUNT ,
215 };
216
217 enum OpcodeByMaskStartIndices
218 {
219 MASKABLE_ALU = 0 ,
220 MASKABLE_BIT = MASKABLE_ALU + 8 - 1 , // first element of bit can't exist, so collapse
221 MASKABLE_DAA = MASKABLE_BIT + 4 ,
222 MASKABLE_INC = MASKABLE_DAA + 4 ,
223 MASKABLE_POP = MASKABLE_INC + 2 ,
224 MASKABLE_INOUT = MASKABLE_POP + 2 ,
225 MASKABLE_OUTIN = MASKABLE_INOUT + 2 - 1 ,
226 MASKABLE_DIEI = MASKABLE_OUTIN + 2 ,
227 MASKABLE_SBC = MASKABLE_DIEI + 2 ,
228 MASKABLE_ARRAY_COUNT = MASKABLE_SBC + 2
229 };
230
231 static const struct ShiftMaskAndIndexStartInfo OpcodeByMaskShiftMaskArray [ OPCODE_MASKABLE_COUNT ] =
232 {
233 {
234 0x37 , MASKABLE_ALU
235 },
236 {
237 0x63 , MASKABLE_BIT
238 },
239 {
240 0x33 , MASKABLE_DAA
241 },
242 { // r
243 0x31 , MASKABLE_INC
244 },
245 { // rrs
246 0x01 , MASKABLE_INC
247 },
248 {
249 0x21 , MASKABLE_POP
250 },
251 {
252 0x01 , MASKABLE_INOUT
253 },
254 {
255 0x31 , MASKABLE_OUTIN
256 },
257 {
258 0x31 , MASKABLE_DIEI
259 },
260 {
261 0x31 , MASKABLE_SBC
262 },
263 };
264
265 static const uint8_t OpcodeByMaskArray [ MASKABLE_ARRAY_COUNT ] =
266 {
267 // MASKABLE_ALU = 0
268 DA_LIT_add , // 0
269 DA_LIT_adc ,
270 DA_LIT_sub ,
271 DA_LIT_sbc ,
272 DA_LIT_and ,
273 DA_LIT_xor ,
274 DA_LIT_or ,
275 // MASKABLE_BIT = 7
276 DA_LIT_cp ,
277
278 DA_LIT_bit , // 8
279 DA_LIT_res ,
280 DA_LIT_set ,
281
282 // MASKABLE_DAA
283 DA_LIT_daa , // 11
284 DA_LIT_cpl ,
285 DA_LIT_scf ,
286 DA_LIT_ccf ,
287
288 // MASKABLE_INC
289 DA_LIT_inc , // 15
290 DA_LIT_dec ,
291
292 // MASKABLE_POP
293 DA_LIT_pop , // 17
294 DA_LIT_push ,
295
296 // MASKABLE_INOUT
297 DA_LIT_in , // 19
298 // MASKABLE_OUTIN
299 DA_LIT_out , // 20
300 DA_LIT_in ,
301
302 // MASKABLE_EIDI
303 DA_LIT_di , // 22
304 DA_LIT_ei ,
305
306 // MASKABLE_SBC
307 DA_LIT_sbc , // 24
308 DA_LIT_adc
309 };
310
311 // ROTATE Main-00-00; ED-80-00; CB-02-00 "r"
312 // SHIFT CB-02-02 "s"
313 // LD ED-07-00 "ld"
314 // CP ED-07-01 "cp"
315 // IN ED-07-02 "in"
316 // OT ED-07-03 "ot
317 // CARRY MAIN/CB-01-01 "c"
318 // LOGIGAL CB-03-03 "l"
319 // ARITH/Acc CB-03-02 "a"
320 // LEFT Main-08-00; "l"
321 // RIGHT Main-08-08; "r"
322 // INC ED-88-80 "i"
323 // DEC ED-88-88 "d"
324 // REPEAT ED-f0-b0 "r"
325
326 enum OpcodeByBuilderIndices
327 {
328 OPCODE_BUILD_RLCA ,
329 OPCODE_BUILD_RRD ,
330 OPCODE_BUILD_LDI ,
331 OPCODE_BUILD_RLC
332 };
333
334 // sync with OpcodeBuilderArray and OpcodeByBuilderIndices
335 static const uint8_t OpcodeBuilderIndexToOpcodeBuilderArrayStartIndex [] = {
336 0 ,
337 6 ,
338 11 ,
339 24 ,
340 33
341 };
342
343 // synch with OpcodeBuilderIndexToOpcodeBuilderArrayStartIndex
344 static const struct OpcodeBuildInfo OpcodeBuilderArray [ 32 ] = {
345 //MAIN table
346 //{
347 // main = 0 (5)
348 { 0x00 , 0x00 , 'r' },
349 { 0x08 , 0x00 , 'l' },
350 { 0x08 , 0x08 , 'r' },
351 { 0x10 , 0x00 , 'c' },
352 { 0x00 , 0x00 , 'a' },
353 { 0x00 , 0x00 , 0 },
354 //},
355 // ED table
356 //{
357 { 0x00 , 0x00 , 'r' },
358 { 0xc8 , 0x40 , 'r' },
359 { 0xc8 , 0x48 , 'l' },
360 { 0x00 , 0x00 , 'd' },
361 { 0x00 , 0x00 , 0 },
362 //},
363 //{
364 { 0xc7 , 0x80 , 'l' },
365 { 0xc7 , 0x80 , 'd' },
366 { 0xc7 , 0x81 , 'c' },
367 { 0xc7 , 0x81 , 'p' },
368 { 0xc7 , 0x82 , 'i' },
369 { 0xc7 , 0x82 , 'n' },
370 { 0xc7 , 0x83 , 'o' },
371 { 0xf7 , 0xa3 , 'u' },
372 { 0xc7 , 0x83 , 't' },
373 { 0x88 , 0x80 , 'i' },
374 { 0x88 , 0x88 , 'd' },
375 { 0xf0 , 0xb0 , 'r' },
376 { 0x00 , 0x00 , 0 },
377 //},
378 // CB table
379 //{
380 { 0x20 , 0x00 , 'r' },
381 { 0x20 , 0x20 , 's' },
382 { 0x08 , 0x00 , 'l' },
383 { 0x08 , 0x08 , 'r' },
384 { 0x30 , 0x00 , 'c' },
385 { 0x30 , 0x20 , 'a' },
386 { 0x30 , 0x30 , 'l' },
387 { 0x00 , 0x00 , 0 },
388 //}
389 };
390
391
392 #define ARG_TYPE_SPECIAL (0x00)
393 #define ARG_TYPE_LIT (0x10)
394 #define ARG_TYPE_MASK (0x20)
395 #define ARG_TYPE_SWAPPABLE (0x40)
396 #define ARG_TYPE_CONTENTS (0x80)
397
398 enum ArgByMaskStartIndices
399 {
400 ARG_ARR_FL = 0 ,
401 ARG_ARR_RRS = ARG_ARR_FL + 8 ,
402 ARG_ARR_RRA = ARG_ARR_RRS + 4 ,
403 ARG_ARR_HLA = ARG_ARR_RRA + 4 ,
404 ARG_ARR_R = ARG_ARR_HLA + 2 ,
405 ARG_ARR_IR = ARG_ARR_R + 8 ,
406 ARG_ARR_IM = ARG_ARR_IR + 2 ,
407 ARG_ARR_COUNT = ARG_ARR_IM + 4
408 };
409
410 static const uint8_t ArgByMaskArray [ ARG_ARR_COUNT ] =
411 {
412 DA_LIT_nz , // 0
413 DA_LIT_z ,
414 DA_LIT_nc ,
415 DA_LIT_c ,
416 DA_LIT_po ,
417 DA_LIT_pe ,
418 DA_LIT_p ,
419 DA_LIT_m ,
420
421 DA_LIT_bc , // 8
422 DA_LIT_de ,
423 DA_LIT_hl ,
424 DA_LIT_sp ,
425
426 DA_LIT_bc , // 12
427 DA_LIT_de ,
428 DA_LIT_hl ,
429 DA_LIT_af ,
430
431 DA_LIT_hl , // 16
432 DA_LIT_a ,
433
434 DA_LIT_b , // 18
435 DA_LIT_c ,
436 DA_LIT_d ,
437 DA_LIT_e ,
438 DA_LIT_h ,
439 DA_LIT_l ,
440 DA_LIT_hl | ARG_TYPE_CONTENTS ,
441 DA_LIT_a ,
442
443 DA_LIT_i , // 42
444 DA_LIT_r ,
445 };
446
447 /*
448 //
449 #define ARG_TYPE_MASK (0x01)
450 // mask, index
451 #define ARG_TYPE_LIT (0x02)
452 // (int8_t)(*(pc)) + pc; pc++;
453 #define ARG_TYPE_REL (0x03)
454 #define ARG_TYPE_IMM8 (0x04)
455 #define ARG_TYPE_IMM16 (0x05)
456 #define ARG_TYPE_ASCII (0x06)
457 #define ARG_TYPE_RST (0x07)
458 */
459
460 // index to next table ED/CB/DDFD
461 #define OPCODE_TYPE_LIT (0x00)
462 // index
463 #define OPCODE_TYPE_ARR (0x40)
464 // mask, index
465 #define OPCODE_TYPE_BUILD (0x80)
466 // index
467 #define OPCODE_TYPE_SUB (0xc0)
468
469
470 // [8:mask],[8:val],[2:opcode, 6:index0] [1: swappable 3: arg0 3: arg1]
471 // index 0 is literal index for literal, or maskables index for maskable. For build, the build index
472 // swapbit is there only if swappable. Swap bit is 3 for main, 4 for ED
473 // arginfo is:
474 // if 00 no arg
475 // if 01 mask [8: mask(-sss-mmm)] [8: arg_arr index] or 3bit is mask index, 5 bits is arg_arr index
476 // if 02 lit [8: lit index]
477 // if 03 uint8 get next byte
478 // if 04 RelAddr get next byte, add to location
479 // if 05 uint16 get next word
480 // bit 8 swappable
481 enum ArgInfo {
482 ARG_INFO_NONE ,
483 ARG_INFO_rel , // 1
484 ARG_INFO_imm8 ,
485 ARG_INFO_imm16 ,
486 ARG_INFO_bit ,
487 ARG_INFO_rst ,
488 ARG_INFO_im ,
489
490 ARG_INFO_LIT_a = ARG_TYPE_LIT , // 4
491 ARG_INFO_LIT_af ,
492 ARG_INFO_LIT_af_alt ,
493 ARG_INFO_LIT_c ,
494 ARG_INFO_LIT_de ,
495
496 ARG_INFO_LIT_hl , // 8
497 ARG_INFO_LIT_sp ,
498 //ARG_INFO_LIT_q,
499
500 ARG_INFO_MASK_30_RRS = ARG_TYPE_MASK ,
501 ARG_INFO_MASK_30_RRA ,
502 ARG_INFO_MASK_07_R ,
503
504 ARG_INFO_MASK_38_R ,
505 ARG_INFO_MASK_18_FL ,
506 ARG_INFO_MASK_38_FL ,
507 ARG_INFO_MASK_08_IR ,
508 };
509
510 /*
511 enum ArgMaskIndex {
512 ARG_MASK_30_RRS,
513 ARG_MASK_30_RRA,
514 ARG_MASK_07_R,
515 ARG_MASK_38_R,
516
517 ARG_MASK_30_FL,
518 ARG_MASK_38_FL,
519 ARG_MASK_38_RST,
520 ARG_MASK_80_IR,
521
522 ARG_MASK_COUNT,
523 };
524 */
525
526 // sync with ArgInfo from ARG_TYPE_LIT
527 static const uint8_t ArgByLitIndexToStringLiteralIndex [] = {
528 DA_LIT_a ,
529 DA_LIT_af ,
530 DA_LIT_af_alt ,
531 DA_LIT_c ,
532
533 DA_LIT_de ,
534 DA_LIT_hl ,
535 DA_LIT_sp
536 };
537
538 // sync with ArgInfo from ARG_TYPE_MASK
539 static const struct ShiftMaskAndIndexStartInfo ArgShiftMaskStartIndex [] =
540 {
541 { /*0x30*/ 0x43 , ARG_ARR_RRS },
542 { /*0x30*/ 0x43 , ARG_ARR_RRA },
543 { /*0x07*/ 0x07 , ARG_ARR_R },
544 { /*0x38*/ 0x37 , ARG_ARR_R },
545
546 { /*0x18*/ 0x33 , ARG_ARR_FL },
547 { /*0x38*/ 0x37 , ARG_ARR_FL },
548 { /*0x08*/ 0x31 , ARG_ARR_IR },
549 };
550
551 char * buildOpcode ( uint8_t opcode , uint8_t table , char * line )
552 {
553 const struct OpcodeBuildInfo * cand = & OpcodeBuilderArray [ OpcodeBuilderIndexToOpcodeBuilderArrayStartIndex [ table ]];
554 while ( cand -> letter != 0 )
555 {
556 if (( opcode & cand -> mask ) == cand -> value )
557 {
558 * line ++ = cand -> letter ;
559 }
560 cand ++ ;
561 }
562 * line ++ = '\0' ;
563 return line ;
564 }
565
566 static const struct InstructionInfo InstructionInfoTableMain_00 [] =
567 {
568 {
569 0xff ,
570 0x00 ,
571 DA_LIT_nop | OPCODE_TYPE_LIT ,
572 ARG_INFO_NONE ,
573 ARG_INFO_NONE ,
574 },
575 {
576 0xff ,
577 0x10 ,
578 DA_LIT_djnz | OPCODE_TYPE_LIT ,
579 ARG_INFO_rel ,
580 ARG_INFO_NONE
581 },
582 {
583 0xe7 ,
584 0x20 ,
585 DA_LIT_jr | OPCODE_TYPE_LIT ,
586 ARG_INFO_MASK_18_FL ,
587 ARG_INFO_rel ,
588 },
589 {
590 0xcf ,
591 0x01 ,
592 DA_LIT_ld | OPCODE_TYPE_LIT ,
593 ARG_INFO_MASK_30_RRS ,
594 ARG_INFO_imm16
595 },
596 {
597 0xe7 ,
598 0x02 ,
599 DA_LIT_ld | OPCODE_TYPE_LIT ,
600 ARG_INFO_MASK_30_RRS | ARG_TYPE_SWAPPABLE | ARG_TYPE_CONTENTS , // swap on 0x08
601 ARG_INFO_LIT_a
602 },
603 {
604 0xcf ,
605 0x09 ,
606 DA_LIT_add | OPCODE_TYPE_LIT ,
607 ARG_INFO_LIT_hl ,
608 ARG_INFO_MASK_30_RRS
609 },
610 {
611 0xf7 ,
612 0x32 ,
613 DA_LIT_ld | OPCODE_TYPE_LIT ,
614 ARG_INFO_imm16 | ARG_TYPE_SWAPPABLE | ARG_TYPE_CONTENTS , // swap on 0x08
615 ARG_INFO_LIT_a
616 },
617 {
618 0xf7 ,
619 0x22 ,
620 DA_LIT_ld | OPCODE_TYPE_LIT ,
621 ARG_INFO_imm16 | ARG_TYPE_SWAPPABLE | ARG_TYPE_CONTENTS , // swap on 0x08
622 ARG_INFO_LIT_hl
623 },
624 {
625 0xc7 ,
626 0x03 ,
627 OPCODE_MASKABLE_INC_RRS | OPCODE_TYPE_ARR ,
628 ARG_INFO_MASK_30_RRS ,
629 ARG_INFO_NONE
630 },
631 {
632 0xc6 ,
633 0x04 ,
634 OPCODE_MASKABLE_INC_R | OPCODE_TYPE_ARR ,
635 ARG_INFO_MASK_38_R ,
636 ARG_INFO_NONE
637 },
638 {
639 0xc7 ,
640 0x06 ,
641 DA_LIT_ld | OPCODE_TYPE_LIT ,
642 ARG_INFO_MASK_38_R ,
643 ARG_INFO_imm8
644 },
645 {
646 0xff ,
647 0x08 ,
648 DA_LIT_ex | OPCODE_TYPE_LIT ,
649 ARG_INFO_LIT_af ,
650 ARG_INFO_LIT_af_alt
651 },
652 {
653 0xff ,
654 0x18 ,
655 DA_LIT_jr | OPCODE_TYPE_LIT ,
656 ARG_INFO_rel ,
657 ARG_INFO_NONE
658 },
659 {
660 0xe7 ,
661 0x27 ,
662 OPCODE_MASKABLE_DAA | OPCODE_TYPE_ARR ,
663 ARG_INFO_NONE ,
664 ARG_INFO_NONE
665 },
666 {
667 0xe7 ,
668 0x07 ,
669 OPCODE_BUILD_RLCA | OPCODE_TYPE_BUILD ,
670 ARG_INFO_NONE ,
671 ARG_INFO_NONE
672 },
673 {
674 0x00 ,
675 0x00 ,
676 DA_LIT_Q | OPCODE_TYPE_LIT ,
677 ARG_INFO_NONE ,
678 ARG_INFO_NONE
679 }
680 };
681 static const struct InstructionInfo InstructionInfoTableMain_40 [] =
682 {
683 { // Must be before ld r,r
684 0xff ,
685 0x76 ,
686 DA_LIT_halt | OPCODE_TYPE_LIT ,
687 ARG_INFO_NONE ,
688 ARG_INFO_NONE
689 },
690
691 { // Must be after halt
692 0xc0 ,
693 0x40 ,
694 DA_LIT_ld | OPCODE_TYPE_LIT ,
695 ARG_INFO_MASK_38_R ,
696 ARG_INFO_MASK_07_R
697 },
698 {
699 0x00 ,
700 0x00 ,
701 DA_LIT_Q | OPCODE_TYPE_LIT ,
702 ARG_INFO_NONE ,
703 ARG_INFO_NONE
704 }
705 };
706 static const struct InstructionInfo InstructionInfoTableMain_80 [] =
707 {
708 {
709 0xc0 ,
710 0x80 ,
711 OPCODE_MASKABLE_ALU | OPCODE_TYPE_ARR ,
712 ARG_INFO_LIT_a ,
713 ARG_INFO_MASK_07_R
714 },
715 {
716 0x00 ,
717 0x00 ,
718 DA_LIT_Q | OPCODE_TYPE_LIT ,
719 ARG_INFO_NONE ,
720 ARG_INFO_NONE
721 }
722 };
723 static const struct InstructionInfo InstructionInfoTableMain_c0 [] =
724 {
725 {
726 0xc7 ,
727 0xc0 ,
728 DA_LIT_ret | OPCODE_TYPE_LIT ,
729 ARG_INFO_MASK_38_FL ,
730 ARG_INFO_NONE
731 },
732 {
733 0xff ,
734 0xcd ,
735 DA_LIT_call | OPCODE_TYPE_LIT ,
736 ARG_INFO_imm16 ,
737 ARG_INFO_NONE
738 },
739 {
740 0xff ,
741 0xc3 ,
742 DA_LIT_jp | OPCODE_TYPE_LIT ,
743 ARG_INFO_imm16 ,
744 ARG_INFO_NONE
745 },
746 {
747 0xff ,
748 0xe9 ,
749 DA_LIT_jp | OPCODE_TYPE_LIT ,
750 ARG_INFO_LIT_hl | ARG_TYPE_CONTENTS ,
751 ARG_INFO_NONE
752 },
753 {
754 0xff ,
755 0xf9 ,
756 DA_LIT_ld | OPCODE_TYPE_LIT ,
757 ARG_INFO_LIT_sp ,
758 ARG_INFO_LIT_hl
759 },
760 {
761 0xcb ,
762 0xc1 ,
763 OPCODE_MASKABLE_POP | OPCODE_TYPE_ARR ,
764 ARG_INFO_MASK_30_RRA ,
765 ARG_INFO_NONE
766 },
767 {
768 0xff ,
769 0xc9 ,
770 DA_LIT_ret | OPCODE_TYPE_LIT ,
771 ARG_INFO_NONE ,
772 ARG_INFO_NONE
773 },
774 {
775 0xff ,
776 0xd9 ,
777 DA_LIT_exx | OPCODE_TYPE_LIT ,
778 ARG_INFO_NONE ,
779 ARG_INFO_NONE
780 },
781 {
782 0xc7 ,
783 0xc2 ,
784 DA_LIT_jp | OPCODE_TYPE_LIT ,
785 ARG_INFO_MASK_38_FL ,
786 ARG_INFO_imm16
787 },
788 {
789 0xc7 ,
790 0xc4 ,
791 DA_LIT_call | OPCODE_TYPE_LIT ,
792 ARG_INFO_MASK_38_FL ,
793 ARG_INFO_imm16
794 },
795 {
796 0xc7 ,
797 0xc7 ,
798 DA_LIT_rst | OPCODE_TYPE_LIT ,
799 ARG_INFO_rst ,
800 ARG_INFO_NONE
801 },
802 {
803 0xc7 ,
804 0xc6 ,
805 OPCODE_MASKABLE_ALU | OPCODE_TYPE_ARR ,
806 ARG_INFO_LIT_a ,
807 ARG_INFO_imm8
808 },
809 {
810 0xf7 ,
811 0xd3 ,
812 OPCODE_MASKABLE_OUTIN | OPCODE_TYPE_ARR ,
813 ARG_INFO_imm8 | ARG_TYPE_CONTENTS | ARG_TYPE_SWAPPABLE , // swap on 0x08
814 ARG_INFO_LIT_a
815 },
816 {
817 0xf7 ,
818 0xf3 ,
819 OPCODE_MASKABLE_DIEI | OPCODE_TYPE_ARR ,
820 ARG_INFO_NONE ,
821 ARG_INFO_NONE
822 },
823 {
824 0xff ,
825 0xe3 ,
826 DA_LIT_ex | OPCODE_TYPE_LIT ,
827 ARG_INFO_LIT_sp | ARG_TYPE_CONTENTS ,
828 ARG_INFO_LIT_hl
829 },
830 {
831 0xff ,
832 0xeb ,
833 DA_LIT_ex | OPCODE_TYPE_LIT ,
834 ARG_INFO_LIT_de ,
835 ARG_INFO_LIT_hl
836 },
837 {
838 0xff ,
839 0xcb ,
840 TABLE_CB | OPCODE_TYPE_SUB ,
841 ARG_INFO_NONE ,
842 ARG_INFO_NONE
843 },
844 {
845 0xff ,
846 0xed ,
847 TABLE_ED | OPCODE_TYPE_SUB ,
848 ARG_INFO_NONE ,
849 ARG_INFO_NONE
850 },
851 {
852 0xfd ,
853 0xfd ,
854 0 | OPCODE_TYPE_SUB ,
855 ARG_INFO_NONE ,
856 ARG_INFO_NONE
857 },
858 {
859 0x00 ,
860 0x00 ,
861 DA_LIT_Q | OPCODE_TYPE_LIT ,
862 ARG_INFO_NONE ,
863 ARG_INFO_NONE
864 }
865 };
866
867 static const struct InstructionInfo InstructionInfoTableCB [] =
868 {
869 // CB
870 {
871 0xc0 ,
872 0x00 ,
873 OPCODE_BUILD_RLC | OPCODE_TYPE_BUILD ,
874 ARG_INFO_MASK_07_R ,
875 ARG_INFO_NONE
876 },
877 {
878 0x00 ,
879 0x00 ,
880 OPCODE_MASKABLE_BIT | OPCODE_TYPE_ARR ,
881 ARG_INFO_bit ,
882 ARG_INFO_MASK_07_R
883 },
884 {
885 0x00 ,
886 0x00 ,
887 DA_LIT_Q | OPCODE_TYPE_LIT ,
888 ARG_INFO_NONE ,
889 ARG_INFO_NONE
890 }
891 };
892
893 static const struct InstructionInfo InstructionInfoTableED [] =
894 {
895 // ED
896 {
897 0xc6 ,
898 0x40 ,
899 OPCODE_MASKABLE_INOUT | OPCODE_TYPE_ARR ,
900 ARG_INFO_MASK_38_R | ARG_TYPE_SWAPPABLE , // TODO swap on 0x01
901 ARG_INFO_LIT_c | ARG_TYPE_CONTENTS
902 },
903 {
904 0xc7 ,
905 0x42 ,
906 OPCODE_MASKABLE_SBC | OPCODE_TYPE_ARR ,
907 ARG_INFO_LIT_hl ,
908 ARG_INFO_MASK_30_RRS
909 },
910 {
911 0xc7 ,
912 0x43 ,
913 DA_LIT_ld | OPCODE_TYPE_LIT ,
914 ARG_INFO_imm16 | ARG_TYPE_CONTENTS | ARG_TYPE_SWAPPABLE , // TODO swap in 0x08
915 ARG_INFO_MASK_30_RRS
916 },
917 {
918 0xc7 ,
919 0x44 ,
920 DA_LIT_neg | OPCODE_TYPE_LIT ,
921 ARG_INFO_NONE ,
922 ARG_INFO_NONE
923 },
924 {
925 0xff ,
926 0x4d ,
927 DA_LIT_reti | OPCODE_TYPE_LIT ,
928 ARG_INFO_NONE ,
929 ARG_INFO_NONE
930 },
931 {
932 0xc7 ,
933 0x45 ,
934 DA_LIT_retn | OPCODE_TYPE_LIT ,
935 ARG_INFO_NONE ,
936 ARG_INFO_NONE
937 },
938 {
939 0xe7 ,
940 0x47 ,
941 DA_LIT_ld | OPCODE_TYPE_LIT ,
942 ARG_INFO_MASK_08_IR | ARG_TYPE_SWAPPABLE , // TODO swap not working -- on bit 4 0x10
943 ARG_INFO_LIT_a
944 },
945 {
946 0xf7 ,
947 0x67 ,
948 OPCODE_BUILD_RRD | OPCODE_TYPE_BUILD ,
949 ARG_INFO_NONE ,
950 ARG_INFO_NONE
951 },
952 {
953 0xc7 ,
954 0x46 ,
955 DA_LIT_im | OPCODE_TYPE_LIT ,
956 ARG_INFO_im ,
957 ARG_INFO_NONE
958 },
959 {
960 0xe4 ,
961 0xa0 ,
962 OPCODE_BUILD_LDI | OPCODE_TYPE_BUILD ,
963 ARG_INFO_NONE ,
964 ARG_INFO_NONE
965 },
966 {
967 0x00 ,
968 0x00 ,
969 DA_LIT_Q | OPCODE_TYPE_LIT ,
970 ARG_INFO_NONE ,
971 ARG_INFO_NONE
972 }
973 };
974
975 // sync with InstructionTableIndices
976 static const struct InstructionInfo * InstructionInfoTableArray [ TABLE_COUNT ] =
977 {
978 InstructionInfoTableMain_00 ,
979 InstructionInfoTableMain_40 ,
980 InstructionInfoTableMain_80 ,
981 InstructionInfoTableMain_c0 ,
982 InstructionInfoTableCB ,
983 InstructionInfoTableED
984 };
985
986 uint8_t shiftMaskToByte ( uint8_t b , uint8_t shiftMaskByte )
987 {
988 return ( b >> ( shiftMaskByte >> 4 )) & shiftMaskByte & 0x0f ;
989 }
990
991 static const char IM_0Q12 [ 4 ] = { '0' , '?' , '1' , '2' };
992 static const char * const FORMAT1C = "%c" ;
993 static const char * const FORMAT1 = "%01xh" ;
994 static const char * const FORMAT2 = "%02xh" ;
995 static const char * const FORMAT4 = "%04xh" ;
996 static const char * const FORMAT_CONTENTS = "(%s)" ;
997
998 uint8_t * disassemble ( uint8_t * loc , char * line )
999 {
1000 uint8_t b ; // instruction byte being disassembled
1001 uint8_t table = 0 ;
1002 const struct InstructionInfo * entry ;
1003 bool swap = false ;
1004 uint8_t argCount = 0 ;
1005 char arg0 [ 8 ];
1006 char arg1 [ 8 ];
1007 char * args [ 2 ] = { arg0 , arg1 };
1008 uint8_t opcodeInfo ;
1009 uint8_t opcodeIndex ;
1010 uint16_t offset ;
1011 uint8_t hl_ix_iy = 0 ;
1012 char offsetStr [ 6 ] = { 0 };
1013
1014 * line = 0 ;
1015 b = * loc ++ ;
1016 table = b >> 6 ;
1017
1018 // See if we need a special table
1019 // 1100 1011 cb
1020 // 1110 1101 ed
1021 // 11-0 1--1
1022 // 1101 1101
1023 // 1111 1101
1024 // 11-1 1101
1025 if (( b & 0xdf ) == 0xdd )
1026 {
1027 if ( b == 0xdd )
1028 {
1029 b = * loc ++ ;
1030 table = b >> 6 ;
1031 hl_ix_iy = 1 ;
1032 }
1033 else if ( b == 0xfd )
1034 {
1035 b = * loc ++ ;
1036 table = b >> 6 ;
1037 hl_ix_iy = 2 ;
1038 }
1039 }
1040 if (( b & 0xd9 ) == 0xc9 )
1041 {
1042 if ( b == 0xcb )
1043 {
1044 b = * loc ++ ;
1045 table = TABLE_CB ;
1046 }
1047 else if ( b == 0xed )
1048 {
1049 b = * loc ++ ;
1050 table = TABLE_ED ;
1051 }
1052 }
1053
1054 entry = InstructionInfoTableArray [ table ];
1055 while ( entry -> mask != 0 )
1056 {
1057 uint8_t opcodeType ;
1058 if (( b & entry -> mask ) == entry -> value )
1059 {
1060 break ;
1061 }
1062 entry ++ ;
1063 }
1064
1065 // got here so we found something to process
1066 opcodeInfo = entry -> opcodeInfo ;
1067 opcodeIndex = entry -> opcodeInfo & 0x3f ;
1068 if (( opcodeInfo & 0x80 ) == 0 )
1069 {
1070 if (( opcodeInfo & 0x40 ) == 0 )
1071 {
1072 // OPCODE_TYPE_LIT
1073 strcpy ( line , LiteralStringArray [ opcodeIndex ]);
1074 }
1075 else
1076 {
1077 // OPCODE_TYPE_ARR
1078 const struct ShiftMaskAndIndexStartInfo * opcodeByMaskInfo = & OpcodeByMaskShiftMaskArray [ opcodeIndex ];
1079 uint8_t index = opcodeByMaskInfo -> indexStart + shiftMaskToByte ( b , opcodeByMaskInfo -> shiftMaskInfo );
1080 strcpy ( line , LiteralStringArray [ OpcodeByMaskArray [ index ]]);
1081 }
1082 }
1083 else
1084 {
1085 // OPCODE_TYPE_BIT
1086 buildOpcode ( b , opcodeIndex , line );
1087 }
1088
1089 for ( argCount = 0 ; argCount < 2 ; argCount ++ )
1090 {
1091 uint8_t argInfo = ( & entry -> argInfoIndex0 )[ argCount ];
1092 char buffer [ 8 ];
1093 const char * argText ;
1094 char * arg = args [ argCount ];
1095 uint16_t argData ;
1096 const char * format = NULL ;
1097 uint8_t lit = 0xff ;
1098 bool contents = false ;
1099
1100 // no more arguments
1101 if ( argInfo == 0 )
1102 {
1103 break ;
1104 }
1105
1106 // extra info --swappable/contents
1107 if ( (( argInfo & ARG_TYPE_SWAPPABLE ) != 0 ) && ! swap )
1108 {
1109 if ( table < 4 )
1110 {
1111 swap = ( b & 0x08 ) != 0 ;
1112 }
1113 else if ( table == TABLE_ED )
1114 {
1115 uint8_t swapMask ;
1116 // entryMask bit
1117 // c6 0/0x01
1118 // c7 3/0x08
1119 // e7 4/0x10
1120 if (( entry -> mask & 0x20 ) == 0 )
1121 {
1122 if (( entry -> mask & 0x01 ) == 0 )
1123 {
1124 swapMask = 0x01 ;
1125 }
1126 else
1127 {
1128 swapMask = 0x08 ;
1129 }
1130 }
1131 else
1132 {
1133 swapMask = 0x10 ;
1134 }
1135 swap = ( b & swapMask ) != 0 ;
1136 }
1137 }
1138 contents = ( argInfo & ARG_TYPE_CONTENTS ) != 0 ;
1139
1140 argInfo &= 0x3f ; // remove swap/contents bits
1141 // either set lit or argText
1142 if ( argInfo < ARG_TYPE_LIT )
1143 {
1144 // Specials
1145 switch ( argInfo & 0x07 )
1146 {
1147 case ARG_INFO_rel :
1148 argData = ( uint16_t )( loc - 1 ) + ( int8_t )( * loc );
1149 loc ++ ;
1150 format = FORMAT4 ;
1151 break ;
1152 case ARG_INFO_imm8 :
1153 argData = ( uint8_t )( * loc );
1154 loc ++ ;
1155 format = FORMAT2 ;
1156 break ;
1157 case ARG_INFO_imm16 :
1158 argData = * ( uint16_t * ) loc ;
1159 loc += 2 ;
1160 format = FORMAT4 ;
1161 break ;
1162 case ARG_INFO_bit :
1163 argData = ( b >> 3 ) & 0x07 ;
1164 format = FORMAT1 ;
1165 break ;
1166 case ARG_INFO_rst :
1167 argData = ( b & 0x38 );
1168 format = FORMAT2 ;
1169 break ;
1170 case ARG_INFO_im :
1171 argData = IM_0Q12 [( b & 0x18 ) >> 3 ];
1172 format = FORMAT1C ;
1173 break ;
1174 }
1175 sprintf ( buffer , format , argData );
1176 argText = & buffer [ 0 ];
1177 }
1178 else if ( argInfo < ARG_TYPE_MASK )
1179 {
1180 // Lit
1181 lit = ArgByLitIndexToStringLiteralIndex [ argInfo & 0x0f ];
1182 }
1183 else
1184 {
1185 // mask
1186 const struct ShiftMaskAndIndexStartInfo * maskInfo = & ArgShiftMaskStartIndex [ argInfo & 0x0f ];
1187 //printf("MASKINGO: %02x b: %02x -> %d\r\n", maskInfo->shiftMaskInfo, b, shiftMaskToByte(b, maskInfo->shiftMaskInfo));
1188 lit = ArgByMaskArray [ maskInfo -> indexStart + shiftMaskToByte ( b , maskInfo -> shiftMaskInfo )];
1189 }
1190
1191 // indexed lit might have the contents flag set
1192 if (( lit != 0xff ) && (( lit & ARG_TYPE_CONTENTS ) != 0 ))
1193 {
1194 lit &= 0x3f ;
1195 contents = true ;
1196 }
1197
1198 // Convert DD/FD, hl to ix/iy and (hl) to (ix/iy+(int8_t)d)
1199 if (( hl_ix_iy > 0 ) && ( lit == DA_LIT_hl ))
1200 {
1201 if ( ! contents || ( table < 4 && b == 0xe9 ))
1202 {
1203 lit = ( DA_LIT_hl + hl_ix_iy );
1204 }
1205 else
1206 {
1207 offset = ( int16_t ) * ( int8_t * ) loc ++ ;
1208 sprintf ( buffer , "%s%c%02x" , LiteralStringArray [ DA_LIT_hl + hl_ix_iy ], ( offset < 0 ) ? '-' : '+' , abs ( offset ));
1209 argText = & buffer [ 0 ];
1210 lit = 0xff ; // switch lit out and argText in
1211 }
1212 }
1213
1214 if ( lit != 0xff )
1215 {
1216 argText = LiteralStringArray [ lit ];
1217 }
1218
1219 if ( contents )
1220 {
1221 sprintf ( arg , "(%s)" , argText );
1222 }
1223 else
1224 {
1225 strcpy ( arg , argText );
1226 }
1227
1228 argInfo >>= 4 ;
1229 }
1230 if ( swap )
1231 {
1232 args [ 0 ] = arg1 ;
1233 args [ 1 ] = arg0 ;
1234 }
1235 if ( argCount > 0 )
1236 {
1237 strcat ( line , " " );
1238 strcat ( line , args [ 0 ]);
1239 }
1240 if ( argCount > 1 )
1241 {
1242 strcat ( line , ", " );
1243 line = strcat ( line , args [ 1 ]);
1244 }
1245 return loc ;
1246 }