fixed bug with "0BEEFH" -- it was "not a number", because of "0b" prefix
[bz80asm.git] / bzasm80.zas
blob74095fe56cdc57ca4277fc9d0ffa0b01bcc8126a
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   ;jp    nz,@error_out_of_range
357   call  nz,JR_TOO_FAR
358 VAL8:
359   ld    a,l
360   jr    BYTE2
362 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
364 ;; GROUP 11 - JP
366 GROUPB:
367   ld    b,a
368   jr    nz,GROUPC
369   call  COND
370   ld    a,c
371   jr    nc,GRPB
372   ld    a,b
373   and   3FH
374   cp    6
375   ld    a,0E9H
376   jr    z,BYTE2
377   ld    a,0C3H
378 GRPB:
379   call  BYTE
380   jr    ADDR
382 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
384 ;; GROUP 12 - CALL
386 GROUPC:
387   djnz  GROUPD
388 GRPC:
389   call  GRPE
390 ADDR:
391   call  NUMBER
392 VAL16:
393   call  VAL8
394   ld    a,h
395   jr    BYTE2
397 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
399 ;; GROUP 13 - RST
401 GROUPD:
402   djnz  GROUPE
403   call  NUMBER
404   and   c
405   or    h
406   jr    nz,TOOFAR
407   ld    a,l
408   or    c
409 BYTE2:
410   jr    BYTE1
412 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
414 ;; GROUP 14 - RET
416 GROUPE:
417   djnz  GROUPF
418 GRPE:
419   call  COND
420   ld    a,c
421   jr    nc,BYTE1
422   or    9
423   jr    BYTE1
425 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
427 ;; GROUP 15 - LD
429 GROUPF:
430   djnz  MISC
431   call  LDOP
432   jr    nc,LDA
433   call  REGHI
434   ex    af,af'
435   call  SKIP
436   cp    '('
437   jr    z,LDIN
438   ex    af,af'
439   jp    nc,G6
440   ld    c,1
441   call  PAIR1
442   ret   c
443   ld    a,14
444   cp    b
445   ld    b,a
446   call  z,PAIR
447   ld    a,b
448   and   3FH
449   cp    12
450   ld    a,c
451   jr    nz,GRPB
452   ld    a,0F9H
453   jr    BYTE1
454   ;
455 LDIN:
456   ex    af,af'
457   push  bc
458   call  nc,REGLO
459   ld    a,c
460   pop   bc
461   jr    nc,BIND
462   ld    c,0AH
463   call  PAIR1
464   call  LD16
465   jr    nc,GRPB
466   call  NUMBER
467   ld    c,2
468   call  PAIR
469   call  LD16
470   ret   c
471   call  BYTE
472   jr    VAL16
474 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
475 ;; misc. instructions
476 MISC:
477   jp    MISC_DEFB
480 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
482 ;; SUBROUTINES
485 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
487 JR_TOO_FAR:
488   ld    hl,(ASM_JR_TOO_FAR_CB)
489   jp    (hl)
491 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
493 LDA:
494   cp    4
495   call  c,EDX
496   ld    a,b
497 BYTE1:
498   jr    BYTE
500 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
502 LD16:
503   ld    a,b
504   jr    c,LD8
505   ld    a,b
506   and   3FH
507   cp    12
508   ld    a,c
509   ret   z
510   call  EDX
511   ld    a,c
512   or    43H
513   ret
515 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
517 LD8:
518   cp    7
519   scf
520   ret   nz
521   ld    a,c
522   or    30H
523   ret
525 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
527 CORN:
528   push  bc
529   call  OPND
530   bit   5,b
531   pop   bc
532   jr    z,NUMBER
533   ld    h,-1
534 EDX:
535   ld    a,0EDH
536   jr    BYTE
538 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
540 CBX:
541   ld    a,0CBH
542 BIND:
543   cp    76H
544   scf
545   ret   z               ;REJECT LD (HL),(HL)
546   call  BYTE
547   inc   d
548   ret   p
549   ld    a,e
550   jr    BYTE
552 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
554 OPND:
555   push  hl
556   ld    hl,OPRNDS
557   call  FIND
558   pop   hl
559   ret   c
560   bit   7,b
561   ret   z
562   bit   3,b
563   push  hl
564   call  z,OFFSET
565   ld    e,l
566   pop   hl
567   ld    a,0DDH
568   bit   6,b
569   jr    z,OP1
570   ld    a,0FDH
571 OP1:
572   or    a
573   inc   d
574   ld    d,a
575   ret   m
576 BYTE:
577   ld    (ix),a
578   inc   ix
579   or    a
580   ret
582 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
584 OFFSET:
585   ld    a,(iy)
586   cp    ')'
587   ld    hl,0
588   ret   z
590 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
591 ;; parse numeric expression
592 NUMBER:
593   call  SKIP
594   push  bc
595   push  de
596   push  ix
597   call  @PARSE_INT_EXPR
598   ; HL: expression value
599   pop   ix
600   pop   de
601   pop   bc
602   ld    a,l
603   or    a
604   ret
606 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
608 REG:
609   call  OPND
610   ret   c
611   ld    a,b
612   and   3FH
613   cp    8
614   ccf
615   ret
617 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
619 REGLO:
620   call  REG
621   ret   c
622   jr    ORC
624 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
626 REGHI:
627   call  REG
628   ret   c
629   jr    SHL3
631 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
633 COND:
634   call  OPND
635   ret   c
636   ld    a,b
637   and   1FH
638   sub   16
639   jr    nc,SHL3
640   cp    -15
641   scf
642   ret   nz
643   ld    a,3
644   jr    SHL3
646 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
648 PAIR:
649   call  OPND
650   ret   c
651 PAIR1:
652   ld    a,b
653   and   0FH
654   sub   8
655   ret   c
656   jr    SHL3
658 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
660 CBIT:
661   call  NUMBER
662   cp    8
663   ccf
664   ret   c
665 SHL3:
666   rlca
667   rlca
668   rlca
669 ORC:
670   or    c
671   ld    c,a
672   ret
675 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
677 ;; common defb/defw code
678 ;;   carry set if we want words
680 COM_DEFBW:
681   push  af
682 COM_DEFBW_LOOP:
683   push  ix
684   call  @PARSE_INT_EXPR
685   pop   ix
686   ; HL: value
687   ld    (ix),l
688   inc   ix
689   pop   af
690   jr    nc,COM_DEFBW_BYTE
691   ld    (ix),h
692   inc   ix
693 COM_DEFBW_BYTE:
694   push  af
695   ; check for comma
696   call  SKIP
697   jr    nz,COM_DEFBW
698   pop   af
699   or    a
700   ret
702 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
704 ;; DEFB
706 MISC_DEFB:
707   djnz  MISC_DEFW
708 DEFB_LOOP:
709   or    a
710   jr    COM_DEFBW
712 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
714 ;; DEFW
716 MISC_DEFW:
717   djnz  MISC_DEFM
718 DEFW_LOOP:
719   scf
720   jr    COM_DEFBW
722 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
724 ;; DEFM
726 MISC_DEFM:
727   djnz  MISC_ORG
728 DEFM_LOOP:
729   push  ix
730   call  @PARSE_STR_EXPR
731   pop   ix
732   ; HL: buffer address
733   ;  E: buffer length
734   xor   a
735   cp    e
736   jr    z,DEFM1_DONE_ONE
737 DEFM1:
738   ld    a,(hl)
739   inc   hl
740   call  BYTE
741   dec   e
742   jr    nz,DEFM1
743 DEFM1_DONE_ONE:
744   ; check for comma
745   call  SKIP
746   ret   z
747   jr    DEFM_LOOP
749 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
751 ;; ORG
753 MISC_ORG:
754   IF BZ80ASM_ORGENTDISP
755   djnz  MISC_DISP
756   ld    a,ORGENT_ORG
757 COM_ORGENT:
758   ld    (ORGENT_TYPE),a
759   call  NUMBER
760   ld    (NEW_ORGENT),hl
761   or    a
762   ret
764 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
766 ;; DISP
768 MISC_DISP:
769   djnz  MISC_ENT
770   ld    a,ORGENT_DISP
771   jr    COM_ORGENT
773 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
775 ;; ENT
777 MISC_ENT:
778   djnz  MISC_WTF
779   ld    a,ORGENT_ENT
780   jr    COM_ORGENT
782 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
784 ;; error (the thing that should not be)
786 MISC_WTF:
787   ENDIF
788   ; set "unknown instruction index"
789   ; b may be zero here
790   ld    a,b
791   inc   a
792   ld    (ASM_BAD_B),a
793   scf
794   ret
797 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
798 ;; search the table for a token from the input buffer
799 ;; skips leading delimiters, and the token itself (if found)
800 ;; tokens in the table must have bit 7 set on the last char
801 ;; table ends with zero byte instead of first token char
802 ;; each token is followed by a data byte
803 ;; IN:
804 ;;   IY: text buffer
805 ;; OUT:
806 ;;   IY: new position in the text buffer
807 ;;    A: token number
808 ;;    B: token data byte
809 ;;   carry flag set on error (invalid char, or token not found)
810 ;;   on error, delimiters are still skipped
812 LDOP:
813   ld    hl,LDOPS
814 ; main table search entry point
815 FIND:
816   call  SKIP
817 EXIT:
818   ld    b,0
819   scf
820   ret   z
821   ; reject chars with high bit set
822   cp    128
823   ccf
824   ret   c
826 FIND0:
827   ; check the first char
828   ld    a,(hl)
829   or    a
830   jr    z,EXIT
831   xor   (iy)
832   and   %01011111   ; for case-insensitivity
833   jr    z,FIND2
834   ; first char is not matched, skip this token
835 FIND1:
836   bit   7,(hl)
837   inc   hl
838   jr    z,FIND1
839   ; skip token data byte
840   inc   hl
841   ; increment token counter
842   inc   b
843   jr    FIND0
845   ; first char matched, check the rest
846   ; A holds zero (due to xor/and)
847 FIND2:
848   push  iy
849 FIND3:
850   ; last token char?
851   bit   7,(hl)
852   inc   iy
853   inc   hl
854   jr    nz,FIND5
855   ; not the last token char
856   ; this compares (HL) with 0, because
857   ; A is guaranteed to hold zero here
858   cp    (hl)
859   ; zero byte in token means "skip delimiters"
860   ; it is used in some opcodes with fixed operands
861   call  z,SKIP0
862   ; load token char
863   ld    a,(hl)
864   ; compare with input char
865   xor   (iy)
866   and   %01011111   ; for case-insensitivity
867   jr    z,FIND3
869   ; alas, doesn't match
870 FIND4:
871   ; restore input stream pointer
872   pop   iy
873   ; and skip this token
874   jr    FIND1
876   ; we'll come here if we succesfully matched a token
877 FIND5:
878   ; if it isn't followed by a delimiter, '+' or '-', this is not a valid token
879   call  DELIM
880   call  nz,SIGN
881   jr    nz,FIND4
883   ; this token is valid
884 FIND6:
885   ; move token index to A
886   ld    a,b
887   ; load B with token data byte
888   ld    b,(hl)
889   ; drop original input stream position
890   pop   hl
891   ; we're done here
892   ; note that carry flag is guaranteed to be reset
893   ret
896 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
897 ;; used by FIND
898 SIGN:
899   cp    '+'
900   ret   z
901   cp    '-'
902   ret
904 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
905 ;; this entry point is used by FIND
906 SKIP0:
907   inc   hl
908 ;; this entry point is used to skip blanks and delimiters
909 ;; note that comma and right paren are considered blanks too
910 ;; as a consequence, operands may be delimited by spaces, or
911 ;; right parens, lol
912 ;; returns current char in A (and IY pointing to it)
913 ;; zero flag set if we hit a terminator
914 ;; zero flag reset if we hit a non-delimiter
915 SKIP:
916   ; delimiter or terminator?
917   call  DELIM
918   ret   nz
919   ; if this is terminator, still stop
920   call  TERM
921   ret   z
922   ; this is delimiter, skip it
923   inc   iy
924   jr    SKIP
926 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
927 ;; used by FIND and SKIP
928 ;; check if the current char is a delimiter or a terminator
929 ;; zero flag set on delimiter/terminator
930 DELIM:
931   ld    a,(iy)          ;ASSEMBLER DELIMITER
932   cp    ' '
933   ret   z
934   cp    ','
935   ret   z
936   cp    ')'
937   ret   z
939 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
940 ;; entry point for SKIP
941 TERM:
942   cp    ';'             ;ASSEMBLER TERMINATOR
943   ret   z
944   ;cp    '\'
945   ;ret   z
947 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
948 ;; also used by assembler to check for command separator
949 ;; the assembler itself does nothing with separators
950 ASM_IS_SEP:
951   cp    ':'             ;ASSEMBLER SEPARATOR
952   ret   nc
953   cp    CR
954   ret
956 csizeend = $
957 $printf "assembler size: %d", csizeend-csizestart
959 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
960 ;; various tables -- mnemonics, operands...
962 csizestart = $
964 ;; number of "trivial" opcodes without any special processing
965 OPC_COUNT_GROUPS_0_AND_1 equ 39
966 ;; number of non-ED-prefixed instructions in "trivial"
967 OPC_COUNT_GROUP_0 equ 15
969 ;; total number of CB-prefixed instructions (GROUPS 2 and 3)
970 OPC_COUNT_GROUPS_2_AND_3 equ 10
971 ;; number of direct bit manipulation instructions in CB list (GROUP 2)
972 OPC_COUNT_GROUP_2 equ 3
974 ;; push, pop, ex (sp),rr
975 OPC_COUNT_GROUP_4 equ 3
977 ;; ALU with accum
978 OPC_COUNT_GROUP_5 equ 5
979 ;; ALU with accum
980 OPC_COUNT_GROUP_6 equ 3
981 ;; GROUPS 5 and 6
982 OPC_COUNT_GROUPS_5_AND_6 equ OPC_COUNT_GROUP_5+OPC_COUNT_GROUP_6
984 ;; INC/DEC
985 OPC_COUNT_GROUP_7 equ 2
987 ;; IN
988 OPC_COUNT_GROUP_8 equ 1
989 ;; OUT
990 OPC_COUNT_GROUP_9 equ 1
991 ;; GROUPS 8 and 9
992 OPC_COUNT_GROUPS_8_AND_9 equ OPC_COUNT_GROUP_8+OPC_COUNT_GROUP_9
994 ; JR,DJNZ
995 OPC_COUNT_GROUP_10 equ 2
996 OPC_COUNT_GROUP_10_JRS equ 1
999 ;; WARNING! the assembler has some hard-coded mnemonics counts
1000 ;;          scattered across the code, so don't mess with the tables!
1001 ;;          i may document this in the future, but for now, leave it as it is.
1002 ;; mnemonics
1003 OPCODS:
1004   ; GROUPS 0 AND 1: "trivial" (39, OPC_COUNT_GROUPS_0_AND_1)
1005   ; GROUP 0: "trivial" one-byte (15, OPC_COUNT_GROUP_0)
1006   defx  "NOP"
1007   defb  0
1008   defx  "RLCA"
1009   defb  7
1010   defm  "EX",0,"AF",0
1011     defx "AF'"
1012   defb  8
1013   defx  "RRCA"
1014   defb  #0F
1015   defx  "RLA"
1016   defb  #17
1017   defx  "RRA"
1018   defb  #1F
1019   defx  "DAA"
1020   defb  #27
1021   defx  "CPL"
1022   defb  #2F
1023   defx  "SCF"
1024   defb  #37
1025   defx  "CCF"
1026   defb  #3F
1027   defx  "HALT"
1028   defb  #76
1029   defx  "EXX"
1030   defb  #D9
1031   defm  "EX",0,"DE",0
1032     defx "HL"
1033   defb  #EB
1034   defx  "DI"
1035   defb  #F3
1036   defx  "EI"
1037   defb  #FB
1038   ; GROUP 1: "trivial" ED-prefixed (24, OPC_COUNT_GROUPS_0_AND_1-OPC_COUNT_GROUP_0)
1039   defx  "NEG"
1040   defb  #44
1041   defm  "IM",0
1042     defx  "0"
1043   defb  #46
1044   defx  "RETN"
1045   defb  #45
1046   defx  "RETI"
1047   defb  #4D
1048   defm  "IM",0
1049     defx  "1"
1050   defb  #56
1051   defm  "IM",0
1052     defx  "2"
1053   defb  #5E
1054   defx  "RRD"
1055   defb  #67
1056   defx  "RLD"
1057   defb  #6F
1058   defx  "LDI"
1059   defb  #A0
1060   defx  "CPI"
1061   defb  #A1
1062   defx  "INI"
1063   defb  #A2
1064   defx  "OUTI"
1065   defb  #A3
1066   defx  "LDD"
1067   defb  #A8
1068   defx  "CPD"
1069   defb  #A9
1070   defx  "IND"
1071   defb  #AA
1072   defx  "OUTD"
1073   defb  #AB
1074   defx  "LDIR"
1075   defb  #B0
1076   defx  "CPIR"
1077   defb  #B1
1078   defx  "INIR"
1079   defb  #B2
1080   defx  "OTIR"
1081   defb  #B3
1082   defx  "LDDR"
1083   defb  #B8
1084   defx  "CPDR"
1085   defb  #B9
1086   defx  "INDR"
1087   defb  #BA
1088   defx  "OTDR"
1089   defb  #BB
1091   ; GROUPS 2 AND 3: CB-prefixed (10, OPC_COUNT_GROUPS_2_AND_3)
1092   ; GROUP 2: direct bit manipulation (3, OPC_COUNT_GROUP_2)
1093   defx  "BIT"
1094   defb  #40
1095   defx  "RES"
1096   defb  #80
1097   defx  "SET"
1098   defb  #C0
1099   ; GROUP 3: shifts (7, OPC_COUNT_GROUPS_2_AND_3-OPC_COUNT_GROUP_2)
1100   defx  "RLC"
1101   defb  0
1102   defx  "RRC"
1103   defb  8
1104   defx  "RL"
1105   defb  #10
1106   defx  "RR"
1107   defb  #18
1108   defx  "SLA"
1109   defb  #20
1110   defx  "SRA"
1111   defb  #28
1112   defx  "SRL"
1113   defb  #38
1115   ; GROUP 4: push,pop,ex (sp),rr (OPC_COUNT_GROUP_4)
1116   defx  "POP"
1117   defb  #C1
1118   defx  "PUSH"
1119   defb  #C5
1120   defm  "EX",0
1121     defx  "(SP"
1122   defb  #E3
1124   ; GROUP 5: ALU with accumulator (OPC_COUNT_GROUP_5)
1125   defx  "SUB"
1126   defb  #90
1127   defx  "AND"
1128   defb  #A0
1129   defx  "XOR"
1130   defb  #A8
1131   defx  "OR"
1132   defb  #B0
1133   defx  "CP"
1134   defb  #B8
1135   ;k8: for some reason i cannot remove those two
1136   ;defb  TAND
1137   ;defb  #A0
1138   ;defb  TOR
1139   ;defb  #B0
1141   ; GROUP 6: ALU with accumulator or HL (OPC_COUNT_GROUP_6)
1142   defx  "ADD"
1143   defb  #80
1144   defx  "ADC"
1145   defb  #88
1146   defx  "SBC"
1147   defb  #98
1149   ; GROUP 7: inc,dec (2, OPC_COUNT_GROUP_7)
1150   defx  "INC"
1151   defb  4
1152   defx  "DEC"
1153   defb  5
1155   ; GROUP 8: in (1, OPC_COUNT_GROUP_8)
1156   defx  "IN"
1157   defb  #40
1158   ; GROUP 9: out (1, OPC_COUNT_GROUP_9)
1159   defx  "OUT"
1160   defb  #41
1162   ; GROUP 10: jr,djnz (2, OPC_COUNT_GROUP_10)
1163   defx  "JR"
1164   defb  #20
1165   defx  "DJNZ"
1166   defb  #10
1168   ; GROUP 11: jp (strictly one)
1169   defx  "JP"
1170   defb  #C2
1172   ; GROUP 12: call (strictly one)
1173   defx  "CALL"
1174   defb  #C4
1176   ; GROUP 13: rst (strictly one)
1177   defx  "RST"
1178   defb  #C7
1180   ; GROUP 14: ret (strictly one)
1181   defx  "RET"
1182   defb  #C0
1184   ; GROUP 15: ld (strictly one)
1185   defx  "LD"
1186   defb  #40
1188   ; miscellaneous assembler instructions
1189   ; WARNING! the order matters!
1190   defx  "DEFB"
1191   defb  0
1192   ;
1193   defx  "DEFW"
1194   defb  0
1195   ;
1196   defx  "DEFM"
1197   defb  0
1199   IF BZ80ASM_ORGENTDISP
1200   defx  "ORG"
1201   defb  0
1202   ;
1203   defx  "DISP"
1204   defb  0
1205   ;
1206   defx  "ENT"
1207   defb  0
1208   ENDIF
1209   ; softinclude user instructions
1210   include "?bzasm80_user_mnemonics.zas"
1212   ; no more
1213   defb  0
1215 ;; operands
1216 OPRNDS:
1217   defx  "B"
1218   defb  0
1219   defx  "C"
1220   defb  1
1221   defx  "D"
1222   defb  2
1223   defx  "E"
1224   defb  3
1225   defx  "H"
1226   defb  4
1227   defx  "L"
1228   defb  5
1229   defx  "(HL"
1230   defb  6
1231   defx  "A"
1232   defb  7
1233   defx  "(IX"
1234   defb  #86
1235   defx  "(IY"
1236   defb  #C6
1237   ;
1238   defx  "BC"
1239   defb  8
1240   defx  "DE"
1241   defb  10
1242   defx  "HL"
1243   defb  12
1244   defx  "IX"
1245   defb  #8C
1246   defx  "IY"
1247   defb  #CC
1248   defx  "AF"
1249   defb  14
1250   defx  "SP"
1251   defb  14
1252   ;
1253   defx  "NZ"
1254   defb  16
1255   defx  "Z"
1256   defb  17
1257   defx  "NC"
1258   defb  18
1259   defx  "PO"
1260   defb  20
1261   defx  "PE"
1262   defb  21
1263   defx  "P"
1264   defb  22
1265   defx  "M"
1266   defb  23
1267   ;
1268   defx  "(C"
1269   defb  #20
1270   ;
1271   defb  0
1274 LDOPS:
1275   defm  "I"
1276   defb  0
1277   defx  "A"
1278   defb  #47
1279   defm  "R"
1280   defb  0
1281   defx  "A"
1282   defb  #4F
1283   defm  "A"
1284   defb  0
1285   defx  "I"
1286   defb  #57
1287   defm  "A"
1288   defb  0
1289   defx  "R"
1290   defb  #5F
1291   defm  "(BC"
1292   defb  0
1293   defx  "A"
1294   defb  2
1295   defm  "(DE"
1296   defb  0
1297   defx  "A"
1298   defb  #12
1299   defm  "A"
1300   defb  0
1301   defx  "(BC"
1302   defb  #0A
1303   defm  "A"
1304   defb  0
1305   defx  "(DE"
1306   defb  #1A
1307   ;
1308   defb  0
1310 csizeend = $
1311 $printf "assembler tables size: %d", csizeend-csizestart
1313   ENDMODULE BZ80ASM