more samples
[bz80asm.git] / bzasm80.zas
blob9584b1a6de1df1e889a65cc2bd03d4a9384bf3bf
1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2 ;; Z80 assembler, based on the code from BBC Basic for Z80
3 ;; original code was written by R.T.Russell
4 ;; the original license:
5 ;;
6 ;; Copyright (c) 1984-2000 R.T. Russell
7 ;;
8 ;; This software is provided 'as-is', without any express or implied
9 ;; warranty. In no event will the authors be held liable for any damages
10 ;; arising from the use of this software.
12 ;; Permission is granted to anyone to use this software for any purpose,
13 ;; including commercial applications, and to alter it and redistribute it
14 ;; freely, subject to the following restrictions:
16 ;; 1. The origin of this software must not be misrepresented; you must not
17 ;;    claim that you wrote the original software. If you use this software
18 ;;    in a product, an acknowledgment in the product documentation would be
19 ;;    appreciated but is not required.
20 ;; 2. Altered source versions must be plainly marked as such, and must not be
21 ;;    misrepresented as being the original software.
22 ;; 3. This notice may not be removed or altered from any source distribution.
24 ;; modifications, cleanups, etc. by Ketmar Dark // Invisible Vector
26 ; define this if you want ORG/ENT/DISP
27 IF !defined(BZ80ASM_ORGENTDISP)
28 BZ80ASM_ORGENTDISP equ 0
29 ENDIF
31   MODULE BZ80ASM
33 PC: defw #C000  ; logical program counter for the code
35 IF @BZ80ASM_ORGENTDISP
36 ; ORG/DISP sets this to its value
37 NEW_ORGENT: defw 0
38 ; ORG/ENT sets this to the corresponding type
39 ; it is reset at each call to ASSEM
40 ORGENT_NONE equ 0
41 ORGENT_ORG equ 1
42 ORGENT_DISP equ 2
43 ORGENT_ENT equ 3
44 ORGENT_TYPE: defw ORGENT_NONE
45 ENDIF
47 ; address of the routine that will be called if JR/DJNZ destination is too far away
48 ; you can simply RET from it if you want to ignore this error
49 ; note that stack is filled with garbage, so use `ASM_ERROR_EXIT` to bail out
50 ; this is not checked for zero, so if you will not init this, "CALL 0" will be executed
51 ; ret L to the byte that will be put on normal return
52 ASM_JR_TOO_FAR_CB: defw 0
54 ; on entry, ASSEM will store SP here
55 ; you can use this to reset the stack, and use RET to return to the caller
56 ; or simply use ASM_ERROR_EXIT (which will set carry too)
57 ASM_SP0: defw 0
59 ; ASSEM sets this if it hits mnemonics without a handler
60 ; you can add your own mnemonics to the assembler, and it
61 ; will set this to non-zero if it hits them
62 ; use this byte as decrementing counter, like this:
63 ;  jr    nc,no_error
64 ;  ld    a,(ASM_BAD_B)
65 ;  or    a
66 ;  jr    z,syntax_error
67 ;  ld    b,a
68 ;  djnz  not_first_one
69 ;    handle first instruction
70 ;  not_first_one:
71 ;  djnz  not_second_one
72 ;    handle second instruction
73 ;  ...and so on
74 ; ADDITIONALLY, this will be set to #FF on invalid token
75 ; this can be used to process labels (because otherwise
76 ; there is no way to tell if we got some bad operands, or
77 ; an unknown mnemonics)
78 ASM_BAD_B: defw 0
80 ; string terminator
81 CR equ 13
84 csizestart = $
85 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
86 ;; ASSEMBLER:
87 ;; LANGUAGE-INDEPENDENT CONTROL SECTION:
88 ;;  Inputs:
89 ;;    IY: text buffer
90 ;;    IX: destination to put generated code at
91 ;;  Outputs:
92 ;;    A: delimiter
93 ;;    IY: delimiter position in text buffer
94 ;;    IX: points right after the generated code
95 ;;    carry set if syntax error (and A is undefined in this case)
96 ;;    others are dead (including extra register set and extra accum/flags)
98 ASSEM:
99   ; reset org/ent type
100   xor   a
101   IF @BZ80ASM_ORGENTDISP
102   ld    (ORGENT_TYPE),a
103   ENDIF
104   ld    (ASM_BAD_B),a
105   ld    (ASM_SP0),sp
106 ASSEM1:
107   call  SKIP
108   inc   iy
109   cp    ':'
110   jr    z,ASSEM1
111   ; this was used to terminate assembler section in BBC Basic
112   ;cp    ']'
113   ;ret   z
114   cp    CR
115   ret   z
116   dec   iy
117   push  ix
118   ;push  iy
119   call  ASMB
120   ;pop   bc
121   pop   de
122   ; exit if syntax error
123   ret   c
124   ; skip delimiters (but not terminators)
125   call  SKIP
126   ; exit with error flag if we're not at a terminator
127   scf
128   ret   nz
129   ; advance PC
130   push  ix
131   pop   hl
132   or    a
133   sbc   hl,de
134   ex    de,hl           ;DE= NO. OF BYTES
135   ld    hl,(PC)
136   add   hl,de
137   ld    (PC),hl         ;UPDATE PC
138   ; reset carry and Z
139   xor   a
140   ret
142 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
144 ;; jump here to restore stack, and exit with error (carry set)
146 ASM_ERROR_EXIT:
147   ld    sp,(ASM_SP0)
148   scf
149   ret
151 ASMB_BAD_MNEMO:
152   ld    a,255
153   ld    (ASM_BAD_B),a
154   ; carry is still set
155   ret
157 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
159 ;; PROCESSOR-SPECIFIC TRANSLATION SECTION:
161 ;; REGISTER USAGE: B - TYPE OF MOST RECENT OPERAND
162 ;;                 C - OPCODE BEING BUILT
163 ;;                 D - (IX) OR (IY) FLAG
164 ;;                 E - OFFSET FROM IX OR IY
165 ;;                HL - NUMERIC OPERAND VALUE
166 ;;                IX - CODE DESTINATION
167 ;;                IY - SOURCE TEXT POINTER
168 ;;    Inputs: A = initial character
169 ;;   Outputs: Carry set if syntax error.
171 ASMB:
172   cp    '.'
173   jr    nz,ASMB1
174   ; skip dot
175   inc   iy
176   ld    hl,(PC)
177   call  @DEFLABEL
178   ; done with the label
179 ASMB1:
180   call  SKIP
181   ret   z
182   ; this code seems to be for tokenized input
183   ; we don't have tokenizer
184   ;cp    TCALL
185   ;ld    c,0C4H
186   ;inc   iy
187   ;jp    z,GRPC
188   ;dec   iy
189   ld    hl,OPCODS
190   call  FIND
191   ; carry flag set on error
192   jr    c,ASMB_BAD_MNEMO
193   ; A contains token index
194   ; B contains token data byte
195   ld    c,b     ;ROOT OPCODE
196   ld    d,0     ;CLEAR IX/IY FLAG
198   ; now:
199   ; A contains token index
200   ; C contains token data byte
201   ; D contains IX/IY flag
203 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
205 ;; GROUP 0 - TRIVIAL CASES REQUIRING NO COMPUTATION
206 ;; GROUP 1 - AS GROUP 0 BUT WITH "ED" PREFIX
208   sub   OPC_COUNT_GROUPS_0_AND_1
209   jr    nc,GROUP2
210   cp    OPC_COUNT_GROUP_0-OPC_COUNT_GROUPS_0_AND_1
211   call  nc,EDX
212   jr    BYTE0
214 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
216 ;; GROUP 2 - BIT, RES, SET
217 ;; GROUP 3 - RLC, RRC, RL, RR, SLA, SRA, SRL
219 GROUP2:
220   sub   OPC_COUNT_GROUPS_2_AND_3
221   jr    nc,GROUP4
222   cp    OPC_COUNT_GROUP_2-OPC_COUNT_GROUPS_2_AND_3
223   call  c,CBIT
224   ret   c
225   call  REGLO
226   ret   c
227   call  CBX
228   jr    BYTE0
230 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
232 ;; GROUP 4 - PUSH, POP, EX (SP)
234 GROUP4:
235   sub   OPC_COUNT_GROUP_4
236   jr    nc,GROUP5
238   call  PAIR
239   ret   c
240   jr    BYTE0
242 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
244 ;; GROUP 5 - SUB, AND, XOR, OR, CP
245 ;; GROUP 6 - ADD, ADC, SBC
247 GROUP5:
248   sub   OPC_COUNT_GROUPS_5_AND_6
249   jr    nc,GROUP7
250   cp    OPC_COUNT_GROUP_5-OPC_COUNT_GROUPS_5_AND_6
251   ld    b,7
252   call  nc,OPND
253   ld    a,b
254   cp    7
255   jr    nz,G6HL
257   call  REGLO
258   ld    a,c
259   jr    nc,BIND1
260   xor   46H
261   call  BIND
262 DBX:
263   call  NUMBER
264   jr    VAL8
266 G6HL:
267   and   3FH
268   cp    12
269   scf
270   ret   nz
271   ld    a,c
272   cp    80H
273   ld    c,9
274   jr    z,G4
275   xor   1CH
276   rrca
277   ld    c,a
278   call  EDX
279   jr    G4
281 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
283 ;; GROUP 7 - INC, DEC
285 GROUP7:
286   sub   OPC_COUNT_GROUP_7
287   jr    nc,GROUP8
288   call  REGHI
289   ld    a,c
290 BIND1:
291   jp    nc,BIND
292   xor   64H
293   rlca
294   rlca
295   rlca
296   ld    c,a
297   call  PAIR1
298   ret   c
299 BYTE0:
300   ld    a,c
301   jr    BYTE2
303 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
305 ;; GROUP 8 - IN
306 ;; GROUP 9 - OUT
308 GROUP8:
309   sub   OPC_COUNT_GROUPS_8_AND_9
310   jr    nc,GROUPA
311   cp    OPC_COUNT_GROUP_8-OPC_COUNT_GROUPS_8_AND_9
312   call  z,CORN
313   ex    af,af'
314   call  REGHI
315   ret   c
316   ex    af,af'
317   call  c,CORN
318   inc   h
319   jr    z,BYTE0
320   ld    a,b
321   cp    7
322   scf
323   ret   nz
324   ld    a,c
325   xor   3
326   rlca
327   rlca
328   rlca
329   call  BYTE
330   jr    VAL8
332 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
334 ;; GROUP 10 - JR, DJNZ
336 GROUPA:
337   sub   OPC_COUNT_GROUP_10
338   jr    nc,GROUPB
339   cp    OPC_COUNT_GROUP_10_JRS-OPC_COUNT_GROUP_10
340   call  nz,COND
341   ld    a,c
342   jr    nc,GRPA
343   ld    a,18H
344 GRPA:
345   call  BYTE
346   call  NUMBER
347   ld    de,(PC)
348   inc   de
349   scf
350   sbc   hl,de
351   ld    a,l
352   rla
353   sbc   a,a
354   cp    h
355 TOOFAR:
356   call  nz,JR_TOO_FAR
357 VAL8:
358   ld    a,l
359   jr    BYTE2
361 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
363 ;; GROUP 11 - JP
365 GROUPB:
366   ld    b,a
367   jr    nz,GROUPC
368   call  COND
369   ld    a,c
370   jr    nc,GRPB
371   ld    a,b
372   and   3FH
373   cp    6
374   ld    a,0E9H
375   jr    z,BYTE2
376   ld    a,0C3H
377 GRPB:
378   call  BYTE
379   jr    ADDR
381 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
383 ;; GROUP 12 - CALL
385 GROUPC:
386   djnz  GROUPD
387 GRPC:
388   call  GRPE
389 ADDR:
390   call  NUMBER
391 VAL16:
392   call  VAL8
393   ld    a,h
394   jr    BYTE2
396 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
398 ;; GROUP 13 - RST
400 GROUPD:
401   djnz  GROUPE
402   call  NUMBER
403   and   c
404   or    h
405   jr    nz,TOOFAR
406   ld    a,l
407   or    c
408 BYTE2:
409   jr    BYTE1
411 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
413 ;; GROUP 14 - RET
415 GROUPE:
416   djnz  GROUPF
417 GRPE:
418   call  COND
419   ld    a,c
420   jr    nc,BYTE1
421   or    9
422   jr    BYTE1
424 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
426 ;; GROUP 15 - LD
428 GROUPF:
429   djnz  MISC
430   call  LDOP
431   jr    nc,LDA
432   call  REGHI
433   ex    af,af'
434   call  SKIP
435   cp    '('
436   jr    z,LDIN
437   ex    af,af'
438   jp    nc,G6
439   ld    c,1
440   call  PAIR1
441   ret   c
442   ld    a,14
443   cp    b
444   ld    b,a
445   call  z,PAIR
446   ld    a,b
447   and   3FH
448   cp    12
449   ld    a,c
450   jr    nz,GRPB
451   ld    a,0F9H
452   jr    BYTE1
453   ;
454 LDIN:
455   ex    af,af'
456   push  bc
457   call  nc,REGLO
458   ld    a,c
459   pop   bc
460   jr    nc,BIND
461   ld    c,0AH
462   call  PAIR1
463   call  LD16
464   jr    nc,GRPB
465   call  NUMBER
466   ld    c,2
467   call  PAIR
468   call  LD16
469   ret   c
470   call  BYTE
471   jr    VAL16
473 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
474 ;; misc. instructions
475 MISC:
476   jp    MISC_DEFB
479 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
481 ;; SUBROUTINES
484 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
486 JR_TOO_FAR:
487   ld    hl,(ASM_JR_TOO_FAR_CB)
488   jp    (hl)
490 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
492 LDA:
493   cp    4
494   call  c,EDX
495   ld    a,b
496 BYTE1:
497   jr    BYTE
499 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
501 LD16:
502   ld    a,b
503   jr    c,LD8
504   ld    a,b
505   and   3FH
506   cp    12
507   ld    a,c
508   ret   z
509   call  EDX
510   ld    a,c
511   or    43H
512   ret
514 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
516 LD8:
517   cp    7
518   scf
519   ret   nz
520   ld    a,c
521   or    30H
522   ret
524 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
526 CORN:
527   push  bc
528   call  OPND
529   bit   5,b
530   pop   bc
531   jr    z,NUMBER
532   ld    h,-1
533 EDX:
534   ld    a,0EDH
535   jr    BYTE
537 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
539 CBX:
540   ld    a,0CBH
541 BIND:
542   cp    76H
543   scf
544   ret   z               ;REJECT LD (HL),(HL)
545   call  BYTE
546   inc   d
547   ret   p
548   ld    a,e
549   jr    BYTE
551 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
553 OPND:
554   push  hl
555   ld    hl,OPRNDS
556   call  FIND
557   pop   hl
558   ret   c
559   bit   7,b
560   ret   z
561   bit   3,b
562   push  hl
563   call  z,OFFSET
564   ld    e,l
565   pop   hl
566   ld    a,0DDH
567   bit   6,b
568   jr    z,OP1
569   ld    a,0FDH
570 OP1:
571   or    a
572   inc   d
573   ld    d,a
574   ret   m
575 BYTE:
576   ld    (ix),a
577   inc   ix
578   or    a
579   ret
581 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
583 OFFSET:
584   ld    a,(iy)
585   cp    ')'
586   ld    hl,0
587   ret   z
589 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
590 ;; parse numeric expression
591 NUMBER:
592   call  SKIP
593   push  bc
594   push  de
595   push  ix
596   call  @PARSE_INT_EXPR
597   ; HL: expression value
598   pop   ix
599   pop   de
600   pop   bc
601   ld    a,l
602   or    a
603   ret
605 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
607 REG:
608   call  OPND
609   ret   c
610   ld    a,b
611   and   3FH
612   cp    8
613   ccf
614   ret
616 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
618 REGLO:
619   call  REG
620   ret   c
621   jr    ORC
623 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
625 REGHI:
626   call  REG
627   ret   c
628   jr    SHL3
630 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
632 COND:
633   call  OPND
634   ret   c
635   ld    a,b
636   and   1FH
637   sub   16
638   jr    nc,SHL3
639   cp    -15
640   scf
641   ret   nz
642   ld    a,3
643   jr    SHL3
645 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
647 PAIR:
648   call  OPND
649   ret   c
650 PAIR1:
651   ld    a,b
652   and   0FH
653   sub   8
654   ret   c
655   jr    SHL3
657 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
659 CBIT:
660   call  NUMBER
661   cp    8
662   ccf
663   ret   c
664 SHL3:
665   rlca
666   rlca
667   rlca
668 ORC:
669   or    c
670   ld    c,a
671   ret
674 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
676 ;; common defb/defw code
677 ;;   carry set if we want words
679 COM_DEFBW:
680   push  af
681   push  ix
682   call  @PARSE_INT_EXPR
683   pop   ix
684   ; HL: value
685   ld    (ix),l
686   inc   ix
687   pop   af
688   jr    nc,COM_DEFBW_BYTE
689   ld    (ix),h
690   inc   ix
691 COM_DEFBW_BYTE:
692   ex    af,af'
693   ; check for comma
694   call  SKIP
695   ret   z
696   ex    af,af'
697   jr    COM_DEFBW
699 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
701 ;; DEFB
703 MISC_DEFB:
704   djnz  MISC_DEFW
705 DEFB_LOOP:
706   or    a
707   jr    COM_DEFBW
709 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
711 ;; DEFW
713 MISC_DEFW:
714   djnz  MISC_DEFM
715 DEFW_LOOP:
716   scf
717   jr    COM_DEFBW
719 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
721 ;; DEFM
723 MISC_DEFM:
724   djnz  MISC_ORG
725 DEFM_LOOP:
726   push  ix
727   call  @PARSE_STR_EXPR
728   pop   ix
729   ; HL: buffer address
730   ;  E: buffer length
731   xor   a
732   cp    e
733   jr    z,DEFM1_DONE_ONE
734 DEFM1:
735   ld    a,(hl)
736   inc   hl
737   call  BYTE
738   dec   e
739   jr    nz,DEFM1
740 DEFM1_DONE_ONE:
741   ; check for comma
742   call  SKIP
743   ret   z
744   jr    DEFM_LOOP
746 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
748 ;; ORG
750 MISC_ORG:
751   IF @BZ80ASM_ORGENTDISP
752   djnz  MISC_DISP
753   ld    a,ORGENT_ORG
754 COM_ORGENT:
755   ld    (ORGENT_TYPE),a
756   call  NUMBER
757   ld    (NEW_ORGENT),hl
758   or    a
759   ret
761 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
763 ;; DISP
765 MISC_DISP:
766   djnz  MISC_ENT
767   ld    a,ORGENT_DISP
768   jr    COM_ORGENT
770 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
772 ;; ENT
774 MISC_ENT:
775   djnz  MISC_WTF
776   ld    a,ORGENT_ENT
777   jr    COM_ORGENT
779 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
781 ;; error (the thing that should not be)
783 MISC_WTF:
784   ENDIF
785   ; set "unknown instruction index"
786   ; b may be zero here
787   ld    a,b
788   inc   a
789   ld    (ASM_BAD_B),a
790   scf
791   ret
794 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
795 ;; search the table for a token from the input buffer
796 ;; skips leading delimiters, and the token itself (if found)
797 ;; tokens in the table must have bit 7 set on the last char
798 ;; table ends with zero byte instead of first token char
799 ;; each token is followed by a data byte
800 ;; IN:
801 ;;   IY: text buffer
802 ;; OUT:
803 ;;   IY: new position in the text buffer
804 ;;    A: token number
805 ;;    B: token data byte
806 ;;   carry flag set on error (invalid char, or token not found)
807 ;;   on error, delimiters are still skipped
809 LDOP:
810   ld    hl,LDOPS
811 ; main table search entry point
812 FIND:
813   call  SKIP
814 EXIT:
815   ld    b,0
816   scf
817   ret   z
818   ; reject chars with high bit set
819   cp    128
820   ccf
821   ret   c
823 FIND0:
824   ; check the first char
825   ld    a,(hl)
826   or    a
827   jr    z,EXIT
828   xor   (iy)
829   and   %01011111   ; for case-insensitivity
830   jr    z,FIND2
831   ; first char is not matched, skip this token
832 FIND1:
833   bit   7,(hl)
834   inc   hl
835   jr    z,FIND1
836   ; skip token data byte
837   inc   hl
838   ; increment token counter
839   inc   b
840   jr    FIND0
842   ; first char matched, check the rest
843   ; A holds zero (due to xor/and)
844 FIND2:
845   push  iy
846 FIND3:
847   ; last token char?
848   bit   7,(hl)
849   inc   iy
850   inc   hl
851   jr    nz,FIND5
852   ; not the last token char
853   ; this compares (HL) with 0, because
854   ; A is guaranteed to hold zero here
855   cp    (hl)
856   ; zero byte in token means "skip delimiters"
857   ; it is used in some opcodes with fixed operands
858   call  z,SKIP0
859   ; load token char
860   ld    a,(hl)
861   ; compare with input char
862   xor   (iy)
863   and   %01011111   ; for case-insensitivity
864   jr    z,FIND3
866   ; alas, doesn't match
867 FIND4:
868   ; restore input stream pointer
869   pop   iy
870   ; and skip this token
871   jr    FIND1
873   ; we'll come here if we succesfully matched a token
874 FIND5:
875   ; if it isn't followed by a delimiter, '+' or '-', this is not a valid token
876   call  DELIM
877   call  nz,SIGN
878   jr    nz,FIND4
880   ; this token is valid
881 FIND6:
882   ; move token index to A
883   ld    a,b
884   ; load B with token data byte
885   ld    b,(hl)
886   ; drop original input stream position
887   pop   hl
888   ; we're done here
889   ; note that carry flag is guaranteed to be reset
890   ret
893 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
894 ;; used by FIND
895 SIGN:
896   cp    '+'
897   ret   z
898   cp    '-'
899   ret
901 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
902 ;; this entry point is used by FIND
903 SKIP0:
904   inc   hl
905 ;; this entry point is used to skip blanks and delimiters
906 ;; note that comma and right paren are considered blanks too
907 ;; as a consequence, operands may be delimited by spaces, or
908 ;; right parens, lol
909 ;; returns current char in A (and IY pointing to it)
910 ;; zero flag set if we hit a terminator
911 ;; zero flag reset if we hit a non-delimiter
912 SKIP:
913   ; delimiter or terminator?
914   call  DELIM
915   ret   nz
916   ; if this is terminator, still stop
917   call  TERM
918   ret   z
919   ; this is delimiter, skip it
920   inc   iy
921   jr    SKIP
923 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
924 ;; used by FIND and SKIP
925 ;; check if the current char is a delimiter or a terminator
926 ;; zero flag set on delimiter/terminator
927 DELIM:
928   ld    a,(iy)          ;ASSEMBLER DELIMITER
929   cp    ' '
930   ret   z
931   cp    ','
932   ret   z
933   cp    ')'
934   ret   z
936 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
937 ;; entry point for SKIP
938 TERM:
939   cp    ';'             ;ASSEMBLER TERMINATOR
940   ret   z
941   ;cp    '\'
942   ;ret   z
944 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
945 ;; also used by assembler to check for command separator
946 ;; the assembler itself does nothing with separators
947 ASM_IS_SEP:
948   cp    ':'             ;ASSEMBLER SEPARATOR
949   ret   nc
950   cp    CR
951   ret
953 csizeend = $
954 $printf "assembler size: %d", csizeend-csizestart
956 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
957 ;; various tables -- mnemonics, operands...
959 csizestart = $
961 ;; number of "trivial" opcodes without any special processing
962 OPC_COUNT_GROUPS_0_AND_1 equ 39
963 ;; number of non-ED-prefixed instructions in "trivial"
964 OPC_COUNT_GROUP_0 equ 15
966 ;; total number of CB-prefixed instructions (GROUPS 2 and 3)
967 OPC_COUNT_GROUPS_2_AND_3 equ 10
968 ;; number of direct bit manipulation instructions in CB list (GROUP 2)
969 OPC_COUNT_GROUP_2 equ 3
971 ;; push, pop, ex (sp),rr
972 OPC_COUNT_GROUP_4 equ 3
974 ;; ALU with accum
975 OPC_COUNT_GROUP_5 equ 5
976 ;; ALU with accum
977 OPC_COUNT_GROUP_6 equ 3
978 ;; GROUPS 5 and 6
979 OPC_COUNT_GROUPS_5_AND_6 equ OPC_COUNT_GROUP_5+OPC_COUNT_GROUP_6
981 ;; INC/DEC
982 OPC_COUNT_GROUP_7 equ 2
984 ;; IN
985 OPC_COUNT_GROUP_8 equ 1
986 ;; OUT
987 OPC_COUNT_GROUP_9 equ 1
988 ;; GROUPS 8 and 9
989 OPC_COUNT_GROUPS_8_AND_9 equ OPC_COUNT_GROUP_8+OPC_COUNT_GROUP_9
991 ; JR,DJNZ
992 OPC_COUNT_GROUP_10 equ 2
993 OPC_COUNT_GROUP_10_JRS equ 1
996 ;; WARNING! the assembler has some hard-coded mnemonics counts
997 ;;          scattered across the code, so don't mess with the tables!
998 ;;          i may document this in the future, but for now, leave it as it is.
999 ;; mnemonics
1000 OPCODS:
1001   ; GROUPS 0 AND 1: "trivial" (39, OPC_COUNT_GROUPS_0_AND_1)
1002   ; GROUP 0: "trivial" one-byte (15, OPC_COUNT_GROUP_0)
1003   defx  "NOP"
1004   defb  0
1005   defx  "RLCA"
1006   defb  7
1007   defm  "EX",0,"AF",0
1008     defx "AF'"
1009   defb  8
1010   defx  "RRCA"
1011   defb  #0F
1012   defx  "RLA"
1013   defb  #17
1014   defx  "RRA"
1015   defb  #1F
1016   defx  "DAA"
1017   defb  #27
1018   defx  "CPL"
1019   defb  #2F
1020   defx  "SCF"
1021   defb  #37
1022   defx  "CCF"
1023   defb  #3F
1024   defx  "HALT"
1025   defb  #76
1026   defx  "EXX"
1027   defb  #D9
1028   defm  "EX",0,"DE",0
1029     defx "HL"
1030   defb  #EB
1031   defx  "DI"
1032   defb  #F3
1033   defx  "EI"
1034   defb  #FB
1035   ; GROUP 1: "trivial" ED-prefixed (24, OPC_COUNT_GROUPS_0_AND_1-OPC_COUNT_GROUP_0)
1036   defx  "NEG"
1037   defb  #44
1038   defm  "IM",0
1039     defx  "0"
1040   defb  #46
1041   defx  "RETN"
1042   defb  #45
1043   defx  "RETI"
1044   defb  #4D
1045   defm  "IM",0
1046     defx  "1"
1047   defb  #56
1048   defm  "IM",0
1049     defx  "2"
1050   defb  #5E
1051   defx  "RRD"
1052   defb  #67
1053   defx  "RLD"
1054   defb  #6F
1055   defx  "LDI"
1056   defb  #A0
1057   defx  "CPI"
1058   defb  #A1
1059   defx  "INI"
1060   defb  #A2
1061   defx  "OUTI"
1062   defb  #A3
1063   defx  "LDD"
1064   defb  #A8
1065   defx  "CPD"
1066   defb  #A9
1067   defx  "IND"
1068   defb  #AA
1069   defx  "OUTD"
1070   defb  #AB
1071   defx  "LDIR"
1072   defb  #B0
1073   defx  "CPIR"
1074   defb  #B1
1075   defx  "INIR"
1076   defb  #B2
1077   defx  "OTIR"
1078   defb  #B3
1079   defx  "LDDR"
1080   defb  #B8
1081   defx  "CPDR"
1082   defb  #B9
1083   defx  "INDR"
1084   defb  #BA
1085   defx  "OTDR"
1086   defb  #BB
1088   ; GROUPS 2 AND 3: CB-prefixed (10, OPC_COUNT_GROUPS_2_AND_3)
1089   ; GROUP 2: direct bit manipulation (3, OPC_COUNT_GROUP_2)
1090   defx  "BIT"
1091   defb  #40
1092   defx  "RES"
1093   defb  #80
1094   defx  "SET"
1095   defb  #C0
1096   ; GROUP 3: shifts (7, OPC_COUNT_GROUPS_2_AND_3-OPC_COUNT_GROUP_2)
1097   defx  "RLC"
1098   defb  0
1099   defx  "RRC"
1100   defb  8
1101   defx  "RL"
1102   defb  #10
1103   defx  "RR"
1104   defb  #18
1105   defx  "SLA"
1106   defb  #20
1107   defx  "SRA"
1108   defb  #28
1109   defx  "SRL"
1110   defb  #38
1112   ; GROUP 4: push,pop,ex (sp),rr (OPC_COUNT_GROUP_4)
1113   defx  "POP"
1114   defb  #C1
1115   defx  "PUSH"
1116   defb  #C5
1117   defm  "EX",0
1118     defx  "(SP"
1119   defb  #E3
1121   ; GROUP 5: ALU with accumulator (OPC_COUNT_GROUP_5)
1122   defx  "SUB"
1123   defb  #90
1124   defx  "AND"
1125   defb  #A0
1126   defx  "XOR"
1127   defb  #A8
1128   defx  "OR"
1129   defb  #B0
1130   defx  "CP"
1131   defb  #B8
1132   ;k8: for some reason i cannot remove those two
1133   ;defb  TAND
1134   ;defb  #A0
1135   ;defb  TOR
1136   ;defb  #B0
1138   ; GROUP 6: ALU with accumulator or HL (OPC_COUNT_GROUP_6)
1139   defx  "ADD"
1140   defb  #80
1141   defx  "ADC"
1142   defb  #88
1143   defx  "SBC"
1144   defb  #98
1146   ; GROUP 7: inc,dec (2, OPC_COUNT_GROUP_7)
1147   defx  "INC"
1148   defb  4
1149   defx  "DEC"
1150   defb  5
1152   ; GROUP 8: in (1, OPC_COUNT_GROUP_8)
1153   defx  "IN"
1154   defb  #40
1155   ; GROUP 9: out (1, OPC_COUNT_GROUP_9)
1156   defx  "OUT"
1157   defb  #41
1159   ; GROUP 10: jr,djnz (2, OPC_COUNT_GROUP_10)
1160   defx  "JR"
1161   defb  #20
1162   defx  "DJNZ"
1163   defb  #10
1165   ; GROUP 11: jp (strictly one)
1166   defx  "JP"
1167   defb  #C2
1169   ; GROUP 12: call (strictly one)
1170   defx  "CALL"
1171   defb  #C4
1173   ; GROUP 13: rst (strictly one)
1174   defx  "RST"
1175   defb  #C7
1177   ; GROUP 14: ret (strictly one)
1178   defx  "RET"
1179   defb  #C0
1181   ; GROUP 15: ld (strictly one)
1182   defx  "LD"
1183   defb  #40
1185   ; miscellaneous assembler instructions
1186   ; WARNING! the order matters!
1187   defx  "DEFB"
1188   defb  0
1189   ;
1190   defx  "DEFW"
1191   defb  0
1192   ;
1193   defx  "DEFM"
1194   defb  0
1196   IF @BZ80ASM_ORGENTDISP
1197   defx  "ORG"
1198   defb  0
1199   ;
1200   defx  "DISP"
1201   defb  0
1202   ;
1203   defx  "ENT"
1204   defb  0
1205   ENDIF
1206   ; softinclude user instructions
1207   include "?bzasm80_user_mnemonics.zas"
1209   ; no more
1210   defb  0
1212 ;; operands
1213 OPRNDS:
1214   defx  "B"
1215   defb  0
1216   defx  "C"
1217   defb  1
1218   defx  "D"
1219   defb  2
1220   defx  "E"
1221   defb  3
1222   defx  "H"
1223   defb  4
1224   defx  "L"
1225   defb  5
1226   defx  "(HL"
1227   defb  6
1228   defx  "A"
1229   defb  7
1230   defx  "(IX"
1231   defb  #86
1232   defx  "(IY"
1233   defb  #C6
1234   ;
1235   defx  "BC"
1236   defb  8
1237   defx  "DE"
1238   defb  10
1239   defx  "HL"
1240   defb  12
1241   defx  "IX"
1242   defb  #8C
1243   defx  "IY"
1244   defb  #CC
1245   defx  "AF"
1246   defb  14
1247   defx  "SP"
1248   defb  14
1249   ;
1250   defx  "NZ"
1251   defb  16
1252   defx  "Z"
1253   defb  17
1254   defx  "NC"
1255   defb  18
1256   defx  "PO"
1257   defb  20
1258   defx  "PE"
1259   defb  21
1260   defx  "P"
1261   defb  22
1262   defx  "M"
1263   defb  23
1264   ;
1265   defx  "(C"
1266   defb  #20
1267   ;
1268   defb  0
1271 LDOPS:
1272   defm  "I"
1273   defb  0
1274   defx  "A"
1275   defb  #47
1276   defm  "R"
1277   defb  0
1278   defx  "A"
1279   defb  #4F
1280   defm  "A"
1281   defb  0
1282   defx  "I"
1283   defb  #57
1284   defm  "A"
1285   defb  0
1286   defx  "R"
1287   defb  #5F
1288   defm  "(BC"
1289   defb  0
1290   defx  "A"
1291   defb  2
1292   defm  "(DE"
1293   defb  0
1294   defx  "A"
1295   defb  #12
1296   defm  "A"
1297   defb  0
1298   defx  "(BC"
1299   defb  #0A
1300   defm  "A"
1301   defb  0
1302   defx  "(DE"
1303   defb  #1A
1304   ;
1305   defb  0
1307 csizeend = $
1308 $printf "assembler tables size: %d", csizeend-csizestart
1310 ; so they won't clutter symbol table
1311 csizeend = -1
1312 csizestart = -1
1314   ENDMODULE BZ80ASM