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.
255 ; this code seems to be for tokenized input
256 ; we don't have tokenizer
264 ; carry flag set on error
266 ; A contains token index
267 ; B contains token data byte
269 ld d,0 ;CLEAR IX/IY FLAG
272 ; A contains token index
273 ; C contains token data byte
274 ; D contains IX/IY flag
276 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
278 ;; GROUP 0 - TRIVIAL CASES REQUIRING NO COMPUTATION
279 ;; GROUP 1 - AS GROUP 0 BUT WITH "ED" PREFIX
281 sub OPC_COUNT_GROUPS_0_AND_1
283 cp OPC_COUNT_GROUP_0-OPC_COUNT_GROUPS_0_AND_1
287 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
289 ;; GROUP 2 - BIT, RES, SET
290 ;; GROUP 3 - RLC, RRC, RL, RR, SLA, SRA, SRL
293 sub OPC_COUNT_GROUPS_2_AND_3
295 cp OPC_COUNT_GROUP_2-OPC_COUNT_GROUPS_2_AND_3
303 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
305 ;; GROUP 4 - PUSH, POP, EX (SP)
308 sub OPC_COUNT_GROUP_4
315 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
317 ;; GROUP 5 - SUB, AND, XOR, OR, CP
318 ;; GROUP 6 - ADD, ADC, SBC
321 sub OPC_COUNT_GROUPS_5_AND_6
323 cp OPC_COUNT_GROUP_5-OPC_COUNT_GROUPS_5_AND_6
354 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
356 ;; GROUP 7 - INC, DEC
359 sub OPC_COUNT_GROUP_7
376 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
382 sub OPC_COUNT_GROUPS_8_AND_9
384 cp OPC_COUNT_GROUP_8-OPC_COUNT_GROUPS_8_AND_9
405 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
407 ;; GROUP 10 - JR, DJNZ
410 sub OPC_COUNT_GROUP_10
412 cp OPC_COUNT_GROUP_10_JRS-OPC_COUNT_GROUP_10
434 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
454 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
469 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
484 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
497 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
546 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
547 ;; misc. instructions
552 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
557 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
560 ld hl,(ASM_JR_TOO_FAR_CB)
563 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
572 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
587 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
597 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
610 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
617 ret z ;REJECT LD (HL),(HL)
624 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
654 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
662 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
663 ;; parse numeric expression
670 ; HL: expression value
678 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
689 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
696 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
703 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
718 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
730 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
747 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
749 ;; common defb/defw code
750 ;; carry set if we want words
772 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
782 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
792 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
819 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
824 IF @BZ80ASM_ORGENTDISP
834 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
843 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
852 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
854 ;; error (the thing that should not be)
858 ; set "unknown instruction index"
867 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
868 ;; search the table for a token from the input buffer
869 ;; skips leading delimiters, and the token itself (if found)
870 ;; tokens in the table must have bit 7 set on the last char
871 ;; table ends with zero byte instead of first token char
872 ;; each token is followed by a data byte
876 ;; IY: new position in the text buffer
878 ;; B: token data byte
879 ;; carry flag set on error (invalid char, or token not found)
880 ;; on error, delimiters are still skipped
884 ; main table search entry point
891 ; reject chars with high bit set
897 ; check the first char
902 and %01011111 ; for case-insensitivity
904 ; first char is not matched, skip this token
909 ; skip token data byte
911 ; increment token counter
915 ; first char matched, check the rest
916 ; A holds zero (due to xor/and)
925 ; not the last token char
926 ; this compares (HL) with 0, because
927 ; A is guaranteed to hold zero here
929 ; zero byte in token means "skip delimiters"
930 ; it is used in some opcodes with fixed operands
934 ; compare with input char
936 and %01011111 ; for case-insensitivity
939 ; alas, doesn't match
941 ; restore input stream pointer
943 ; and skip this token
946 ; we'll come here if we succesfully matched a token
948 ; if it isn't followed by a delimiter, '+' or '-', this is not a valid token
953 ; this token is valid
955 ; move token index to A
957 ; load B with token data byte
959 ; drop original input stream position
962 ; note that carry flag is guaranteed to be reset
966 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
974 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
975 ;; this entry point is used by FIND
978 ;; this entry point is used to skip blanks and delimiters
979 ;; note that comma and right paren are considered blanks too
980 ;; as a consequence, operands may be delimited by spaces, or
982 ;; returns current char in A (and IY pointing to it)
983 ;; zero flag set if we hit a terminator
984 ;; zero flag reset if we hit a non-delimiter
986 ; delimiter or terminator?
989 ; if this is terminator, still stop
992 ; this is delimiter, skip it
996 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
997 ;; used by FIND and SKIP
998 ;; check if the current char is a delimiter or a terminator
999 ;; zero flag set on delimiter/terminator
1001 ld a,(iy) ;ASSEMBLER DELIMITER
1009 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1010 ;; entry point for SKIP
1012 cp ';' ;ASSEMBLER TERMINATOR
1017 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1018 ;; also used by assembler to check for command separator
1019 ;; the assembler itself does nothing with separators
1021 cp ':' ;ASSEMBLER SEPARATOR
1027 $printf "assembler size: %d", csizest
1032 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1033 ;; parse integer number (without sign)
1034 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1036 ;; this is advanced number parser
1037 ;; it understands alot of suffixes and prefixes:
1038 ;; $ -- lone "$" means "current PC"
1049 ;; everything is case-insensitive
1050 ;; you can separate digits with underscores
1051 ;; (i.e. "12_34_5" will work, underscores are simply ignored)
1054 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1056 ;; parse a number, push it onto the stack
1057 ;; understands prefixes and suffixes
1062 ;; IY: text buffer after the expression
1065 ;; OR: (cannot parse as a number)
1068 ;; DE,AF,flags: dead
1071 call PARSER_SKIP_BLANKS
1074 push iy ; we will need to rollback on error
1075 ; A already contains a char, loaded by `PARSER_SKIP_BLANKS`
1079 jr z,.maybe_lone_dollar
1084 ; no, leading zero doesn't mean "octal", this is stupid
1085 ; but we may have prefixes like "0x" and such
1087 jr z,.maybe_zero_prefix
1088 ; check if we have a digit here
1089 call PARSER_CONV_DIGIT
1090 jr c,.not_a_number_carry_set
1092 ; nope, do not allow it, all numbers must start with a digit
1093 ;jr nc,.must_be_hex_with_sfx
1095 jr c,.not_a_number_carry_set
1097 ; done with prefixes, try decimal number
1098 ; we'll switch to suffix checking on hex digit
1099 ld hl,0 ; accumulator
1104 jr nc,.must_be_hex_with_sfx
1121 and %11011111 ; cheap uppercase
1123 jr z,.must_be_hex_with_sfx
1128 ; no suffix, we're done
1136 .not_a_number_carry_set:
1145 jr c,.not_a_number_carry_set
1149 ; lone dollar means "PC"
1152 ; the only case we may gen an error here is
1153 ; when our dollar isn't followed by a digit
1155 ; lone dollar is good too
1156 ; IY points right after the dollar here
1167 ; things like "0BEEFh" should be parsed as hex
1171 jr c,.must_be_hex_with_sfx
1174 and %11011111 ; cheap uppercase
1176 jr z,.must_be_hex_with_sfx
1186 ; check for '0x' and such
1190 ; there's no need to skip it, as it will be
1191 ; skipped by the corresponding subroutine
1193 ; so IY will point to the actual number
1194 and %11011111 ; cheap uppercase
1198 jr z,.maybe_binprefix
1201 ; do not reparse '0', no need to backup
1202 jr .do_normal_decimal
1204 .must_be_hex_with_sfx:
1205 ; reparse as hex, and check for suffix
1209 jr c,.not_a_number_carry_set
1212 and %11011111 ; cheap uppercase
1217 ; reparse as bin, skip suffix (it is guaranteed to be there)
1221 .done_guaranteed_suffix:
1222 jr c,.not_a_number_carry_set
1228 ; reparse as bin, skip suffix (it is guaranteed to be there)
1232 jr .done_guaranteed_suffix
1235 ld hl,0 ; accumulator
1236 ; check first digit (as this is general parser)
1237 call .getDigitNoUnder
1249 jr nc,.parse_as_hex_loop
1250 ; clear carry flag (it is always set here)
1255 ld hl,0 ; accumulator
1256 ; check first digit (as this is general parser)
1258 call .getDigitNoUnderBin
1267 jr nc,.parse_as_bin_loop
1268 ; clear carry flag (it is always set here)
1273 ld hl,0 ; accumulator
1274 ; check first digit (as this is general parser)
1276 call .getDigitNoUnderOct
1286 jr nc,.parse_as_oct_loop
1287 ; clear carry flag (it is always set here)
1298 jp PARSER_CONV_DIGIT
1310 jp PARSER_CONV_DIGIT
1316 .getDigitNoUnderOct:
1322 .getDigitNoUnderBin:
1329 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1330 ;; converts 'A' to digit (assume hex)
1331 ;; carry set: not a digit char (and A is destroyed)
1340 and %11011111 ; cheap uppercase
1348 $printf "assembler numparse size: %d", csizest
1353 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1354 ;; math expression parser
1355 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1358 ld hl,(EXPR_ERROR_CB)
1361 PARSE_EXPR_ERROR_INT:
1362 ld a,EXPR_ERR_NUMBER_EXPECTED
1363 jr PARSE_EXPR_ERROR_A
1365 PARSE_EXPR_ERROR_STR:
1366 ld a,EXPR_ERR_STRING_EXPECTED
1367 jr PARSE_EXPR_ERROR_A
1369 PARSE_EXPR_ERROR_0DIV:
1370 ld a,EXPR_ERR_DIVISION_BY_ZERO
1371 jr PARSE_EXPR_ERROR_A
1373 PARSE_EXPR_ERROR_RPAREN:
1374 ld a,EXPR_ERR_RPAREN_EXPECTED
1375 jr PARSE_EXPR_ERROR_A
1378 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1380 ;; parse an integer expression
1384 ;; IY: text buffer after the expression
1385 ;; HL: expression value
1386 ;; everything other (including all alternate registers) is dead
1395 call PARSER_SKIP_BLANKS
1396 jp z,PARSE_EXPR_ERROR_INT
1418 ; already done above
1421 ; check for operation
1422 call PARSER_SKIP_BLANKS
1426 ; get second operand
1442 ; check for operation
1443 call PARSER_SKIP_BLANKS
1447 ; get second operand
1463 ; check for operation
1464 call PARSER_SKIP_BLANKS
1468 ; get second operand
1483 ; check for operation
1484 call PARSER_SKIP_BLANKS
1486 ; (iy+0) and (iy+1) should be equal
1494 ; get second operand
1495 inc iy ; skip operation part
1499 ; HL: number to shift
1503 jr nz,.shift_too_far
1506 jr nc,.shift_too_far
1533 ; check for operation
1534 call PARSER_SKIP_BLANKS
1541 ; get second operand
1557 ; check for operation
1558 call PARSER_SKIP_BLANKS
1567 ; get second operand
1573 ex af,af' ; save operation
1577 jp z,PARSE_EXPR_ERROR_0DIV
1578 call PARSER_UDIV_BC_DE
1579 ; was it div or mod?
1582 jr z,.muldiv_next ; remainder already in hl
1587 call PARSER_UMUL_BC_DE
1590 ;; parse term, also process unaries and parens
1592 call PARSER_SKIP_BLANKS
1593 jp z,PARSE_EXPR_ERROR_INT
1594 inc iy ; skip operation
1603 ; this must be number
1608 push iy ; for correct error position
1609 push ix ; the only register we care about
1610 ld hl,.term_checklabel_ret
1614 .term_checklabel_ret:
1619 ; restore position for correct error reporting
1622 jp PARSE_EXPR_ERROR_INT
1626 ;; C contains matching rparen
1629 call PARSER_SKIP_BLANKS
1630 jp z,PARSE_EXPR_ERROR_RPAREN
1633 jp nz,PARSE_EXPR_ERROR_RPAREN
1648 ;; call subroutine at BC
1651 ;; DE: subroutine result
1652 ;; i.e. HL is op0, DE is op1
1655 push af ; A holds operation
1656 inc iy ; skip operation
1657 ld hl,.go_down_bc_ret
1668 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1672 ;; BC,DE,A,flags: dead
1692 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1718 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1720 ;; parse a string expression
1725 ;; HL: string buffer start
1726 ;; E: parsed string length
1727 ;; everything other (including all alternate registers) is dead
1730 call PARSER_SKIP_BLANKS
1731 jp z,PARSE_EXPR_ERROR_STR
1735 jp nz,PARSE_EXPR_ERROR_STR
1739 ; remember buffer start
1744 jp z,PARSE_EXPR_ERROR_STR
1746 jp z,PARSE_EXPR_ERROR_STR
1750 ; done string parsing, calc length
1751 pop hl ; buffer start
1763 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1765 ;; returns current char in A
1766 ;; sets zero flag on EOL
1770 ;; IY: text buffer at non-blank or EOL
1771 ;; A: non-blank or EOL char
1772 ;; zero flag is set on EOL
1782 jr c,PARSER_SKIP_BLANKS
1789 $printf "assembler exprparse size: %d", csizest
1792 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1793 ;; various tables -- mnemonics, operands...
1797 ;; number of "trivial" opcodes without any special processing
1798 OPC_COUNT_GROUPS_0_AND_1 equ 39
1799 ;; number of non-ED-prefixed instructions in "trivial"
1800 OPC_COUNT_GROUP_0 equ 15
1802 ;; total number of CB-prefixed instructions (GROUPS 2 and 3)
1803 OPC_COUNT_GROUPS_2_AND_3 equ 10
1804 ;; number of direct bit manipulation instructions in CB list (GROUP 2)
1805 OPC_COUNT_GROUP_2 equ 3
1807 ;; push, pop, ex (sp),rr
1808 OPC_COUNT_GROUP_4 equ 3
1811 OPC_COUNT_GROUP_5 equ 5
1813 OPC_COUNT_GROUP_6 equ 3
1815 OPC_COUNT_GROUPS_5_AND_6 equ OPC_COUNT_GROUP_5+OPC_COUNT_GROUP_6
1818 OPC_COUNT_GROUP_7 equ 2
1821 OPC_COUNT_GROUP_8 equ 1
1823 OPC_COUNT_GROUP_9 equ 1
1825 OPC_COUNT_GROUPS_8_AND_9 equ OPC_COUNT_GROUP_8+OPC_COUNT_GROUP_9
1828 OPC_COUNT_GROUP_10 equ 2
1829 OPC_COUNT_GROUP_10_JRS equ 1
1832 ;; WARNING! the assembler has some hard-coded mnemonics counts
1833 ;; scattered across the code, so don't mess with the tables!
1834 ;; i may document this in the future, but for now, leave it as it is.
1837 ; GROUPS 0 AND 1: "trivial" (39, OPC_COUNT_GROUPS_0_AND_1)
1838 ; GROUP 0: "trivial" one-byte (15, OPC_COUNT_GROUP_0)
1871 ; GROUP 1: "trivial" ED-prefixed (24, OPC_COUNT_GROUPS_0_AND_1-OPC_COUNT_GROUP_0)
1924 ; GROUPS 2 AND 3: CB-prefixed (10, OPC_COUNT_GROUPS_2_AND_3)
1925 ; GROUP 2: direct bit manipulation (3, OPC_COUNT_GROUP_2)
1932 ; GROUP 3: shifts (7, OPC_COUNT_GROUPS_2_AND_3-OPC_COUNT_GROUP_2)
1948 ; GROUP 4: push,pop,ex (sp),rr (OPC_COUNT_GROUP_4)
1957 ; GROUP 5: ALU with accumulator (OPC_COUNT_GROUP_5)
1968 ;k8: for some reason i cannot remove those two
1974 ; GROUP 6: ALU with accumulator or HL (OPC_COUNT_GROUP_6)
1982 ; GROUP 7: inc,dec (2, OPC_COUNT_GROUP_7)
1988 ; GROUP 8: in (1, OPC_COUNT_GROUP_8)
1991 ; GROUP 9: out (1, OPC_COUNT_GROUP_9)
1995 ; GROUP 10: jr,djnz (2, OPC_COUNT_GROUP_10)
2001 ; GROUP 11: jp (strictly one)
2005 ; GROUP 12: call (strictly one)
2009 ; GROUP 13: rst (strictly one)
2013 ; GROUP 14: ret (strictly one)
2017 ; GROUP 15: ld (strictly one)
2021 ; miscellaneous assembler instructions
2022 ; WARNING! the order matters!
2032 IF @BZ80ASM_ORGENTDISP
2042 ; softinclude user instructions
2043 include "?bzasm80_user_mnemonics.zas"
2144 $printf "assembler tables size: %d", csizest
2146 asmsizest = $-asmsizest
2147 $printf "full assembler size: %d", asmsizest
2149 ; so they won't clutter symbol table