implemented "division by zero" check in asm; still, it is 7 bytes smaller! ;-)
[bz80asm.git] / disz80.zas
blobb3f42f14292f5e7e2456cb7ac949e6b9d03779ab
1 ;  This code is been found in a ZX Spectrum tool called UTILITY3 v1.3
3 ; set this to 0 to avoid dumping the address
4 DISZ80_DUMP_ADDRESS equ 1
5 ; set this to 0 to avoid dumping the code
6 DISZ80_DUMP_CODE equ 1
8   MODULE DISZ80
9 dissizest = $
11 ;; emit routine should preserve all registers except AF and HL
12 EMIT_CB: defw 0
14 CHROP:
15   push  hl
16   ld    hl,CHROP_RET
17   push  hl
18   ld    hl,(EMIT_CB)
19   jp    (hl)
20 CHROP_RET:
21   pop   hl
22   ret
24 DISASM_USE_HEX_PREFIX equ 1
25 ; Einar Saukas' optimisation, cut 2 bytes
26 DISASM_EINAR_OPTIMISATION equ 1
28 ; ====================
29 ; DIS-Z80 was published in the SUBSET column of Personal Computer World 1987.
30 ; The routine disassembles a single Z80 instruction at address DE.
31 ; It is required to be followed by a routine called CHROP that outputs a
32 ; single ASCII character.
33 ; It was originally developed for CP/M on an Amstrad CPC128.
35 ; The original ORG was $0100. I have added $5000 to all addresses.
36 ; The stated aim was to write a Z80 disassembly routine in as short a space
37 ; as possible and, at just over 1K (1090 bytes), it is a rather incredible
38 ; program.
40 ; The SUBSET editor David Barrow was able to trim only one byte from John
41 ; Kerr's compact code. I've forgotten where so there's a challenge.
43 ; k8: sadly, i had to add some mode code, so it is 1101 bytes now
44 ; (including `EMIT_CB` variable)
45 ; or 1099 bytes with Einar's optimisation ;-)
47 ; it is using 18 bytes on the stack as a temp buffer, so make sure
48 ; that you have enough stack space for the buffer, and for all other data
49 ; in practice, i guess that 32 bytes will be enough (if your emitter doesn't
50 ; need more).
52 ; IN:
53 ;   DE: address to disasm from
54 ; OUT:
55 ;   DE: addres of the next instruction
56 ;   IX,HL,BC,AF: dead
57 ; ====================
59 DISASM:
60   $IF @DISZ80_DUMP_ADDRESS
61   call  ADRSP
62   $ENDIF
63   ld    bc,$0900
64   ld    hl,$2020
66 BUFFER:
67   push  hl
68   djnz  BUFFER
69   ld    h,b
70   ld    l,c
71   add   hl,sp
73   push  bc
74   ex    (sp),ix
75   push  bc
76   push  bc
77   add   ix,sp
79   push  hl
80   ld    hl,GROUP3
82 TRYNDX:
83   call  FETCH
85   ld    b,c
86   cp    $ED
87   jr    z,CONFLG
89   inc   b
90   cp    $DD
91   jr    z,CONFLG
93   inc   b
94   cp    $FD
95   jr    nz,NOTNDX
97 CONFLG:
98   ld    (ix+1),b
99   inc   b
100   djnz  TRYNDX
102   jr    NXBYTE
104 NOTNDX:
105   ld    c,a
106   ld    a,(ix+1)
107   or    a
108   jr    z,NODISP
110   ld    a,c
111   cp    $CB
112   jr    z,GETDIS
114   and   $44
115   cp    4
116   jr    z,GETDIS
118   ld    a,c
119   and   $C0
120   cp    $40
121   jr    nz,NODISP
123 GETDIS:
124   call  FETCH
125   ld    (ix+2),a
127 NODISP:
128   ld    hl,GROUP1
129   ld    a,c
130   cp    $CB
131   jr    nz,NEWMSK
133   ld    hl,GROUP2
135 NXBYTE:
136   call  FETCH
137   ld    c,a
139 NEWMSK:
140   ld    a,(hl)
141   or    a
142   jr    z,TABEND
144   and   c
145   inc   hl
147 NEWMOD:
148   ld    b,(hl)
149   inc   hl
150   inc   b
151   jr    z,NEWMSK
153 TRYMAT:
154   cp    (hl)
155   inc   hl
156   jr    z,GETNDX
158   bit   7,(hl)
159   inc   hl
160   jr    z,TRYMAT
162   jr    NEWMOD
164 GETNDX:
165   ld    a,(hl)
166   and   $7F
167   dec   b
169 TABEND:
170   pop   hl
171   push  de
172   push  hl
174   ex    de,hl
175   ld    hl,MONICS
176   call  XTRACT
178   pop   hl
179   ld    de,5
180   add   hl,de
181   pop   de
183   ld    a,b
184   and   $F0
185   jr    z,SECOND
187   rra
188   rra
189   rra
190   rra
191   push  bc
193   ld    b,a
194   ld    a,c
195   call  OPRND1
197   pop   bc
198   ld    a,b
199   and   $0F
200   jr    z,OPDONE
202   ld    (hl),44     ;,
203   inc   hl
205 SECOND:
206   ld    a,b
207   and   $0F
209   ld    b,a
210   ld    a,c
211   call  nz,OPRND2
213 OPDONE:
214   ld    a,3
215   sub   (ix+0)
217   pop   hl
218   pop   hl
219   pop   ix
221   jr    c,OUTEXT
223   $IF @DISZ80_DUMP_CODE
224   inc   a
225   ld    b,a
226   add   a,b
227   add   a,b
228   ld    b,a
230 SPACES:
231   ld    a,$20
232   call  CHROP
233   djnz  SPACES
234   $ENDIF
236 OUTEXT:
237   ld  b,18
239 PUTOUT:
240   dec   sp
241   pop   hl
242   ld    a,h
243   call  CHROP
244   djnz  PUTOUT
246   ret
249 ;***********************
251 GROUP2:
252   defb  $C0,$36,$40
253   defb  $04,$80,$2D,$C0,$BE
254   defb  $FF,$F8,$06,$00,$33
255   defb  $08,$38,$10,$35,$18
256   defb  $3A,$20,$3F,$28,$40
257   defb  $30,$00,$38,$C1
260 GROUP1:
261   defb  $FF,$00,$00
262   defb  $24,$07,$32,$0F,$37
263   defb  $17,$31,$1F,$36,$27
264   defb  $0D,$2F,$0B,$37,$3D
265   defb  $3F,$06,$76,$14,$C9
266   defb  $30,$D9,$12,$F3,$0F
267   defb  $FB,$91,$72,$C6,$02
268   defb  $CE,$01,$de,$bc,$02
269   defb  $D6,$42,$E6,$03,$EE
270   defb  $43,$F6,$25,$FE,$8C
271   defb  $04,$08,$93,$01,$10
272   defb  $10,$18,$9D,$af,$22
273   defb  $A2,$FA,$2A,$A2,$A7
274   defb  $32,$A2,$7A,$3A,$A2
275   defb  $03,$C3,$1C,$CD,$85
276   defb  $97,$D3,$AA,$79,$db
277   defb  $9B,$5F,$E3,$93,$0E
278   defb  $E9,$9C,$05,$EB,$93
279   defb  $DF,$F9,$A2,$FF,$C0
280   defb  $B6,$40,$A2,$FF,$F8
281   defb  $76,$80,$02,$88,$01
282   defb  $98,$bc,$06,$90,$42
283   defb  $A0,$03,$A8,$43,$B0
284   defb  $25,$B8,$8C,$FF,$C7
285   defb  $0B,$04,$16,$05,$8E
286   defb  $B2,$06,$A2,$20,$C0
287   defb  $B0,$23,$C2,$1C,$C4
288   defb  $85,$10,$C7,$BB,$FF
289   defb  $CF,$D3,$01,$A2,$0D
290   defb  $03,$16,$0B,$8E,$FD
291   defb  $09,$82,$60,$C1,$2B
292   defb  $C5,$AC,$FF,$E7,$21
293   defb  $20,$9D,$FF,$EF,$E7
294   defb  $02,$A2,$7E,$0A,$A2
297 GROUP3:
298   defb  $FF,$00,$44
299   defb  $23,$45,$2F,$4D,$2E
300   defb  $4E,$00,$67,$39,$6F
301   defb  $34,$70,$00,$71,$00
302   defb  $A0,$21,$A1,$0A,$A2
303   defb  $1A,$A3,$29,$A8,$1F
304   defb  $A9,$08,$AA,$18,$AB
305   defb  $28,$B0,$20,$B1,$09
306   defb  $B2,$19,$B3,$27,$B8
307   defb  $1E,$B9,$07,$BA,$17
308   defb  $BB,$A6,$FF,$C7,$B8
309   defb  $40,$9B,$8B,$41,$AA
310   defb  $FF,$CF,$FD,$42,$3C
311   defb  $4A,$81,$AD,$43,$A2
312   defb  $DA,$4B,$A2,$FF,$E7
313   defb  $40,$46,$95,$FF,$F7
314   defb  $C7,$47,$A2,$7C,$57
315   defb  $A2,$FF,$00
317 ;_______________
319 MONICS:
320   defb  $BF
321   defb  'A','D','C'+$80     ; ADC
322   defb  'A','D','D'+$80     ; ADD
323   defb  'A','N','D'+$80     ; AND
324   defb  'B','I','T'+$80     ; BIT
325   defb  'C','A','L','L'+$80 ; CALL
326   defb  'C','C','F'+$80     ; CCF
327   defb  'C','P','D','R'+$80 ; CPDR
328   defb  'C','P','D'+$80     ; CPD
329   defb  'C','P','I','R'+$80 ; CPIR
330   defb  'C','P','I'+$80     ; CPI
331   defb  'C','P','L'+$80     ; CPL
332   defb  'C','P'+$80       ; CP
333   defb  'D','A','A'+$80     ; DAA
334   defb  'D','E','C'+$80     ; DEC
335   defb  'D','I'+$80       ; DI
336   defb  'D','J','N','Z'+$80 ; DJNZ
337   defb  'E','I'+$80       ; EI
338   defb  'E','X','X'+$80     ; EXX
339   defb  'E','X'+$80       ; EX
340   defb  'H','A','L','T'+$80 ; HALT
341   defb  'I','M'+$80       ; IM
342   defb  'I','N','C'+$80     ; INC
343   defb  'I','N','D','R'+$80 ; INDR
344   defb  'I','N','D'+$80     ; IND
345   defb  'I','N','I','R'+$80 ; INIR
346   defb  'I','N','I'+$80     ; INI
347   defb  'I','N'+$80       ; IN
348   defb  'J','P'+$80       ; JP
349   defb  'J','R'+$80       ; JR
350   defb  'L','D','D','R'+$80 ; LDDR
351   defb  'L','D','D'+$80     ; LDD
352   defb  'L','D','I','R'+$80 ; LDIR
353   defb  'L','D','I'+$80     ; LDI
354   defb  'L','D'+$80       ; LD
355   defb  'N','E','G'+$80     ; NEG
356   defb  'N','O','P'+$80     ; NOP
357   defb  'O','R'+$80       ; OR
358   defb  'O','T','D','R'+$80 ; OTDR
359   defb  'O','T','I','R'+$80 ; OTIR
360   defb  'O','U','T','D'+$80 ; OUTD
361   defb  'O','U','T','I'+$80 ; OUTI
362   defb  'O','U','T'+$80     ; OUT
363   defb  'P','O','P'+$80     ; POP
364   defb  'P','U','S','H'+$80 ; PUSH
365   defb  'R','E','S'+$80     ; RES
366   defb  'R','E','T','I'+$80 ; RETI
367   defb  'R','E','T','N'+$80 ; RETN
368   defb  'R','E','T'+$80     ; RET
369   defb  'R','L','A'+$80     ; RLA
370   defb  'R','L','C','A'+$80 ; RLCA
371   defb  'R','L','C'+$80     ; RLC
372   defb  'R','L','D'+$80     ; RLD
373   defb  'R','L'+$80       ; RL
374   defb  'R','R','A'+$80     ; RRA
375   defb  'R','R','C','A'+$80 ; RA
376   defb  'R','R','C'+$80     ; RRC
377   defb  'R','R','D'+$80     ; RRD
378   defb  'R','R'+$80       ; RR
379   defb  'R','S','T'+$80     ; RST
380   defb  'S','B','C'+$80     ; SBC
381   defb  'S','C','F'+$80     ; SCF
382   defb  'S','E','T'+$80     ; SET
383   defb  'S','L','A'+$80     ; SLA
384   defb  'S','R','A'+$80     ; SRA
385   defb  'S','R','L'+$80     ; SRL
386   defb  'S','U','B'+$80     ; SUB
387   defb  'X','O','R'+$80     ; XOR
391 ;*****************
393 OPRND1:
394   djnz  CONDIT
396 RSTADR:
397   and   $38
398   jr    DA
400 OPRND2:
401   djnz  DAT8
403 RELADR:
404   call  FETCH
405   ld    c,a
406   rla
407   sbc   a,a
408   ld    b,a
409   ex    de,hl
410   push  hl
411   add   hl,bc
412   jr    DHL
414 CONDIT:
415   rra
416   rra
417   rra
418   djnz  BITNUM
420   bit   4,a
421   jr    nz,ABS
423   and   3
425 ABS:
426   and   7
427   add   a,$14
428   jr    PS1
430 DAT8:
431   djnz  DAT16
434   call  FETCH
435   jr    DA
437 BITNUM:
438   djnz  INTMOD
439   and   7
442   ld    c,a
443   sub   a
444   jr    DAC
446 DAT16:
447   djnz  EXAF
449 D16:
450   call  FETCH
451   ld    c,a
452   call  FETCH
454 DAC:
455   ex    de,hl
456   push  hl
457   ld    h,a
458   ld    l,c
460 DHL:
461   push  hl
462   $IF !DISASM_USE_HEX_PREFIX
463   ld    c,$F8
464   $ELSE
465   or    a
466   $ENDIF
467   call  CONVHL
468   pop   hl
469   ld    bc,$000A
470   or    a
471   sbc   hl,bc
472   pop   hl
473   ex    de,hl
474   $IF !DISASM_USE_HEX_PREFIX
475   ret   c
477   ; hex suffix
478   ld    (hl),'H'
479   inc   hl
480   $ENDIF
481   ret
483 INTMOD:
484   djnz  STKTOP
485   and   3
486   add   a,$1C
488 PS1:
489   jr    PS3
491 STKTOP:
492   ld    c,$13
493   dec   b
494   jr    z,PS2
496 REG16P:
497   djnz  COMMON
498   rra
499   and   3
500   cp    3
501   jr    nz,RX
503   dec   a
504   jr    RNX
506 EXAF:
507   ld    c,$0A
508   dec   b
509   jr    z,PS2
511 EXDE:
512   inc   c
513   dec   b
514   jr    z,PS2
516 REG8S:
517   djnz  ACCUM
520   and   7
521   cp    6
522   jr    nz,PS3
524   ld    (hl),'('
525   inc   hl
526   call  REGX
527   ld    a,(ix+2)
528   or    a
529   jr    z,RP
531   ld    (hl),43     ;+
532   rlca
533   rrca
534   jr    nc,POS
536   ld    (hl),45     ;-
537   neg
539 POS:
540   inc   hl
541   ex    de,hl
542   push  hl
543   ld    h,b
544   ld    l,a
545   $IF DISASM_USE_HEX_PREFIX
546   ld    c,$FB
547   else
548   scf
549   $ENDIF
550   call  CONVHL
551   pop   hl
552   ex    de,hl
553   jr    RP
555 ACCUM:
556   rra
557   rra
558   rra
560 COMMON:
561   ld    c,7
562   dec   b
563   jr    z,PS2
565 PORTC:
566   dec   c
567   djnz  IDAT8
569 PS2:
570   ld    a,c
571 PS3:
572   jr    PS4
574 IDAT8:
575   djnz  IDAT16
576   ld    (hl),'('
577   inc   hl
578   call  D8
579   jr    RP
581 IDAT16:
582   djnz  REG8
583   ld    (hl),'('
584   inc   hl
585   call  D16
586   jr    RP
588 REG8:
589   dec   b
590   jr    z,R8
592 IPAREF:
593   djnz  REG16
594   and   9
595   jr    PS4
597 REG16:
598   rra
599   djnz  IREG16
601 R16:
602   and   3
604   cp    2
605   jr    z,REGX
607 RNX:
608   add   a,$0C
609   jr    PS4
611 IREG16:
612   djnz  REGX
613   ld    (hl),'('
614   inc   hl
615   call  R16
618   ld    (hl),')'
619   inc   hl
620   ret
622 REGX:
623   ld    a,(ix+1)
624   add   a,$10
626 PS4:
627   ex    de,hl
628   push  hl
629   ld    hl,RGSTRS
630   call  XTRACT
631   pop   hl
632   ex    de,hl
633   ret
635 ;*************
637 RGSTRS:
638   defb  'B'       +$80
639   defb  'C'             +$80
640   defb  'D'             +$80
641   defb  'E'             +$80
642   defb  'H'             +$80
643   defb  'L'             +$80
644   defb  '(','C',')'       +$80
645   defb  'A'             +$80
646   defb  'I'             +$80
647   defb  'R'             +$80
648   defb  'A','F',',','A','F','\''    +$80
649   defb  'D','E',',','H','L'       +$80
650   defb  'B','C'                 +$80
651   defb  'D','E'                 +$80
652   defb  'A','F'                 +$80
653   defb  'S','P'                 +$80
654   defb  'H','L'                 +$80
655   defb  'I','X'                 +$80
656   defb  'I','Y'                 +$80
657   defb  '(','S','P',')'           +$80
658   defb  'N','Z'                 +$80
659   defb  'Z'                   +$80
660   defb  'N','C'                 +$80
661   defb  'C'                   +$80
662   defb  'P','O'                 +$80
663   defb  'P','E'                 +$80
664   defb  'P'                   +$80
665   defb  'M'                   +$80
666   defb  '0'           +$80
667   defb  '?'           +$80
668   defb  '1'           +$80
669   defb  '2'           +$80
671 ;********************
673 CONVHL:
674 $IF !DISASM_USE_HEX_PREFIX
675   sub   a
677 CVHL1:
678   push  af
679   sub   a
680   ld    b,16
682 CVHL2:
683   add   a,c
684   jr    c,CVHL3
685   sub   c
687 CVHL3:
688   adc   hl,hl
689   rla
690   djnz  CVHL2
692   jr    nz,CVHL1
694   cp    10
695   inc   b
696   jr    nc,CVHL1
698 CVHL4:
699   cp  10
700   sbc   a,$69
701   daa
702   ld    (de),a
703   inc   de
704   pop   af
705   jr    nz,CVHL4
707   ret
708 $ELSE
709   ld    a,'#'
710   ld    (de),a
711   inc   de
712   jr    c,.CVHL_BYTE
714   ld    a,h
715   call  .print_byte
717 .CVHL_BYTE:
718   ld    a,l
720 .print_byte:
721   push  af
722   rrca
723   rrca
724   rrca
725   rrca
726   call  .print_nibble
727   pop   af
728 .print_nibble:
729 ; convert nibble (low 4 bits of A) to hexadecimal digit
730 ; IN: A: nibble
731 ; OUT: A: digit ready to print
732   and   a,#0F
733   cp    a,10
734   sbc   a,#69
735   daa
736   ld    (de),a
737   inc   de
738   ret
739 $ENDIF
741 ;****************
743 $IF DISASM_EINAR_OPTIMISATION
744 SKIP:
745   bit   7,(hl)
746   inc   hl
747   jr    z,SKIP
748   dec   a
749 XTRACT:
750   or    a
751   jr    nz,SKIP
753 $ELSE
755 XTRACT:
756   or    a
757   jr    z,COPY
758 SKIP:
759   bit   7,(hl)
760   inc   hl
761   jr    z,SKIP
762   dec   a
763   jr    nz,SKIP
764 $ENDIF
766 COPY:
767   ld    a,(hl)
768   rlca
769   srl   a
770   ld    (de),a
772   inc   de
773   inc   hl
774   jr    nc,COPY
776   ret
778 ;*******************
780 FETCH:
781   ld    a,(de)
782   inc   de
783   inc   (ix+0)
784   $IF @DISZ80_DUMP_CODE
785   push  af
786   call  BYTSP
787   pop   af
788   $ENDIF
789   ret
791   $IF @DISZ80_DUMP_ADDRESS
792 ADRSP:
793   ld    a,d
794   call  BYTOP
795   ld    a,e
796   $ENDIF
798   $IF @DISZ80_DUMP_ADDRESS || @DISZ80_DUMP_CODE
799 BYTSP:
800   call  BYTOP
801   ld    a,$20
802   jp    CHROP
804 BYTOP:
805   push  af
806   rra
807   rra
808   rra
809   rra
810   call  HEXOP
811   pop   af
813 HEXOP:
814   and   $0F
815   cp    10
816   sbc   a,$69
817   daa
818   jp    CHROP
819   $ENDIF
820 ; -----------------------------------
821 ; End of John Kerr's DIS-Z80 routine.
822 ; -------------------------------------
823 dissizest = $-dissizest
824 $printf "disasm size: %d bytes", dissizest
825 dissizest = -1  ; so it won't clutter symbol table
827   ENDMODULE DISZ80