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:
6 ;; Copyright (c) 1984-2000 R.T. Russell
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
33 PC: defw #C000 ; logical program counter for the code
35 IF @BZ80ASM_ORGENTDISP
36 ; ORG/DISP sets this to its value
38 ; ORG/ENT sets this to the corresponding type
39 ; it is reset at each call to ASSEM
44 ORGENT_TYPE: defw ORGENT_NONE
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)
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:
69 ; handle first instruction
72 ; handle second instruction
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)
81 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
82 ;; expression parser variables
84 ;; set this to the address of error routine
85 ;; note that you cannot return from it, you HAVE to abort everything
86 ;; also note that machine stack is undefined, and SP should be set
87 ;; to some initial value
88 ;; "undefined" means that machine stack can contain alot of garbage,
89 ;; but will never be underflowed
91 ;; this function is called with error code in A
93 ;; you can load your own error code in A, and do:
94 ;; jp BZ80ASM.PARSE_EXPR_ERROR_A
98 ;; expected number, but got something incomprehensible
99 EXPR_ERR_NUMBER_EXPECTED equ 1
100 ;; expected string, but got something incomprehensible
101 EXPR_ERR_STRING_EXPECTED equ 2
102 ;; expected ")", but got something strange
103 EXPR_ERR_RPAREN_EXPECTED equ 3
104 ;; expected ")", but got something strange
105 EXPR_ERR_DIVISION_BY_ZERO equ 4
107 ;; the asm never generates the following errors, but
108 ;; they may be useful for a main driver
110 ;; you can use this to dispatch "short jump destination is too far" error
111 ;; just do this in `ASM_JR_TOO_FAR_CB`:
112 ;; ld a,EXPR_ERR_JR_TOO_FAR
113 ;; jp BZ80ASM.PARSE_EXPR_ERROR_A
114 EXPR_ERR_JR_TOO_FAR equ 5
116 ;; this "unknown label" error can be used by label manager
117 EXPR_ERR_UNKNOWN_LABEL equ 6
118 ;; this error can be used by label manager if it cannot parse a label
119 EXPR_ERR_INVALID_LABEL_NAME equ 7
120 ;; this error can be used by label manager
121 EXPR_ERR_DUPLICATE_LABEL equ 8
123 ;; general "bad syntax" error, when you don't have anything better
124 EXPR_ERR_BAD_SYNTAX equ 9
126 ;; offset your own error codes with this
127 EXPR_ERR_USERDEF equ 10
130 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
131 ;; label manager callback
134 ;; this is called from assembler to find an existing label.
135 ;; IY points to the first char of a label name.
136 ;; after parsing, IY should point right after the parsed name.
137 ;; all registers expect IY can be trashed (including IX).
139 ;; for forward referencing, label manager can create unknown
140 ;; labels, and set their value to (BZ80ASM.PC).
141 ;; it is important to set new labels to PC to avoid errors
142 ;; with short jumps if your "jr too far" error handler always
143 ;; bombs out. otherwise, you can set the label to anything
147 ;; IY: text input buffer
149 ;; IY: text input buffer after the label
151 ;; CARRY FLAG: set if label wasn't found
152 ;; expression parser will bomb out in this case
153 ;; on error, IY doesn't matter, because it will be restored
154 ;; by the calling code
158 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
166 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
168 ;; LANGUAGE-INDEPENDENT CONTROL SECTION:
171 ;; IX: destination to put generated code at
174 ;; IY: delimiter position in text buffer
175 ;; IX: points right after the generated code
176 ;; carry set if syntax error (and A is undefined in this case)
177 ;; others are dead (including extra register set and extra accum/flags)
182 IF @BZ80ASM_ORGENTDISP
192 ; this was used to terminate assembler section in BBC Basic
203 ; exit if syntax error
205 ; skip delimiters (but not terminators)
207 ; exit with error flag if we're not at a terminator
215 ex de,hl ;DE= NO. OF BYTES
218 ld (PC),hl ;UPDATE PC
223 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
225 ;; jump here to restore stack, and exit with error (carry set)
238 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
240 ;; PROCESSOR-SPECIFIC TRANSLATION SECTION:
242 ;; REGISTER USAGE: B - TYPE OF MOST RECENT OPERAND
243 ;; C - OPCODE BEING BUILT
244 ;; D - (IX) OR (IY) FLAG
245 ;; E - OFFSET FROM IX OR IY
246 ;; HL - NUMERIC OPERAND VALUE
247 ;; IX - CODE DESTINATION
248 ;; IY - SOURCE TEXT POINTER
249 ;; Inputs: A = initial character
250 ;; Outputs: Carry set if syntax error.
257 ; carry flag set on error
259 ; A contains token index
260 ; B contains token data byte
262 ld d,0 ;CLEAR IX/IY FLAG
265 ; A contains token index
266 ; C contains token data byte
267 ; D contains IX/IY flag
269 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
271 ;; GROUP 0 - TRIVIAL CASES REQUIRING NO COMPUTATION
272 ;; GROUP 1 - AS GROUP 0 BUT WITH "ED" PREFIX
274 sub OPC_COUNT_GROUPS_0_AND_1
276 cp OPC_COUNT_GROUP_0-OPC_COUNT_GROUPS_0_AND_1
280 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
282 ;; GROUP 2 - BIT, RES, SET
283 ;; GROUP 3 - RLC, RRC, RL, RR, SLA, SRA, SRL
286 sub OPC_COUNT_GROUPS_2_AND_3
288 cp OPC_COUNT_GROUP_2-OPC_COUNT_GROUPS_2_AND_3
296 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
298 ;; GROUP 4 - PUSH, POP, EX (SP)
301 sub OPC_COUNT_GROUP_4
308 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
310 ;; GROUP 5 - SUB, AND, XOR, OR, CP
311 ;; GROUP 6 - ADD, ADC, SBC
314 sub OPC_COUNT_GROUPS_5_AND_6
316 cp OPC_COUNT_GROUP_5-OPC_COUNT_GROUPS_5_AND_6
347 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
349 ;; GROUP 7 - INC, DEC
352 sub OPC_COUNT_GROUP_7
369 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
375 sub OPC_COUNT_GROUPS_8_AND_9
377 cp OPC_COUNT_GROUP_8-OPC_COUNT_GROUPS_8_AND_9
398 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
400 ;; GROUP 10 - JR, DJNZ
403 sub OPC_COUNT_GROUP_10
405 cp OPC_COUNT_GROUP_10_JRS-OPC_COUNT_GROUP_10
427 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
447 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
462 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
477 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
490 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
539 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
540 ;; misc. instructions
545 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
550 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
553 ld hl,(ASM_JR_TOO_FAR_CB)
556 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
565 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
580 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
590 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
603 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
610 ret z ;REJECT LD (HL),(HL)
617 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
647 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
655 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
656 ;; parse numeric expression
663 ; HL: expression value
671 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
682 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
689 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
696 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
711 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
723 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
740 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
742 ;; common defb/defw code
743 ;; carry set if we want words
765 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
775 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
785 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
812 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
817 IF @BZ80ASM_ORGENTDISP
827 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
836 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
845 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
847 ;; error (the thing that should not be)
851 ; set "unknown instruction index"
860 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
861 ;; search the table for a token from the input buffer
862 ;; skips leading delimiters, and the token itself (if found)
863 ;; tokens in the table must have bit 7 set on the last char
864 ;; table ends with zero byte instead of first token char
865 ;; each token is followed by a data byte
869 ;; IY: new position in the text buffer
871 ;; B: token data byte
872 ;; carry flag set on error (invalid char, or token not found)
873 ;; on error, delimiters are still skipped
877 ; main table search entry point
884 ; reject chars with high bit set
890 ; check the first char
895 and %01011111 ; for case-insensitivity
897 ; first char is not matched, skip this token
902 ; skip token data byte
904 ; increment token counter
908 ; first char matched, check the rest
909 ; A holds zero (due to xor/and)
918 ; not the last token char
919 ; this compares (HL) with 0, because
920 ; A is guaranteed to hold zero here
922 ; zero byte in token means "skip delimiters"
923 ; it is used in some opcodes with fixed operands
927 ; compare with input char
929 and %01011111 ; for case-insensitivity
932 ; alas, doesn't match
934 ; restore input stream pointer
936 ; and skip this token
939 ; we'll come here if we succesfully matched a token
941 ; if it isn't followed by a delimiter, '+' or '-', this is not a valid token
946 ; this token is valid
948 ; move token index to A
950 ; load B with token data byte
952 ; drop original input stream position
955 ; note that carry flag is guaranteed to be reset
959 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
967 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
968 ;; this entry point is used by FIND
971 ;; this entry point is used to skip blanks and delimiters
972 ;; note that comma and right paren are considered blanks too
973 ;; as a consequence, operands may be delimited by spaces, or
975 ;; returns current char in A (and IY pointing to it)
976 ;; zero flag set if we hit a terminator
977 ;; zero flag reset if we hit a non-delimiter
979 ; delimiter or terminator?
982 ; if this is terminator, still stop
985 ; this is delimiter, skip it
989 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
990 ;; used by FIND and SKIP
991 ;; check if the current char is a delimiter or a terminator
992 ;; zero flag set on delimiter/terminator
994 ld a,(iy) ;ASSEMBLER DELIMITER
1002 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1003 ;; entry point for SKIP
1005 cp ';' ;ASSEMBLER TERMINATOR
1010 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1011 ;; also used by assembler to check for command separator
1012 ;; the assembler itself does nothing with separators
1014 cp ':' ;ASSEMBLER SEPARATOR
1020 $printf "assembler size: %d", csizest
1025 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1026 ;; parse integer number (without sign)
1027 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1029 ;; this is advanced number parser
1030 ;; it understands alot of suffixes and prefixes:
1031 ;; $ -- lone "$" means "current PC"
1042 ;; everything is case-insensitive
1043 ;; you can separate digits with underscores
1044 ;; (i.e. "12_34_5" will work, underscores are simply ignored)
1047 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1049 ;; parse a number, push it onto the stack
1050 ;; understands prefixes and suffixes
1055 ;; IY: text buffer after the expression
1058 ;; OR: (cannot parse as a number)
1061 ;; DE,AF,flags: dead
1064 call PARSER_SKIP_BLANKS
1067 push iy ; we will need to rollback on error
1068 ; A already contains a char, loaded by `PARSER_SKIP_BLANKS`
1072 jr z,.maybe_lone_dollar
1077 ; no, leading zero doesn't mean "octal", this is stupid
1078 ; but we may have prefixes like "0x" and such
1080 jr z,.maybe_zero_prefix
1081 ; check if we have a digit here
1082 call PARSER_CONV_DIGIT
1083 jr c,.not_a_number_carry_set
1085 ; nope, do not allow it, all numbers must start with a digit
1086 ;jr nc,.must_be_hex_with_sfx
1088 jr c,.not_a_number_carry_set
1090 ; done with prefixes, try decimal number
1091 ; we'll switch to suffix checking on hex digit
1092 ld hl,0 ; accumulator
1097 jr nc,.must_be_hex_with_sfx
1114 and %11011111 ; cheap uppercase
1116 jr z,.must_be_hex_with_sfx
1121 ; no suffix, we're done
1129 .not_a_number_carry_set:
1138 jr c,.not_a_number_carry_set
1142 ; lone dollar means "PC"
1145 ; the only case we may gen an error here is
1146 ; when our dollar isn't followed by a digit
1148 ; lone dollar is good too
1149 ; IY points right after the dollar here
1160 ; things like "0BEEFh" should be parsed as hex
1164 jr c,.must_be_hex_with_sfx
1167 and %11011111 ; cheap uppercase
1169 jr z,.must_be_hex_with_sfx
1179 ; check for '0x' and such
1183 ; there's no need to skip it, as it will be
1184 ; skipped by the corresponding subroutine
1186 ; so IY will point to the actual number
1187 and %11011111 ; cheap uppercase
1191 jr z,.maybe_binprefix
1194 ; do not reparse '0', no need to backup
1195 jr .do_normal_decimal
1197 .must_be_hex_with_sfx:
1198 ; reparse as hex, and check for suffix
1202 jr c,.not_a_number_carry_set
1205 and %11011111 ; cheap uppercase
1210 ; reparse as bin, skip suffix (it is guaranteed to be there)
1214 .done_guaranteed_suffix:
1215 jr c,.not_a_number_carry_set
1221 ; reparse as bin, skip suffix (it is guaranteed to be there)
1225 jr .done_guaranteed_suffix
1228 ld hl,0 ; accumulator
1229 ; check first digit (as this is general parser)
1230 call .getDigitNoUnder
1242 jr nc,.parse_as_hex_loop
1243 ; clear carry flag (it is always set here)
1248 ld hl,0 ; accumulator
1249 ; check first digit (as this is general parser)
1251 call .getDigitNoUnderBin
1260 jr nc,.parse_as_bin_loop
1261 ; clear carry flag (it is always set here)
1266 ld hl,0 ; accumulator
1267 ; check first digit (as this is general parser)
1269 call .getDigitNoUnderOct
1279 jr nc,.parse_as_oct_loop
1280 ; clear carry flag (it is always set here)
1291 jr PARSER_CONV_DIGIT
1303 jr PARSER_CONV_DIGIT
1309 .getDigitNoUnderOct:
1315 .getDigitNoUnderBin:
1322 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1323 ;; converts 'A' to digit (assume hex)
1324 ;; carry set: not a digit char (and A is destroyed)
1333 and %11011111 ; cheap uppercase
1341 $printf "assembler numparse size: %d", csizest
1346 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1347 ;; math expression parser
1348 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1351 ld hl,(EXPR_ERROR_CB)
1354 PARSE_EXPR_ERROR_0DIV:
1355 ld a,EXPR_ERR_DIVISION_BY_ZERO
1356 jr PARSE_EXPR_ERROR_A
1358 PARSE_EXPR_ERROR_INT:
1359 ld a,EXPR_ERR_NUMBER_EXPECTED
1360 jr PARSE_EXPR_ERROR_A
1363 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1365 ;; parse an integer expression
1369 ;; IY: text buffer after the expression
1370 ;; HL: expression value
1371 ;; everything other (including all alternate registers) is dead
1380 call PARSER_SKIP_BLANKS
1381 jr z,PARSE_EXPR_ERROR_INT
1403 ; already done above
1406 ; check for operation
1407 call PARSER_SKIP_BLANKS
1411 ; get second operand
1427 ; check for operation
1428 call PARSER_SKIP_BLANKS
1432 ; get second operand
1448 ; check for operation
1449 call PARSER_SKIP_BLANKS
1453 ; get second operand
1468 ; check for operation
1469 call PARSER_SKIP_BLANKS
1471 ; (iy+0) and (iy+1) should be equal
1479 ; get second operand
1480 inc iy ; skip operation part
1484 ; HL: number to shift
1488 jr nz,.shift_too_far
1491 jr nc,.shift_too_far
1518 ; check for operation
1519 call PARSER_SKIP_BLANKS
1526 ; get second operand
1542 ; check for operation
1543 call PARSER_SKIP_BLANKS
1552 ; get second operand
1558 ex af,af' ; save operation
1562 jp z,PARSE_EXPR_ERROR_0DIV
1563 call PARSER_UDIV_BC_DE
1564 ; was it div or mod?
1567 jr z,.muldiv_next ; remainder already in hl
1572 call PARSER_UMUL_BC_DE
1575 ;; parse term, also process unaries and parens
1577 call PARSER_SKIP_BLANKS
1578 jp z,PARSE_EXPR_ERROR_INT
1579 inc iy ; skip operation
1588 ; this must be number
1593 push iy ; for correct error position
1594 push ix ; the only register we care about
1595 ld hl,.term_checklabel_ret
1599 .term_checklabel_ret:
1604 ; restore position for correct error reporting
1607 jp PARSE_EXPR_ERROR_INT
1611 ;; C contains matching rparen
1614 call PARSER_SKIP_BLANKS
1615 jr z,PARSE_EXPR_ERROR_RPAREN
1618 jr nz,PARSE_EXPR_ERROR_RPAREN
1633 ;; call subroutine at BC
1636 ;; DE: subroutine result
1637 ;; i.e. HL is op0, DE is op1
1640 push af ; A holds operation
1641 inc iy ; skip operation
1642 ld hl,.go_down_bc_ret
1652 PARSE_EXPR_ERROR_RPAREN:
1653 ld a,EXPR_ERR_RPAREN_EXPECTED
1654 jp PARSE_EXPR_ERROR_A
1657 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1661 ;; BC,DE,A,flags: dead
1681 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1707 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1709 ;; parse a string expression
1714 ;; HL: string buffer start
1715 ;; E: parsed string length
1716 ;; everything other (including all alternate registers) is dead
1719 call PARSER_SKIP_BLANKS
1720 jr z,PARSE_EXPR_ERROR_STR
1724 jr nz,PARSE_EXPR_ERROR_STR
1728 ; remember buffer start
1733 jr z,PARSE_EXPR_ERROR_STR
1735 jr z,PARSE_EXPR_ERROR_STR
1739 ; done string parsing, calc length
1740 pop hl ; buffer start
1751 PARSE_EXPR_ERROR_STR:
1752 ld a,EXPR_ERR_STRING_EXPECTED
1753 jp PARSE_EXPR_ERROR_A
1756 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1758 ;; returns current char in A
1759 ;; sets zero flag on EOL
1763 ;; IY: text buffer at non-blank or EOL
1764 ;; A: non-blank or EOL char
1765 ;; zero flag is set on EOL
1775 jr c,PARSER_SKIP_BLANKS
1782 $printf "assembler exprparse size: %d", csizest
1785 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1786 ;; various tables -- mnemonics, operands...
1790 ;; number of "trivial" opcodes without any special processing
1791 OPC_COUNT_GROUPS_0_AND_1 equ 39
1792 ;; number of non-ED-prefixed instructions in "trivial"
1793 OPC_COUNT_GROUP_0 equ 15
1795 ;; total number of CB-prefixed instructions (GROUPS 2 and 3)
1796 OPC_COUNT_GROUPS_2_AND_3 equ 10
1797 ;; number of direct bit manipulation instructions in CB list (GROUP 2)
1798 OPC_COUNT_GROUP_2 equ 3
1800 ;; push, pop, ex (sp),rr
1801 OPC_COUNT_GROUP_4 equ 3
1804 OPC_COUNT_GROUP_5 equ 5
1806 OPC_COUNT_GROUP_6 equ 3
1808 OPC_COUNT_GROUPS_5_AND_6 equ OPC_COUNT_GROUP_5+OPC_COUNT_GROUP_6
1811 OPC_COUNT_GROUP_7 equ 2
1814 OPC_COUNT_GROUP_8 equ 1
1816 OPC_COUNT_GROUP_9 equ 1
1818 OPC_COUNT_GROUPS_8_AND_9 equ OPC_COUNT_GROUP_8+OPC_COUNT_GROUP_9
1821 OPC_COUNT_GROUP_10 equ 2
1822 OPC_COUNT_GROUP_10_JRS equ 1
1825 ;; WARNING! the assembler has some hard-coded mnemonics counts
1826 ;; scattered across the code, so don't mess with the tables!
1827 ;; i may document this in the future, but for now, leave it as it is.
1830 ; GROUPS 0 AND 1: "trivial" (39, OPC_COUNT_GROUPS_0_AND_1)
1831 ; GROUP 0: "trivial" one-byte (15, OPC_COUNT_GROUP_0)
1864 ; GROUP 1: "trivial" ED-prefixed (24, OPC_COUNT_GROUPS_0_AND_1-OPC_COUNT_GROUP_0)
1917 ; GROUPS 2 AND 3: CB-prefixed (10, OPC_COUNT_GROUPS_2_AND_3)
1918 ; GROUP 2: direct bit manipulation (3, OPC_COUNT_GROUP_2)
1925 ; GROUP 3: shifts (7, OPC_COUNT_GROUPS_2_AND_3-OPC_COUNT_GROUP_2)
1941 ; GROUP 4: push,pop,ex (sp),rr (OPC_COUNT_GROUP_4)
1950 ; GROUP 5: ALU with accumulator (OPC_COUNT_GROUP_5)
1961 ;k8: for some reason i cannot remove those two
1967 ; GROUP 6: ALU with accumulator or HL (OPC_COUNT_GROUP_6)
1975 ; GROUP 7: inc,dec (2, OPC_COUNT_GROUP_7)
1981 ; GROUP 8: in (1, OPC_COUNT_GROUP_8)
1984 ; GROUP 9: out (1, OPC_COUNT_GROUP_9)
1988 ; GROUP 10: jr,djnz (2, OPC_COUNT_GROUP_10)
1994 ; GROUP 11: jp (strictly one)
1998 ; GROUP 12: call (strictly one)
2002 ; GROUP 13: rst (strictly one)
2006 ; GROUP 14: ret (strictly one)
2010 ; GROUP 15: ld (strictly one)
2014 ; miscellaneous assembler instructions
2015 ; WARNING! the order matters!
2025 IF @BZ80ASM_ORGENTDISP
2035 ; softinclude user instructions
2036 include "?bzasm80_user_mnemonics.zas"
2137 $printf "assembler tables size: %d", csizest
2139 asmsizest = $-asmsizest
2140 $printf "full assembler size: %d", asmsizest
2142 ; so they won't clutter symbol table