1 /* coded by Ketmar // Invisible Vector (ketmar@ketmar.no-ip.org)
2 * Understanding is not required. Only obedience.
4 * URASM Z80 assembler/disassembler core v0.1.2 (with ZXNext support)
6 * This program is free software. It comes without any warranty, to
7 * the extent permitted by applicable law. You can redistribute it
8 * and/or modify it under the terms of the Do What The Fuck You Want
9 * To Public License, Version 2, as published by Sam Hocevar. See
10 * http://sam.zoy.org/wtfpl/COPYING for more details.
20 int urasm_allow_zxnext
= 0;
21 int urasm_disasm_decimal
= 0;
22 const char *urasm_disasm_mnemo_delimiter
= "\t";
23 const char *urasm_disasm_operand_delimiter
= ",";
24 urasm_label_by_addr_fn urasm_label_by_addr
= NULL
;
25 urasm_label_by_name_fn urasm_label_by_name
= NULL
;
26 urasm_getbyte_fn urasm_getbyte
= NULL
;
27 urasm_putbyte_fn urasm_putbyte
= NULL
;
28 urasm_fixup_operand_fn urasm_fixup_operand
= NULL
;
31 const char *URASM_TOKENS
[URASM_MAX_TOKEN
] = {
32 "ADC", "ADD", "AND", "BIT", "CALL","CCF", "CP", "CPD",
33 "CPDR","CPI", "CPIR","CPL", "DAA", "DEC", "DI", "DJNZ",
34 "EI", "EX", "EXX", "HALT","IM", "IN", "INC", "IND",
35 "INDR","INI", "INIR","JP", "JR", "LD", "LDD", "LDDR",
36 "LDI", "LDIR","NEG", "NOP", "OR", "OTDR","OTIR","OUT",
37 "OUTD","OUTI","POP", "PUSH","RES", "RET", "RETI","RETN",
38 "RL", "RLA", "RLC", "RLCA","RLD", "RR", "RRA", "RRC",
39 "RRCA","RRD", "RST", "SBC", "SCF", "SET", "SLA", "SLI",
40 "SLL", "SRA", "SRL", "SUB", "XOR", "XSLT","NOPX","NOPY",
42 "LDIX", "LDWS", "LDIRX", "LDDX",
43 "LDDRX", "LDPIRX", "OUTINB", "MUL",
44 "SWAPNIB", "MIRROR", "NEXTREG", "PIXELDN",
45 "PIXELAD", "SETAE", "TEST", "BSLA",
46 "BSRA", "BSRL", "BSRF", "BRLC"
50 const char *URA_REGS8
[8] = {"B","C","D","E","H","L","(HL)","A"};
51 const char *URA_REGS16
[4] = {"BC","DE","HL","SP"};
52 const char *URA_REGS16A
[4] = {"BC","DE","HL","AF"};
53 const char *URA_COND
[8] = {"NZ","Z","NC","C","PO","PE","P","M"};
56 // the longest matches must come first (for disassembler)
57 // solid-masked must come first (for disassembler)
58 // assembler searches the table from the last command
59 // disassembler searches the table from the first command
60 // heh, i spent a whole night creating this shit! %-)
61 const urasm_cmdinfo_t URASM_COMMANDS
[URASM_MAX_COMMAND
] = {
62 {.mnemo
=UT_NOPX
, .code
=0x000000DDUL
, .mask
=0x00000000UL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
63 {.mnemo
=UT_NOPY
, .code
=0x000000FDUL
, .mask
=0x00000000UL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
64 // DD/CB opcodes (special)
66 {.mnemo
=UT_RLC
, .code
=0x0600CBDDUL
, .mask
=0xFF00FFFFUL
, .ops
={UO_MIX
, UO_NONE
, UO_NONE
}},
68 {.mnemo
=UT_RRC
, .code
=0x0E00CBDDUL
, .mask
=0xFF00FFFFUL
, .ops
={UO_MIX
, UO_NONE
, UO_NONE
}},
70 {.mnemo
=UT_RL
, .code
=0x1600CBDDUL
, .mask
=0xFF00FFFFUL
, .ops
={UO_MIX
, UO_NONE
, UO_NONE
}},
72 {.mnemo
=UT_RR
, .code
=0x1E00CBDDUL
, .mask
=0xFF00FFFFUL
, .ops
={UO_MIX
, UO_NONE
, UO_NONE
}},
74 {.mnemo
=UT_SLA
, .code
=0x2600CBDDUL
, .mask
=0xFF00FFFFUL
, .ops
={UO_MIX
, UO_NONE
, UO_NONE
}},
76 {.mnemo
=UT_SRA
, .code
=0x2E00CBDDUL
, .mask
=0xFF00FFFFUL
, .ops
={UO_MIX
, UO_NONE
, UO_NONE
}},
78 {.mnemo
=UT_SLL
, .code
=0x3600CBDDUL
, .mask
=0xFF00FFFFUL
, .ops
={UO_MIX
, UO_NONE
, UO_NONE
}},
80 {.mnemo
=UT_SLI
, .code
=0x3600CBDDUL
, .mask
=0xFF00FFFFUL
, .ops
={UO_MIX
, UO_NONE
, UO_NONE
}},
82 {.mnemo
=UT_SRL
, .code
=0x3E00CBDDUL
, .mask
=0xFF00FFFFUL
, .ops
={UO_MIX
, UO_NONE
, UO_NONE
}},
84 {.mnemo
=UT_RES
, .code
=0x8600CBDDUL
, .mask
=0xC700FFFFUL
, .ops
={UO_BITN
, UO_MIX
, UO_NONE
}},
86 {.mnemo
=UT_SET
, .code
=0xC600CBDDUL
, .mask
=0xC700FFFFUL
, .ops
={UO_BITN
, UO_MIX
, UO_NONE
}},
87 // FD/CB opcodes (special)
89 {.mnemo
=UT_RLC
, .code
=0x0600CBFDUL
, .mask
=0xFF00FFFFUL
, .ops
={UO_MIY
, UO_NONE
, UO_NONE
}},
91 {.mnemo
=UT_RRC
, .code
=0x0E00CBFDUL
, .mask
=0xFF00FFFFUL
, .ops
={UO_MIY
, UO_NONE
, UO_NONE
}},
93 {.mnemo
=UT_RL
, .code
=0x1600CBFDUL
, .mask
=0xFF00FFFFUL
, .ops
={UO_MIY
, UO_NONE
, UO_NONE
}},
95 {.mnemo
=UT_RR
, .code
=0x1E00CBFDUL
, .mask
=0xFF00FFFFUL
, .ops
={UO_MIY
, UO_NONE
, UO_NONE
}},
97 {.mnemo
=UT_SLA
, .code
=0x2600CBFDUL
, .mask
=0xFF00FFFFUL
, .ops
={UO_MIY
, UO_NONE
, UO_NONE
}},
99 {.mnemo
=UT_SRA
, .code
=0x2E00CBFDUL
, .mask
=0xFF00FFFFUL
, .ops
={UO_MIY
, UO_NONE
, UO_NONE
}},
101 {.mnemo
=UT_SLL
, .code
=0x3600CBFDUL
, .mask
=0xFF00FFFFUL
, .ops
={UO_MIY
, UO_NONE
, UO_NONE
}},
103 {.mnemo
=UT_SLI
, .code
=0x3600CBFDUL
, .mask
=0xFF00FFFFUL
, .ops
={UO_MIY
, UO_NONE
, UO_NONE
}},
105 {.mnemo
=UT_SRL
, .code
=0x3E00CBFDUL
, .mask
=0xFF00FFFFUL
, .ops
={UO_MIY
, UO_NONE
, UO_NONE
}},
107 {.mnemo
=UT_RES
, .code
=0x8600CBFDUL
, .mask
=0xC700FFFFUL
, .ops
={UO_BITN
, UO_MIY
, UO_NONE
}},
109 {.mnemo
=UT_SET
, .code
=0xC600CBFDUL
, .mask
=0xC700FFFFUL
, .ops
={UO_BITN
, UO_MIY
, UO_NONE
}},
113 {.mnemo
=UT_RLC
, .code
=0x0000CBDDUL
, .mask
=0xF800FFFFUL
, .ops
={UO_MIX
, UO_R8_NOM
, UO_NONE
}},
115 {.mnemo
=UT_RRC
, .code
=0x0800CBDDUL
, .mask
=0xF800FFFFUL
, .ops
={UO_MIX
, UO_R8_NOM
, UO_NONE
}},
117 {.mnemo
=UT_RL
, .code
=0x1000CBDDUL
, .mask
=0xF800FFFFUL
, .ops
={UO_MIX
, UO_R8_NOM
, UO_NONE
}},
119 {.mnemo
=UT_RR
, .code
=0x1800CBDDUL
, .mask
=0xF800FFFFUL
, .ops
={UO_MIX
, UO_R8_NOM
, UO_NONE
}},
121 {.mnemo
=UT_SLA
, .code
=0x2000CBDDUL
, .mask
=0xF800FFFFUL
, .ops
={UO_MIX
, UO_R8_NOM
, UO_NONE
}},
123 {.mnemo
=UT_SRA
, .code
=0x2800CBDDUL
, .mask
=0xF800FFFFUL
, .ops
={UO_MIX
, UO_R8_NOM
, UO_NONE
}},
125 {.mnemo
=UT_SLL
, .code
=0x3000CBDDUL
, .mask
=0xF800FFFFUL
, .ops
={UO_MIX
, UO_R8_NOM
, UO_NONE
}},
127 {.mnemo
=UT_SLI
, .code
=0x3000CBDDUL
, .mask
=0xF800FFFFUL
, .ops
={UO_MIX
, UO_R8_NOM
, UO_NONE
}},
129 {.mnemo
=UT_SRL
, .code
=0x3800CBDDUL
, .mask
=0xF800FFFFUL
, .ops
={UO_MIX
, UO_R8_NOM
, UO_NONE
}},
131 {.mnemo
=UT_BIT
, .code
=0x4600CBDDUL
, .mask
=0xC700FFFFUL
, .ops
={UO_BITN
, UO_MIX
, UO_NONE
}},
133 {.mnemo
=UT_BIT
, .code
=0x4000CBDDUL
, .mask
=0xC000FFFFUL
, .ops
={UO_BITN
, UO_MIX
, UO_R8_NOM
}},
135 {.mnemo
=UT_RES
, .code
=0x8000CBDDUL
, .mask
=0xC000FFFFUL
, .ops
={UO_BITN
, UO_MIX
, UO_R8_NOM
}},
137 {.mnemo
=UT_SET
, .code
=0xC000CBDDUL
, .mask
=0xC000FFFFUL
, .ops
={UO_BITN
, UO_MIX
, UO_R8_NOM
}},
140 {.mnemo
=UT_RLC
, .code
=0x0000CBFDUL
, .mask
=0xF800FFFFUL
, .ops
={UO_MIY
, UO_R8_NOM
, UO_NONE
}},
142 {.mnemo
=UT_RRC
, .code
=0x0800CBFDUL
, .mask
=0xF800FFFFUL
, .ops
={UO_MIY
, UO_R8_NOM
, UO_NONE
}},
144 {.mnemo
=UT_RL
, .code
=0x1000CBFDUL
, .mask
=0xF800FFFFUL
, .ops
={UO_MIY
, UO_R8_NOM
, UO_NONE
}},
146 {.mnemo
=UT_RR
, .code
=0x1800CBFDUL
, .mask
=0xF800FFFFUL
, .ops
={UO_MIY
, UO_R8_NOM
, UO_NONE
}},
148 {.mnemo
=UT_SLA
, .code
=0x2000CBFDUL
, .mask
=0xF800FFFFUL
, .ops
={UO_MIY
, UO_R8_NOM
, UO_NONE
}},
150 {.mnemo
=UT_SRA
, .code
=0x2800CBFDUL
, .mask
=0xF800FFFFUL
, .ops
={UO_MIY
, UO_R8_NOM
, UO_NONE
}},
152 {.mnemo
=UT_SLL
, .code
=0x3000CBFDUL
, .mask
=0xF800FFFFUL
, .ops
={UO_MIY
, UO_R8_NOM
, UO_NONE
}},
154 {.mnemo
=UT_SLI
, .code
=0x3000CBFDUL
, .mask
=0xF800FFFFUL
, .ops
={UO_MIY
, UO_R8_NOM
, UO_NONE
}},
156 {.mnemo
=UT_SRL
, .code
=0x3800CBFDUL
, .mask
=0xF800FFFFUL
, .ops
={UO_MIY
, UO_R8_NOM
, UO_NONE
}},
158 {.mnemo
=UT_BIT
, .code
=0x4600CBFDUL
, .mask
=0xC700FFFFUL
, .ops
={UO_BITN
, UO_MIY
, UO_NONE
}},
160 {.mnemo
=UT_BIT
, .code
=0x4000CBFDUL
, .mask
=0xC000FFFFUL
, .ops
={UO_BITN
, UO_MIY
, UO_R8_NOM
}},
162 {.mnemo
=UT_RES
, .code
=0x8000CBFDUL
, .mask
=0xC000FFFFUL
, .ops
={UO_BITN
, UO_MIY
, UO_R8_NOM
}},
164 {.mnemo
=UT_SET
, .code
=0xC000CBFDUL
, .mask
=0xC000FFFFUL
, .ops
={UO_BITN
, UO_MIY
, UO_R8_NOM
}},
165 // standard CB opcodes
167 {.mnemo
=UT_RLC
, .code
=0x00CBUL
, .mask
=0xF8FFUL
, .ops
={UO_R8
, UO_NONE
, UO_NONE
}},
169 {.mnemo
=UT_RRC
, .code
=0x08CBUL
, .mask
=0xF8FFUL
, .ops
={UO_R8
, UO_NONE
, UO_NONE
}},
171 {.mnemo
=UT_RL
, .code
=0x10CBUL
, .mask
=0xF8FFUL
, .ops
={UO_R8
, UO_NONE
, UO_NONE
}},
173 {.mnemo
=UT_RR
, .code
=0x18CBUL
, .mask
=0xF8FFUL
, .ops
={UO_R8
, UO_NONE
, UO_NONE
}},
175 {.mnemo
=UT_SLA
, .code
=0x20CBUL
, .mask
=0xF8FFUL
, .ops
={UO_R8
, UO_NONE
, UO_NONE
}},
177 {.mnemo
=UT_SRA
, .code
=0x28CBUL
, .mask
=0xF8FFUL
, .ops
={UO_R8
, UO_NONE
, UO_NONE
}},
179 {.mnemo
=UT_SLL
, .code
=0x30CBUL
, .mask
=0xF8FFUL
, .ops
={UO_R8
, UO_NONE
, UO_NONE
}},
181 {.mnemo
=UT_SLI
, .code
=0x30CBUL
, .mask
=0xF8FFUL
, .ops
={UO_R8
, UO_NONE
, UO_NONE
}},
183 {.mnemo
=UT_SRL
, .code
=0x38CBUL
, .mask
=0xF8FFUL
, .ops
={UO_R8
, UO_NONE
, UO_NONE
}},
185 {.mnemo
=UT_BIT
, .code
=0x40CBUL
, .mask
=0xC0FFUL
, .ops
={UO_BITN
, UO_R8
, UO_NONE
}},
187 {.mnemo
=UT_RES
, .code
=0x80CBUL
, .mask
=0xC0FFUL
, .ops
={UO_BITN
, UO_R8
, UO_NONE
}},
189 {.mnemo
=UT_SET
, .code
=0xC0CBUL
, .mask
=0xC0FFUL
, .ops
={UO_BITN
, UO_R8
, UO_NONE
}},
193 {.mnemo
=UT_XSLT
, .code
=0xFBEDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
194 // ED string instructions
195 {.mnemo
=UT_LDI
, .code
=0xA0EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
196 {.mnemo
=UT_LDIR
, .code
=0xB0EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
197 {.mnemo
=UT_CPI
, .code
=0xA1EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
198 {.mnemo
=UT_CPIR
, .code
=0xB1EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
199 {.mnemo
=UT_INI
, .code
=0xA2EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
200 {.mnemo
=UT_INIR
, .code
=0xB2EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
201 {.mnemo
=UT_OUTI
, .code
=0xA3EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
202 {.mnemo
=UT_OTIR
, .code
=0xB3EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
203 {.mnemo
=UT_LDD
, .code
=0xA8EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
204 {.mnemo
=UT_LDDR
, .code
=0xB8EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
205 {.mnemo
=UT_CPD
, .code
=0xA9EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
206 {.mnemo
=UT_CPDR
, .code
=0xB9EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
207 {.mnemo
=UT_IND
, .code
=0xAAEDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
208 {.mnemo
=UT_INDR
, .code
=0xBAEDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
209 {.mnemo
=UT_OUTD
, .code
=0xABEDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
210 {.mnemo
=UT_OTDR
, .code
=0xBBEDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
212 /* ZXNext opcodes (always ED-prefixed) */
213 /* operand-less opcodes */
214 {.mnemo
=UT_LDIX
, .code
=0xA4EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NEXT
}},
215 {.mnemo
=UT_LDWS
, .code
=0xA5EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NEXT
}},
216 {.mnemo
=UT_LDIRX
, .code
=0xB4EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NEXT
}},
217 {.mnemo
=UT_LDDX
, .code
=0xACEDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NEXT
}},
218 {.mnemo
=UT_LDDRX
, .code
=0xBCEDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NEXT
}},
219 {.mnemo
=UT_LDPIRX
, .code
=0xB7EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NEXT
}},
220 {.mnemo
=UT_OUTINB
, .code
=0x90EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NEXT
}},
221 {.mnemo
=UT_MUL
, .code
=0x30EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NEXT
}},
222 {.mnemo
=UT_SWAPNIB
, .code
=0x23EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NEXT
}},
223 {.mnemo
=UT_PIXELDN
, .code
=0x93EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NEXT
}},
224 {.mnemo
=UT_PIXELAD
, .code
=0x94EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NEXT
}},
225 {.mnemo
=UT_SETAE
, .code
=0x95EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NEXT
}},
226 {.mnemo
=UT_MIRROR
, .code
=0x24EDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_NONE
, UO_NEXT
}},
228 {.mnemo
=UT_ADD
, .code
=0x31EDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16HL
, UO_R8_A
, UO_NEXT
}},
229 {.mnemo
=UT_ADD
, .code
=0x32EDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16DE
, UO_R8_A
, UO_NEXT
}},
230 {.mnemo
=UT_ADD
, .code
=0x33EDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16BC
, UO_R8_A
, UO_NEXT
}},
232 {.mnemo
=UT_ADD
, .code
=0x34EDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16HL
, UO_IMM16
, UO_NEXT
}},
233 {.mnemo
=UT_ADD
, .code
=0x35EDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16DE
, UO_IMM16
, UO_NEXT
}},
234 {.mnemo
=UT_ADD
, .code
=0x36EDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16BC
, UO_IMM16
, UO_NEXT
}},
236 {.mnemo
=UT_PUSH
, .code
=0x8AEDUL
, .mask
=0xFFFFUL
, .ops
={UO_IMM16BE
, UO_NONE
, UO_NEXT
}},
238 {.mnemo
=UT_TEST
, .code
=0x27EDUL
, .mask
=0xFFFFUL
, .ops
={UO_IMM8
, UO_NONE
, UO_NEXT
}},
240 {.mnemo
=UT_NEXTREG
, .code
=0x91EDUL
, .mask
=0xFFFFUL
, .ops
={UO_IMM8
, UO_IMM8
, UO_NEXT
}},
242 {.mnemo
=UT_NEXTREG
, .code
=0x92EDUL
, .mask
=0xFFFFUL
, .ops
={UO_IMM8
, UO_R8_A
, UO_NEXT
}},
244 {.mnemo
=UT_BSLA
, .code
=0x28EDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16DE
, UO_R8_B
, UO_NEXT
}},
245 {.mnemo
=UT_BSRA
, .code
=0x29EDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16DE
, UO_R8_B
, UO_NEXT
}},
246 {.mnemo
=UT_BSRL
, .code
=0x2AEDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16DE
, UO_R8_B
, UO_NEXT
}},
247 {.mnemo
=UT_BSRF
, .code
=0x2BEDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16DE
, UO_R8_B
, UO_NEXT
}},
248 {.mnemo
=UT_BRLC
, .code
=0x2CEDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16DE
, UO_R8_B
, UO_NEXT
}},
250 {.mnemo
=UT_JP
, .code
=0x98EDUL
, .mask
=0xFFFFUL
, .ops
={UO_PORTC
, UO_NONE
, UO_NEXT
}},
253 {.mnemo
=UT_RRD
, .code
=0x67EDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
254 {.mnemo
=UT_RLD
, .code
=0x6FEDUL
, .mask
=0xFFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
257 {.mnemo
=UT_IN
, .code
=0x70EDUL
, .mask
=0xFFFFUL
, .ops
={UO_PORTC
, UO_NONE
, UO_NONE
}},
259 {.mnemo
=UT_OUT
, .code
=0x71EDUL
, .mask
=0xFFFFUL
, .ops
={UO_PORTC
, UO_IM0
, UO_NONE
}},
262 {.mnemo
=UT_LD
, .code
=0x47EDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_I
, UO_R8_A
, UO_NONE
}},
264 {.mnemo
=UT_LD
, .code
=0x57EDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_I
, UO_NONE
}},
266 {.mnemo
=UT_LD
, .code
=0x4FEDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_R
, UO_R8_A
, UO_NONE
}},
268 {.mnemo
=UT_LD
, .code
=0x5FEDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_R
, UO_NONE
}},
270 //(.mnemo=UT_IM, .code=0x4EEDUL, .mask=0xFFFFUL, .ops={UO_IM01, UO_NONE, UO_NONE}},
273 {.mnemo
=UT_RETN
, .code
=0x45EDUL
, .mask
=0xCFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
274 {.mnemo
=UT_RETI
, .code
=0x4DEDUL
, .mask
=0xCFFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
277 {.mnemo
=UT_SBC
, .code
=0x42EDUL
, .mask
=0xCFFFUL
, .ops
={UO_R16HL
, UO_R16
, UO_NONE
}},
279 {.mnemo
=UT_ADC
, .code
=0x4AEDUL
, .mask
=0xCFFFUL
, .ops
={UO_R16HL
, UO_R16
, UO_NONE
}},
281 {.mnemo
=UT_LD
, .code
=0x43EDUL
, .mask
=0xCFFFUL
, .ops
={UO_MEM16
, UO_R16
, UO_NONE
}},
283 {.mnemo
=UT_LD
, .code
=0x4BEDUL
, .mask
=0xCFFFUL
, .ops
={UO_R16
, UO_MEM16
, UO_NONE
}},
286 {.mnemo
=UT_NEG
, .code
=0x44EDUL
, .mask
=0xC7FFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
289 {.mnemo
=UT_IN
, .code
=0x40EDUL
, .mask
=0xC7FFUL
, .ops
={UO_2R8_NOM
, UO_PORTC
, UO_NONE
}},
291 {.mnemo
=UT_OUT
, .code
=0x41EDUL
, .mask
=0xC7FFUL
, .ops
={UO_PORTC
, UO_2R8_NOM
, UO_NONE
}},
294 {.mnemo
=UT_IM
, .code
=0x5EEDUL
, .mask
=0xDFFFUL
, .ops
={UO_IM2
, UO_NONE
, UO_NONE
}},
296 {.mnemo
=UT_IM
, .code
=0x56EDUL
, .mask
=0xDFFFUL
, .ops
={UO_IM1
, UO_NONE
, UO_NONE
}},
298 {.mnemo
=UT_IM
, .code
=0x46EDUL
, .mask
=0xD7FFUL
, .ops
={UO_IM0
, UO_NONE
, UO_NONE
}},
301 {.mnemo
=UT_LD
, .code
=0xF9DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16SP
, UO_R16IX
, UO_NONE
}},
303 {.mnemo
=UT_LD
, .code
=0xF9FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16SP
, UO_R16IY
, UO_NONE
}},
306 {.mnemo
=UT_EX
, .code
=0xE3DDUL
, .mask
=0xFFFFUL
, .ops
={UO_MSP
, UO_R16IX
, UO_NONE
}},
307 // EX IX,(SP) (ditto)
308 {.mnemo
=UT_EX
, .code
=0xE3DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IX
, UO_MSP
, UO_NONE
}},
310 {.mnemo
=UT_EX
, .code
=0xE3FDUL
, .mask
=0xFFFFUL
, .ops
={UO_MSP
, UO_R16IY
, UO_NONE
}},
311 // EX IY,(SP) (ditto)
312 {.mnemo
=UT_EX
, .code
=0xE3FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IY
, UO_MSP
, UO_NONE
}},
315 {.mnemo
=UT_JP
, .code
=0xE9DDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIX0
, UO_NONE
, UO_NONE
}},
317 {.mnemo
=UT_JP
, .code
=0xE9FDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIY0
, UO_NONE
, UO_NONE
}},
319 {.mnemo
=UT_JP
, .code
=0xE9DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IX
, UO_NONE
, UO_NONE
}},
321 {.mnemo
=UT_JP
, .code
=0xE9FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IY
, UO_NONE
, UO_NONE
}},
324 {.mnemo
=UT_POP
, .code
=0xE1DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IX
, UO_NONE
, UO_NONE
}},
326 {.mnemo
=UT_PUSH
, .code
=0xE5DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IX
, UO_NONE
, UO_NONE
}},
328 {.mnemo
=UT_POP
, .code
=0xE1FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IY
, UO_NONE
, UO_NONE
}},
330 {.mnemo
=UT_PUSH
, .code
=0xE5FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IY
, UO_NONE
, UO_NONE
}},
333 {.mnemo
=UT_ADD
, .code
=0x86DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_MIX
, UO_NONE
}},
335 {.mnemo
=UT_ADD
, .code
=0x86DDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIX
, UO_NONE
, UO_NONE
}},
337 {.mnemo
=UT_ADC
, .code
=0x8EDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_MIX
, UO_NONE
}},
339 {.mnemo
=UT_ADC
, .code
=0x8EDDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIX
, UO_NONE
, UO_NONE
}},
341 {.mnemo
=UT_SUB
, .code
=0x96DDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIX
, UO_NONE
, UO_NONE
}},
343 {.mnemo
=UT_SUB
, .code
=0x96DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_MIX
, UO_NONE
}},
345 {.mnemo
=UT_SBC
, .code
=0x9EDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_MIX
, UO_NONE
}},
347 {.mnemo
=UT_SBC
, .code
=0x9EDDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIX
, UO_NONE
, UO_NONE
}},
349 {.mnemo
=UT_AND
, .code
=0xA6DDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIX
, UO_NONE
, UO_NONE
}},
351 {.mnemo
=UT_AND
, .code
=0xA6DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_MIX
, UO_NONE
}},
353 {.mnemo
=UT_XOR
, .code
=0xAEDDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIX
, UO_NONE
, UO_NONE
}},
355 {.mnemo
=UT_XOR
, .code
=0xAEDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_MIX
, UO_NONE
}},
357 {.mnemo
=UT_OR
, .code
=0xB6DDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIX
, UO_NONE
, UO_NONE
}},
359 {.mnemo
=UT_OR
, .code
=0xB6DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_MIX
, UO_NONE
}},
361 {.mnemo
=UT_CP
, .code
=0xBEDDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIX
, UO_NONE
, UO_NONE
}},
363 {.mnemo
=UT_CP
, .code
=0xBEDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_MIX
, UO_NONE
}},
365 {.mnemo
=UT_ADD
, .code
=0x86FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_MIY
, UO_NONE
}},
367 {.mnemo
=UT_ADD
, .code
=0x86FDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIY
, UO_NONE
, UO_NONE
}},
369 {.mnemo
=UT_ADC
, .code
=0x8EFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_MIY
, UO_NONE
}},
371 {.mnemo
=UT_ADC
, .code
=0x8EFDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIY
, UO_NONE
, UO_NONE
}},
373 {.mnemo
=UT_SUB
, .code
=0x96FDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIY
, UO_NONE
, UO_NONE
}},
375 {.mnemo
=UT_SUB
, .code
=0x96FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_MIY
, UO_NONE
}},
377 {.mnemo
=UT_SBC
, .code
=0x9EFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_MIY
, UO_NONE
}},
379 {.mnemo
=UT_SBC
, .code
=0x9EFDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIY
, UO_NONE
, UO_NONE
}},
381 {.mnemo
=UT_AND
, .code
=0xA6FDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIY
, UO_NONE
, UO_NONE
}},
383 {.mnemo
=UT_AND
, .code
=0xA6FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_MIY
, UO_NONE
}},
385 {.mnemo
=UT_XOR
, .code
=0xAEFDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIY
, UO_NONE
, UO_NONE
}},
387 {.mnemo
=UT_XOR
, .code
=0xAEFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_MIY
, UO_NONE
}},
389 {.mnemo
=UT_OR
, .code
=0xB6FDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIY
, UO_NONE
, UO_NONE
}},
391 {.mnemo
=UT_OR
, .code
=0xB6FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_MIY
, UO_NONE
}},
393 {.mnemo
=UT_CP
, .code
=0xBEFDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIY
, UO_NONE
, UO_NONE
}},
395 {.mnemo
=UT_CP
, .code
=0xBEFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_MIY
, UO_NONE
}},
397 {.mnemo
=UT_ADD
, .code
=0x84DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_XH
, UO_NONE
}},
399 {.mnemo
=UT_ADD
, .code
=0x84DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XH
, UO_NONE
, UO_NONE
}},
401 {.mnemo
=UT_ADC
, .code
=0x8CDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_XH
, UO_NONE
}},
403 {.mnemo
=UT_ADC
, .code
=0x8CDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XH
, UO_NONE
, UO_NONE
}},
405 {.mnemo
=UT_SUB
, .code
=0x94DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XH
, UO_NONE
, UO_NONE
}},
407 {.mnemo
=UT_SUB
, .code
=0x94DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_XH
, UO_NONE
}},
409 {.mnemo
=UT_SBC
, .code
=0x9CDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_XH
, UO_NONE
}},
411 {.mnemo
=UT_SBC
, .code
=0x9CDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XH
, UO_NONE
, UO_NONE
}},
413 {.mnemo
=UT_AND
, .code
=0xA4DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XH
, UO_NONE
, UO_NONE
}},
415 {.mnemo
=UT_AND
, .code
=0xA4DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_XH
, UO_NONE
}},
417 {.mnemo
=UT_XOR
, .code
=0xACDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XH
, UO_NONE
, UO_NONE
}},
419 {.mnemo
=UT_XOR
, .code
=0xACDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_XH
, UO_NONE
}},
421 {.mnemo
=UT_OR
, .code
=0xB4DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XH
, UO_NONE
, UO_NONE
}},
423 {.mnemo
=UT_OR
, .code
=0xB4DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_XH
, UO_NONE
}},
425 {.mnemo
=UT_CP
, .code
=0xBCDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XH
, UO_NONE
, UO_NONE
}},
427 {.mnemo
=UT_CP
, .code
=0xBCDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_XH
, UO_NONE
}},
429 {.mnemo
=UT_ADD
, .code
=0x85DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_XL
, UO_NONE
}},
431 {.mnemo
=UT_ADD
, .code
=0x85DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XL
, UO_NONE
, UO_NONE
}},
433 {.mnemo
=UT_ADC
, .code
=0x8DDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_XL
, UO_NONE
}},
435 {.mnemo
=UT_ADC
, .code
=0x8DDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XL
, UO_NONE
, UO_NONE
}},
437 {.mnemo
=UT_SUB
, .code
=0x95DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XL
, UO_NONE
, UO_NONE
}},
439 {.mnemo
=UT_SUB
, .code
=0x95DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_XL
, UO_NONE
}},
441 {.mnemo
=UT_SBC
, .code
=0x9DDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_XL
, UO_NONE
}},
443 {.mnemo
=UT_SBC
, .code
=0x9DDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XL
, UO_NONE
, UO_NONE
}},
445 {.mnemo
=UT_AND
, .code
=0xA5DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XL
, UO_NONE
, UO_NONE
}},
447 {.mnemo
=UT_AND
, .code
=0xA5DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_XL
, UO_NONE
}},
449 {.mnemo
=UT_XOR
, .code
=0xADDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XL
, UO_NONE
, UO_NONE
}},
451 {.mnemo
=UT_XOR
, .code
=0xADDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_XL
, UO_NONE
}},
453 {.mnemo
=UT_OR
, .code
=0xB5DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XL
, UO_NONE
, UO_NONE
}},
455 {.mnemo
=UT_OR
, .code
=0xB5DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_XL
, UO_NONE
}},
457 {.mnemo
=UT_CP
, .code
=0xBDDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XL
, UO_NONE
, UO_NONE
}},
459 {.mnemo
=UT_CP
, .code
=0xBDDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_XL
, UO_NONE
}},
461 {.mnemo
=UT_ADD
, .code
=0x84FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_YH
, UO_NONE
}},
463 {.mnemo
=UT_ADD
, .code
=0x84FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YH
, UO_NONE
, UO_NONE
}},
465 {.mnemo
=UT_ADC
, .code
=0x8CFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_YH
, UO_NONE
}},
467 {.mnemo
=UT_ADC
, .code
=0x8CFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YH
, UO_NONE
, UO_NONE
}},
469 {.mnemo
=UT_SUB
, .code
=0x94FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YH
, UO_NONE
, UO_NONE
}},
471 {.mnemo
=UT_SUB
, .code
=0x94FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_YH
, UO_NONE
}},
473 {.mnemo
=UT_SBC
, .code
=0x9CFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_YH
, UO_NONE
}},
475 {.mnemo
=UT_SBC
, .code
=0x9CFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YH
, UO_NONE
, UO_NONE
}},
477 {.mnemo
=UT_AND
, .code
=0xA4FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YH
, UO_NONE
, UO_NONE
}},
479 {.mnemo
=UT_AND
, .code
=0xA4FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_YH
, UO_NONE
}},
481 {.mnemo
=UT_XOR
, .code
=0xACFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YH
, UO_NONE
, UO_NONE
}},
483 {.mnemo
=UT_XOR
, .code
=0xACFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_YH
, UO_NONE
}},
485 {.mnemo
=UT_OR
, .code
=0xB4FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YH
, UO_NONE
, UO_NONE
}},
487 {.mnemo
=UT_OR
, .code
=0xB4FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_YH
, UO_NONE
}},
489 {.mnemo
=UT_CP
, .code
=0xBCFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YH
, UO_NONE
, UO_NONE
}},
491 {.mnemo
=UT_CP
, .code
=0xBCFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_YH
, UO_NONE
}},
493 {.mnemo
=UT_ADD
, .code
=0x85FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_YL
, UO_NONE
}},
495 {.mnemo
=UT_ADD
, .code
=0x85FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YL
, UO_NONE
, UO_NONE
}},
497 {.mnemo
=UT_ADC
, .code
=0x8DFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_YL
, UO_NONE
}},
499 {.mnemo
=UT_ADC
, .code
=0x8DFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YL
, UO_NONE
, UO_NONE
}},
501 {.mnemo
=UT_SUB
, .code
=0x95FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YL
, UO_NONE
, UO_NONE
}},
503 {.mnemo
=UT_SUB
, .code
=0x95FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_YL
, UO_NONE
}},
505 {.mnemo
=UT_SBC
, .code
=0x9DFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_YL
, UO_NONE
}},
507 {.mnemo
=UT_SBC
, .code
=0x9DFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YL
, UO_NONE
, UO_NONE
}},
509 {.mnemo
=UT_AND
, .code
=0xA5FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YL
, UO_NONE
, UO_NONE
}},
511 {.mnemo
=UT_AND
, .code
=0xA5FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_YL
, UO_NONE
}},
513 {.mnemo
=UT_XOR
, .code
=0xADFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YL
, UO_NONE
, UO_NONE
}},
515 {.mnemo
=UT_XOR
, .code
=0xADFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_YL
, UO_NONE
}},
517 {.mnemo
=UT_OR
, .code
=0xB5FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YL
, UO_NONE
, UO_NONE
}},
519 {.mnemo
=UT_OR
, .code
=0xB5FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_YL
, UO_NONE
}},
521 {.mnemo
=UT_CP
, .code
=0xBDFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YL
, UO_NONE
, UO_NONE
}},
523 {.mnemo
=UT_CP
, .code
=0xBDFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_A
, UO_R8_YL
, UO_NONE
}},
526 {.mnemo
=UT_LD
, .code
=0x64DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XH
, UO_R8_XH
, UO_NONE
}},
528 {.mnemo
=UT_LD
, .code
=0x65DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XH
, UO_R8_XL
, UO_NONE
}},
530 {.mnemo
=UT_LD
, .code
=0x6CDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XL
, UO_R8_XH
, UO_NONE
}},
532 {.mnemo
=UT_LD
, .code
=0x6DDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XL
, UO_R8_XL
, UO_NONE
}},
534 {.mnemo
=UT_LD
, .code
=0x64FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YH
, UO_R8_YH
, UO_NONE
}},
536 {.mnemo
=UT_LD
, .code
=0x65FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YH
, UO_R8_YL
, UO_NONE
}},
538 {.mnemo
=UT_LD
, .code
=0x6CFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YL
, UO_R8_YH
, UO_NONE
}},
540 {.mnemo
=UT_LD
, .code
=0x6DFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YL
, UO_R8_YL
, UO_NONE
}},
543 {.mnemo
=UT_LD
, .code
=0x22DDUL
, .mask
=0xFFFFUL
, .ops
={UO_MEM16
, UO_R16IX
, UO_NONE
}},
545 {.mnemo
=UT_LD
, .code
=0x2ADDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IX
, UO_MEM16
, UO_NONE
}},
547 {.mnemo
=UT_LD
, .code
=0x22FDUL
, .mask
=0xFFFFUL
, .ops
={UO_MEM16
, UO_R16IY
, UO_NONE
}},
549 {.mnemo
=UT_LD
, .code
=0x2AFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IY
, UO_MEM16
, UO_NONE
}},
552 {.mnemo
=UT_LD
, .code
=0x21DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IX
, UO_IMM16
, UO_NONE
}},
554 {.mnemo
=UT_LD
, .code
=0x21FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IY
, UO_IMM16
, UO_NONE
}},
557 {.mnemo
=UT_INC
, .code
=0x23DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IX
, UO_NONE
, UO_NONE
}},
559 {.mnemo
=UT_DEC
, .code
=0x2BDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IX
, UO_NONE
, UO_NONE
}},
561 {.mnemo
=UT_INC
, .code
=0x23FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IY
, UO_NONE
, UO_NONE
}},
563 {.mnemo
=UT_DEC
, .code
=0x2BFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IY
, UO_NONE
, UO_NONE
}},
566 {.mnemo
=UT_INC
, .code
=0x34DDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIX
, UO_NONE
, UO_NONE
}},
568 {.mnemo
=UT_DEC
, .code
=0x35DDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIX
, UO_NONE
, UO_NONE
}},
570 {.mnemo
=UT_LD
, .code
=0x36DDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIX
, UO_IMM8
, UO_NONE
}},
572 {.mnemo
=UT_INC
, .code
=0x34FDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIY
, UO_NONE
, UO_NONE
}},
574 {.mnemo
=UT_DEC
, .code
=0x35FDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIY
, UO_NONE
, UO_NONE
}},
576 {.mnemo
=UT_LD
, .code
=0x36FDUL
, .mask
=0xFFFFUL
, .ops
={UO_MIY
, UO_IMM8
, UO_NONE
}},
579 {.mnemo
=UT_INC
, .code
=0x24DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XH
, UO_NONE
, UO_NONE
}},
581 {.mnemo
=UT_DEC
, .code
=0x25DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XH
, UO_NONE
, UO_NONE
}},
583 {.mnemo
=UT_INC
, .code
=0x2CDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XL
, UO_NONE
, UO_NONE
}},
585 {.mnemo
=UT_DEC
, .code
=0x2DDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XL
, UO_NONE
, UO_NONE
}},
587 {.mnemo
=UT_INC
, .code
=0x24FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YH
, UO_NONE
, UO_NONE
}},
589 {.mnemo
=UT_DEC
, .code
=0x25FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YH
, UO_NONE
, UO_NONE
}},
591 {.mnemo
=UT_INC
, .code
=0x2CFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YL
, UO_NONE
, UO_NONE
}},
593 {.mnemo
=UT_DEC
, .code
=0x2DFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YL
, UO_NONE
, UO_NONE
}},
596 {.mnemo
=UT_LD
, .code
=0x26DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XH
, UO_IMM8
, UO_NONE
}},
598 {.mnemo
=UT_LD
, .code
=0x2EDDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_XL
, UO_IMM8
, UO_NONE
}},
600 {.mnemo
=UT_LD
, .code
=0x26FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YH
, UO_IMM8
, UO_NONE
}},
602 {.mnemo
=UT_LD
, .code
=0x2EFDUL
, .mask
=0xFFFFUL
, .ops
={UO_R8_YL
, UO_IMM8
, UO_NONE
}},
605 {.mnemo
=UT_ADD
, .code
=0x09DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IX
, UO_R16BC
, UO_NONE
}},
607 {.mnemo
=UT_ADD
, .code
=0x19DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IX
, UO_R16DE
, UO_NONE
}},
609 {.mnemo
=UT_ADD
, .code
=0x29DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IX
, UO_R16IX
, UO_NONE
}},
611 {.mnemo
=UT_ADD
, .code
=0x39DDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IX
, UO_R16SP
, UO_NONE
}},
613 {.mnemo
=UT_ADD
, .code
=0x09FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IY
, UO_R16BC
, UO_NONE
}},
615 {.mnemo
=UT_ADD
, .code
=0x19FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IY
, UO_R16DE
, UO_NONE
}},
617 {.mnemo
=UT_ADD
, .code
=0x29FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IY
, UO_R16IY
, UO_NONE
}},
619 {.mnemo
=UT_ADD
, .code
=0x39FDUL
, .mask
=0xFFFFUL
, .ops
={UO_R16IY
, UO_R16SP
, UO_NONE
}},
622 {.mnemo
=UT_LD
, .code
=0x60DDUL
, .mask
=0xF8FFUL
, .ops
={UO_R8_XH
, UO_R8_NOM
, UO_NONE
}},
624 {.mnemo
=UT_LD
, .code
=0x68DDUL
, .mask
=0xF8FFUL
, .ops
={UO_R8_XL
, UO_R8_NOM
, UO_NONE
}},
626 {.mnemo
=UT_LD
, .code
=0x70DDUL
, .mask
=0xF8FFUL
, .ops
={UO_MIX
, UO_R8_NOM
, UO_NONE
}},
628 {.mnemo
=UT_LD
, .code
=0x60FDUL
, .mask
=0xF8FFUL
, .ops
={UO_R8_YH
, UO_R8_NOM
, UO_NONE
}},
630 {.mnemo
=UT_LD
, .code
=0x68FDUL
, .mask
=0xF8FFUL
, .ops
={UO_R8_YL
, UO_R8_NOM
, UO_NONE
}},
632 {.mnemo
=UT_LD
, .code
=0x70FDUL
, .mask
=0xF8FFUL
, .ops
={UO_MIY
, UO_R8_NOM
, UO_NONE
}},
635 {.mnemo
=UT_LD
, .code
=0x44DDUL
, .mask
=0xC7FFUL
, .ops
={UO_2R8_NOM
, UO_R8_XH
, UO_NONE
}},
637 {.mnemo
=UT_LD
, .code
=0x45DDUL
, .mask
=0xC7FFUL
, .ops
={UO_2R8_NOM
, UO_R8_XL
, UO_NONE
}},
639 {.mnemo
=UT_LD
, .code
=0x46DDUL
, .mask
=0xC7FFUL
, .ops
={UO_2R8_NOM
, UO_MIX
, UO_NONE
}},
642 {.mnemo
=UT_LD
, .code
=0x44FDUL
, .mask
=0xC7FFUL
, .ops
={UO_2R8_NOM
, UO_R8_YH
, UO_NONE
}},
644 {.mnemo
=UT_LD
, .code
=0x45FDUL
, .mask
=0xC7FFUL
, .ops
={UO_2R8_NOM
, UO_R8_YL
, UO_NONE
}},
646 {.mnemo
=UT_LD
, .code
=0x46FDUL
, .mask
=0xC7FFUL
, .ops
={UO_2R8_NOM
, UO_MIY
, UO_NONE
}},
648 // instructions w/o operands or with unchangeable operands
649 {.mnemo
=UT_NOP
, .code
=0x00UL
, .mask
=0xFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
650 {.mnemo
=UT_RLCA
, .code
=0x07UL
, .mask
=0xFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
651 {.mnemo
=UT_RRCA
, .code
=0x0FUL
, .mask
=0xFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
652 {.mnemo
=UT_RLA
, .code
=0x17UL
, .mask
=0xFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
653 {.mnemo
=UT_RRA
, .code
=0x1FUL
, .mask
=0xFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
654 {.mnemo
=UT_DAA
, .code
=0x27UL
, .mask
=0xFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
655 {.mnemo
=UT_CPL
, .code
=0x2FUL
, .mask
=0xFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
656 {.mnemo
=UT_SCF
, .code
=0x37UL
, .mask
=0xFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
657 {.mnemo
=UT_CCF
, .code
=0x3FUL
, .mask
=0xFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
658 {.mnemo
=UT_HALT
, .code
=0x76UL
, .mask
=0xFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
659 {.mnemo
=UT_RET
, .code
=0xC9UL
, .mask
=0xFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
660 {.mnemo
=UT_EXX
, .code
=0xD9UL
, .mask
=0xFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
661 {.mnemo
=UT_DI
, .code
=0xF3UL
, .mask
=0xFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
662 {.mnemo
=UT_EI
, .code
=0xFBUL
, .mask
=0xFFUL
, .ops
={UO_NONE
, UO_NONE
, UO_NONE
}},
664 {.mnemo
=UT_LD
, .code
=0xF9UL
, .mask
=0xFFUL
, .ops
={UO_R16SP
, UO_R16HL
, UO_NONE
}},
666 {.mnemo
=UT_EX
, .code
=0x08UL
, .mask
=0xFFUL
, .ops
={UO_R16AF
, UO_R16AFX
, UO_NONE
}},
668 {.mnemo
=UT_EX
, .code
=0x08UL
, .mask
=0xFFUL
, .ops
={UO_R16AFX
, UO_R16AF
, UO_NONE
}},
670 {.mnemo
=UT_EX
, .code
=0xE3UL
, .mask
=0xFFUL
, .ops
={UO_MSP
, UO_R16HL
, UO_NONE
}},
671 // EX HL,(SP) (ditto)
672 {.mnemo
=UT_EX
, .code
=0xE3UL
, .mask
=0xFFUL
, .ops
={UO_R16HL
, UO_MSP
, UO_NONE
}},
674 {.mnemo
=UT_EX
, .code
=0xEBUL
, .mask
=0xFFUL
, .ops
={UO_R16DE
, UO_R16HL
, UO_NONE
}},
676 {.mnemo
=UT_EX
, .code
=0xEBUL
, .mask
=0xFFUL
, .ops
={UO_R16HL
, UO_R16DE
, UO_NONE
}},
678 {.mnemo
=UT_JP
, .code
=0xE9UL
, .mask
=0xFFUL
, .ops
={UO_MHL
, UO_NONE
, UO_NONE
}},
680 {.mnemo
=UT_JP
, .code
=0xE9UL
, .mask
=0xFFUL
, .ops
={UO_R16HL
, UO_NONE
, UO_NONE
}},
682 {.mnemo
=UT_JP
, .code
=0xC3UL
, .mask
=0xFFUL
, .ops
={UO_ADDR16
, UO_NONE
, UO_NONE
}},
684 {.mnemo
=UT_CALL
, .code
=0xCDUL
, .mask
=0xFFUL
, .ops
={UO_ADDR16
, UO_NONE
, UO_NONE
}},
686 {.mnemo
=UT_OUT
, .code
=0xD3UL
, .mask
=0xFFUL
, .ops
={UO_PORTIMM
, UO_R8_A
, UO_NONE
}},
688 {.mnemo
=UT_IN
, .code
=0xDBUL
, .mask
=0xFFUL
, .ops
={UO_R8_A
, UO_PORTIMM
, UO_NONE
}},
691 {.mnemo
=UT_ADD
, .code
=0xC6UL
, .mask
=0xFFUL
, .ops
={UO_R8_A
, UO_IMM8
, UO_NONE
}},
693 {.mnemo
=UT_ADD
, .code
=0xC6UL
, .mask
=0xFFUL
, .ops
={UO_IMM8
, UO_NONE
, UO_NONE
}},
695 {.mnemo
=UT_ADC
, .code
=0xCEUL
, .mask
=0xFFUL
, .ops
={UO_R8_A
, UO_IMM8
, UO_NONE
}},
697 {.mnemo
=UT_ADC
, .code
=0xCEUL
, .mask
=0xFFUL
, .ops
={UO_IMM8
, UO_NONE
, UO_NONE
}},
699 {.mnemo
=UT_SUB
, .code
=0xD6UL
, .mask
=0xFFUL
, .ops
={UO_IMM8
, UO_NONE
, UO_NONE
}},
701 {.mnemo
=UT_SUB
, .code
=0xD6UL
, .mask
=0xFFUL
, .ops
={UO_R8_A
, UO_IMM8
, UO_NONE
}},
703 {.mnemo
=UT_SBC
, .code
=0xDEUL
, .mask
=0xFFUL
, .ops
={UO_R8_A
, UO_IMM8
, UO_NONE
}},
705 {.mnemo
=UT_SBC
, .code
=0xDEUL
, .mask
=0xFFUL
, .ops
={UO_IMM8
, UO_NONE
, UO_NONE
}},
707 {.mnemo
=UT_AND
, .code
=0xE6UL
, .mask
=0xFFUL
, .ops
={UO_IMM8
, UO_NONE
, UO_NONE
}},
709 {.mnemo
=UT_AND
, .code
=0xE6UL
, .mask
=0xFFUL
, .ops
={UO_R8_A
, UO_IMM8
, UO_NONE
}},
711 {.mnemo
=UT_XOR
, .code
=0xEEUL
, .mask
=0xFFUL
, .ops
={UO_IMM8
, UO_NONE
, UO_NONE
}},
713 {.mnemo
=UT_XOR
, .code
=0xEEUL
, .mask
=0xFFUL
, .ops
={UO_R8_A
, UO_IMM8
, UO_NONE
}},
715 {.mnemo
=UT_OR
, .code
=0xF6UL
, .mask
=0xFFUL
, .ops
={UO_IMM8
, UO_NONE
, UO_NONE
}},
717 {.mnemo
=UT_OR
, .code
=0xF6UL
, .mask
=0xFFUL
, .ops
={UO_R8_A
, UO_IMM8
, UO_NONE
}},
719 {.mnemo
=UT_CP
, .code
=0xFEUL
, .mask
=0xFFUL
, .ops
={UO_IMM8
, UO_NONE
, UO_NONE
}},
721 {.mnemo
=UT_CP
, .code
=0xFEUL
, .mask
=0xFFUL
, .ops
={UO_R8_A
, UO_IMM8
, UO_NONE
}},
723 {.mnemo
=UT_LD
, .code
=0x02UL
, .mask
=0xFFUL
, .ops
={UO_MBC
, UO_R8_A
, UO_NONE
}},
725 {.mnemo
=UT_LD
, .code
=0x12UL
, .mask
=0xFFUL
, .ops
={UO_MDE
, UO_R8_A
, UO_NONE
}},
727 {.mnemo
=UT_LD
, .code
=0x0AUL
, .mask
=0xFFUL
, .ops
={UO_R8_A
, UO_MBC
, UO_NONE
}},
729 {.mnemo
=UT_LD
, .code
=0x1AUL
, .mask
=0xFFUL
, .ops
={UO_R8_A
, UO_MDE
, UO_NONE
}},
731 {.mnemo
=UT_LD
, .code
=0x22UL
, .mask
=0xFFUL
, .ops
={UO_MEM16
, UO_R16HL
, UO_NONE
}},
733 {.mnemo
=UT_LD
, .code
=0x2AUL
, .mask
=0xFFUL
, .ops
={UO_R16HL
, UO_MEM16
, UO_NONE
}},
735 {.mnemo
=UT_LD
, .code
=0x32UL
, .mask
=0xFFUL
, .ops
={UO_MEM16
, UO_R8_A
, UO_NONE
}},
737 {.mnemo
=UT_LD
, .code
=0x3AUL
, .mask
=0xFFUL
, .ops
={UO_R8_A
, UO_MEM16
, UO_NONE
}},
739 {.mnemo
=UT_DJNZ
, .code
=0x10UL
, .mask
=0xFFUL
, .ops
={UO_ADDR8
, UO_NONE
, UO_NONE
}},
741 {.mnemo
=UT_JR
, .code
=0x18UL
, .mask
=0xFFUL
, .ops
={UO_ADDR8
, UO_NONE
, UO_NONE
}},
744 {.mnemo
=UT_ADD
, .code
=0x09UL
, .mask
=0xCFUL
, .ops
={UO_R16HL
, UO_R16
, UO_NONE
}},
747 {.mnemo
=UT_ADD
, .code
=0x80UL
, .mask
=0xF8UL
, .ops
={UO_R8_A
, UO_R8
, UO_NONE
}},
749 {.mnemo
=UT_ADD
, .code
=0x80UL
, .mask
=0xF8UL
, .ops
={UO_R8
, UO_NONE
, UO_NONE
}},
751 {.mnemo
=UT_ADC
, .code
=0x88UL
, .mask
=0xF8UL
, .ops
={UO_R8_A
, UO_R8
, UO_NONE
}},
753 {.mnemo
=UT_ADC
, .code
=0x88UL
, .mask
=0xF8UL
, .ops
={UO_R8
, UO_NONE
, UO_NONE
}},
755 {.mnemo
=UT_SUB
, .code
=0x90UL
, .mask
=0xF8UL
, .ops
={UO_R8
, UO_NONE
, UO_NONE
}},
757 {.mnemo
=UT_SUB
, .code
=0x90UL
, .mask
=0xF8UL
, .ops
={UO_R8_A
, UO_R8
, UO_NONE
}},
759 {.mnemo
=UT_SBC
, .code
=0x98UL
, .mask
=0xF8UL
, .ops
={UO_R8_A
, UO_R8
, UO_NONE
}},
761 {.mnemo
=UT_SBC
, .code
=0x98UL
, .mask
=0xF8UL
, .ops
={UO_R8
, UO_NONE
, UO_NONE
}},
763 {.mnemo
=UT_AND
, .code
=0xA0UL
, .mask
=0xF8UL
, .ops
={UO_R8
, UO_NONE
, UO_NONE
}},
765 {.mnemo
=UT_AND
, .code
=0xA0UL
, .mask
=0xF8UL
, .ops
={UO_R8_A
, UO_R8
, UO_NONE
}},
767 {.mnemo
=UT_XOR
, .code
=0xA8UL
, .mask
=0xF8UL
, .ops
={UO_R8
, UO_NONE
, UO_NONE
}},
769 {.mnemo
=UT_XOR
, .code
=0xA8UL
, .mask
=0xF8UL
, .ops
={UO_R8_A
, UO_R8
, UO_NONE
}},
771 {.mnemo
=UT_OR
, .code
=0xB0UL
, .mask
=0xF8UL
, .ops
={UO_R8
, UO_NONE
, UO_NONE
}},
773 {.mnemo
=UT_OR
, .code
=0xB0UL
, .mask
=0xF8UL
, .ops
={UO_R8_A
, UO_R8
, UO_NONE
}},
775 {.mnemo
=UT_CP
, .code
=0xB8UL
, .mask
=0xF8UL
, .ops
={UO_R8
, UO_NONE
, UO_NONE
}},
777 {.mnemo
=UT_CP
, .code
=0xB8UL
, .mask
=0xF8UL
, .ops
={UO_R8_A
, UO_R8
, UO_NONE
}},
780 {.mnemo
=UT_JR
, .code
=0x20UL
, .mask
=0xE7UL
, .ops
={UO_JRCOND
, UO_ADDR8
, UO_NONE
}},
783 {.mnemo
=UT_POP
, .code
=0xC1UL
, .mask
=0xCFUL
, .ops
={UO_R16A
, UO_NONE
, UO_NONE
}},
785 {.mnemo
=UT_PUSH
, .code
=0xC5UL
, .mask
=0xCFUL
, .ops
={UO_R16A
, UO_NONE
, UO_NONE
}},
787 {.mnemo
=UT_RET
, .code
=0xC0UL
, .mask
=0xC7UL
, .ops
={UO_COND
, UO_NONE
, UO_NONE
}},
789 {.mnemo
=UT_JP
, .code
=0xC2UL
, .mask
=0xC7UL
, .ops
={UO_COND
, UO_ADDR16
, UO_NONE
}},
791 {.mnemo
=UT_CALL
, .code
=0xC4UL
, .mask
=0xC7UL
, .ops
={UO_COND
, UO_ADDR16
, UO_NONE
}},
793 {.mnemo
=UT_RST
, .code
=0xC7UL
, .mask
=0xC7UL
, .ops
={UO_RSTDEST
, UO_NONE
, UO_NONE
}},
796 {.mnemo
=UT_INC
, .code
=0x04UL
, .mask
=0xC7UL
, .ops
={UO_2R8
, UO_NONE
, UO_NONE
}},
798 {.mnemo
=UT_DEC
, .code
=0x05UL
, .mask
=0xC7UL
, .ops
={UO_2R8
, UO_NONE
, UO_NONE
}},
800 {.mnemo
=UT_LD
, .code
=0x06UL
, .mask
=0xC7UL
, .ops
={UO_2R8
, UO_IMM8
, UO_NONE
}},
803 {.mnemo
=UT_LD
, .code
=0x01UL
, .mask
=0xCFUL
, .ops
={UO_R16
, UO_IMM16
, UO_NONE
}},
805 {.mnemo
=UT_INC
, .code
=0x03UL
, .mask
=0xCFUL
, .ops
={UO_R16
, UO_NONE
, UO_NONE
}},
807 {.mnemo
=UT_DEC
, .code
=0x0BUL
, .mask
=0xCFUL
, .ops
={UO_R16
, UO_NONE
, UO_NONE
}},
810 {.mnemo
=UT_LD
, .code
=0x40UL
, .mask
=0xC0UL
, .ops
={UO_2R8
, UO_R8
, UO_NONE
}},
814 {.mnemo
=UT_LD
, .code
=0x4940UL
, .mask
=0xFFFFUL
, .ops
={UO_R16BC
, UO_R16BC
, UO_NONE
}},
816 {.mnemo
=UT_LD
, .code
=0x4B42UL
, .mask
=0xFFFFUL
, .ops
={UO_R16BC
, UO_R16DE
, UO_NONE
}},
818 {.mnemo
=UT_LD
, .code
=0x4D44UL
, .mask
=0xFFFFUL
, .ops
={UO_R16BC
, UO_R16HL
, UO_NONE
}},
820 {.mnemo
=UT_LD
, .code
=0x5950UL
, .mask
=0xFFFFUL
, .ops
={UO_R16DE
, UO_R16BC
, UO_NONE
}},
822 {.mnemo
=UT_LD
, .code
=0x5B52UL
, .mask
=0xFFFFUL
, .ops
={UO_R16DE
, UO_R16DE
, UO_NONE
}},
824 {.mnemo
=UT_LD
, .code
=0x5D54UL
, .mask
=0xFFFFUL
, .ops
={UO_R16DE
, UO_R16HL
, UO_NONE
}},
826 {.mnemo
=UT_LD
, .code
=0x6960UL
, .mask
=0xFFFFUL
, .ops
={UO_R16HL
, UO_R16BC
, UO_NONE
}},
828 {.mnemo
=UT_LD
, .code
=0x6B62UL
, .mask
=0xFFFFUL
, .ops
={UO_R16HL
, UO_R16DE
, UO_NONE
}},
830 {.mnemo
=UT_LD
, .code
=0x6D64UL
, .mask
=0xFFFFUL
, .ops
={UO_R16HL
, UO_R16HL
, UO_NONE
}},
834 // instructions unaffected by DD/FF prefixes
835 // this table used by disassembler (we don't want to eat prefixes)
836 const unsigned char URASM_DDFD_INSENSITIVE
[256] = {
837 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
838 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
839 1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,
840 1,1,1,1,0,0,0,1,1,0,1,1,1,1,1,1,
841 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
842 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
843 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
844 0,0,0,0,0,0,1,0,1,1,1,1,0,0,0,1,
845 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
846 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
847 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
848 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
849 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,
850 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
851 1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,
852 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
854 0xff,0xbf,0xff,0xbf,0x81,0x81,0xf1,0xbf,0xf1,0xf1,0xf1,0xf1,0x00,0x00,0x02,0xf1,
855 0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xff,0xef,0xff,0xff,0xab,0xbf,0xff,0xbf,
859 #define IS_DD_SENSITIVE(c) URASM_DDFD_INSENSITIVE[(c)&0xff]
861 static inline int IS_DD_SENSITIVE (uint8_t opc) {
862 return URASM_DDFD_INSENSITIVE[opc/8]&(0x80>>(opc%8));
868 const unsigned char URASM_DDFD_HAS_DISP
[256] = {
870 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
871 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
872 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
873 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
874 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
875 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
876 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
877 1,1,1,1,1,1,0,1,0,0,0,0,0,0,1,0,
878 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
879 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
880 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
881 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
882 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
883 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
884 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
885 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
887 0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x00,0x02,0x02,0x02,0x02,0x02,0x02,0xfd,0x02,
888 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
891 static inline int HAS_DDFD_DISP (uint8_t opc
) {
892 return URASM_DDFD_HAS_DISP
[opc
/8]&(0x80>>(opc
%8));
897 static __attribute__((always_inline
)) inline const char *label_by_addr (uint16_t addr
) {
898 if (!urasm_label_by_addr
) return NULL
;
899 return urasm_label_by_addr(addr
);
903 static __attribute__((always_inline
)) inline char ur_toupper (char ch
) {
904 return (ch
>= 'a' && ch
<= 'z' ? ch
-'a'+'A' : ch
);
908 static __attribute__((always_inline
)) inline char ur_isalpha (char ch
) {
910 (ch
>= 'A' && ch
<= 'Z') ||
911 (ch
>= 'a' && ch
<= 'z');
915 static __attribute__((always_inline
)) inline char ur_isalnum (char ch
) {
917 (ch
>= 'A' && ch
<= 'Z') ||
918 (ch
>= 'a' && ch
<= 'z') ||
919 (ch
>= '0' && ch
<= '9');
923 static __attribute__((always_inline
)) inline char ur_isspace (char ch
) {
924 return (ch
!= 0 && ((ch
&0xff) <= 32 || ch
== 127));
928 static inline int dig2n (char ch
, int base
) {
929 if (ch
< '0') return -1;
931 if (ch
> '0'+base
) return -1;
934 if (ch
>= '0' && ch
<= '9') return ch
-'0';
935 if (ch
>= 'a' && ch
<= 'z') ch
= ch
-'a'+10;
936 else if (ch
>= 'A' && ch
<= 'Z') ch
= ch
-'A'+10;
938 if (ch
>= base
) return -1;
943 /******************************************************************************/
945 /******************************************************************************/
948 /* nextW: next 2 bytes (after opcode) */
949 /* idx: I? displacement */
950 static void ua_op2str (char *res
, int op
, uint16_t addr
, uint8_t opc
, uint16_t nextW
, int idx
) {
954 case UO_NONE
: case UO_NEXT
: strcpy(res
, ""); break;
956 if (!urasm_disasm_decimal
) sprintf(res
, "#%02X", nextW
&0xFFU
); else sprintf(res
, "%u", nextW
&0xFFU
);
959 if (!urasm_disasm_decimal
) sprintf(res
, "#%04X", nextW
); else sprintf(res
, "%u", nextW
);
962 nextW
= (uint16_t)(((nextW
>>8)&0xffu
)|((nextW
<<8)&0xff00u
));
963 if (!urasm_disasm_decimal
) sprintf(res
, "#%04X", nextW
); else sprintf(res
, "%u", nextW
);
966 addr
+= 2; nextW
&= 0xFFU
;
967 add
= (nextW
< 128 ? nextW
: ((int)nextW
)-256);
973 lbl
= label_by_addr(nextW
);
974 if (lbl
) { strcpy(res
, lbl
); break; }
975 lbl
= label_by_addr(nextW
-1);
976 if (lbl
) { sprintf(res
, "%s-1", lbl
); break; }
977 lbl
= label_by_addr(nextW
-2);
978 if (lbl
) { sprintf(res
, "%s-2", lbl
); break; }
979 lbl
= label_by_addr(nextW
+1);
980 if (lbl
) { sprintf(res
, "%s+1", lbl
); break; }
981 lbl
= label_by_addr(nextW
+2);
982 if (lbl
) { sprintf(res
, "%s+2", lbl
); break; }
983 if (!urasm_disasm_decimal
) sprintf(res
, "#%04X", nextW
); else sprintf(res
, "%u", nextW
);
987 strcpy(res
, "("); ++res
;
991 strcpy(res
, URA_REGS8
[opc
&0x07UL
]);
995 strcpy(res
, URA_REGS8
[(opc
>>3)&0x07UL
]);
997 case UO_PORTC
: strcpy(res
, "(C)"); break;
999 if (!urasm_disasm_decimal
) sprintf(res
, "(#%02X)", nextW
&0xFFU
); else sprintf(res
, "(%u)", nextW
&0xFFU
);
1001 case UO_R8_XH
: strcpy(res
, "XH"); break;
1002 case UO_R8_XL
: strcpy(res
, "XL"); break;
1003 case UO_R8_YH
: strcpy(res
, "YH"); break;
1004 case UO_R8_YL
: strcpy(res
, "YL"); break;
1005 case UO_R8_A
: strcpy(res
, "A"); break;
1006 case UO_R8_B
: strcpy(res
, "B"); break;
1007 case UO_R8_R
: strcpy(res
, "R"); break;
1008 case UO_R8_I
: strcpy(res
, "I"); break;
1009 case UO_R16
: strcpy(res
, URA_REGS16
[(opc
>>4)&0x03UL
]); break;
1010 case UO_R16A
: strcpy(res
, URA_REGS16A
[(opc
>>4)&0x03UL
]); break;
1011 case UO_R16AF
: strcpy(res
, "AF"); break;
1012 case UO_R16AFX
: strcpy(res
, "AF'"); break;
1013 case UO_R16BC
: strcpy(res
, "BC"); break;
1014 case UO_R16DE
: strcpy(res
, "DE"); break;
1015 case UO_R16HL
: strcpy(res
, "HL"); break;
1016 case UO_R16IX
: strcpy(res
, "IX"); break;
1017 case UO_R16IY
: strcpy(res
, "IY"); break;
1018 case UO_R16SP
: strcpy(res
, "SP"); break;
1019 case UO_MSP
: strcpy(res
, "(SP)"); break;
1020 case UO_MBC
: strcpy(res
, "(BC)"); break;
1021 case UO_MDE
: strcpy(res
, "(DE)"); break;
1022 case UO_MHL
: strcpy(res
, "(HL)"); break;
1023 case UO_MIX0
: strcpy(res
, "(IX)"); break;
1024 case UO_MIY0
: strcpy(res
, "(IY)"); break;
1027 sprintf(res
, "(IX%s%d)", (idx
< 0 ? "" : "+"), idx
);
1029 strcpy(res
, "(IX)");
1034 sprintf(res
, "(IY%s%d)", (idx
< 0 ? "" : "+"), idx
);
1036 strcpy(res
, "(IY)");
1039 case UO_JRCOND
: strcpy(res
, URA_COND
[(opc
>>3)&0x03U
]); break;
1040 case UO_COND
: strcpy(res
, URA_COND
[(opc
>>3)&0x07U
]); break;
1041 case UO_BITN
: sprintf(res
, "%u", (opc
>>3)&0x07U
); break;
1043 if (!urasm_disasm_decimal
) sprintf(res
, "#%02X", opc
&0x38U
); else sprintf(res
, "%u", opc
&0x38U
);
1045 case UO_IM0
: strcpy(res
, "0"); break;
1046 case UO_IM1
: strcpy(res
, "1"); break;
1047 case UO_IM2
: strcpy(res
, "2"); break;
1048 default: strcpy(res
, ""); break; /* we'll never come here */
1050 if (ismem
) strcat(res
, ")");
1054 /* find the corresponding record in URASM_COMMANDS */
1055 int urasm_disasm_opfind (uint16_t addr
) {
1060 if (!urasm_getbyte
) return -1;
1061 for (f
= 0; f
< 8; ++f
) buf
[f
] = urasm_getbyte(addr
+f
);
1062 if (buf
[0] == 0xDDU
|| buf
[0] == 0xFDU
) {
1064 if (IS_DD_SENSITIVE(buf
[1])) return (buf
[0] == 0xDDU
? 0 : 1);
1066 ci
= ((uint32_t)buf
[0]) | (((uint32_t)buf
[1])<<8) | (((uint32_t)buf
[2])<<16) | (((uint32_t)buf
[3])<<24);
1067 for (opn
= 0; opn
< URASM_MAX_COMMAND
; ++opn
) {
1069 for (; opn
< URASM_MAX_COMMAND
&& (ci
&URASM_COMMANDS
[opn
].mask
) != URASM_COMMANDS
[opn
].code
; ++opn
) {}
1070 if (!urasm_allow_zxnext
&& URASM_COMMANDS
[opn
].ops
[2] == UO_NEXT
) opn
= URASM_MAX_COMMAND
; /* skip ZXNext if not allowed */
1071 if (opn
>= URASM_MAX_COMMAND
) {
1072 if (buf
[0] == 0xEDU
) return -2;
1075 /* skip prefixes, determine command length */
1076 f
= URASM_COMMANDS
[opn
].mask
; c
= URASM_COMMANDS
[opn
].code
;
1077 for (bpos
= 0; ; ++bpos
) {
1079 if ((f
&0xFFUL
) != 0xFFUL
) break;
1081 if (b
!= 0xFDU
&& b
!= 0xDDU
&& b
!= 0xEDU
&& b
!= 0xCBU
) break;
1084 /* are there any operands? */
1085 if (URASM_COMMANDS
[opn
].ops
[0] == UO_NONE
) return opn
;
1086 /* is this CB-prefixed? */
1087 if (((URASM_COMMANDS
[opn
].code
&0xFFFFUL
) == 0xCBDDUL
) ||
1088 ((URASM_COMMANDS
[opn
].code
&0xFFFFUL
) == 0xCBFDUL
)) ++bpos
; /* skip displacement */
1091 for (f
= 0; f
<= 3; ++f
) {
1092 if (f
== 3) return opn
;
1093 op
= URASM_COMMANDS
[opn
].ops
[f
];
1094 if (op
== UO_NONE
|| op
== UO_NEXT
) return opn
;
1095 /* check for valid operand */
1096 if (op
== UO_R8_NOM
) {
1097 if ((opc
&0x07U
) == 6) break; /* bad (HL) */
1099 if (op
== UO_2R8_NOM
) {
1100 if (((opc
>>3)&0x07U
) == 6) break; /* bad (HL) */
1108 /* length of the corresponding instruction */
1109 int urasm_disasm_oplen (int idx
) {
1112 if (idx
== -2) return 2;
1113 if (idx
< 0 || idx
>= URASM_MAX_COMMAND
) return 1;
1114 if (idx
< 2) return 1;
1115 m
= URASM_COMMANDS
[idx
].mask
; c
= URASM_COMMANDS
[idx
].code
;
1118 if (((m&0xFFFFUL) == 0xFFFFUL) &&
1119 ((c&0xFF00UL) == 0xCBUL) && ((c&0xFFUL) == 0xDDUL || (c&0xFFUL) == 0xFDUL)) return 4;
1121 /* skip prefixes, determine command length */
1124 if ((m
&0xFFUL
) != 0xFFUL
) break;
1126 if (b
!= 0xFDU
&& b
!= 0xDDU
&& b
!= 0xEDU
&& b
!= 0xCBU
) break;
1127 m
>>= 8; c
>>= 8; ++res
;
1129 /* is this CB-prefixed? */
1130 if (((URASM_COMMANDS
[idx
].code
&0xFFFFUL
) == 0xCBDDUL
) ||
1131 ((URASM_COMMANDS
[idx
].code
&0xFFFFUL
) == 0xCBFDUL
)) m
>>= 8;
1133 while (m
!= 0) { m
>>= 8; ++res
; }
1134 /* process operands */
1135 for (f
= 0; f
<= 2; ++f
) {
1136 op
= URASM_COMMANDS
[idx
].ops
[f
];
1137 if (op
== UO_NONE
|| op
== UO_NEXT
) break;
1139 /* command with displacement */
1140 case UO_MIX
: case UO_MIY
: ++res
; break;
1141 /* command has immediate operand */
1142 case UO_IMM8
: case UO_ADDR8
: case UO_PORTIMM
: ++res
; break;
1143 case UO_IMM16
: case UO_IMM16BE
: case UO_ADDR16
: case UO_MEM16
: res
+= 2; break;
1150 extern int urasm_disasm_opdisasm_ex (char *dstr
, uint16_t addr
, const uint8_t mem
[8]) {
1157 if (!dstr
) return -1;
1158 if (mem
[0] == 0xDDU
|| mem
[0] == 0xFDU
) {
1160 if (IS_DD_SENSITIVE(mem
[1])) {
1161 strcpy(dstr
, URASM_TOKENS
[mem
[0]==0xDDU
? UT_NOPX
: UT_NOPY
]);
1164 /* take possible I? displacement */
1165 idx
= (int8_t)mem
[2];
1167 ci
= ((uint32_t)mem
[0]) | (((uint32_t)mem
[1])<<8) | (((uint32_t)mem
[2])<<16) | (((uint32_t)mem
[3])<<24);
1168 for (opn
= 0; opn
< URASM_MAX_COMMAND
; ++opn
) {
1169 res
= 0; dstr
[0] = '\0';
1171 for (; opn
< URASM_MAX_COMMAND
&& (ci
&URASM_COMMANDS
[opn
].mask
) != URASM_COMMANDS
[opn
].code
; ++opn
) {}
1172 if (!urasm_allow_zxnext
&& URASM_COMMANDS
[opn
].ops
[2] == UO_NEXT
) opn
= URASM_MAX_COMMAND
; /* skip ZXNext if not allowed */
1173 if (opn
>= URASM_MAX_COMMAND
) {
1174 if (mem
[0] == 0xEDU
) {
1175 if (!urasm_disasm_decimal
) sprintf(opstr
, "#%02X,#%02X", mem
[0], mem
[1]); else sprintf(opstr
, "%u,%u", mem
[0], mem
[1]);
1176 /*if (!urasm_disasm_decimal) sprintf(opstr, "#%04X", (uint16_t)buf[0]|(((uint16_t)buf[1])<<8));
1177 else sprintf(opstr, "%u", (uint16_t)buf[0]|(((uint16_t)buf[1])<<8));*/
1178 sprintf(dstr
, "DB\t%s", opstr
);
1181 if (!urasm_disasm_decimal
) sprintf(opstr
, "#%02X", mem
[0]); else sprintf(opstr
, "%u", mem
[0]);
1182 sprintf(dstr
, "DB\t%s", opstr
);
1185 /* skip prefixes, determine command length */
1186 f
= URASM_COMMANDS
[opn
].mask
; c
= URASM_COMMANDS
[opn
].code
;
1187 for (bpos
= 0; ; ++bpos
) {
1189 if ((f
&0xFFUL
) != 0xFFUL
) break;
1191 if (b
!= 0xFDU
&& b
!= 0xDDU
&& b
!= 0xEDU
&& b
!= 0xCBU
) break;
1192 f
>>= 8; c
>>= 8; ++res
;
1194 /* is this CB-prefixed? */
1195 if (((URASM_COMMANDS
[opn
].code
&0xFFFFUL
) == 0xCBDDUL
) ||
1196 ((URASM_COMMANDS
[opn
].code
&0xFFFFUL
) == 0xCBFDUL
)) f
>>= 8;
1197 while (f
!= 0) { f
>>= 8; ++res
; }
1198 /* copy mnemonics */
1199 strcpy(dstr
, URASM_TOKENS
[URASM_COMMANDS
[opn
].mnemo
]);
1200 /* are there any operands? */
1201 if (URASM_COMMANDS
[opn
].ops
[0] == UO_NONE
) return res
;
1202 /* is this CB-prefixed? */
1203 if (((URASM_COMMANDS
[opn
].code
&0xFFFFUL
) == 0xCBDDUL
) ||
1204 ((URASM_COMMANDS
[opn
].code
&0xFFFFUL
) == 0xCBFDUL
)) ++bpos
; /* skip displacement */
1206 if ((URASM_COMMANDS
[opn
].ops
[0] == UO_MIX
|| URASM_COMMANDS
[opn
].ops
[0] == UO_MIY
) &&
1207 URASM_COMMANDS
[opn
].ops
[1] == UO_IMM8
&&
1208 (URASM_COMMANDS
[opn
].ops
[2] == UO_NONE
|| URASM_COMMANDS
[opn
].ops
[2] == UO_NEXT
)) ++bpos
; /* skip displacement */
1211 nextW
= (uint16_t)mem
[bpos
] | (((uint16_t)mem
[bpos
+1])<<8);
1213 for (f
= 0; f
<= 3; ++f
) {
1215 //printf("OPN=%d\n", opn);
1218 op
= URASM_COMMANDS
[opn
].ops
[f
];
1219 if (op
== UO_NONE
|| op
== UO_NEXT
) {
1220 //printf("OPN=%d\n", opn);
1223 /* check for valid operand */
1224 if (op
== UO_R8_NOM
) {
1225 if ((opc
&0x07U
) == 6) break; /* bad (HL) */
1227 if (op
== UO_2R8_NOM
) {
1228 if (((opc
>>3)&0x07U
) == 6) break; /* bad (HL) */
1230 /* command with displacement? */
1231 if (op
== UO_MIX
|| op
== UO_MIY
) ++res
;
1232 /* command has immediate operand? */
1233 if (op
== UO_IMM8
|| op
== UO_ADDR8
|| op
== UO_PORTIMM
) ++res
;
1234 if (op
== UO_IMM16
|| op
== UO_IMM16BE
|| op
== UO_ADDR16
|| op
== UO_MEM16
) res
+= 2;
1236 strcat(dstr
, (f
== 0 ? urasm_disasm_mnemo_delimiter
: urasm_disasm_operand_delimiter
));
1237 /* decode operand */
1238 ua_op2str(opstr
, op
, addr
, opc
, nextW
, idx
);
1239 strcat(dstr
, opstr
);
1246 int urasm_disasm_opdisasm (char *dstr
, uint16_t addr
) {
1248 if (!urasm_getbyte
) return -1;
1249 for (unsigned f
= 0; f
< 8; ++f
) mem
[f
] = urasm_getbyte((uint16_t)((addr
+f
)&0xffffu
));
1250 return urasm_disasm_opdisasm_ex(dstr
, addr
, mem
);
1254 ///////////////////////////////////////////////////////////////////////////////
1257 /* returns 0 if label name conflicts with reserved word */
1258 /* (or if the label is just a bad one) */
1259 int urasm_is_valid_name (const char *lbl
) {
1262 if (!lbl
|| !lbl
[0]) return 0;
1263 if (lbl
[0] == '@') {
1268 if (ch
>= '0' && ch
<= '9') return 0;
1269 if (!ur_isalpha(ch
) && ch
!= '.' && ch
!= '_' && ch
!= '@') return 0;
1270 for (f
= 1; lbl
[f
]; ++f
) {
1272 if (ch
>= '0' && ch
<= '9') continue;
1273 if (!ur_isalpha(ch
)) {
1275 if (ch
!= '$' && ch
!= '.' && ch
!= '_' && ch
!= '@') return 0;
1278 if (hasNA
|| f
> 4) return 1;
1279 for (f
= 0; lbl
[f
]; ++f
) buf
[f
] = ur_toupper(lbl
[f
]); buf
[f
] = '\0';
1280 for (f
= 0; f
< (!urasm_allow_zxnext
? URASM_MAX_NORMAL_TOKEN
: URASM_MAX_TOKEN
); ++f
) if (!strcmp(buf
, URASM_TOKENS
[f
])) return 0;
1281 for (f
= 0; f
< 8; ++f
) if (!strcmp(buf
, URA_REGS8
[f
])) return 0;
1282 for (f
= 0; f
< 4; ++f
) if (!strcmp(buf
, URA_REGS16
[f
])) return 0;
1283 for (f
= 0; f
< 4; ++f
) if (!strcmp(buf
, URA_REGS16A
[f
])) return 0;
1284 for (f
= 0; f
< 8; ++f
) if (!strcmp(buf
, URA_COND
[f
])) return 0;
1285 if (!strcmp(buf
, "AFX")) return 0;
1286 if (!strcmp(buf
, "IXH")) return 0;
1287 if (!strcmp(buf
, "IXL")) return 0;
1288 if (!strcmp(buf
, "IYH")) return 0;
1289 if (!strcmp(buf
, "IYL")) return 0;
1290 if (!strcmp(buf
, "IX")) return 0;
1291 if (!strcmp(buf
, "IY")) return 0;
1292 if (!strcmp(buf
, "XH")) return 0;
1293 if (!strcmp(buf
, "HX")) return 0;
1294 if (!strcmp(buf
, "XL")) return 0;
1295 if (!strcmp(buf
, "LX")) return 0;
1296 if (!strcmp(buf
, "YH")) return 0;
1297 if (!strcmp(buf
, "HY")) return 0;
1298 if (!strcmp(buf
, "YL")) return 0;
1299 if (!strcmp(buf
, "LY")) return 0;
1300 if (!strcmp(buf
, "R")) return 0;
1301 if (!strcmp(buf
, "I")) return 0;
1306 ///////////////////////////////////////////////////////////////////////////////
1309 // parse and calculate expression
1310 static inline const char *skip_blanks (const char *expr
) {
1311 while (*expr
&& ur_isspace(*expr
)) ++expr
;
1316 ///////////////////////////////////////////////////////////////////////////////
1317 // expression parser
1318 urasm_getval_fn urasm_getval
= NULL
;
1319 urasm_expand_fn urasm_expand
= NULL
;
1322 typedef struct ur_function_s
{
1323 struct ur_function_s
*next
;
1328 static ur_function_t
*fnlist
= NULL
;
1330 static void atexit_func_finalize (void) {
1331 while (fnlist
!= NULL
) {
1332 ur_function_t
*f
= fnlist
;
1340 void urasm_expr_register_func (const char *name
, urasm_func_fn fn
) {
1341 if (name
!= NULL
&& name
[0]) {
1342 static int atexitset
= 0;
1343 ur_function_t
*p
, *c
;
1344 if (!atexitset
) { atexit(atexit_func_finalize
); atexitset
= 1; }
1345 for (p
= NULL
, c
= fnlist
; c
!= NULL
; p
= c
, c
= c
->next
) {
1346 if (strcasecmp(name
, c
->name
) == 0) {
1347 /* replace or remove */
1350 if (p
== NULL
) fnlist
= c
->next
; else p
->next
= c
->next
;
1362 c
= malloc(sizeof(*c
));
1363 c
->name
= strdup(name
);
1372 urasm_func_fn
urasm_expr_find_func (const char *name
) {
1373 if (name
!= NULL
&& name
[0]) {
1374 for (ur_function_t
*c
= fnlist
; c
!= NULL
; c
= c
->next
) if (strcasecmp(name
, c
->name
) == 0) return c
->fn
;
1380 ///////////////////////////////////////////////////////////////////////////////
1382 const char *expr
; /* can be changed */
1383 uint16_t addr
; /* current address */
1384 int defined
; /* !0: all used labels are defined */
1385 int error
; /* !0: error */
1386 const char *errpos
; /* will be set on error, has no meaning otherwise */
1393 /* do math; op0 is the result */
1394 typedef void (*expr_doit_fn
) (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
);
1407 char sn
; /* short name or 0 */
1408 const char *ln
; /* long name or NULL if `sn`!=0 */
1409 int prio
; /* priority */
1415 ///////////////////////////////////////////////////////////////////////////////
1417 /* returns !0 is passed string is not NULL, and longer than 2 chars */
1418 static inline __attribute__((always_inline
)) __attribute__((pure
))
1419 int ur_is_long_str (const char *s
) { return (s
&& s
[0] && s
[1] && s
[2]); }
1421 #define EERROR(code) longjmp(ei->errJP, code)
1423 #define CHECKVALNOTSTR(_v,_vkill) do { \
1424 if ((_v)->str != NULL) { \
1425 if (ur_is_long_str((_v)->str)) { \
1426 if ((_vkill) != NULL) urasm_exprval_clear((_vkill)); \
1427 EERROR(UR_EXPRERR_TYPE); \
1434 #define CHECKARGSNOTSTR do { \
1435 CHECKVALNOTSTR(op0, op1); \
1436 CHECKVALNOTSTR(op1, op1); \
1440 #define PROPAGATE_FIXUP do { \
1441 if (op0->fixuptype == UR_FIXUP_NONE) { \
1442 op0->fixuptype = op1->fixuptype; \
1443 } else if (op0->fixuptype == UR_FIXUP_WORD) { \
1444 if (op1->fixuptype != UR_FIXUP_NONE) op0->fixuptype = op1->fixuptype; \
1445 } else if (op1->fixuptype != UR_FIXUP_NONE && op0->fixuptype != op1->fixuptype) { \
1446 urasm_exprval_clear(op1);\
1447 urasm_exprval_clear(op0); \
1448 EERROR(UR_EXPRERR_FIXUP); \
1453 static void mdo_bitnot (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) {
1454 op0
->val
= ~op0
->val
;
1455 op0
->fixuptype
= UR_FIXUP_NONE
;
1457 static void mdo_lognot (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) {
1458 op0
->val
= !op0
->val
;
1459 op0
->fixuptype
= UR_FIXUP_NONE
;
1461 static void mdo_uminus (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) {
1462 op0
->val
= -op0
->val
;
1463 op0
->fixuptype
= UR_FIXUP_NONE
;
1465 static void mdo_uplus (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) {
1468 static void mdo_bitand (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) {
1469 op0
->val
&= op1
->val
;
1470 if (op1
->val
== 0) op0
->fixuptype
= UR_FIXUP_NONE
;
1471 else if (op0
->fixuptype
!= UR_FIXUP_NONE
) {
1473 case 0x00ff: op0
->fixuptype
= (op0
->fixuptype
== UR_FIXUP_WORD
? UR_FIXUP_LOBYTE
: UR_FIXUP_NONE
); break;
1474 case 0xff00: op0
->fixuptype
= (op0
->fixuptype
== UR_FIXUP_WORD
? UR_FIXUP_HIBYTE
: UR_FIXUP_NONE
); break;
1480 static void mdo_bitor (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) { op0
->val
|= op1
->val
; op0
->fixuptype
= UR_FIXUP_NONE
; }
1481 static void mdo_bitxor (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) { op0
->val
^= op1
->val
; op0
->fixuptype
= UR_FIXUP_NONE
; }
1482 static void mdo_shl (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) { op0
->val
<<= op1
->val
; op0
->fixuptype
= UR_FIXUP_NONE
; }
1483 static void mdo_shr (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) { op0
->val
>>= op1
->val
; }
1484 static void mdo_shru (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) { *(uint32_t *)&op0
->val
>>= op1
->val
; }
1485 static void mdo_mul (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) { op0
->val
*= op1
->val
; op0
->fixuptype
= UR_FIXUP_NONE
; }
1486 static void mdo_div (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) { if (op1
->val
== 0) EERROR(UR_EXPRERR_DIV0
); op0
->val
/= op1
->val
; op0
->fixuptype
= UR_FIXUP_NONE
; }
1487 static void mdo_mod (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) { if (op1
->val
== 0) EERROR(UR_EXPRERR_DIV0
); op0
->val
%= op1
->val
; op0
->fixuptype
= UR_FIXUP_NONE
; }
1488 static void mdo_add (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) { op0
->val
+= op1
->val
; PROPAGATE_FIXUP
; }
1489 static void mdo_sub (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) { op0
->val
-= op1
->val
; PROPAGATE_FIXUP
; }
1491 static int mdo_compare (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) {
1492 const int isnum0
= !ur_is_long_str(op0
->str
);
1493 const int isnum1
= !ur_is_long_str(op1
->str
);
1494 //fprintf(stderr, "mdo_compare: num0=%d; num1=%d (%s) (%s)\n", isnum0, isnum1, op0->str, op1->str);
1495 if (isnum0
!= isnum1
) EERROR(UR_EXPRERR_TYPES
);
1498 op0
->val
< op1
->val
? -1 :
1499 op0
->val
> op1
->val
? 1 :
1502 return strcmp(op0
->str
, op1
->str
);
1506 static void mdo_set_int (urasm_exprval_t
*op0
, const int32_t v
) {
1507 urasm_exprval_clear(op0
);
1511 static void mdo_cmp_ls (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) { mdo_set_int(op0
, (mdo_compare(op0
, op1
, ei
) < 0)); }
1512 static void mdo_cmp_gt (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) { mdo_set_int(op0
, (mdo_compare(op0
, op1
, ei
) > 0)); }
1513 static void mdo_cmp_eq (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) { mdo_set_int(op0
, (mdo_compare(op0
, op1
, ei
) == 0)); }
1514 static void mdo_cmp_ne (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) { mdo_set_int(op0
, (mdo_compare(op0
, op1
, ei
) != 0)); }
1515 static void mdo_cmp_le (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) { mdo_set_int(op0
, (mdo_compare(op0
, op1
, ei
) <= 0)); }
1516 static void mdo_cmp_ge (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) { mdo_set_int(op0
, (mdo_compare(op0
, op1
, ei
) >= 0)); }
1518 static void mdo_log_and (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) {
1519 ei
->logic_res
= op0
->val
= (op0
->val
&& op1
->val
);
1520 if (!op0
->val
) ei
->logic_done
= 1;
1521 op0
->fixuptype
= UR_FIXUP_NONE
;
1524 static void mdo_log_or (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) {
1525 ei
->logic_res
= op0
->val
= (op0
->val
|| op1
->val
);
1526 if (op0
->val
) ei
->logic_done
= 1;
1527 op0
->fixuptype
= UR_FIXUP_NONE
;
1531 // priority level 1 -- opertiors line "." and "[]", function calls
1532 // priority level 2 -- unary opertiors like "!" and "~"
1533 // short forms must be put before long
1534 // priorities must be sorted
1535 static const expr_operator_t operators_old
[] = {
1537 { '~', NULL
, 2, mdo_bitnot
, optype_unary
},
1538 { '!', NULL
, 2, mdo_lognot
, optype_unary
},
1539 { '-', NULL
, 2, mdo_uminus
, optype_unary
},
1540 { '+', NULL
, 2, mdo_uplus
, optype_unary
},
1542 { 0, "<<", 3, mdo_shl
, optype_shift
},
1543 { 0, ">>", 3, mdo_shr
, optype_shift
},
1544 { 0, ">>>", 3, mdo_shru
, optype_shift
},
1546 { '&', NULL
, 4, mdo_bitand
, optype_bitwise
},
1547 // bitwise or and xor
1548 { '|', NULL
, 5, mdo_bitor
, optype_bitwise
},
1549 { '^', NULL
, 5, mdo_bitxor
, optype_bitwise
},
1551 { '*', NULL
, 6, mdo_mul
, optype_math
},
1552 { '/', NULL
, 6, mdo_div
, optype_math
},
1553 { '%', NULL
, 6, mdo_mod
, optype_math
},
1555 { '+', NULL
, 7, mdo_add
, optype_math
},
1556 { '-', NULL
, 7, mdo_sub
, optype_math
},
1558 { 0, "&&", 8, mdo_log_and
, optype_logic
},
1560 { 0, "||", 9, mdo_log_or
, optype_logic
},
1562 { '<', NULL
, 10, mdo_cmp_ls
, optype_comparison
},
1563 { '>', NULL
, 10, mdo_cmp_gt
, optype_comparison
},
1564 { '=', NULL
, 10, mdo_cmp_eq
, optype_comparison
},
1565 { 0, "==", 10, mdo_cmp_eq
, optype_comparison
},
1566 { 0, "!=", 10, mdo_cmp_ne
, optype_comparison
},
1567 { 0, "<>", 10, mdo_cmp_ne
, optype_comparison
},
1568 { 0, "<=", 10, mdo_cmp_le
, optype_comparison
},
1569 { 0, ">=", 10, mdo_cmp_ge
, optype_comparison
},
1571 { 0, NULL
, -1, NULL
, optype_none
},
1573 // new C-like priorities
1574 static const expr_operator_t operators_new
[] = {
1576 { '~', NULL
, 2, mdo_bitnot
, optype_unary
},
1577 { '!', NULL
, 2, mdo_lognot
, optype_unary
},
1578 { '-', NULL
, 2, mdo_uminus
, optype_unary
},
1579 { '+', NULL
, 2, mdo_uplus
, optype_unary
},
1581 { 0, "<<", 3, mdo_shl
, optype_shift
},
1582 { 0, ">>", 3, mdo_shr
, optype_shift
},
1583 { 0, ">>>", 3, mdo_shru
, optype_shift
},
1585 { '&', NULL
, 4, mdo_bitand
, optype_bitwise
},
1586 // bitwise or and xor
1587 { '|', NULL
, 5, mdo_bitor
, optype_bitwise
},
1588 { '^', NULL
, 5, mdo_bitxor
, optype_bitwise
},
1590 { '*', NULL
, 6, mdo_mul
, optype_math
},
1591 { '/', NULL
, 6, mdo_div
, optype_math
},
1592 { '%', NULL
, 6, mdo_mod
, optype_math
},
1594 { '+', NULL
, 7, mdo_add
, optype_math
},
1595 { '-', NULL
, 7, mdo_sub
, optype_math
},
1597 { '<', NULL
, 8, mdo_cmp_ls
, optype_comparison
},
1598 { '>', NULL
, 8, mdo_cmp_gt
, optype_comparison
},
1599 { '=', NULL
, 8, mdo_cmp_eq
, optype_comparison
},
1600 { 0, "==", 8, mdo_cmp_eq
, optype_comparison
},
1601 { 0, "!=", 8, mdo_cmp_ne
, optype_comparison
},
1602 { 0, "<>", 8, mdo_cmp_ne
, optype_comparison
},
1603 { 0, "<=", 8, mdo_cmp_le
, optype_comparison
},
1604 { 0, ">=", 8, mdo_cmp_ge
, optype_comparison
},
1606 { 0, "&&", 9, mdo_log_and
, optype_logic
},
1608 { 0, "||", 10, mdo_log_or
, optype_logic
},
1610 { 0, NULL
, -1, NULL
, optype_none
},
1612 #define UNARY_PRIO (2)
1614 #define MAX_PRIO (10)
1615 #define PRIO_LAND (8)
1616 #define PRIO_LOR (9)
1618 static int max_prio_old
= 0;
1619 static int prio_land_old
= 0;
1620 static int prio_lor_old
= 0;
1622 static int max_prio
= 0;
1623 static int prio_land
= 0;
1624 static int prio_lor
= 0;
1626 int urasm_use_old_priorities
= 0;
1628 static inline __attribute__((always_inline
)) int get_max_prio () { return (!urasm_use_old_priorities
? max_prio
: max_prio_old
); }
1629 static inline __attribute__((always_inline
)) int get_land_prio () { return (!urasm_use_old_priorities
? prio_land
: prio_land_old
); }
1630 static inline __attribute__((always_inline
)) int get_lor_prio () { return (!urasm_use_old_priorities
? prio_lor
: prio_lor_old
); }
1632 static __attribute((constructor
)) void init_priorities (void) {
1633 if (max_prio_old
) return;
1635 for (const expr_operator_t
*op
= operators_old
; op
->prio
>= 0; ++op
) {
1636 if (max_prio_old
< op
->prio
) max_prio_old
= op
->prio
;
1637 if (op
->doer
== &mdo_log_and
) prio_land_old
= op
->prio
;
1638 else if (op
->doer
== &mdo_log_or
) prio_lor_old
= op
->prio
;
1641 for (const expr_operator_t
*op
= operators_new
; op
->prio
>= 0; ++op
) {
1642 if (max_prio
< op
->prio
) max_prio
= op
->prio
;
1643 if (op
->doer
== &mdo_log_and
) prio_land
= op
->prio
;
1644 else if (op
->doer
== &mdo_log_or
) prio_lor
= op
->prio
;
1649 /******************************************************************************/
1650 /* expression parser engine */
1651 /******************************************************************************/
1652 static void expression (urasm_exprval_t
*res
, expr_info_t
*ei
);
1655 #define SKIP_BLANKS { ei->errpos = ei->expr = skip_blanks(ei->expr); }
1657 #define PSEMITCHAR(_ch) do { \
1658 if (!doinglen) res->str[len++] = (_ch); else ++len; \
1662 static const char *parse_string (urasm_exprval_t
*res
, char qch
, const char *expr
, int *error
, int *lenp
) {
1664 if (lenp
) *lenp
= 0;
1665 if (*error
) return expr
;
1666 if (!expr
[0]) { *error
= 1; return expr
; }
1667 //memset(buf, 0, sizeof(buf));
1669 int len
= 0, n
, f
, base
;
1670 const char *a
= expr
;
1676 case 'a': PSEMITCHAR('\a'); break;
1677 case 'b': PSEMITCHAR('\b'); break;
1678 case 'e': PSEMITCHAR('\x1b'); break;
1679 case 'f': PSEMITCHAR('\f'); break;
1680 case 'n': PSEMITCHAR('\n'); break;
1681 case 'r': PSEMITCHAR('\r'); break;
1682 case 't': PSEMITCHAR('\t'); break;
1683 case 'v': PSEMITCHAR('\v'); break;
1684 case 'z': PSEMITCHAR('\0'); break;
1685 case 'x': case 'X': /* hex */
1688 donum
: for (n
= 0; f
> 0; --f
) {
1689 char ch
= dig2n(*a
++, base
);
1690 if (ch
< 0) { --a
; break; }
1695 --a
; /* return to the last digit, 'for' will skip it */
1697 case '0': /* octal */
1700 case '1' ... '9': /* decimal */
1703 default: PSEMITCHAR(a
[0]); break; /* others */
1706 if (*a
== qch
) { ++a
; break; }
1711 res
->str
= calloc(len
+1, 1);
1712 if (lenp
) *lenp
= len
;
1720 static int try_suffix_base (const char *s
, char sfx
, int base
) {
1721 if (!s
|| !s
[0]) return 0;
1722 while (*s
== '_') ++s
; /* just in case */
1723 if (dig2n(*s
++, base
) < 0) return 0;
1724 /* we don't need to check for zero here, because `dig2n()` will do this for us */
1726 const char ch
= *s
++;
1727 if (ch
!= '_' && dig2n(ch
, base
) < 0) {
1728 return (ur_toupper(ch
) == sfx
&& (!ch
|| dig2n(*s
, 16) < 0));
1734 /*TODO: make suffix detector one-pass */
1735 static int check_number_base_sfx (const char *s
) {
1736 if (!s
|| !s
[0]) return 0;
1737 while (*s
== '_') ++s
; /* just in case */
1738 /* check suffixes (suffix char must be passed as uppercase) */
1739 if (try_suffix_base(s
, 'H', 16)) return 16;
1740 if (try_suffix_base(s
, 'B', 2)) return 2;
1741 if (try_suffix_base(s
, 'O', 8)) return 9;
1746 static int check_number_base_char (char ch
) {
1747 switch (ur_toupper(ch
)) {
1748 case 'X': case 'H': return 16;
1751 case 'D': return 10;
1758 static const char *parse_number (urasm_exprval_t
*res
, const char *expr
, int *error
) {
1760 if (*error
) return expr
;
1761 if (!expr
[0]) { *error
= 1; return expr
; }
1762 const char *estart
= expr
;
1763 /* detect suffix first */
1764 int base
= check_number_base_sfx(expr
);
1766 /* the suffix is ok */
1767 prefixed
= 0; /* note that it is suffixed number, not prefixed */
1769 /* no good suffix, check prefixes */
1771 case '0': /* this allows "0habcd" as hex number too; why not? */
1772 base
= check_number_base_char(expr
[1]);
1773 if (base
) expr
+= 2; else base
= 8;
1775 case '%': base
= 2; ++expr
; break;
1776 case '#': case '$': base
= 16; ++expr
; break;
1777 case '1' ... '9': base
= 10; break;
1779 base
= check_number_base_char(expr
[1]);
1780 if (base
) { expr
+= 2; break; }
1782 default: *error
= 1; return estart
;
1785 /* parse number (ignore underscores) */
1786 while (*expr
&& *expr
== '_') ++expr
;
1787 if (dig2n(*expr
, base
) < 0) { *error
= 1; return estart
; }
1791 if (ch
== '_') continue;
1792 int d
= dig2n(ch
, base
);
1793 if (d
< 0) { res
->val
= n
; return expr
-prefixed
; } /* `prefixed` set to 1 if there's no suffix */
1795 /* this check is UB in standards-compliant C. because standard was created by morons. */
1796 if (n
< 0) { *error
= 1; return estart
; }
1802 static void get_addr (const char *lbl
, urasm_exprval_t
*res
, expr_info_t
*ei
) {
1803 int defined
= 0, found
= 0;
1805 if (urasm_label_by_name
== NULL
) EERROR(UR_EXPRERR_LABEL
);
1806 res
->fixuptype
= UR_FIXUP_NONE
;
1807 val
= urasm_label_by_name(lbl
, ei
->addr
, &defined
, &found
, &res
->fixuptype
);
1808 if (!found
) EERROR(UR_EXPRERR_LABEL
);
1809 if (!defined
) ei
->defined
= 0;
1814 // !0: invalid label
1815 static int read_label_name (char *buf
, expr_info_t
*ei
) {
1818 if (pos
>= 128) return -3;
1819 char ch
= ei
->expr
[0];
1821 if (ur_isalnum(ch
) || ch
== '$' || ch
== '.' || ch
== '_' || ch
== '@') {
1828 if (pos
< 1) return -2;
1830 if (!urasm_is_valid_name(buf
)) return -1;
1835 static void term (urasm_exprval_t
*res
, expr_info_t
*ei
) {
1838 if (res
->str
!= NULL
) { free(res
->str
); res
->str
= NULL
; }
1840 ch
= (res
->pos
= ei
->errpos
= ei
->expr
)[0];
1841 if (!ch
) EERROR(UR_EXPRERR_EOS
);
1845 ch
= (ch
== '[' ? ']' : ')');
1846 expression(res
, ei
);
1847 if (ei
->expr
[0] != ch
) EERROR(UR_EXPRERR_PARENS
);
1850 case '0' ... '9': case '#': case '%':
1852 ei
->expr
= parse_number(res
, ei
->expr
, &tmp
);
1853 if (tmp
) EERROR(UR_EXPRERR_NUMBER
);
1856 if (dig2n(ei
->expr
[1], 16) >= 0) goto donumber
;
1857 res
->val
= ei
->addr
;
1858 res
->fixuptype
= UR_FIXUP_WORD
;
1862 if (ur_toupper(ei
->expr
[1]) == 'H' && dig2n(ei
->expr
[2], 16) >= 0) goto donumber
;
1863 if (ur_toupper(ei
->expr
[1]) == 'X' && dig2n(ei
->expr
[2], 16) >= 0) goto donumber
;
1864 if (ur_toupper(ei
->expr
[1]) == 'O' && dig2n(ei
->expr
[2], 8) >= 0) goto donumber
;
1865 if (ur_toupper(ei
->expr
[1]) == 'B' && dig2n(ei
->expr
[2], 2) >= 0) goto donumber
;
1866 if (ur_toupper(ei
->expr
[1]) == 'D' && dig2n(ei
->expr
[2], 10) >= 0) goto donumber
;
1868 case '"': /* char or 2 chars */
1869 case '\'': /* char or 2 reversed chars */
1871 ei
->expr
= parse_string(res
, ch
, ei
->expr
+1, &tmp
, &len
);
1872 if (tmp
) EERROR(UR_EXPRERR_STRING
);
1874 res
->val
= (unsigned char)res
->str
[0];
1875 } else if (len
>= 2) {
1876 res
->val
= ((unsigned char)res
->str
[0])<<(ch
== '"' ? 0 : 8);
1877 res
->val
|= ((unsigned char)res
->str
[1])<<(ch
== '"' ? 8 : 0);
1882 EERROR(UR_EXPRERR_TERM
);
1888 if (urasm_getval
!= NULL
) {
1889 ei
->expr
= urasm_getval(res
, ei
->expr
, ei
->addr
, ei
->logic_done
, &ei
->defined
, &ei
->error
);
1890 if (ei
->error
!= UR_EXPRERR_NONE
) EERROR(ei
->error
);
1892 EERROR(UR_EXPRERR_MARG
);
1897 if (read_label_name(lbl
, ei
)) EERROR(UR_EXPRERR_LABEL
);
1899 if (ei
->expr
[0] == '(') {
1901 urasm_func_fn fn
= urasm_expr_find_func(lbl
);
1903 if (fn
== NULL
) EERROR(UR_EXPRERR_FUNC
);
1904 ++(ei
->expr
); /* skip '(' */
1905 e
= fn(res
, ei
->expr
, ei
->addr
, ei
->logic_done
, &ei
->defined
, &ei
->error
);
1906 if (ei
->error
!= UR_EXPRERR_NONE
) EERROR(ei
->error
);
1907 else if (e
== NULL
) EERROR(UR_EXPRERR_FUNC
);
1911 if (!ei
->logic_done
) get_addr(lbl
, res
, ei
);
1918 static const expr_operator_t
*get_operator (int prio
, expr_info_t
*ei
) {
1919 const char opc
= ei
->expr
[0];
1921 const expr_operator_t
*res
= NULL
;
1922 for (const expr_operator_t
*op
= (!urasm_use_old_priorities
? operators_new
: operators_old
); op
->prio
>= 0; ++op
) {
1924 //fprintf(stderr, "get_operator: prio=%d; sn=%c; opc=%c\n", prio, op->sn, opc);
1925 if (op
->prio
== prio
&& oplen
<= 1 && opc
== op
->sn
) { res
= op
; oplen
= 1; }
1927 const int l
= (int)strlen(op
->ln
);
1928 if (l
> oplen
&& strncmp(ei
->expr
, op
->ln
, l
) == 0) { res
= op
; oplen
= l
; }
1931 if (res
&& res
->prio
!= prio
) res
= NULL
;
1932 //if (res) fprintf(stderr, "res: prio=%d; sn='%c' \"%s\" (%d : %.*s)\n", prio, res->sn, res->ln, oplen, (unsigned)oplen, ei->expr);
1933 if (res
) ei
->expr
+= oplen
; /* eat operator */
1938 #define CHECKNOTSTR do { \
1939 if (ur_is_long_str(res->str) || ur_is_long_str(o1.str)) { \
1940 urasm_exprval_clear(&o1); \
1941 urasm_exprval_clear(res); \
1942 EERROR(UR_EXPRERR_TYPE); \
1947 static void expr_do (int prio
, urasm_exprval_t
*res
, expr_info_t
*ei
) {
1948 const expr_operator_t
*op
;
1951 if (ei
->expr
[0] == ')' || ei
->expr
[0] == ']') return;
1952 if (prio
<= 0) { term(res
, ei
); return; }
1953 urasm_exprval_init(&o1
);
1954 //fprintf(stderr, "expr_do: prio=%d <%s>\n", prio, ei->expr);
1955 if (prio
== UNARY_PRIO
) {
1956 //fprintf(stderr, "expr_do: prio=%d <%s>\n", prio, ei->expr);
1960 ei
->errpos
= ei
->expr
;
1961 if (!(op
= get_operator(prio
, ei
))) break;
1962 //fprintf(stderr, "UNARY: op=%c\n", op->sn);
1963 //expression(res, ei);
1964 if (op
->sn
== '-' || op
->sn
== '+') {
1965 expr_do(prio
-1, res
, ei
); /* left-associative */
1967 expr_do(prio
, res
, ei
); /* right-associative */
1969 if (!ei
->logic_done
) {
1971 op
->doer(res
, &o1
, ei
);
1973 res
->fixuptype
= UR_FIXUP_NONE
;
1974 res
->val
= ei
->logic_res
;
1977 if (op
->sn
== '-' || op
->sn
== '+') break;
1979 if (!wasIt
) expr_do(prio
-1, res
, ei
); /* left-associative */
1983 expr_do(prio
-1, res
, ei
); /* first operand, left-associative */
1987 ei
->errpos
= ei
->expr
;
1988 if (!ei
->expr
[0] || ei
->expr
[0] == ';' || ei
->expr
[0] == ':' || ei
->expr
[0] == ')' || ei
->expr
[0] == ']') break;
1989 //fprintf(stderr, "BINARY: prio=%d; expr=<%s>\n", prio, ei->expr);
1990 if (!(op
= get_operator(prio
, ei
))) break;
1991 if (!ei
->logic_done
) {
1992 if (prio
== get_land_prio()) {
1994 if (!res
->val
) { ei
->logic_done
= 1; ei
->logic_res
= 0; }
1995 } else if (prio
== get_lor_prio()) {
1997 if (res
->val
) { ei
->logic_done
= 1; ei
->logic_res
= res
->val
; }
2000 //fprintf(stderr, "BINARY:000: prio=%d; expr=<%s>; op=%c(%s)\n", prio, ei->expr, op->sn, op->ln);
2001 expr_do(prio
-1, &o1
, ei
); /* second operand, left-associative */
2002 //fprintf(stderr, "BINARY:001: prio=%d; expr=<%s>; op=%c(%s)\n", prio, ei->expr, op->sn, op->ln);
2003 if (!ei
->logic_done
) {
2004 if (op
->type
!= optype_comparison
) {
2007 //fprintf(stderr, "DOER:BEFORE: op=%c(%s); prio=%d; val=%d (%d : %d)\n", op->sn, op->ln, op->prio, res->val, ei->logic_done, ei->logic_res);
2008 op
->doer(res
, &o1
, ei
);
2009 //fprintf(stderr, "DOER:AFTER: val=%d (%d : %d)\n", res->val, ei->logic_done, ei->logic_res);
2010 urasm_exprval_clear(&o1
);
2012 res
->fixuptype
= UR_FIXUP_NONE
;
2013 res
->val
= ei
->logic_res
;
2019 static void expression (urasm_exprval_t
*res
, expr_info_t
*ei
) {
2021 ei
->errpos
= ei
->expr
;
2022 if (!ei
->expr
[0]) EERROR(UR_EXPRERR_EOS
);
2023 expr_do(get_max_prio(), res
, ei
);
2028 const char *urasm_expr_ex (urasm_exprval_t
*res
, const char *expr
, uint16_t addr
, int *donteval
, int *defined
, int *error
) {
2031 urasm_exprval_clear(res
);
2032 if (error
) *error
= 0;
2033 if (!expr
) { if (error
) *error
= UR_EXPRERR_EOS
; return NULL
; }
2034 if (res
->str
!= NULL
) { free(res
->str
); res
->str
= NULL
; }
2037 ei
.defined
= (defined
? *defined
: 1);
2039 ei
.logic_done
= (donteval
? *donteval
: 0);
2041 jr
= setjmp(ei
.errJP
);
2043 urasm_exprval_clear(res
);
2044 if (error
) *error
= ei
.error
;
2047 expression(res
, &ei
);
2048 if (defined
) *defined
= ei
.defined
;
2049 if (donteval
) *donteval
= ei
.logic_done
;
2054 const char *urasm_expr (int32_t *res
, const char *expr
, uint16_t addr
, int *defined
, int *fixuptype
, int *error
) {
2058 if (defined
) *defined
= 1;
2059 if (fixuptype
) *fixuptype
= UR_FIXUP_NONE
;
2060 urasm_exprval_init(&r
);
2061 ret
= urasm_expr_ex(&r
, expr
, addr
, NULL
, defined
, &err
);
2062 if (error
) *error
= err
;
2064 if (fixuptype
) *fixuptype
= r
.fixuptype
;
2065 if (ur_is_long_str(r
.str
)) {
2066 if (error
) *error
= UR_EXPRERR_TYPE
;
2074 urasm_exprval_clear(&r
);
2079 void urasm_exprval_init (urasm_exprval_t
*res
) {
2081 memset(res
, 0, sizeof(*res
));
2082 res
->fixuptype
= UR_FIXUP_NONE
;
2087 void urasm_exprval_clear (urasm_exprval_t
*res
) {
2089 if (res
->str
!= NULL
) {
2094 res
->fixuptype
= UR_FIXUP_NONE
;
2099 void urasm_exprval_setint (urasm_exprval_t
*res
, int32_t v
) {
2100 if (res
->str
) { free(res
->str
); res
->str
= NULL
; }
2105 /* sets val as in double quotes */
2106 void urasm_exprval_tostr (urasm_exprval_t
*res
, const char *str
) {
2108 urasm_exprval_setint(res
, 0);
2110 const size_t slen
= strlen(str
);
2111 res
->str
= realloc(res
->str
, slen
+1);
2112 strcpy(res
->str
, str
);
2114 res
->val
= (unsigned char)res
->str
[0];
2116 res
->val
= (unsigned char)res
->str
[0];
2117 res
->val
|= ((unsigned char)res
->str
[1])<<8;
2123 /* sets val as in single quotes */
2124 void urasm_exprval_tostr_rev (urasm_exprval_t
*res
, const char *str
) {
2126 urasm_exprval_setint(res
, 0);
2128 const size_t slen
= strlen(str
);
2129 res
->str
= realloc(res
->str
, slen
+1);
2130 strcpy(res
->str
, str
);
2132 res
->val
= (unsigned char)res
->str
[0];
2134 res
->val
= ((unsigned char)res
->str
[0])<<8;
2135 res
->val
|= (unsigned char)res
->str
[1];
2141 ///////////////////////////////////////////////////////////////////////////////
2144 const char *urasm_skip_operand (const char *expr
, int *seenarg
) {
2145 if (seenarg
) *seenarg
= 0;
2146 if (!expr
) return NULL
;
2147 expr
= skip_blanks(expr
);
2148 if (!expr
[0] || expr
[0] == ';') return NULL
;
2149 if (expr
[0] == ':' || expr
[0] == ',') return expr
; /* colon or comma, nothing to do here */
2150 if (seenarg
) *seenarg
= 1;
2153 const char *oe
= expr
;
2154 for (; *expr
; ++expr
) {
2155 const char ch
= *expr
;
2157 if (ch
== inQ
) inQ
= 0;
2158 else if (ch
== '\\' && expr
[1]) ++expr
;
2160 if (ch
== '"' || ch
== '`') inQ
= ch
;
2161 else if (ch
== '\'' && (expr
== oe
|| !ur_isalnum(expr
[-1]))) inQ
= ch
;
2162 else if (ch
== '(') ++parens
;
2163 else if (ch
== ')') { if (--parens
< 0) parens
= 0; }
2164 else if (ch
== ';') break;
2165 else if (parens
== 0 && (ch
== ',' || ch
== ':')) break;
2172 /* error is `UR_EXPRERR_XXX` */
2173 const char *urasm_next_operand (urasm_operand_t
*op
, const char *expr
, uint16_t addr
, int *error
) {
2179 *error
= UR_EXPRERR_NONE
;
2180 memset(op
, 0, sizeof(urasm_operand_t
));
2182 if (!expr
) return NULL
;
2183 expr
= skip_blanks(expr
);
2184 if (!expr
[0] || expr
[0] == ';') return NULL
;
2185 if (expr
[0] == ':') return expr
;
2187 op
->fixuptype
= UR_FIXUP_NONE
;
2189 for (oe
= expr
; *expr
; ++expr
) {
2190 const char ch
= *expr
;
2192 if (ch
== inQ
) inQ
= 0;
2193 else if (ch
== '\\' && expr
[1]) ++expr
;
2195 if (ch
== '"' || ch
== '`') inQ
= ch
;
2196 else if (ch
== '\'' && (oe
== expr
|| !ur_isalnum(expr
[-1]))) inQ
= ch
;
2197 else if (ch
== '(') ++parens
;
2198 else if (ch
== ')') { if (--parens
< 0) parens
= 0; }
2199 else if (ch
== ';') break;
2200 else if (parens
== 0 && (ch
== ',' || ch
== ':')) break;
2203 if (expr
-oe
> 255) { *error
= UR_EXPRERR_TOOLONG
; return oe
; }
2204 memset(opstr
, 0, sizeof(opstr
));
2205 memcpy(opstr
, oe
, expr
-oe
);
2206 while (opstr
[0] && ur_isspace(opstr
[strlen(opstr
)-1])) opstr
[strlen(opstr
)-1] = '\0';
2207 if (!opstr
[0]) { *error
= UR_EXPRERR_EOS
; return oe
; }
2208 /* determine operand type */
2209 if (opstr
[0] == '=' && urasm_expand
!= NULL
) {
2210 if (urasm_expand(opstr
, (int)sizeof(opstr
)-1) != 0) { *error
= UR_EXPRERR_MARG
; return oe
; }
2211 //fprintf(stderr, "exp: [%s]\n", opstr);
2213 if (ur_isalpha(opstr
[0]) && urasm_is_valid_name(opstr
)) {
2216 if (opstr
[0] == '(') {
2218 op
->mem
= 1; op
->special
= 1;
2219 if (!opstr
[1] || opstr
[strlen(opstr
)-1] != ')') { *error
= UR_EXPRERR_PARENS
; return oe
; }
2220 /* operand w/o "()" */
2221 opstr
[strlen(opstr
)-1] = '\0';
2222 memmove(opstr
, opstr
+1, sizeof(opstr
)-1);
2224 while (opstr
[0] && ur_isspace(opstr
[0])) memmove(opstr
, opstr
+1, sizeof(opstr
)-1);
2225 while (opstr
[0] && ur_isspace(opstr
[strlen(opstr
)-1])) opstr
[strlen(opstr
)-1] = '\0';
2226 /* empty brackets? */
2227 if (!opstr
[0]) { *error
= UR_EXPRERR_TERM
; return oe
; }
2228 for (f
= 0; opstr
[f
]; ++f
) op
->s
[f
] = ur_toupper(opstr
[f
]);
2229 if (!strcmp(op
->s
, "C")) {
2230 op
->special
= 1; op
->mem
= 0; strcpy(op
->s
, "(C)");
2233 if (!strcmp(op
->s
, "HL")) return expr
;
2234 if (!strcmp(op
->s
, "DE")) return expr
;
2235 if (!strcmp(op
->s
, "BC")) return expr
;
2236 if (!strcmp(op
->s
, "SP")) return expr
;
2237 if (op
->s
[0] == 'I' && (op
->s
[1] == 'X' || op
->s
[1] == 'Y')) {
2238 /* memref: IX or IY */
2239 op
->ixy
= op
->s
[1]=='X' ? 0xDDU
: 0xFDU
;
2241 memmove(opstr
, opstr
+1, sizeof(opstr
)-1);
2243 while (opstr
[1] && ur_isspace(opstr
[1])) memmove(opstr
+1, opstr
+2, sizeof(opstr
)-2);
2244 if (!opstr
[1]) return expr
;
2245 if (opstr
[1] != '+' && opstr
[1] != '-') { *error
= UR_EXPRERR_NUMBER
; return oe
; }
2246 /* opstr must be an expression */
2247 const char *t
= urasm_expr(&op
->v
, opstr
, addr
, &op
->defined
, NULL
, error
);
2248 if (*error
) return oe
;
2249 if (t
[0]) { *error
= UR_EXPRERR_TOOLONG
; return oe
; }
2250 if (op
->defined
&& (op
->v
< -128 || op
->v
> 127)) { *error
= UR_EXPRERR_NUMBER
; return oe
; }
2255 if (!strcasecmp(opstr
, "af'")) goto registerop
;
2256 for (f
= 0; ur_isalpha(opstr
[f
]); ++f
) {}
2259 for (f
= 0; opstr
[f
]; ++f
) opstr
[f
] = ur_toupper(opstr
[f
]);
2260 strcpy(op
->s
, opstr
);
2262 return skip_blanks(expr
);
2265 /* this must be an expression */
2267 strcpy(op
->s
, opstr
);
2272 urasm_exprval_init(&e
);
2273 t
= urasm_expr_ex(&e
, opstr
, addr
, &donteval
, &op
->defined
, error
);
2275 op
->fixuptype
= e
.fixuptype
;
2276 urasm_exprval_clear(&e
);
2277 //const char *t = urasm_expr(&op->v, opstr, addr, &op->defined, error);
2278 if (*error
) { op
->parsed
= 0; return oe
; }
2279 if (t
== NULL
|| t
[0]) { op
->parsed
= 0; *error
= UR_EXPRERR_EOS
; return oe
; }
2281 return skip_blanks(expr
);
2285 ///////////////////////////////////////////////////////////////////////////////
2288 // for regsters & conditions: op->v will be set to reg number
2289 int urasm_is_valid_operand (urasm_operand_t
*op
, uint16_t addr
, unsigned optype
) {
2291 if (optype
== UO_NONE
|| optype
== UO_NEXT
) return (op
->s
[0] == '\0');
2292 if (!op
->s
[0]) return 0;
2295 if (op
->special
|| op
->mem
) return 0;
2296 if (op
->defined
&& (op
->v
< -128 || op
->v
> 255)) return 0;
2299 if (op
->special
|| op
->mem
) return 0;
2300 if (op
->defined
&& (op
->v
< -32768 || op
->v
> 65535)) return 0;
2303 if (op
->special
|| op
->mem
) return 0;
2304 if (op
->defined
&& (op
->v
< -32768 || op
->v
> 65535)) return 0;
2307 if (op
->special
|| op
->mem
) return 0;
2308 if (op
->defined
&& (op
->v
< -32768 || op
->v
> 65535)) return 0;
2309 if (op
->v
< 0) op
->v
= 65536+op
->v
;
2312 if (op
->special
|| op
->mem
) return 0;
2313 if (op
->defined
&& (op
->v
< -32768 || op
->v
> 65535)) return 0;
2314 if (!op
->defined
) op
->v
= addr
;
2315 if (op
->v
< 0) op
->v
= 65536+op
->v
;
2316 i
= op
->v
-((int)addr
+2);
2317 if (i
< -128 || i
> 127) return 0;
2321 if (op
->special
|| !op
->mem
) return 0;
2322 if (op
->defined
&& (op
->v
< -32768 || op
->v
> 65535)) return 0;
2323 if (op
->v
< 0) op
->v
= 65536+op
->v
;
2325 case UO_R8
: case UO_2R8
:
2326 if (op
->mem
&& !strcmp(op
->s
, "HL")) { /*strcpy(op->s, "M");*/ op
->v
= 6; return 1; }
2328 case UO_R8_NOM
: case UO_2R8_NOM
:
2329 if (!op
->special
|| op
->mem
|| op
->s
[1]) return 0;
2331 case 'B': op
->v
= 0; break;
2332 case 'C': op
->v
= 1; break;
2333 case 'D': op
->v
= 2; break;
2334 case 'E': op
->v
= 3; break;
2335 case 'H': op
->v
= 4; break;
2336 case 'L': op
->v
= 5; break;
2337 case 'A': op
->v
= 7; break;
2342 if (!op
->special
|| op
->mem
) return 0;
2343 return strcmp(op
->s
, "(C)")==0;
2344 case UO_PORTIMM
: /* mem, 'cause (n) */
2345 if (op
->special
|| !op
->mem
) return 0;
2347 if (op
->defined
&& (op
->v
< 0 || op
->v
> 255)) return 0;
2350 if (!op
->special
|| op
->mem
) return 0;
2351 if (!strcmp(op
->s
, "XH") || !strcmp(op
->s
, "HX") || !strcmp(op
->s
, "IXH")) return 1;
2354 if (!op
->special
|| op
->mem
) return 0;
2355 if (!strcmp(op
->s
, "XL") || !strcmp(op
->s
, "LX") || !strcmp(op
->s
, "IXL")) return 1;
2358 if (!op
->special
|| op
->mem
) return 0;
2359 if (!strcmp(op
->s
, "YH") || !strcmp(op
->s
, "HY") || !strcmp(op
->s
, "IYH")) return 1;
2362 if (!op
->special
|| op
->mem
) return 0;
2363 if (!strcmp(op
->s
, "YL") || !strcmp(op
->s
, "LY") || !strcmp(op
->s
, "IYL")) return 1;
2366 if (!op
->special
|| op
->mem
) return 0;
2367 if (!strcmp(op
->s
, "A")) return 1;
2370 if (!op
->special
|| op
->mem
) return 0;
2371 if (!strcmp(op
->s
, "B")) return 1;
2374 if (!op
->special
|| op
->mem
) return 0;
2375 if (!strcmp(op
->s
, "R")) return 1;
2378 if (!op
->special
|| op
->mem
) return 0;
2379 if (!strcmp(op
->s
, "I")) return 1;
2382 if (!op
->special
|| op
->mem
|| !op
->s
[1] || op
->s
[2]) return 0;
2383 if (!strcmp(op
->s
, "BC")) { op
->v
= 0; return 1; }
2384 if (!strcmp(op
->s
, "DE")) { op
->v
= 1; return 1; }
2385 if (!strcmp(op
->s
, "HL")) { op
->v
= 2; return 1; }
2386 if (!strcmp(op
->s
, "SP")) { op
->v
= 3; return 1; }
2389 if (!op
->special
|| op
->mem
|| !op
->s
[1] || op
->s
[2]) return 0;
2390 if (!strcmp(op
->s
, "BC")) { op
->v
= 0; return 1; }
2391 if (!strcmp(op
->s
, "DE")) { op
->v
= 1; return 1; }
2392 if (!strcmp(op
->s
, "HL")) { op
->v
= 2; return 1; }
2393 if (!strcmp(op
->s
, "AF")) { op
->v
= 3; return 1; }
2396 if (!op
->special
|| op
->mem
|| strcmp(op
->s
, "AF")) return 0;
2400 if (!op
->special
|| op
->mem
|| (strcmp(op
->s
, "AF'") && strcmp(op
->s
, "AFX"))) return 0;
2404 if (!op
->special
|| op
->mem
|| strcmp(op
->s
, "BC")) return 0;
2408 if (!op
->special
|| op
->mem
|| strcmp(op
->s
, "DE")) return 0;
2412 if (!op
->special
|| op
->mem
|| strcmp(op
->s
, "HL")) return 0;
2416 if (!op
->special
|| op
->mem
|| strcmp(op
->s
, "IX")) return 0;
2420 if (!op
->special
|| op
->mem
|| strcmp(op
->s
, "IY")) return 0;
2424 if (!op
->special
|| op
->mem
|| strcmp(op
->s
, "SP")) return 0;
2428 if (!op
->special
|| !op
->mem
|| strcmp(op
->s
, "SP")) return 0;
2432 if (!op
->special
|| !op
->mem
|| strcmp(op
->s
, "BC")) return 0;
2436 if (!op
->special
|| !op
->mem
|| strcmp(op
->s
, "DE")) return 0;
2440 if (!op
->special
|| !op
->mem
|| strcmp(op
->s
, "HL")) return 0;
2444 if (!op
->special
|| !op
->mem
|| op
->ixy
!= 0xDDU
) return 0;
2445 if (op
->defined
&& (op
->v
< -128 || op
->v
> 127)) return 0;
2448 if (!op
->special
|| !op
->mem
|| op
->ixy
!= 0xFDU
) return 0;
2449 if (op
->defined
&& (op
->v
< -128 || op
->v
> 127)) return 0;
2452 if (!op
->special
|| !op
->mem
|| op
->ixy
!= 0xDDU
) return 0;
2453 if (op
->defined
&& op
->v
!= 0) return 0;
2456 if (!op
->special
|| !op
->mem
|| op
->ixy
!= 0xFDU
) return 0;
2457 if (op
->defined
&& op
->v
!= 0) return 0;
2460 if (!op
->special
|| op
->mem
|| ur_is_long_str(op
->s
)) return 0;
2461 if (!strcmp(op
->s
, "NZ")) { op
->v
= 0; return 1; }
2462 if (!strcmp(op
->s
, "Z")) { op
->v
= 1; return 1; }
2463 if (!strcmp(op
->s
, "NC")) { op
->v
= 2; return 1; }
2464 if (!strcmp(op
->s
, "C")) { op
->v
= 3; return 1; }
2467 if (!op
->special
|| op
->mem
|| ur_is_long_str(op
->s
)) return 0;
2468 if (!strcmp(op
->s
, "NZ")) { op
->v
= 0; return 1; }
2469 if (!strcmp(op
->s
, "Z")) { op
->v
= 1; return 1; }
2470 if (!strcmp(op
->s
, "NC")) { op
->v
= 2; return 1; }
2471 if (!strcmp(op
->s
, "C")) { op
->v
= 3; return 1; }
2472 if (!strcmp(op
->s
, "PO")) { op
->v
= 4; return 1; }
2473 if (!strcmp(op
->s
, "PE")) { op
->v
= 5; return 1; }
2474 if (!strcmp(op
->s
, "P")) { op
->v
= 6; return 1; }
2475 if (!strcmp(op
->s
, "M")) { op
->v
= 7; return 1; }
2478 if (op
->special
|| op
->mem
) return 0;
2479 if (op
->defined
&& (op
->v
< 0 || op
->v
> 7)) return 0;
2482 if (op
->special
|| op
->mem
) return 0;
2483 if (op
->defined
&& (op
->v
< 0 || op
->v
> 0x38 || (op
->v
&7))) return 0;
2487 if (op
->special
|| op
->mem
) return 0;
2488 if (op
->defined
&& op
->v
!= 0) return 0;
2491 if (op
->special
|| op
->mem
) return 0;
2492 if (op
->defined
&& op
->v
!= 1) return 0;
2495 if (op
->special
|| op
->mem
) return 0;
2496 if (op
->defined
&& op
->v
!= 2) return 0;
2503 // mem size should be at least 7 bytes
2504 // returns size of the assembled code
2505 // result <0 on error
2506 // understands comments
2507 int urasm_opasm (const char *expr
, uint16_t destaddr
, uint16_t addr
, const char **errpos
) {
2513 urasm_operand_t ops
[3];
2514 const urasm_cmdinfo_t
*cm
;
2515 uint32_t code
, mask
;
2516 int opcPos
; /* opcode will be placed here */
2519 int doOperand (int idx
) {
2520 const urasm_operand_t
*op
= ops
+idx
;
2521 switch (cm
->ops
[idx
]) {
2523 if (op
->fixuptype
!= UR_FIXUP_NONE
&& urasm_fixup_operand
!= NULL
) {
2524 if (op
->fixuptype
== UR_FIXUP_WORD
) return UR_EXPRERR_FIXUP
+URA_EXPR_ERR
;
2525 urasm_fixup_operand(op
, (destaddr
+len
)&0xffff, (destaddr
+len
)&0xffff, op
->fixuptype
, 1);
2530 buf
[len
++] = op
->v
&0xFFU
;
2535 if (op
->fixuptype
!= UR_FIXUP_NONE
&& urasm_fixup_operand
!= NULL
) {
2536 urasm_fixup_operand(op
, (destaddr
+len
)&0xffff, (destaddr
+len
)&0xffff, op
->fixuptype
, 2);
2538 buf
[len
++] = op
->v
&0xFFU
;
2539 buf
[len
++] = ((op
->v
&0xFFFFU
)>>8)&0xFFU
;
2542 /*FIXME: this is prolly not right*/
2543 if (op
->fixuptype
!= UR_FIXUP_NONE
&& urasm_fixup_operand
!= NULL
) {
2544 switch (op
->fixuptype
) {
2546 urasm_fixup_operand(op
, (destaddr
+len
)&0xffff, (destaddr
+len
)&0xffff, UR_FIXUP_HIBYTE
, 1);
2547 urasm_fixup_operand(op
, (destaddr
+len
+1)&0xffff, (destaddr
+len
+1)&0xffff, UR_FIXUP_LOBYTE
, 1);
2549 case UR_FIXUP_LOBYTE
:
2550 urasm_fixup_operand(op
, (destaddr
+len
)&0xffff, (destaddr
+len
)&0xffff, UR_FIXUP_HIBYTE
, 1);
2552 case UR_FIXUP_HIBYTE
:
2553 urasm_fixup_operand(op
, (destaddr
+len
+1)&0xffff, (destaddr
+len
+1)&0xffff, UR_FIXUP_LOBYTE
, 1);
2558 buf
[len
++] = ((op
->v
&0xFFFFU
)>>8)&0xFFU
;
2559 buf
[len
++] = op
->v
&0xFFU
;
2563 code
|= op
->v
&0xFFU
;
2571 code
|= (op
->v
&0xFFU
)<<3;
2575 code
|= (op
->v
&0xFFU
)<<4;
2585 /* <0: error; 0: ok; >0: last operand (ops[opix].parsed != 0: non-empty one) */
2586 int parseOperand (int opidx
) {
2588 const char *oe
= expr
;
2589 expr
= urasm_next_operand(ops
+opidx
, expr
, addr
, &error
);
2591 if (errpos
) *errpos
= oe
;
2592 //return URA_BAD_OPERAND;
2593 return -error
+URA_EXPR_ERR
;
2595 if (!expr
|| !expr
[0] || expr
[0] == ';' || expr
[0] == ':') return 1;
2596 if (*expr
!= ',') { if (errpos
) *errpos
= oe
; return URA_BAD_OPERAND
; }
2601 int genCode (void) {
2603 for (int pos
= URASM_MAX_COMMAND
-1; pos
>= 0; --pos
) {
2605 if (tkn
!= URASM_COMMANDS
[pos
].mnemo
) continue;
2606 for (f
= 0; f
< 3; ++f
) {
2607 if (!urasm_is_valid_operand(&ops
[f
], addr
, URASM_COMMANDS
[pos
].ops
[f
])) break;
2609 if (f
< 3) continue;
2610 /* command found, generate code */
2611 len
= 0; cm
= URASM_COMMANDS
+pos
;
2612 code
= cm
->code
; mask
= cm
->mask
;
2613 if ((code
&0xFFFFUL
) == 0xCBDDUL
|| (code
&0xFFFFUL
) == 0xCBFDUL
) {
2614 /* special commands */
2615 /* emit unmasked code */
2616 buf
[0] = (code
&0xFFU
); buf
[1] = 0xCBU
;
2617 for (f
= 0; f
< 3; ++f
) {
2618 if (cm
->ops
[f
] == UO_MIX
|| cm
->ops
[f
] == UO_MIY
) {
2619 if (ops
[f
].defined
&& (ops
[f
].v
< -128 || ops
[f
].v
> 127)) f
= -1;
2620 else if (ops
[f
].defined
) buf
[2] = ops
[f
].v
;
2624 if (f
< 0) continue; /* not me */
2626 code
>>= 24; mask
>>= 24;
2627 if ((mask
&0xFFUL
) != 0xFFUL
) {
2628 for (f
= 0; f
< 3; ++f
) if (cm
->ops
[f
] != UO_MIX
&& cm
->ops
[f
] != UO_MIY
) {
2629 if ((operr
= doOperand(f
)) != 0) goto badi
;
2634 for (f
= 0; f
< len
; ++f
) { urasm_putbyte(destaddr
++, buf
[f
]); ++addr
; }
2637 /* normal commands */
2638 /* emit unmasked code */
2639 while ((mask
&0xFFUL
) == 0xFFUL
) {
2640 buf
[len
++] = code
&0xFFUL
;
2641 code
>>= 8; mask
>>= 8;
2643 //ASSERT((code&0xFFFFFF00UL) == 0);
2649 if ((operr
= doOperand(0)) != 0) goto badi
;
2650 if ((operr
= doOperand(1)) != 0) goto badi
;
2651 if ((operr
= doOperand(2)) != 0) goto badi
;
2654 for (f
= 0; f
< len
; ++f
) { urasm_putbyte(destaddr
++, buf
[f
]); ++addr
; }
2659 if (errpos
) *errpos
= oe
;
2660 return (operr
< 0 ? operr
: URA_BAD_INSTRUCTION
);
2663 int doPushPop (void) {
2665 for (f
= len
= 0; ; ++f
) {
2667 const char *oe
= expr
;
2668 int res
= parseOperand(0);
2669 if (res
< 0) return res
;
2671 if (f
== 0 && !ops
[0].parsed
) { *errpos
= oe
; return URA_BAD_INSTRUCTION
; }
2674 code
= (tkn
== UT_POP
? 0xC1U
: 0xC5U
);
2675 if (urasm_is_valid_operand(ops
, addr
, UO_R16A
)) {
2676 code
|= (ops
[0].v
&0xFFU
)<<4;
2677 urasm_putbyte(destaddr
++, code
);
2680 } else if (urasm_is_valid_operand(ops
, addr
, UO_R16IX
)) {
2681 code
|= (ops
[0].v
&0xFFU
)<<4;
2682 urasm_putbyte(destaddr
++, 0xDDU
);
2683 urasm_putbyte(destaddr
++, code
);
2686 } else if (urasm_is_valid_operand(ops
, addr
, UO_R16IY
)) {
2687 code
|= (ops
[0].v
&0xFFU
)<<4;
2688 urasm_putbyte(destaddr
++, 0xFDU
);
2689 urasm_putbyte(destaddr
++, code
);
2692 } else if (urasm_allow_zxnext
&& code
== 0xC5U
&& urasm_is_valid_operand(ops
, addr
, UO_IMM16BE
)) {
2693 /* ZXNext PUSH nnnn */
2694 urasm_putbyte(destaddr
++, 0xEDU
);
2695 urasm_putbyte(destaddr
++, 0x8AU
);
2696 /*FIXME: this is prolly not right*/
2697 if (ops
[0].fixuptype
!= UR_FIXUP_NONE
&& urasm_fixup_operand
!= NULL
) {
2698 switch (ops
[0].fixuptype
) {
2700 urasm_fixup_operand(&ops
[0], (destaddr
+len
)&0xffff, (destaddr
+len
)&0xffff, UR_FIXUP_HIBYTE
, 1);
2701 urasm_fixup_operand(&ops
[0], (destaddr
+len
+1)&0xffff, (destaddr
+len
+1)&0xffff, UR_FIXUP_LOBYTE
, 1);
2703 case UR_FIXUP_LOBYTE
:
2704 urasm_fixup_operand(&ops
[0], (destaddr
+len
)&0xffff, (destaddr
+len
)&0xffff, UR_FIXUP_HIBYTE
, 1);
2706 case UR_FIXUP_HIBYTE
:
2707 urasm_fixup_operand(&ops
[0], (destaddr
+len
+1)&0xffff, (destaddr
+len
+1)&0xffff, UR_FIXUP_LOBYTE
, 1);
2712 urasm_putbyte(destaddr
++, ((ops
[0].v
&0xFFFFU
)>>8)&0xFFU
);
2713 urasm_putbyte(destaddr
++, ops
[0].v
&0xFFU
);
2717 if (errpos
) *errpos
= oe
;
2718 return URA_BAD_OPERAND
;
2723 expr
= skip_blanks(expr
);
2724 if (expr
[0] && expr
[0] != ';') {
2725 if (errpos
) *errpos
= expr
;
2726 if (expr
[0] != ':') return URA_EXTRA_TEXT
;
2732 int dorep (int opcnt
) {
2734 memset(ops
, 0, sizeof(ops
));
2735 for (f
= len
= 0; ; ++f
) {
2736 int doQuit
= 0, res
;
2738 for (int c
= 0; c
< opcnt
; ++c
) {
2740 res
= parseOperand(c
);
2741 if (res
< 0) return res
;
2743 if (c
!= opcnt
-1 || !ops
[c
].parsed
) { *errpos
= oe
; return URA_BAD_INSTRUCTION
; }
2747 if ((res
= genCode()) < 0) return res
;
2753 expr
= skip_blanks(expr
);
2754 if (expr
[0] && expr
[0] != ';') {
2755 if (errpos
) *errpos
= expr
;
2756 if (expr
[0] != ':') return URA_EXTRA_TEXT
;
2762 if (errpos
) *errpos
= NULL
;
2763 if (!urasm_putbyte
|| !expr
) return URA_GENERIC
;
2765 expr
= skip_blanks(expr
);
2766 if (!expr
[0] || expr
[0] == ';') return 0;
2767 if (expr
[0] == ':') { if (errpos
) *errpos
= expr
; return 0; }
2768 for (oe
= expr
; *expr
&& !ur_isspace(*expr
) && *expr
!= ':' && *expr
!= ';'; ++expr
) {}
2769 if (urasm_allow_zxnext
) {
2770 if (expr
-oe
> 7) { if (errpos
) *errpos
= oe
; return URA_BAD_MNEMO
; } /* bad mnemonics */
2772 if (expr
-oe
> 4) { if (errpos
) *errpos
= oe
; return URA_BAD_MNEMO
; } /* bad mnemonics */
2775 memset(mnem
, 0, sizeof(mnem
));
2776 memcpy(mnem
, oe
, expr
-oe
);
2777 for (int f
= 0; mnem
[f
]; ++f
) mnem
[f
] = ur_toupper(mnem
[f
]);
2779 for (tkn
= 0; tkn
< URASM_MAX_TOKEN
; ++tkn
) if (!strcmp(mnem
, URASM_TOKENS
[tkn
])) break;
2780 if (tkn
>= URASM_MAX_TOKEN
) { if (errpos
) *errpos
= oe
; return URA_BAD_MNEMO
; } /* unknown mnemonics */
2782 expr
= skip_blanks(expr
);
2783 if (expr
[0] == ',') { if (errpos
) *errpos
= oe
; return URA_BAD_OPERAND
; }
2784 /* special for PUSH and POP */
2785 if (tkn
== UT_POP
|| tkn
== UT_PUSH
) return doPushPop();
2786 /* special for LD */
2787 if (tkn
== UT_LD
/*|| tkn == UT_ADD || tkn == UT_ADC || tkn == UT_SBC*/) return dorep(2);
2788 /* special for RR/RL */
2789 if (tkn
== UT_RL
|| tkn
== UT_RR
|| tkn
== UT_INC
|| tkn
== UT_DEC
||
2790 tkn
== UT_SRL
|| tkn
== UT_SRA
|| tkn
== UT_SLI
|| tkn
== UT_SLL
|| tkn
== UT_SLA
) return dorep(1);
2792 memset(ops
, 0, sizeof(ops
));
2793 for (int f
= 0; f
< 3; ++f
) {
2794 int res
= parseOperand(f
);
2796 if (res
< 0) return res
;
2801 if (ret
>= 0 && expr
) {
2802 expr
= skip_blanks(expr
);
2803 if (expr
[0] && expr
[0] != ';') {
2804 if (errpos
) *errpos
= expr
;
2805 if (expr
[0] != ':') return URA_EXTRA_TEXT
;
2813 // ////////////////////////////////////////////////////////////////////////// //
2814 static const char *error_messages_asm
[5] = {
2818 "extra text after instruction",
2823 static const char *error_messages_expr
[14] = {
2825 "unexpected end of expression",
2827 "unbalanced parens",
2831 "term expected", /*FIXME: better message!*/
2833 "invalid operand type", /*FIXME: better message! this is string/number conflict*/
2834 "unknown macro argument", /*FIXME: better message! */
2836 "type mismatch", /* in comparisons */
2837 "operand text too long",
2841 const char *urasm_errormsg (int errcode
) {
2842 if (errcode
>= 0) return "";
2843 if (errcode
< URA_EXPR_ERR
) {
2844 errcode
= -(errcode
-URA_EXPR_ERR
);
2845 if (errcode
>= UR_EXPRERR_EOS
&& errcode
<= UR_EXPRERR_TOOLONG
) {
2846 return error_messages_expr
[errcode
-1];
2848 return "unknown error";
2850 if (errcode
< -5) return "unknown error";
2851 return error_messages_asm
[(-errcode
)-1];