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.3 (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 the 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_NOHL
, UO_NONE
}},
624 {.mnemo
=UT_LD
, .code
=0x68DDUL
, .mask
=0xF8FFUL
, .ops
={UO_R8_XL
, UO_R8_NOM_NOHL
, 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_NOHL
, UO_NONE
}},
630 {.mnemo
=UT_LD
, .code
=0x68FDUL
, .mask
=0xF8FFUL
, .ops
={UO_R8_YL
, UO_R8_NOM_NOHL
, 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_NOHL
, UO_R8_XH
, UO_NONE
}},
637 {.mnemo
=UT_LD
, .code
=0x45DDUL
, .mask
=0xC7FFUL
, .ops
={UO_2R8_NOM_NOHL
, 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_NOHL
, UO_R8_YH
, UO_NONE
}},
644 {.mnemo
=UT_LD
, .code
=0x45FDUL
, .mask
=0xC7FFUL
, .ops
={UO_2R8_NOM_NOHL
, 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
}},
833 {.mnemo
=UT_LD
, .code
=0x4DDD44DDUL
, .mask
=0xFFFFFFFFUL
, .ops
={UO_R16BC
, UO_R16IX
, UO_NONE
}},
835 {.mnemo
=UT_LD
, .code
=0x4DFD44FDUL
, .mask
=0xFFFFFFFFUL
, .ops
={UO_R16BC
, UO_R16IY
, UO_NONE
}},
837 {.mnemo
=UT_LD
, .code
=0x5DDD54DDUL
, .mask
=0xFFFFFFFFUL
, .ops
={UO_R16DE
, UO_R16IX
, UO_NONE
}},
839 {.mnemo
=UT_LD
, .code
=0x5DFD54FDUL
, .mask
=0xFFFFFFFFUL
, .ops
={UO_R16DE
, UO_R16IY
, UO_NONE
}},
841 {.mnemo
=UT_LD
, .code
=0x69DD60DDUL
, .mask
=0xFFFFFFFFUL
, .ops
={UO_R16IX
, UO_R16BC
, UO_NONE
}},
843 {.mnemo
=UT_LD
, .code
=0x69FD60FDUL
, .mask
=0xFFFFFFFFUL
, .ops
={UO_R16IY
, UO_R16BC
, UO_NONE
}},
845 {.mnemo
=UT_LD
, .code
=0x6BDD62DDUL
, .mask
=0xFFFFFFFFUL
, .ops
={UO_R16IX
, UO_R16DE
, UO_NONE
}},
847 {.mnemo
=UT_LD
, .code
=0x6BFD62FDUL
, .mask
=0xFFFFFFFFUL
, .ops
={UO_R16IY
, UO_R16DE
, UO_NONE
}},
851 // instructions unaffected by DD/FF prefixes
852 // this table used by disassembler (we don't want to eat prefixes)
853 const unsigned char URASM_DDFD_INSENSITIVE
[256] = {
854 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
855 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
856 1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,
857 1,1,1,1,0,0,0,1,1,0,1,1,1,1,1,1,
858 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
859 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
860 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
861 0,0,0,0,0,0,1,0,1,1,1,1,0,0,0,1,
862 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
863 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
864 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
865 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
866 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,
867 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
868 1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,
869 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
871 0xff,0xbf,0xff,0xbf,0x81,0x81,0xf1,0xbf,0xf1,0xf1,0xf1,0xf1,0x00,0x00,0x02,0xf1,
872 0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xff,0xef,0xff,0xff,0xab,0xbf,0xff,0xbf,
876 #define IS_DD_SENSITIVE(c) URASM_DDFD_INSENSITIVE[(c)&0xff]
878 static inline int IS_DD_SENSITIVE (uint8_t opc) {
879 return URASM_DDFD_INSENSITIVE[opc/8]&(0x80>>(opc%8));
885 const unsigned char URASM_DDFD_HAS_DISP
[256] = {
887 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
888 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
889 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
890 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
891 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
892 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
893 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
894 1,1,1,1,1,1,0,1,0,0,0,0,0,0,1,0,
895 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
896 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
897 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
898 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
899 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
900 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
901 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
902 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
904 0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x00,0x02,0x02,0x02,0x02,0x02,0x02,0xfd,0x02,
905 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
908 static inline int HAS_DDFD_DISP (uint8_t opc
) {
909 return URASM_DDFD_HAS_DISP
[opc
/8]&(0x80>>(opc
%8));
914 static __attribute__((always_inline
)) inline const char *label_by_addr (uint16_t addr
) {
915 if (!urasm_label_by_addr
) return NULL
;
916 return urasm_label_by_addr(addr
);
920 static __attribute__((always_inline
)) inline char ur_toupper (char ch
) {
921 return (ch
>= 'a' && ch
<= 'z' ? ch
-'a'+'A' : ch
);
925 static __attribute__((always_inline
)) inline char ur_isalpha (char ch
) {
927 (ch
>= 'A' && ch
<= 'Z') ||
928 (ch
>= 'a' && ch
<= 'z');
932 static __attribute__((always_inline
)) inline char ur_isalnum (char ch
) {
934 (ch
>= 'A' && ch
<= 'Z') ||
935 (ch
>= 'a' && ch
<= 'z') ||
936 (ch
>= '0' && ch
<= '9');
940 static __attribute__((always_inline
)) inline char ur_isspace (char ch
) {
941 return (ch
!= 0 && ((ch
&0xff) <= 32 || ch
== 127));
945 static inline int dig2n (char ch
, int base
) {
946 if (ch
< '0') return -1;
948 if (ch
> '0'+base
) return -1;
951 if (ch
>= '0' && ch
<= '9') return ch
-'0';
952 if (ch
>= 'a' && ch
<= 'z') ch
= ch
-'a'+10;
953 else if (ch
>= 'A' && ch
<= 'Z') ch
= ch
-'A'+10;
955 if (ch
>= base
) return -1;
960 /******************************************************************************/
962 /******************************************************************************/
965 /* nextW: next 2 bytes (after opcode) */
966 /* idx: I? displacement */
967 static void ua_op2str (char *res
, int op
, uint16_t addr
, uint8_t opc
, uint16_t nextW
, int idx
) {
971 case UO_NONE
: case UO_NEXT
: strcpy(res
, ""); break;
973 if (!urasm_disasm_decimal
) sprintf(res
, "#%02X", nextW
&0xFFU
); else sprintf(res
, "%u", nextW
&0xFFU
);
976 if (!urasm_disasm_decimal
) sprintf(res
, "#%04X", nextW
); else sprintf(res
, "%u", nextW
);
979 nextW
= (uint16_t)(((nextW
>>8)&0xffu
)|((nextW
<<8)&0xff00u
));
980 if (!urasm_disasm_decimal
) sprintf(res
, "#%04X", nextW
); else sprintf(res
, "%u", nextW
);
983 addr
+= 2; nextW
&= 0xFFU
;
984 add
= (nextW
< 128 ? nextW
: ((int)nextW
)-256);
990 lbl
= label_by_addr(nextW
);
991 if (lbl
) { strcpy(res
, lbl
); break; }
992 lbl
= label_by_addr(nextW
-1);
993 if (lbl
) { sprintf(res
, "%s-1", lbl
); break; }
994 lbl
= label_by_addr(nextW
-2);
995 if (lbl
) { sprintf(res
, "%s-2", lbl
); break; }
996 lbl
= label_by_addr(nextW
+1);
997 if (lbl
) { sprintf(res
, "%s+1", lbl
); break; }
998 lbl
= label_by_addr(nextW
+2);
999 if (lbl
) { sprintf(res
, "%s+2", lbl
); break; }
1000 if (!urasm_disasm_decimal
) sprintf(res
, "#%04X", nextW
); else sprintf(res
, "%u", nextW
);
1004 strcpy(res
, "("); ++res
;
1008 case UO_R8_NOM_NOHL
:
1009 strcpy(res
, URA_REGS8
[opc
&0x07UL
]);
1013 case UO_2R8_NOM_NOHL
:
1014 strcpy(res
, URA_REGS8
[(opc
>>3)&0x07UL
]);
1016 case UO_PORTC
: strcpy(res
, "(C)"); break;
1018 if (!urasm_disasm_decimal
) sprintf(res
, "(#%02X)", nextW
&0xFFU
); else sprintf(res
, "(%u)", nextW
&0xFFU
);
1020 case UO_R8_XH
: strcpy(res
, "XH"); break;
1021 case UO_R8_XL
: strcpy(res
, "XL"); break;
1022 case UO_R8_YH
: strcpy(res
, "YH"); break;
1023 case UO_R8_YL
: strcpy(res
, "YL"); break;
1024 case UO_R8_A
: strcpy(res
, "A"); break;
1025 case UO_R8_B
: strcpy(res
, "B"); break;
1026 case UO_R8_R
: strcpy(res
, "R"); break;
1027 case UO_R8_I
: strcpy(res
, "I"); break;
1028 case UO_R16
: strcpy(res
, URA_REGS16
[(opc
>>4)&0x03UL
]); break;
1029 case UO_R16A
: strcpy(res
, URA_REGS16A
[(opc
>>4)&0x03UL
]); break;
1030 case UO_R16AF
: strcpy(res
, "AF"); break;
1031 case UO_R16AFX
: strcpy(res
, "AF'"); break;
1032 case UO_R16BC
: strcpy(res
, "BC"); break;
1033 case UO_R16DE
: strcpy(res
, "DE"); break;
1034 case UO_R16HL
: strcpy(res
, "HL"); break;
1035 case UO_R16IX
: strcpy(res
, "IX"); break;
1036 case UO_R16IY
: strcpy(res
, "IY"); break;
1037 case UO_R16SP
: strcpy(res
, "SP"); break;
1038 case UO_MSP
: strcpy(res
, "(SP)"); break;
1039 case UO_MBC
: strcpy(res
, "(BC)"); break;
1040 case UO_MDE
: strcpy(res
, "(DE)"); break;
1041 case UO_MHL
: strcpy(res
, "(HL)"); break;
1042 case UO_MIX0
: strcpy(res
, "(IX)"); break;
1043 case UO_MIY0
: strcpy(res
, "(IY)"); break;
1046 sprintf(res
, "(IX%s%d)", (idx
< 0 ? "" : "+"), idx
);
1048 strcpy(res
, "(IX)");
1053 sprintf(res
, "(IY%s%d)", (idx
< 0 ? "" : "+"), idx
);
1055 strcpy(res
, "(IY)");
1058 case UO_JRCOND
: strcpy(res
, URA_COND
[(opc
>>3)&0x03U
]); break;
1059 case UO_COND
: strcpy(res
, URA_COND
[(opc
>>3)&0x07U
]); break;
1060 case UO_BITN
: sprintf(res
, "%u", (opc
>>3)&0x07U
); break;
1062 if (!urasm_disasm_decimal
) sprintf(res
, "#%02X", opc
&0x38U
); else sprintf(res
, "%u", opc
&0x38U
);
1064 case UO_IM0
: strcpy(res
, "0"); break;
1065 case UO_IM1
: strcpy(res
, "1"); break;
1066 case UO_IM2
: strcpy(res
, "2"); break;
1067 default: strcpy(res
, ""); break; /* we'll never come here */
1069 if (ismem
) strcat(res
, ")");
1073 /* common code for two disasm functions */
1074 static inline int is_opc_invalid_op (int op
, uint8_t opc
) {
1077 return ((opc
&0x07U
) == 6); /* bad (HL) */
1078 case UO_R8_NOM_NOHL
:
1080 return (opc
>= 4 && opc
<= 6); /* bad H,L,(HL) */
1082 return (((opc
>>3)&0x07U
) == 6); /* bad (HL) */
1083 case UO_2R8_NOM_NOHL
:
1084 opc
= (opc
>>3)&0x07U
;
1085 return (opc
>= 4 && opc
<= 6); /* bad H,L,(HL) */
1091 /* find the corresponding record in URASM_COMMANDS */
1092 int urasm_disasm_opfind (uint16_t addr
) {
1097 if (!urasm_getbyte
) return -1;
1098 for (f
= 0; f
< 8; ++f
) buf
[f
] = urasm_getbyte(addr
+f
);
1099 if (buf
[0] == 0xDDU
|| buf
[0] == 0xFDU
) {
1101 if (IS_DD_SENSITIVE(buf
[1])) return (buf
[0] == 0xDDU
? 0 : 1);
1103 ci
= ((uint32_t)buf
[0]) | (((uint32_t)buf
[1])<<8) | (((uint32_t)buf
[2])<<16) | (((uint32_t)buf
[3])<<24);
1104 for (opn
= 0; opn
< URASM_MAX_COMMAND
; ++opn
) {
1106 for (; opn
< URASM_MAX_COMMAND
&& (ci
&URASM_COMMANDS
[opn
].mask
) != URASM_COMMANDS
[opn
].code
; ++opn
) {}
1107 if (!urasm_allow_zxnext
&& URASM_COMMANDS
[opn
].ops
[2] == UO_NEXT
) opn
= URASM_MAX_COMMAND
; /* skip ZXNext if not allowed */
1108 if (opn
>= URASM_MAX_COMMAND
) {
1109 if (buf
[0] == 0xEDU
) return -2;
1112 /* skip prefixes, determine command length */
1113 f
= URASM_COMMANDS
[opn
].mask
; c
= URASM_COMMANDS
[opn
].code
;
1114 for (bpos
= 0; ; ++bpos
) {
1116 if ((f
&0xFFUL
) != 0xFFUL
) break;
1118 if (b
!= 0xFDU
&& b
!= 0xDDU
&& b
!= 0xEDU
&& b
!= 0xCBU
) break;
1121 /* are there any operands? */
1122 if (URASM_COMMANDS
[opn
].ops
[0] == UO_NONE
) return opn
;
1123 /* is this CB-prefixed? */
1124 if (((URASM_COMMANDS
[opn
].code
&0xFFFFUL
) == 0xCBDDUL
) ||
1125 ((URASM_COMMANDS
[opn
].code
&0xFFFFUL
) == 0xCBFDUL
)) ++bpos
; /* skip displacement */
1128 for (f
= 0; f
<= 3; ++f
) {
1129 if (f
== 3) return opn
;
1130 op
= URASM_COMMANDS
[opn
].ops
[f
];
1131 if (op
== UO_NONE
|| op
== UO_NEXT
) return opn
;
1132 /* check for valid operand */
1133 if (is_opc_invalid_op(op
, opc
)) break;
1140 /* length of the corresponding instruction */
1141 int urasm_disasm_oplen (int idx
) {
1144 if (idx
== -2) return 2;
1145 if (idx
< 0 || idx
>= URASM_MAX_COMMAND
) return 1;
1146 if (idx
< 2) return 1;
1147 m
= URASM_COMMANDS
[idx
].mask
; c
= URASM_COMMANDS
[idx
].code
;
1150 if (((m&0xFFFFUL) == 0xFFFFUL) &&
1151 ((c&0xFF00UL) == 0xCBUL) && ((c&0xFFUL) == 0xDDUL || (c&0xFFUL) == 0xFDUL)) return 4;
1153 /* skip prefixes, determine command length */
1156 if ((m
&0xFFUL
) != 0xFFUL
) break;
1158 if (b
!= 0xFDU
&& b
!= 0xDDU
&& b
!= 0xEDU
&& b
!= 0xCBU
) break;
1159 m
>>= 8; c
>>= 8; ++res
;
1161 /* is this CB-prefixed? */
1162 if (((URASM_COMMANDS
[idx
].code
&0xFFFFUL
) == 0xCBDDUL
) ||
1163 ((URASM_COMMANDS
[idx
].code
&0xFFFFUL
) == 0xCBFDUL
)) m
>>= 8;
1165 while (m
!= 0) { m
>>= 8; ++res
; }
1166 /* process operands */
1167 for (f
= 0; f
<= 2; ++f
) {
1168 op
= URASM_COMMANDS
[idx
].ops
[f
];
1169 if (op
== UO_NONE
|| op
== UO_NEXT
) break;
1171 /* command with displacement */
1172 case UO_MIX
: case UO_MIY
: ++res
; break;
1173 /* command has immediate operand */
1174 case UO_IMM8
: case UO_ADDR8
: case UO_PORTIMM
: ++res
; break;
1175 case UO_IMM16
: case UO_IMM16BE
: case UO_ADDR16
: case UO_MEM16
: res
+= 2; break;
1182 extern int urasm_disasm_opdisasm_ex (char *dstr
, uint16_t addr
, const uint8_t mem
[8]) {
1189 if (!dstr
) return -1;
1190 if (mem
[0] == 0xDDU
|| mem
[0] == 0xFDU
) {
1192 if (IS_DD_SENSITIVE(mem
[1])) {
1193 strcpy(dstr
, URASM_TOKENS
[mem
[0]==0xDDU
? UT_NOPX
: UT_NOPY
]);
1196 /* take possible I? displacement */
1197 idx
= (int8_t)mem
[2];
1199 ci
= ((uint32_t)mem
[0]) | (((uint32_t)mem
[1])<<8) | (((uint32_t)mem
[2])<<16) | (((uint32_t)mem
[3])<<24);
1200 for (opn
= 0; opn
< URASM_MAX_COMMAND
; ++opn
) {
1201 res
= 0; dstr
[0] = '\0';
1203 for (; opn
< URASM_MAX_COMMAND
&& (ci
&URASM_COMMANDS
[opn
].mask
) != URASM_COMMANDS
[opn
].code
; ++opn
) {}
1204 if (!urasm_allow_zxnext
&& URASM_COMMANDS
[opn
].ops
[2] == UO_NEXT
) opn
= URASM_MAX_COMMAND
; /* skip ZXNext if not allowed */
1205 if (opn
>= URASM_MAX_COMMAND
) {
1206 if (mem
[0] == 0xEDU
) {
1207 if (!urasm_disasm_decimal
) sprintf(opstr
, "#%02X,#%02X", mem
[0], mem
[1]); else sprintf(opstr
, "%u,%u", mem
[0], mem
[1]);
1208 /*if (!urasm_disasm_decimal) sprintf(opstr, "#%04X", (uint16_t)buf[0]|(((uint16_t)buf[1])<<8));
1209 else sprintf(opstr, "%u", (uint16_t)buf[0]|(((uint16_t)buf[1])<<8));*/
1210 sprintf(dstr
, "DB\t%s", opstr
);
1213 if (!urasm_disasm_decimal
) sprintf(opstr
, "#%02X", mem
[0]); else sprintf(opstr
, "%u", mem
[0]);
1214 sprintf(dstr
, "DB\t%s", opstr
);
1217 /* skip prefixes, determine command length */
1218 f
= URASM_COMMANDS
[opn
].mask
; c
= URASM_COMMANDS
[opn
].code
;
1219 for (bpos
= 0; ; ++bpos
) {
1221 if ((f
&0xFFUL
) != 0xFFUL
) break;
1223 if (b
!= 0xFDU
&& b
!= 0xDDU
&& b
!= 0xEDU
&& b
!= 0xCBU
) break;
1224 f
>>= 8; c
>>= 8; ++res
;
1226 /* is this CB-prefixed? */
1227 if (((URASM_COMMANDS
[opn
].code
&0xFFFFUL
) == 0xCBDDUL
) ||
1228 ((URASM_COMMANDS
[opn
].code
&0xFFFFUL
) == 0xCBFDUL
)) f
>>= 8;
1229 while (f
!= 0) { f
>>= 8; ++res
; }
1230 /* copy mnemonics */
1231 strcpy(dstr
, URASM_TOKENS
[URASM_COMMANDS
[opn
].mnemo
]);
1232 /* are there any operands? */
1233 if (URASM_COMMANDS
[opn
].ops
[0] == UO_NONE
) return res
;
1234 /* is this CB-prefixed? */
1235 if (((URASM_COMMANDS
[opn
].code
&0xFFFFUL
) == 0xCBDDUL
) ||
1236 ((URASM_COMMANDS
[opn
].code
&0xFFFFUL
) == 0xCBFDUL
)) ++bpos
; /* skip displacement */
1238 if ((URASM_COMMANDS
[opn
].ops
[0] == UO_MIX
|| URASM_COMMANDS
[opn
].ops
[0] == UO_MIY
) &&
1239 URASM_COMMANDS
[opn
].ops
[1] == UO_IMM8
&&
1240 (URASM_COMMANDS
[opn
].ops
[2] == UO_NONE
|| URASM_COMMANDS
[opn
].ops
[2] == UO_NEXT
)) ++bpos
; /* skip displacement */
1243 nextW
= (uint16_t)mem
[bpos
] | (((uint16_t)mem
[bpos
+1])<<8);
1245 for (f
= 0; f
<= 3; ++f
) {
1247 //printf("OPN=%d\n", opn);
1250 op
= URASM_COMMANDS
[opn
].ops
[f
];
1251 if (op
== UO_NONE
|| op
== UO_NEXT
) {
1252 //printf("OPN=%d\n", opn);
1255 /* check for valid operand */
1256 if (is_opc_invalid_op(op
, opc
)) break;
1257 /* command with displacement? */
1258 if (op
== UO_MIX
|| op
== UO_MIY
) ++res
;
1259 /* command has immediate operand? */
1260 if (op
== UO_IMM8
|| op
== UO_ADDR8
|| op
== UO_PORTIMM
) ++res
;
1261 if (op
== UO_IMM16
|| op
== UO_IMM16BE
|| op
== UO_ADDR16
|| op
== UO_MEM16
) res
+= 2;
1263 strcat(dstr
, (f
== 0 ? urasm_disasm_mnemo_delimiter
: urasm_disasm_operand_delimiter
));
1264 /* decode operand */
1265 ua_op2str(opstr
, op
, addr
, opc
, nextW
, idx
);
1266 strcat(dstr
, opstr
);
1273 int urasm_disasm_opdisasm (char *dstr
, uint16_t addr
) {
1275 if (!urasm_getbyte
) return -1;
1276 for (unsigned f
= 0; f
< 8; ++f
) mem
[f
] = urasm_getbyte((uint16_t)((addr
+f
)&0xffffu
));
1277 return urasm_disasm_opdisasm_ex(dstr
, addr
, mem
);
1281 ///////////////////////////////////////////////////////////////////////////////
1284 /* returns 0 if label name conflicts with reserved word */
1285 /* (or if the label is just a bad one) */
1286 int urasm_is_valid_name (const char *lbl
) {
1289 if (!lbl
|| !lbl
[0]) return 0;
1290 if (lbl
[0] == '@') {
1295 if (ch
>= '0' && ch
<= '9') return 0;
1296 if (!ur_isalpha(ch
) && ch
!= '.' && ch
!= '_' && ch
!= '@') return 0;
1297 for (f
= 1; lbl
[f
]; ++f
) {
1299 if (ch
>= '0' && ch
<= '9') continue;
1300 if (!ur_isalpha(ch
)) {
1302 if (ch
!= '$' && ch
!= '.' && ch
!= '_' && ch
!= '@') return 0;
1305 if (hasNA
|| f
> 4) return 1;
1306 for (f
= 0; lbl
[f
]; ++f
) buf
[f
] = ur_toupper(lbl
[f
]); buf
[f
] = '\0';
1307 for (f
= 0; f
< (!urasm_allow_zxnext
? URASM_MAX_NORMAL_TOKEN
: URASM_MAX_TOKEN
); ++f
) if (!strcmp(buf
, URASM_TOKENS
[f
])) return 0;
1308 for (f
= 0; f
< 8; ++f
) if (!strcmp(buf
, URA_REGS8
[f
])) return 0;
1309 for (f
= 0; f
< 4; ++f
) if (!strcmp(buf
, URA_REGS16
[f
])) return 0;
1310 for (f
= 0; f
< 4; ++f
) if (!strcmp(buf
, URA_REGS16A
[f
])) return 0;
1311 for (f
= 0; f
< 8; ++f
) if (!strcmp(buf
, URA_COND
[f
])) return 0;
1312 if (!strcmp(buf
, "AFX")) return 0;
1313 if (!strcmp(buf
, "IXH")) return 0;
1314 if (!strcmp(buf
, "IXL")) return 0;
1315 if (!strcmp(buf
, "IYH")) return 0;
1316 if (!strcmp(buf
, "IYL")) return 0;
1317 if (!strcmp(buf
, "IX")) return 0;
1318 if (!strcmp(buf
, "IY")) return 0;
1319 if (!strcmp(buf
, "XH")) return 0;
1320 if (!strcmp(buf
, "HX")) return 0;
1321 if (!strcmp(buf
, "XL")) return 0;
1322 if (!strcmp(buf
, "LX")) return 0;
1323 if (!strcmp(buf
, "YH")) return 0;
1324 if (!strcmp(buf
, "HY")) return 0;
1325 if (!strcmp(buf
, "YL")) return 0;
1326 if (!strcmp(buf
, "LY")) return 0;
1327 if (!strcmp(buf
, "R")) return 0;
1328 if (!strcmp(buf
, "I")) return 0;
1333 ///////////////////////////////////////////////////////////////////////////////
1336 // parse and calculate expression
1337 static inline const char *skip_blanks (const char *expr
) {
1338 while (*expr
&& ur_isspace(*expr
)) ++expr
;
1343 ///////////////////////////////////////////////////////////////////////////////
1344 // expression parser
1345 urasm_getval_fn urasm_getval
= NULL
;
1346 urasm_expand_fn urasm_expand
= NULL
;
1349 typedef struct ur_function_s
{
1350 struct ur_function_s
*next
;
1355 static ur_function_t
*fnlist
= NULL
;
1357 static void atexit_func_finalize (void) {
1358 while (fnlist
!= NULL
) {
1359 ur_function_t
*f
= fnlist
;
1367 void urasm_expr_register_func (const char *name
, urasm_func_fn fn
) {
1368 if (name
!= NULL
&& name
[0]) {
1369 static int atexitset
= 0;
1370 ur_function_t
*p
, *c
;
1371 if (!atexitset
) { atexit(atexit_func_finalize
); atexitset
= 1; }
1372 for (p
= NULL
, c
= fnlist
; c
!= NULL
; p
= c
, c
= c
->next
) {
1373 if (strcasecmp(name
, c
->name
) == 0) {
1374 /* replace or remove */
1377 if (p
== NULL
) fnlist
= c
->next
; else p
->next
= c
->next
;
1389 c
= malloc(sizeof(*c
));
1390 c
->name
= strdup(name
);
1399 urasm_func_fn
urasm_expr_find_func (const char *name
) {
1400 if (name
!= NULL
&& name
[0]) {
1401 for (ur_function_t
*c
= fnlist
; c
!= NULL
; c
= c
->next
) if (strcasecmp(name
, c
->name
) == 0) return c
->fn
;
1407 ///////////////////////////////////////////////////////////////////////////////
1409 const char *expr
; /* can be changed */
1410 uint16_t addr
; /* current address */
1411 int defined
; /* !0: all used labels are defined */
1412 int error
; /* !0: error */
1413 const char *errpos
; /* will be set on error, has no meaning otherwise */
1420 /* do math; op0 is the result */
1421 typedef void (*expr_doit_fn
) (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
);
1434 char sn
; /* short name or 0 */
1435 const char *ln
; /* long name or NULL if `sn`!=0 */
1436 int prio
; /* priority */
1442 ///////////////////////////////////////////////////////////////////////////////
1444 /* returns !0 is passed string is not NULL, and longer than 2 chars */
1445 static inline __attribute__((always_inline
)) __attribute__((pure
))
1446 int ur_is_long_str (const char *s
) { return (s
&& s
[0] && s
[1] && s
[2]); }
1448 #define EERROR(code) longjmp(ei->errJP, code)
1450 #define CHECKVALNOTSTR(_v,_vkill) do { \
1451 if ((_v)->str != NULL) { \
1452 if (ur_is_long_str((_v)->str)) { \
1453 if ((_vkill) != NULL) urasm_exprval_clear((_vkill)); \
1454 EERROR(UR_EXPRERR_TYPE); \
1461 #define CHECKARGSNOTSTR do { \
1462 CHECKVALNOTSTR(op0, op1); \
1463 CHECKVALNOTSTR(op1, op1); \
1467 #define PROPAGATE_FIXUP do { \
1468 if (op0->fixuptype == UR_FIXUP_NONE) { \
1469 op0->fixuptype = op1->fixuptype; \
1470 } else if (op0->fixuptype == UR_FIXUP_WORD) { \
1471 if (op1->fixuptype != UR_FIXUP_NONE) op0->fixuptype = op1->fixuptype; \
1472 } else if (op1->fixuptype != UR_FIXUP_NONE && op0->fixuptype != op1->fixuptype) { \
1473 urasm_exprval_clear(op1);\
1474 urasm_exprval_clear(op0); \
1475 EERROR(UR_EXPRERR_FIXUP); \
1480 static void mdo_bitnot (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) {
1481 op0
->val
= ~op0
->val
;
1482 op0
->fixuptype
= UR_FIXUP_NONE
;
1484 static void mdo_lognot (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) {
1485 op0
->val
= !op0
->val
;
1486 op0
->fixuptype
= UR_FIXUP_NONE
;
1488 static void mdo_uminus (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) {
1489 op0
->val
= -op0
->val
;
1490 op0
->fixuptype
= UR_FIXUP_NONE
;
1492 static void mdo_uplus (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) {
1495 static void mdo_bitand (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) {
1496 op0
->val
&= op1
->val
;
1497 if (op1
->val
== 0) op0
->fixuptype
= UR_FIXUP_NONE
;
1498 else if (op0
->fixuptype
!= UR_FIXUP_NONE
) {
1500 case 0x00ff: op0
->fixuptype
= (op0
->fixuptype
== UR_FIXUP_WORD
? UR_FIXUP_LOBYTE
: UR_FIXUP_NONE
); break;
1501 case 0xff00: op0
->fixuptype
= (op0
->fixuptype
== UR_FIXUP_WORD
? UR_FIXUP_HIBYTE
: UR_FIXUP_NONE
); break;
1507 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
; }
1508 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
; }
1509 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
; }
1510 static void mdo_shr (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) { op0
->val
>>= op1
->val
; }
1511 static void mdo_shru (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) { *(uint32_t *)&op0
->val
>>= op1
->val
; }
1512 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
; }
1513 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
; }
1514 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
; }
1515 static void mdo_add (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) { op0
->val
+= op1
->val
; PROPAGATE_FIXUP
; }
1516 static void mdo_sub (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) { op0
->val
-= op1
->val
; PROPAGATE_FIXUP
; }
1518 static int mdo_compare (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) {
1519 const int isnum0
= !ur_is_long_str(op0
->str
);
1520 const int isnum1
= !ur_is_long_str(op1
->str
);
1521 //fprintf(stderr, "mdo_compare: num0=%d; num1=%d (%s) (%s)\n", isnum0, isnum1, op0->str, op1->str);
1522 if (isnum0
!= isnum1
) EERROR(UR_EXPRERR_TYPES
);
1525 op0
->val
< op1
->val
? -1 :
1526 op0
->val
> op1
->val
? 1 :
1529 return strcmp(op0
->str
, op1
->str
);
1533 static void mdo_set_int (urasm_exprval_t
*op0
, const int32_t v
) {
1534 urasm_exprval_clear(op0
);
1538 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)); }
1539 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)); }
1540 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)); }
1541 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)); }
1542 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)); }
1543 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)); }
1545 static void mdo_log_and (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) {
1546 ei
->logic_res
= op0
->val
= (op0
->val
&& op1
->val
);
1547 if (!op0
->val
) ei
->logic_done
= 1;
1548 op0
->fixuptype
= UR_FIXUP_NONE
;
1551 static void mdo_log_or (urasm_exprval_t
*op0
, urasm_exprval_t
*op1
, expr_info_t
*ei
) {
1552 ei
->logic_res
= op0
->val
= (op0
->val
|| op1
->val
);
1553 if (op0
->val
) ei
->logic_done
= 1;
1554 op0
->fixuptype
= UR_FIXUP_NONE
;
1558 // priority level 1 -- opertiors line "." and "[]", function calls
1559 // priority level 2 -- unary opertiors like "!" and "~"
1560 // short forms must be put before long
1561 // priorities must be sorted
1562 static const expr_operator_t operators_old
[] = {
1564 { '~', NULL
, 2, mdo_bitnot
, optype_unary
},
1565 { '!', NULL
, 2, mdo_lognot
, optype_unary
},
1566 { '-', NULL
, 2, mdo_uminus
, optype_unary
},
1567 { '+', NULL
, 2, mdo_uplus
, optype_unary
},
1569 { 0, "<<", 3, mdo_shl
, optype_shift
},
1570 { 0, ">>", 3, mdo_shr
, optype_shift
},
1571 { 0, ">>>", 3, mdo_shru
, optype_shift
},
1573 { '&', NULL
, 4, mdo_bitand
, optype_bitwise
},
1574 // bitwise or and xor
1575 { '|', NULL
, 5, mdo_bitor
, optype_bitwise
},
1576 { '^', NULL
, 5, mdo_bitxor
, optype_bitwise
},
1578 { '*', NULL
, 6, mdo_mul
, optype_math
},
1579 { '/', NULL
, 6, mdo_div
, optype_math
},
1580 { '%', NULL
, 6, mdo_mod
, optype_math
},
1582 { '+', NULL
, 7, mdo_add
, optype_math
},
1583 { '-', NULL
, 7, mdo_sub
, optype_math
},
1585 { 0, "&&", 8, mdo_log_and
, optype_logic
},
1587 { 0, "||", 9, mdo_log_or
, optype_logic
},
1589 { '<', NULL
, 10, mdo_cmp_ls
, optype_comparison
},
1590 { '>', NULL
, 10, mdo_cmp_gt
, optype_comparison
},
1591 { '=', NULL
, 10, mdo_cmp_eq
, optype_comparison
},
1592 { 0, "==", 10, mdo_cmp_eq
, optype_comparison
},
1593 { 0, "!=", 10, mdo_cmp_ne
, optype_comparison
},
1594 { 0, "<>", 10, mdo_cmp_ne
, optype_comparison
},
1595 { 0, "<=", 10, mdo_cmp_le
, optype_comparison
},
1596 { 0, ">=", 10, mdo_cmp_ge
, optype_comparison
},
1598 { 0, NULL
, -1, NULL
, optype_none
},
1600 // new C-like priorities
1601 static const expr_operator_t operators_new
[] = {
1603 { '~', NULL
, 2, mdo_bitnot
, optype_unary
},
1604 { '!', NULL
, 2, mdo_lognot
, optype_unary
},
1605 { '-', NULL
, 2, mdo_uminus
, optype_unary
},
1606 { '+', NULL
, 2, mdo_uplus
, optype_unary
},
1608 { 0, "<<", 3, mdo_shl
, optype_shift
},
1609 { 0, ">>", 3, mdo_shr
, optype_shift
},
1610 { 0, ">>>", 3, mdo_shru
, optype_shift
},
1612 { '&', NULL
, 4, mdo_bitand
, optype_bitwise
},
1613 // bitwise or and xor
1614 { '|', NULL
, 5, mdo_bitor
, optype_bitwise
},
1615 { '^', NULL
, 5, mdo_bitxor
, optype_bitwise
},
1617 { '*', NULL
, 6, mdo_mul
, optype_math
},
1618 { '/', NULL
, 6, mdo_div
, optype_math
},
1619 { '%', NULL
, 6, mdo_mod
, optype_math
},
1621 { '+', NULL
, 7, mdo_add
, optype_math
},
1622 { '-', NULL
, 7, mdo_sub
, optype_math
},
1624 { '<', NULL
, 8, mdo_cmp_ls
, optype_comparison
},
1625 { '>', NULL
, 8, mdo_cmp_gt
, optype_comparison
},
1626 { '=', NULL
, 8, mdo_cmp_eq
, optype_comparison
},
1627 { 0, "==", 8, mdo_cmp_eq
, optype_comparison
},
1628 { 0, "!=", 8, mdo_cmp_ne
, optype_comparison
},
1629 { 0, "<>", 8, mdo_cmp_ne
, optype_comparison
},
1630 { 0, "<=", 8, mdo_cmp_le
, optype_comparison
},
1631 { 0, ">=", 8, mdo_cmp_ge
, optype_comparison
},
1633 { 0, "&&", 9, mdo_log_and
, optype_logic
},
1635 { 0, "||", 10, mdo_log_or
, optype_logic
},
1637 { 0, NULL
, -1, NULL
, optype_none
},
1639 #define UNARY_PRIO (2)
1641 #define MAX_PRIO (10)
1642 #define PRIO_LAND (8)
1643 #define PRIO_LOR (9)
1645 static int max_prio_old
= 0;
1646 static int prio_land_old
= 0;
1647 static int prio_lor_old
= 0;
1649 static int max_prio
= 0;
1650 static int prio_land
= 0;
1651 static int prio_lor
= 0;
1653 int urasm_use_old_priorities
= 0;
1654 int urasm_allow_hex_castrates
= 0;
1656 static inline __attribute__((always_inline
)) int get_max_prio () { return (!urasm_use_old_priorities
? max_prio
: max_prio_old
); }
1657 static inline __attribute__((always_inline
)) int get_land_prio () { return (!urasm_use_old_priorities
? prio_land
: prio_land_old
); }
1658 static inline __attribute__((always_inline
)) int get_lor_prio () { return (!urasm_use_old_priorities
? prio_lor
: prio_lor_old
); }
1660 static __attribute((constructor
)) void init_priorities (void) {
1661 if (max_prio_old
) return;
1663 for (const expr_operator_t
*op
= operators_old
; op
->prio
>= 0; ++op
) {
1664 if (max_prio_old
< op
->prio
) max_prio_old
= op
->prio
;
1665 if (op
->doer
== &mdo_log_and
) prio_land_old
= op
->prio
;
1666 else if (op
->doer
== &mdo_log_or
) prio_lor_old
= op
->prio
;
1669 for (const expr_operator_t
*op
= operators_new
; op
->prio
>= 0; ++op
) {
1670 if (max_prio
< op
->prio
) max_prio
= op
->prio
;
1671 if (op
->doer
== &mdo_log_and
) prio_land
= op
->prio
;
1672 else if (op
->doer
== &mdo_log_or
) prio_lor
= op
->prio
;
1677 /******************************************************************************/
1678 /* expression parser engine */
1679 /******************************************************************************/
1680 static void expression (urasm_exprval_t
*res
, expr_info_t
*ei
);
1683 #define SKIP_BLANKS { ei->errpos = ei->expr = skip_blanks(ei->expr); }
1685 #define PSEMITCHAR(_ch) do { \
1686 if (!doinglen) res->str[len++] = (_ch); else ++len; \
1690 static const char *parse_string (urasm_exprval_t
*res
, char qch
, const char *expr
, int *error
, int *lenp
) {
1692 if (lenp
) *lenp
= 0;
1693 if (*error
) return expr
;
1694 if (!expr
[0]) { *error
= 1; return expr
; }
1695 //memset(buf, 0, sizeof(buf));
1697 int len
= 0, n
, f
, base
;
1698 const char *a
= expr
;
1704 case 'a': PSEMITCHAR('\a'); break;
1705 case 'b': PSEMITCHAR('\b'); break;
1706 case 'e': PSEMITCHAR('\x1b'); break;
1707 case 'f': PSEMITCHAR('\f'); break;
1708 case 'n': PSEMITCHAR('\n'); break;
1709 case 'r': PSEMITCHAR('\r'); break;
1710 case 't': PSEMITCHAR('\t'); break;
1711 case 'v': PSEMITCHAR('\v'); break;
1712 case 'z': PSEMITCHAR('\0'); break;
1713 case 'x': case 'X': /* hex */
1716 donum
: for (n
= 0; f
> 0; --f
) {
1717 char ch
= dig2n(*a
++, base
);
1718 if (ch
< 0) { --a
; break; }
1723 --a
; /* return to the last digit, 'for' will skip it */
1725 case '0': /* octal */
1728 case '1' ... '9': /* decimal */
1731 default: PSEMITCHAR(a
[0]); break; /* others */
1734 if (*a
== qch
) { ++a
; break; }
1739 res
->str
= calloc(len
+1, 1);
1740 if (lenp
) *lenp
= len
;
1748 static int try_suffix_base (const char *s
, char sfx
, int base
) {
1749 if (!s
|| !s
[0]) return 0;
1750 while (*s
== '_') ++s
; /* just in case */
1751 if (dig2n(*s
++, base
) < 0) return 0;
1752 /* we don't need to check for zero here, because `dig2n()` will do this for us */
1754 const char ch
= *s
++;
1755 if (ch
!= '_' && dig2n(ch
, base
) < 0) {
1756 return (ch
&& ur_toupper(ch
) == sfx
&& dig2n(*s
, 16) < 0);
1762 /*TODO: make suffix detector one-pass */
1763 static int check_number_base_sfx (const char *s
) {
1764 if (!s
|| !s
[0]) return 0;
1765 while (*s
== '_') ++s
; /* just in case */
1766 /* check suffixes (suffix char must be passed as uppercase) */
1767 if (try_suffix_base(s
, 'H', 16)) return 16;
1768 if (try_suffix_base(s
, 'B', 2)) return 2;
1769 if (try_suffix_base(s
, 'O', 8)) return 8;
1770 if (try_suffix_base(s
, 'D', 10)) return 10;
1775 static int check_number_base_char (char ch
) {
1776 switch (ur_toupper(ch
)) {
1777 case 'X': case 'H': return 16;
1780 case 'D': return 10;
1787 static const char *parse_number (urasm_exprval_t
*res
, const char *expr
, int *error
) {
1789 if (*error
) return expr
;
1790 if (!expr
[0]) { *error
= 1; return expr
; }
1791 const char *estart
= expr
;
1792 /* detect suffix first */
1793 int base
= check_number_base_sfx(expr
);
1795 /* the suffix is ok */
1796 prefixed
= 0; /* note that it is suffixed number, not prefixed */
1798 /* no good suffix, check prefixes */
1800 case '0': /* this allows "0habcd" as hex number too; why not? */
1801 base
= check_number_base_char(expr
[1]);
1802 if (base
) expr
+= 2; else base
= 8;
1804 case '%': base
= 2; ++expr
; break;
1805 case '#': case '$': base
= 16; ++expr
; break;
1806 case '1' ... '9': base
= 10; break;
1808 base
= check_number_base_char(expr
[1]);
1809 // check for ambiguity
1810 if (urasm_allow_hex_castrates
&& base
== 2) {
1811 // '&b10' can be either binary, or hex; parse it as hex if castrates are allowed
1814 if (base
) { expr
+= 2; break; }
1815 // some assemblers are using lone '&' for hex numbers, let's support it too
1816 // note that there is an ambiguity: '&b10' can be either binary, or hex
1817 // currently, it will be parsed as binary
1818 if (urasm_allow_hex_castrates
&& dig2n(expr
[1], 16) >= 0) { base
= 16; ++expr
; break; }
1820 default: *error
= 1; return estart
;
1823 /* parse number (ignore underscores) */
1824 while (*expr
&& *expr
== '_') ++expr
;
1825 if (dig2n(*expr
, base
) < 0) { *error
= 1; return estart
; }
1829 if (ch
== '_') continue;
1830 int d
= dig2n(ch
, base
);
1831 if (d
< 0) { res
->val
= n
; return expr
-prefixed
; } /* `prefixed` set to 1 if there's no suffix */
1833 /* this check is UB in standards-compliant C, because standard was created by morons */
1834 if (n
< 0) { *error
= 1; return estart
; }
1840 static void get_addr (const char *lbl
, urasm_exprval_t
*res
, expr_info_t
*ei
) {
1841 int defined
= 0, found
= 0;
1843 if (urasm_label_by_name
== NULL
) EERROR(UR_EXPRERR_LABEL
);
1844 res
->fixuptype
= UR_FIXUP_NONE
;
1845 val
= urasm_label_by_name(lbl
, ei
->addr
, &defined
, &found
, &res
->fixuptype
);
1846 if (!found
) EERROR(UR_EXPRERR_LABEL
);
1847 if (!defined
) ei
->defined
= 0;
1852 // !0: invalid label
1853 static int read_label_name (char *buf
, expr_info_t
*ei
) {
1856 if (pos
>= 128) return -3;
1857 char ch
= ei
->expr
[0];
1859 if (ur_isalnum(ch
) || ch
== '$' || ch
== '.' || ch
== '_' || ch
== '@') {
1866 if (pos
< 1) return -2;
1868 if (!urasm_is_valid_name(buf
)) return -1;
1873 static void term (urasm_exprval_t
*res
, expr_info_t
*ei
) {
1876 if (res
->str
!= NULL
) { free(res
->str
); res
->str
= NULL
; }
1878 ch
= (res
->pos
= ei
->errpos
= ei
->expr
)[0];
1879 if (!ch
) EERROR(UR_EXPRERR_EOS
);
1883 ch
= (ch
== '[' ? ']' : ')');
1884 expression(res
, ei
);
1885 if (ei
->expr
[0] != ch
) EERROR(UR_EXPRERR_PARENS
);
1888 case '0' ... '9': case '#': case '%':
1890 ei
->expr
= parse_number(res
, ei
->expr
, &tmp
);
1891 if (tmp
) EERROR(UR_EXPRERR_NUMBER
);
1894 if (dig2n(ei
->expr
[1], 16) >= 0) goto donumber
;
1895 res
->val
= ei
->addr
;
1896 res
->fixuptype
= UR_FIXUP_WORD
;
1900 if (ur_toupper(ei
->expr
[1]) == 'H' && dig2n(ei
->expr
[2], 16) >= 0) goto donumber
;
1901 if (ur_toupper(ei
->expr
[1]) == 'X' && dig2n(ei
->expr
[2], 16) >= 0) goto donumber
;
1902 if (ur_toupper(ei
->expr
[1]) == 'O' && dig2n(ei
->expr
[2], 8) >= 0) goto donumber
;
1903 if (ur_toupper(ei
->expr
[1]) == 'B' && dig2n(ei
->expr
[2], 2) >= 0) goto donumber
;
1904 if (ur_toupper(ei
->expr
[1]) == 'D' && dig2n(ei
->expr
[2], 10) >= 0) goto donumber
;
1905 // some assemblers are using lone '&' for hex numbers, let's support it too
1906 if (urasm_allow_hex_castrates
&& dig2n(ei
->expr
[1], 16) >= 0) goto donumber
;
1908 case '"': /* char or 2 chars */
1909 case '\'': /* char or 2 reversed chars */
1911 ei
->expr
= parse_string(res
, ch
, ei
->expr
+1, &tmp
, &len
);
1912 if (tmp
) EERROR(UR_EXPRERR_STRING
);
1914 res
->val
= (unsigned char)res
->str
[0];
1915 } else if (len
>= 2) {
1916 res
->val
= ((unsigned char)res
->str
[0])<<(ch
== '"' ? 0 : 8);
1917 res
->val
|= ((unsigned char)res
->str
[1])<<(ch
== '"' ? 8 : 0);
1922 EERROR(UR_EXPRERR_TERM
);
1928 if (urasm_getval
!= NULL
) {
1929 ei
->expr
= urasm_getval(res
, ei
->expr
, ei
->addr
, ei
->logic_done
, &ei
->defined
, &ei
->error
);
1930 if (ei
->error
!= UR_EXPRERR_NONE
) EERROR(ei
->error
);
1932 EERROR(UR_EXPRERR_MARG
);
1937 if (read_label_name(lbl
, ei
)) EERROR(UR_EXPRERR_LABEL
);
1939 if (ei
->expr
[0] == '(') {
1941 urasm_func_fn fn
= urasm_expr_find_func(lbl
);
1943 if (fn
== NULL
) EERROR(UR_EXPRERR_FUNC
);
1944 ++(ei
->expr
); /* skip '(' */
1945 e
= fn(res
, ei
->expr
, ei
->addr
, ei
->logic_done
, &ei
->defined
, &ei
->error
);
1946 if (ei
->error
!= UR_EXPRERR_NONE
) EERROR(ei
->error
);
1947 else if (e
== NULL
) EERROR(UR_EXPRERR_FUNC
);
1951 if (!ei
->logic_done
) get_addr(lbl
, res
, ei
);
1958 static const expr_operator_t
*get_operator (int prio
, expr_info_t
*ei
) {
1959 const char opc
= ei
->expr
[0];
1961 const expr_operator_t
*res
= NULL
;
1962 for (const expr_operator_t
*op
= (!urasm_use_old_priorities
? operators_new
: operators_old
); op
->prio
>= 0; ++op
) {
1964 //fprintf(stderr, "get_operator: prio=%d; sn=%c; opc=%c\n", prio, op->sn, opc);
1965 if (op
->prio
== prio
&& oplen
<= 1 && opc
== op
->sn
) { res
= op
; oplen
= 1; }
1967 const int l
= (int)strlen(op
->ln
);
1968 if (l
> oplen
&& strncmp(ei
->expr
, op
->ln
, l
) == 0) { res
= op
; oplen
= l
; }
1971 if (res
&& res
->prio
!= prio
) res
= NULL
;
1972 //if (res) fprintf(stderr, "res: prio=%d; sn='%c' \"%s\" (%d : %.*s)\n", prio, res->sn, res->ln, oplen, (unsigned)oplen, ei->expr);
1973 if (res
) ei
->expr
+= oplen
; /* eat operator */
1978 #define CHECKNOTSTR do { \
1979 if (ur_is_long_str(res->str) || ur_is_long_str(o1.str)) { \
1980 urasm_exprval_clear(&o1); \
1981 urasm_exprval_clear(res); \
1982 EERROR(UR_EXPRERR_TYPE); \
1987 static void expr_do (int prio
, urasm_exprval_t
*res
, expr_info_t
*ei
) {
1988 const expr_operator_t
*op
;
1991 if (ei
->expr
[0] == ')' || ei
->expr
[0] == ']') return;
1992 if (prio
<= 0) { term(res
, ei
); return; }
1993 urasm_exprval_init(&o1
);
1994 //fprintf(stderr, "expr_do: prio=%d <%s>\n", prio, ei->expr);
1995 if (prio
== UNARY_PRIO
) {
1996 //fprintf(stderr, "expr_do: prio=%d <%s>\n", prio, ei->expr);
2000 ei
->errpos
= ei
->expr
;
2001 if (!(op
= get_operator(prio
, ei
))) break;
2002 //fprintf(stderr, "UNARY: op=%c\n", op->sn);
2003 //expression(res, ei);
2004 if (op
->sn
== '-' || op
->sn
== '+') {
2005 expr_do(prio
-1, res
, ei
); /* left-associative */
2007 expr_do(prio
, res
, ei
); /* right-associative */
2009 if (!ei
->logic_done
) {
2011 op
->doer(res
, &o1
, ei
);
2013 res
->fixuptype
= UR_FIXUP_NONE
;
2014 res
->val
= ei
->logic_res
;
2017 if (op
->sn
== '-' || op
->sn
== '+') break;
2019 if (!wasIt
) expr_do(prio
-1, res
, ei
); /* left-associative */
2023 expr_do(prio
-1, res
, ei
); /* first operand, left-associative */
2027 ei
->errpos
= ei
->expr
;
2028 if (!ei
->expr
[0] || ei
->expr
[0] == ';' || ei
->expr
[0] == ':' || ei
->expr
[0] == ')' || ei
->expr
[0] == ']') break;
2029 //fprintf(stderr, "BINARY: prio=%d; expr=<%s>\n", prio, ei->expr);
2030 if (!(op
= get_operator(prio
, ei
))) break;
2031 if (!ei
->logic_done
) {
2032 if (prio
== get_land_prio()) {
2034 if (!res
->val
) { ei
->logic_done
= 1; ei
->logic_res
= 0; }
2035 } else if (prio
== get_lor_prio()) {
2037 if (res
->val
) { ei
->logic_done
= 1; ei
->logic_res
= res
->val
; }
2040 //fprintf(stderr, "BINARY:000: prio=%d; expr=<%s>; op=%c(%s)\n", prio, ei->expr, op->sn, op->ln);
2041 expr_do(prio
-1, &o1
, ei
); /* second operand, left-associative */
2042 //fprintf(stderr, "BINARY:001: prio=%d; expr=<%s>; op=%c(%s)\n", prio, ei->expr, op->sn, op->ln);
2043 if (!ei
->logic_done
) {
2044 if (op
->type
!= optype_comparison
) {
2047 //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);
2048 op
->doer(res
, &o1
, ei
);
2049 //fprintf(stderr, "DOER:AFTER: val=%d (%d : %d)\n", res->val, ei->logic_done, ei->logic_res);
2050 urasm_exprval_clear(&o1
);
2052 res
->fixuptype
= UR_FIXUP_NONE
;
2053 res
->val
= ei
->logic_res
;
2059 static void expression (urasm_exprval_t
*res
, expr_info_t
*ei
) {
2061 ei
->errpos
= ei
->expr
;
2062 if (!ei
->expr
[0]) EERROR(UR_EXPRERR_EOS
);
2063 expr_do(get_max_prio(), res
, ei
);
2068 const char *urasm_expr_ex (urasm_exprval_t
*res
, const char *expr
, uint16_t addr
, int *donteval
, int *defined
, int *error
) {
2071 urasm_exprval_clear(res
);
2072 if (error
) *error
= 0;
2073 if (!expr
) { if (error
) *error
= UR_EXPRERR_EOS
; return NULL
; }
2074 if (res
->str
!= NULL
) { free(res
->str
); res
->str
= NULL
; }
2077 ei
.defined
= (defined
? *defined
: 1);
2079 ei
.logic_done
= (donteval
? *donteval
: 0);
2081 jr
= setjmp(ei
.errJP
);
2083 urasm_exprval_clear(res
);
2084 if (error
) *error
= ei
.error
;
2087 expression(res
, &ei
);
2088 if (defined
) *defined
= ei
.defined
;
2089 if (donteval
) *donteval
= ei
.logic_done
;
2094 const char *urasm_expr (int32_t *res
, const char *expr
, uint16_t addr
, int *defined
, int *fixuptype
, int *error
) {
2098 if (defined
) *defined
= 1;
2099 if (fixuptype
) *fixuptype
= UR_FIXUP_NONE
;
2100 urasm_exprval_init(&r
);
2101 ret
= urasm_expr_ex(&r
, expr
, addr
, NULL
, defined
, &err
);
2102 if (error
) *error
= err
;
2104 if (fixuptype
) *fixuptype
= r
.fixuptype
;
2105 if (ur_is_long_str(r
.str
)) {
2106 if (error
) *error
= UR_EXPRERR_TYPE
;
2114 urasm_exprval_clear(&r
);
2119 void urasm_exprval_init (urasm_exprval_t
*res
) {
2121 memset(res
, 0, sizeof(*res
));
2122 res
->fixuptype
= UR_FIXUP_NONE
;
2127 void urasm_exprval_clear (urasm_exprval_t
*res
) {
2129 if (res
->str
!= NULL
) {
2134 res
->fixuptype
= UR_FIXUP_NONE
;
2139 void urasm_exprval_setint (urasm_exprval_t
*res
, int32_t v
) {
2140 if (res
->str
) { free(res
->str
); res
->str
= NULL
; }
2145 /* sets val as in double quotes */
2146 void urasm_exprval_tostr (urasm_exprval_t
*res
, const char *str
) {
2148 urasm_exprval_setint(res
, 0);
2150 const size_t slen
= strlen(str
);
2151 res
->str
= realloc(res
->str
, slen
+1);
2152 strcpy(res
->str
, str
);
2154 res
->val
= (unsigned char)res
->str
[0];
2156 res
->val
= (unsigned char)res
->str
[0];
2157 res
->val
|= ((unsigned char)res
->str
[1])<<8;
2163 /* sets val as in single quotes */
2164 void urasm_exprval_tostr_rev (urasm_exprval_t
*res
, const char *str
) {
2166 urasm_exprval_setint(res
, 0);
2168 const size_t slen
= strlen(str
);
2169 res
->str
= realloc(res
->str
, slen
+1);
2170 strcpy(res
->str
, str
);
2172 res
->val
= (unsigned char)res
->str
[0];
2174 res
->val
= ((unsigned char)res
->str
[0])<<8;
2175 res
->val
|= (unsigned char)res
->str
[1];
2181 ///////////////////////////////////////////////////////////////////////////////
2184 const char *urasm_skip_operand (const char *expr
, int *seenarg
) {
2185 if (seenarg
) *seenarg
= 0;
2186 if (!expr
) return NULL
;
2187 expr
= skip_blanks(expr
);
2188 if (!expr
[0] || expr
[0] == ';') return NULL
;
2189 if (expr
[0] == ':' || expr
[0] == ',') return expr
; /* colon or comma, nothing to do here */
2190 if (seenarg
) *seenarg
= 1;
2193 const char *oe
= expr
;
2194 for (; *expr
; ++expr
) {
2195 const char ch
= *expr
;
2197 if (ch
== inQ
) inQ
= 0;
2198 else if (ch
== '\\' && expr
[1]) ++expr
;
2200 if (ch
== '"' || ch
== '`') inQ
= ch
;
2201 else if (ch
== '\'' && (expr
== oe
|| !ur_isalnum(expr
[-1]))) inQ
= ch
;
2202 else if (ch
== '(') ++parens
;
2203 else if (ch
== ')') { if (--parens
< 0) parens
= 0; }
2204 else if (ch
== ';') break;
2205 else if (parens
== 0 && (ch
== ',' || ch
== ':')) break;
2212 /* error is `UR_EXPRERR_XXX` */
2213 const char *urasm_next_operand (urasm_operand_t
*op
, const char *expr
, uint16_t addr
, int *error
) {
2219 *error
= UR_EXPRERR_NONE
;
2220 memset(op
, 0, sizeof(urasm_operand_t
));
2222 if (!expr
) return NULL
;
2223 expr
= skip_blanks(expr
);
2224 if (!expr
[0] || expr
[0] == ';') return NULL
;
2225 if (expr
[0] == ':') return expr
;
2227 op
->fixuptype
= UR_FIXUP_NONE
;
2229 for (oe
= expr
; *expr
; ++expr
) {
2230 const char ch
= *expr
;
2232 if (ch
== inQ
) inQ
= 0;
2233 else if (ch
== '\\' && expr
[1]) ++expr
;
2235 if (ch
== '"' || ch
== '`') inQ
= ch
;
2236 else if (ch
== '\'' && (oe
== expr
|| !ur_isalnum(expr
[-1]))) inQ
= ch
;
2237 else if (ch
== '(') ++parens
;
2238 else if (ch
== ')') { if (--parens
< 0) parens
= 0; }
2239 else if (ch
== ';') break;
2240 else if (parens
== 0 && (ch
== ',' || ch
== ':')) break;
2243 if (expr
-oe
> 255) { *error
= UR_EXPRERR_TOOLONG
; return oe
; }
2244 memset(opstr
, 0, sizeof(opstr
));
2245 memcpy(opstr
, oe
, expr
-oe
);
2246 while (opstr
[0] && ur_isspace(opstr
[strlen(opstr
)-1])) opstr
[strlen(opstr
)-1] = '\0';
2247 if (!opstr
[0]) { *error
= UR_EXPRERR_EOS
; return oe
; }
2248 /* determine operand type */
2249 if (opstr
[0] == '=' && urasm_expand
!= NULL
) {
2250 if (urasm_expand(opstr
, (int)sizeof(opstr
)-1) != 0) { *error
= UR_EXPRERR_MARG
; return oe
; }
2251 //fprintf(stderr, "exp: [%s]\n", opstr);
2253 if (ur_isalpha(opstr
[0]) && urasm_is_valid_name(opstr
)) {
2256 if (opstr
[0] == '(') {
2258 op
->mem
= 1; op
->special
= 1;
2259 if (!opstr
[1] || opstr
[strlen(opstr
)-1] != ')') { *error
= UR_EXPRERR_PARENS
; return oe
; }
2260 /* operand w/o "()" */
2261 opstr
[strlen(opstr
)-1] = '\0';
2262 memmove(opstr
, opstr
+1, sizeof(opstr
)-1);
2264 while (opstr
[0] && ur_isspace(opstr
[0])) memmove(opstr
, opstr
+1, sizeof(opstr
)-1);
2265 while (opstr
[0] && ur_isspace(opstr
[strlen(opstr
)-1])) opstr
[strlen(opstr
)-1] = '\0';
2266 /* empty brackets? */
2267 if (!opstr
[0]) { *error
= UR_EXPRERR_TERM
; return oe
; }
2268 for (f
= 0; opstr
[f
]; ++f
) op
->s
[f
] = ur_toupper(opstr
[f
]);
2269 if (!strcmp(op
->s
, "C")) {
2270 op
->special
= 1; op
->mem
= 0; strcpy(op
->s
, "(C)");
2273 if (!strcmp(op
->s
, "HL")) return expr
;
2274 if (!strcmp(op
->s
, "DE")) return expr
;
2275 if (!strcmp(op
->s
, "BC")) return expr
;
2276 if (!strcmp(op
->s
, "SP")) return expr
;
2277 if (op
->s
[0] == 'I' && (op
->s
[1] == 'X' || op
->s
[1] == 'Y')) {
2278 /* memref: IX or IY */
2279 op
->ixy
= op
->s
[1]=='X' ? 0xDDU
: 0xFDU
;
2281 memmove(opstr
, opstr
+1, sizeof(opstr
)-1);
2283 while (opstr
[1] && ur_isspace(opstr
[1])) memmove(opstr
+1, opstr
+2, sizeof(opstr
)-2);
2284 if (!opstr
[1]) return expr
;
2285 if (opstr
[1] != '+' && opstr
[1] != '-') { *error
= UR_EXPRERR_NUMBER
; return oe
; }
2286 /* opstr must be an expression */
2287 const char *t
= urasm_expr(&op
->v
, opstr
, addr
, &op
->defined
, NULL
, error
);
2288 if (*error
) return oe
;
2289 if (t
[0]) { *error
= UR_EXPRERR_TOOLONG
; return oe
; }
2290 if (op
->defined
&& (op
->v
< -128 || op
->v
> 127)) { *error
= UR_EXPRERR_NUMBER
; return oe
; }
2295 if (!strcasecmp(opstr
, "af'")) goto registerop
;
2296 for (f
= 0; ur_isalpha(opstr
[f
]); ++f
) {}
2299 for (f
= 0; opstr
[f
]; ++f
) opstr
[f
] = ur_toupper(opstr
[f
]);
2300 strcpy(op
->s
, opstr
);
2302 return skip_blanks(expr
);
2305 /* this must be an expression */
2307 strcpy(op
->s
, opstr
);
2312 urasm_exprval_init(&e
);
2313 t
= urasm_expr_ex(&e
, opstr
, addr
, &donteval
, &op
->defined
, error
);
2315 op
->fixuptype
= e
.fixuptype
;
2316 urasm_exprval_clear(&e
);
2317 //const char *t = urasm_expr(&op->v, opstr, addr, &op->defined, error);
2318 if (*error
) { op
->parsed
= 0; return oe
; }
2319 if (t
== NULL
|| t
[0]) { op
->parsed
= 0; *error
= UR_EXPRERR_EOS
; return oe
; }
2321 return skip_blanks(expr
);
2325 ///////////////////////////////////////////////////////////////////////////////
2328 // for regsters & conditions: op->v will be set to reg number
2329 int urasm_is_valid_operand (urasm_operand_t
*op
, uint16_t addr
, unsigned optype
) {
2331 if (optype
== UO_NONE
|| optype
== UO_NEXT
) return (op
->s
[0] == '\0');
2332 if (!op
->s
[0]) return 0;
2335 if (op
->special
|| op
->mem
) return 0;
2336 if (op
->defined
&& (op
->v
< -128 || op
->v
> 255)) return 0;
2339 if (op
->special
|| op
->mem
) return 0;
2340 if (op
->defined
&& (op
->v
< -32768 || op
->v
> 65535)) return 0;
2343 if (op
->special
|| op
->mem
) return 0;
2344 if (op
->defined
&& (op
->v
< -32768 || op
->v
> 65535)) return 0;
2347 if (op
->special
|| op
->mem
) return 0;
2348 if (op
->defined
&& (op
->v
< -32768 || op
->v
> 65535)) return 0;
2349 if (op
->v
< 0) op
->v
= 65536+op
->v
;
2352 if (op
->special
|| op
->mem
) return 0;
2353 if (op
->defined
&& (op
->v
< -32768 || op
->v
> 65535)) return 0;
2354 if (!op
->defined
) op
->v
= addr
;
2355 if (op
->v
< 0) op
->v
= 65536+op
->v
;
2356 i
= op
->v
-((int)addr
+2);
2357 if (i
< -128 || i
> 127) return 0;
2361 if (op
->special
|| !op
->mem
) return 0;
2362 if (op
->defined
&& (op
->v
< -32768 || op
->v
> 65535)) return 0;
2363 if (op
->v
< 0) op
->v
= 65536+op
->v
;
2365 case UO_R8
: case UO_2R8
:
2366 if (op
->mem
&& !strcmp(op
->s
, "HL")) { /*strcpy(op->s, "M");*/ op
->v
= 6; return 1; }
2368 case UO_R8_NOM
: case UO_2R8_NOM
:
2369 if (!op
->special
|| op
->mem
|| op
->s
[1]) return 0;
2371 case 'B': op
->v
= 0; break;
2372 case 'C': op
->v
= 1; break;
2373 case 'D': op
->v
= 2; break;
2374 case 'E': op
->v
= 3; break;
2375 case 'H': op
->v
= 4; break;
2376 case 'L': op
->v
= 5; break;
2377 case 'A': op
->v
= 7; break;
2381 case UO_R8_NOM_NOHL
: case UO_2R8_NOM_NOHL
:
2382 if (!op
->special
|| op
->mem
|| op
->s
[1]) return 0;
2384 case 'B': op
->v
= 0; break;
2385 case 'C': op
->v
= 1; break;
2386 case 'D': op
->v
= 2; break;
2387 case 'E': op
->v
= 3; break;
2388 case 'A': op
->v
= 7; break;
2393 if (!op
->special
|| op
->mem
) return 0;
2394 return strcmp(op
->s
, "(C)")==0;
2395 case UO_PORTIMM
: /* mem, 'cause (n) */
2396 if (op
->special
|| !op
->mem
) return 0;
2398 if (op
->defined
&& (op
->v
< 0 || op
->v
> 255)) return 0;
2401 if (!op
->special
|| op
->mem
) return 0;
2402 if (!strcmp(op
->s
, "XH") || !strcmp(op
->s
, "HX") || !strcmp(op
->s
, "IXH")) return 1;
2405 if (!op
->special
|| op
->mem
) return 0;
2406 if (!strcmp(op
->s
, "XL") || !strcmp(op
->s
, "LX") || !strcmp(op
->s
, "IXL")) return 1;
2409 if (!op
->special
|| op
->mem
) return 0;
2410 if (!strcmp(op
->s
, "YH") || !strcmp(op
->s
, "HY") || !strcmp(op
->s
, "IYH")) return 1;
2413 if (!op
->special
|| op
->mem
) return 0;
2414 if (!strcmp(op
->s
, "YL") || !strcmp(op
->s
, "LY") || !strcmp(op
->s
, "IYL")) return 1;
2417 if (!op
->special
|| op
->mem
) return 0;
2418 if (!strcmp(op
->s
, "A")) return 1;
2421 if (!op
->special
|| op
->mem
) return 0;
2422 if (!strcmp(op
->s
, "B")) return 1;
2425 if (!op
->special
|| op
->mem
) return 0;
2426 if (!strcmp(op
->s
, "R")) return 1;
2429 if (!op
->special
|| op
->mem
) return 0;
2430 if (!strcmp(op
->s
, "I")) return 1;
2433 if (!op
->special
|| op
->mem
|| !op
->s
[1] || op
->s
[2]) return 0;
2434 if (!strcmp(op
->s
, "BC")) { op
->v
= 0; return 1; }
2435 if (!strcmp(op
->s
, "DE")) { op
->v
= 1; return 1; }
2436 if (!strcmp(op
->s
, "HL")) { op
->v
= 2; return 1; }
2437 if (!strcmp(op
->s
, "SP")) { op
->v
= 3; return 1; }
2440 if (!op
->special
|| op
->mem
|| !op
->s
[1] || op
->s
[2]) return 0;
2441 if (!strcmp(op
->s
, "BC")) { op
->v
= 0; return 1; }
2442 if (!strcmp(op
->s
, "DE")) { op
->v
= 1; return 1; }
2443 if (!strcmp(op
->s
, "HL")) { op
->v
= 2; return 1; }
2444 if (!strcmp(op
->s
, "AF")) { op
->v
= 3; return 1; }
2447 if (!op
->special
|| op
->mem
|| strcmp(op
->s
, "AF")) return 0;
2451 if (!op
->special
|| op
->mem
|| (strcmp(op
->s
, "AF'") && strcmp(op
->s
, "AFX"))) return 0;
2455 if (!op
->special
|| op
->mem
|| strcmp(op
->s
, "BC")) return 0;
2459 if (!op
->special
|| op
->mem
|| strcmp(op
->s
, "DE")) return 0;
2463 if (!op
->special
|| op
->mem
|| strcmp(op
->s
, "HL")) return 0;
2467 if (!op
->special
|| op
->mem
|| strcmp(op
->s
, "IX")) return 0;
2471 if (!op
->special
|| op
->mem
|| strcmp(op
->s
, "IY")) return 0;
2475 if (!op
->special
|| op
->mem
|| strcmp(op
->s
, "SP")) return 0;
2479 if (!op
->special
|| !op
->mem
|| strcmp(op
->s
, "SP")) return 0;
2483 if (!op
->special
|| !op
->mem
|| strcmp(op
->s
, "BC")) return 0;
2487 if (!op
->special
|| !op
->mem
|| strcmp(op
->s
, "DE")) return 0;
2491 if (!op
->special
|| !op
->mem
|| strcmp(op
->s
, "HL")) return 0;
2495 if (!op
->special
|| !op
->mem
|| op
->ixy
!= 0xDDU
) return 0;
2496 if (op
->defined
&& (op
->v
< -128 || op
->v
> 127)) return 0;
2499 if (!op
->special
|| !op
->mem
|| op
->ixy
!= 0xFDU
) return 0;
2500 if (op
->defined
&& (op
->v
< -128 || op
->v
> 127)) return 0;
2503 if (!op
->special
|| !op
->mem
|| op
->ixy
!= 0xDDU
) return 0;
2504 if (op
->defined
&& op
->v
!= 0) return 0;
2507 if (!op
->special
|| !op
->mem
|| op
->ixy
!= 0xFDU
) return 0;
2508 if (op
->defined
&& op
->v
!= 0) return 0;
2511 if (!op
->special
|| op
->mem
|| ur_is_long_str(op
->s
)) return 0;
2512 if (!strcmp(op
->s
, "NZ")) { op
->v
= 0; return 1; }
2513 if (!strcmp(op
->s
, "Z")) { op
->v
= 1; return 1; }
2514 if (!strcmp(op
->s
, "NC")) { op
->v
= 2; return 1; }
2515 if (!strcmp(op
->s
, "C")) { op
->v
= 3; return 1; }
2518 if (!op
->special
|| op
->mem
|| ur_is_long_str(op
->s
)) return 0;
2519 if (!strcmp(op
->s
, "NZ")) { op
->v
= 0; return 1; }
2520 if (!strcmp(op
->s
, "Z")) { op
->v
= 1; return 1; }
2521 if (!strcmp(op
->s
, "NC")) { op
->v
= 2; return 1; }
2522 if (!strcmp(op
->s
, "C")) { op
->v
= 3; return 1; }
2523 if (!strcmp(op
->s
, "PO")) { op
->v
= 4; return 1; }
2524 if (!strcmp(op
->s
, "PE")) { op
->v
= 5; return 1; }
2525 if (!strcmp(op
->s
, "P")) { op
->v
= 6; return 1; }
2526 if (!strcmp(op
->s
, "M")) { op
->v
= 7; return 1; }
2529 if (op
->special
|| op
->mem
) return 0;
2530 if (op
->defined
&& (op
->v
< 0 || op
->v
> 7)) return 0;
2533 if (op
->special
|| op
->mem
) return 0;
2534 if (op
->defined
&& (op
->v
< 0 || op
->v
> 0x38 || (op
->v
&7))) return 0;
2538 if (op
->special
|| op
->mem
) return 0;
2539 if (op
->defined
&& op
->v
!= 0) return 0;
2542 if (op
->special
|| op
->mem
) return 0;
2543 if (op
->defined
&& op
->v
!= 1) return 0;
2546 if (op
->special
|| op
->mem
) return 0;
2547 if (op
->defined
&& op
->v
!= 2) return 0;
2554 // mem size should be at least 7 bytes
2555 // returns size of the assembled code
2556 // result <0 on error
2557 // understands comments
2558 int urasm_opasm (const char *expr
, uint16_t destaddr
, uint16_t addr
, const char **errpos
) {
2564 urasm_operand_t ops
[3];
2565 const urasm_cmdinfo_t
*cm
;
2566 uint32_t code
, mask
;
2567 int opcPos
; /* opcode will be placed here */
2570 int doOperand (int idx
) {
2571 const urasm_operand_t
*op
= ops
+idx
;
2572 switch (cm
->ops
[idx
]) {
2574 if (op
->fixuptype
!= UR_FIXUP_NONE
&& urasm_fixup_operand
!= NULL
) {
2575 if (op
->fixuptype
== UR_FIXUP_WORD
) return URA_EXPR_ERR
-UR_EXPRERR_FIXUP
;
2576 urasm_fixup_operand(op
, (destaddr
+len
)&0xffff, (destaddr
+len
)&0xffff, op
->fixuptype
, 1);
2581 buf
[len
++] = op
->v
&0xFFU
;
2586 if (op
->fixuptype
!= UR_FIXUP_NONE
&& urasm_fixup_operand
!= NULL
) {
2587 urasm_fixup_operand(op
, (destaddr
+len
)&0xffff, (destaddr
+len
)&0xffff, op
->fixuptype
, 2);
2589 buf
[len
++] = op
->v
&0xFFU
;
2590 buf
[len
++] = ((op
->v
&0xFFFFU
)>>8)&0xFFU
;
2593 /*FIXME: this is prolly not right*/
2594 if (op
->fixuptype
!= UR_FIXUP_NONE
&& urasm_fixup_operand
!= NULL
) {
2595 switch (op
->fixuptype
) {
2597 urasm_fixup_operand(op
, (destaddr
+len
)&0xffff, (destaddr
+len
)&0xffff, UR_FIXUP_HIBYTE
, 1);
2598 urasm_fixup_operand(op
, (destaddr
+len
+1)&0xffff, (destaddr
+len
+1)&0xffff, UR_FIXUP_LOBYTE
, 1);
2600 case UR_FIXUP_LOBYTE
:
2601 urasm_fixup_operand(op
, (destaddr
+len
)&0xffff, (destaddr
+len
)&0xffff, UR_FIXUP_HIBYTE
, 1);
2603 case UR_FIXUP_HIBYTE
:
2604 urasm_fixup_operand(op
, (destaddr
+len
+1)&0xffff, (destaddr
+len
+1)&0xffff, UR_FIXUP_LOBYTE
, 1);
2609 buf
[len
++] = ((op
->v
&0xFFFFU
)>>8)&0xFFU
;
2610 buf
[len
++] = op
->v
&0xFFU
;
2614 case UO_R8_NOM_NOHL
:
2615 code
|= op
->v
&0xFFU
;
2623 case UO_2R8_NOM_NOHL
:
2624 code
|= (op
->v
&0xFFU
)<<3;
2628 code
|= (op
->v
&0xFFU
)<<4;
2638 /* <0: error; 0: ok; >0: last operand (ops[opix].parsed != 0: non-empty one) */
2639 int parseOperand (int opidx
) {
2641 const char *oe
= expr
;
2642 expr
= urasm_next_operand(ops
+opidx
, expr
, addr
, &error
);
2644 if (errpos
) *errpos
= oe
;
2645 //return URA_BAD_OPERAND;
2646 return -error
+URA_EXPR_ERR
;
2648 if (!expr
|| !expr
[0] || expr
[0] == ';' || expr
[0] == ':') return 1;
2649 if (*expr
!= ',') { if (errpos
) *errpos
= oe
; return URA_BAD_OPERAND
; }
2654 int genCode (void) {
2656 /* special macro for ADD DE,HL */
2657 if (tkn
== UT_ADD
&&
2658 urasm_is_valid_operand(&ops
[0], addr
, UO_R16DE
) &&
2659 urasm_is_valid_operand(&ops
[1], addr
, UO_R16HL
) &&
2660 urasm_is_valid_operand(&ops
[2], addr
, UO_NONE
))
2669 for (unsigned n
= 0; n
< 3; ++n
) urasm_putbyte(destaddr
++, buf
[n
]);
2673 /* hack for invalid instructions */
2674 for (int pos
= URASM_MAX_COMMAND
-1; pos
>= 0; --pos
) {
2676 if (tkn
!= URASM_COMMANDS
[pos
].mnemo
) continue;
2677 if (!urasm_allow_zxnext
&& URASM_COMMANDS
[pos
].ops
[2] == UO_NEXT
) continue;
2678 for (f
= 0; f
< 3; ++f
) {
2679 if (!urasm_is_valid_operand(&ops
[f
], addr
, URASM_COMMANDS
[pos
].ops
[f
])) break;
2681 if (f
< 3) continue;
2682 /* command found, generate code */
2683 len
= 0; cm
= URASM_COMMANDS
+pos
;
2684 code
= cm
->code
; mask
= cm
->mask
;
2685 if ((code
&0xFFFFUL
) == 0xCBDDUL
|| (code
&0xFFFFUL
) == 0xCBFDUL
) {
2686 /* special commands */
2687 /* emit unmasked code */
2688 buf
[0] = (code
&0xFFU
); buf
[1] = 0xCBU
;
2689 for (f
= 0; f
< 3; ++f
) {
2690 if (cm
->ops
[f
] == UO_MIX
|| cm
->ops
[f
] == UO_MIY
) {
2691 if (ops
[f
].defined
&& (ops
[f
].v
< -128 || ops
[f
].v
> 127)) f
= -1;
2692 else if (ops
[f
].defined
) buf
[2] = ops
[f
].v
;
2696 if (f
< 0) continue; /* not me */
2698 code
>>= 24; mask
>>= 24;
2699 if ((mask
&0xFFUL
) != 0xFFUL
) {
2700 for (f
= 0; f
< 3; ++f
) if (cm
->ops
[f
] != UO_MIX
&& cm
->ops
[f
] != UO_MIY
) {
2701 if ((operr
= doOperand(f
)) != 0) goto badi
;
2706 for (f
= 0; f
< len
; ++f
) { urasm_putbyte(destaddr
++, buf
[f
]); ++addr
; }
2709 /* normal commands */
2710 /* emit unmasked code */
2711 while ((mask
&0xFFUL
) == 0xFFUL
) {
2712 buf
[len
++] = code
&0xFFUL
;
2713 code
>>= 8; mask
>>= 8;
2715 //ASSERT((code&0xFFFFFF00UL) == 0);
2721 if ((operr
= doOperand(0)) != 0) goto badi
;
2722 if ((operr
= doOperand(1)) != 0) goto badi
;
2723 if ((operr
= doOperand(2)) != 0) goto badi
;
2726 for (f
= 0; f
< len
; ++f
) { urasm_putbyte(destaddr
++, buf
[f
]); ++addr
; }
2731 if (errpos
) *errpos
= oe
;
2732 return (operr
< 0 ? operr
: URA_BAD_INSTRUCTION
);
2735 int doPushPop (void) {
2737 for (f
= len
= 0; ; ++f
) {
2739 const char *oe
= expr
;
2740 int res
= parseOperand(0);
2741 if (res
< 0) return res
;
2743 if (f
== 0 && !ops
[0].parsed
) { *errpos
= oe
; return URA_BAD_INSTRUCTION
; }
2746 code
= (tkn
== UT_POP
? 0xC1U
: 0xC5U
);
2747 if (urasm_is_valid_operand(ops
, addr
, UO_R16A
)) {
2748 code
|= (ops
[0].v
&0xFFU
)<<4;
2749 urasm_putbyte(destaddr
++, code
);
2752 } else if (urasm_is_valid_operand(ops
, addr
, UO_R16IX
)) {
2753 code
|= (ops
[0].v
&0xFFU
)<<4;
2754 urasm_putbyte(destaddr
++, 0xDDU
);
2755 urasm_putbyte(destaddr
++, code
);
2758 } else if (urasm_is_valid_operand(ops
, addr
, UO_R16IY
)) {
2759 code
|= (ops
[0].v
&0xFFU
)<<4;
2760 urasm_putbyte(destaddr
++, 0xFDU
);
2761 urasm_putbyte(destaddr
++, code
);
2764 } else if (urasm_allow_zxnext
&& code
== 0xC5U
&& urasm_is_valid_operand(ops
, addr
, UO_IMM16BE
)) {
2765 /* ZXNext PUSH nnnn */
2766 urasm_putbyte(destaddr
++, 0xEDU
);
2767 urasm_putbyte(destaddr
++, 0x8AU
);
2768 /*FIXME: this is prolly not right*/
2769 if (ops
[0].fixuptype
!= UR_FIXUP_NONE
&& urasm_fixup_operand
!= NULL
) {
2770 switch (ops
[0].fixuptype
) {
2772 urasm_fixup_operand(&ops
[0], (destaddr
+len
)&0xffff, (destaddr
+len
)&0xffff, UR_FIXUP_HIBYTE
, 1);
2773 urasm_fixup_operand(&ops
[0], (destaddr
+len
+1)&0xffff, (destaddr
+len
+1)&0xffff, UR_FIXUP_LOBYTE
, 1);
2775 case UR_FIXUP_LOBYTE
:
2776 urasm_fixup_operand(&ops
[0], (destaddr
+len
)&0xffff, (destaddr
+len
)&0xffff, UR_FIXUP_HIBYTE
, 1);
2778 case UR_FIXUP_HIBYTE
:
2779 urasm_fixup_operand(&ops
[0], (destaddr
+len
+1)&0xffff, (destaddr
+len
+1)&0xffff, UR_FIXUP_LOBYTE
, 1);
2784 urasm_putbyte(destaddr
++, ((ops
[0].v
&0xFFFFU
)>>8)&0xFFU
);
2785 urasm_putbyte(destaddr
++, ops
[0].v
&0xFFU
);
2789 if (errpos
) *errpos
= oe
;
2790 return URA_BAD_OPERAND
;
2795 expr
= skip_blanks(expr
);
2796 if (expr
[0] && expr
[0] != ';') {
2797 if (errpos
) *errpos
= expr
;
2798 if (expr
[0] != ':') return URA_EXTRA_TEXT
;
2804 int dorep (int opcnt
) {
2806 memset(ops
, 0, sizeof(ops
));
2807 for (f
= len
= 0; ; ++f
) {
2808 int doQuit
= 0, res
;
2810 for (int c
= 0; c
< opcnt
; ++c
) {
2812 res
= parseOperand(c
);
2813 if (res
< 0) return res
;
2815 if (c
!= opcnt
-1 || !ops
[c
].parsed
) { *errpos
= oe
; return URA_BAD_INSTRUCTION
; }
2819 if ((res
= genCode()) < 0) return res
;
2825 expr
= skip_blanks(expr
);
2826 if (expr
[0] && expr
[0] != ';') {
2827 if (errpos
) *errpos
= expr
;
2828 if (expr
[0] != ':') return URA_EXTRA_TEXT
;
2834 if (errpos
) *errpos
= NULL
;
2835 if (!urasm_putbyte
|| !expr
) return URA_GENERIC
;
2837 expr
= skip_blanks(expr
);
2838 if (!expr
[0] || expr
[0] == ';') return 0;
2839 if (expr
[0] == ':') { if (errpos
) *errpos
= expr
; return 0; }
2840 for (oe
= expr
; *expr
&& !ur_isspace(*expr
) && *expr
!= ':' && *expr
!= ';'; ++expr
) {}
2841 if (urasm_allow_zxnext
) {
2842 if (expr
-oe
> 7) { if (errpos
) *errpos
= oe
; return URA_BAD_MNEMO
; } /* bad mnemonics */
2844 if (expr
-oe
> 4) { if (errpos
) *errpos
= oe
; return URA_BAD_MNEMO
; } /* bad mnemonics */
2847 memset(mnem
, 0, sizeof(mnem
));
2848 memcpy(mnem
, oe
, expr
-oe
);
2849 for (int f
= 0; mnem
[f
]; ++f
) mnem
[f
] = ur_toupper(mnem
[f
]);
2851 for (tkn
= 0; tkn
< URASM_MAX_TOKEN
; ++tkn
) if (!strcmp(mnem
, URASM_TOKENS
[tkn
])) break;
2852 if (tkn
>= URASM_MAX_TOKEN
) { if (errpos
) *errpos
= oe
; return URA_BAD_MNEMO
; } /* unknown mnemonics */
2854 expr
= skip_blanks(expr
);
2855 if (expr
[0] == ',') { if (errpos
) *errpos
= oe
; return URA_BAD_OPERAND
; }
2856 /* special for PUSH and POP */
2857 if (tkn
== UT_POP
|| tkn
== UT_PUSH
) return doPushPop();
2858 /* special for LD */
2859 if (tkn
== UT_LD
/*|| tkn == UT_ADD || tkn == UT_ADC || tkn == UT_SBC*/) return dorep(2);
2860 /* special for RR/RL */
2861 if (tkn
== UT_RL
|| tkn
== UT_RR
|| tkn
== UT_INC
|| tkn
== UT_DEC
||
2862 tkn
== UT_SRL
|| tkn
== UT_SRA
|| tkn
== UT_SLI
|| tkn
== UT_SLL
|| tkn
== UT_SLA
) return dorep(1);
2864 memset(ops
, 0, sizeof(ops
));
2865 for (int f
= 0; f
< 3; ++f
) {
2866 int res
= parseOperand(f
);
2868 if (res
< 0) return res
;
2873 if (ret
>= 0 && expr
) {
2874 expr
= skip_blanks(expr
);
2875 if (expr
[0] && expr
[0] != ';') {
2876 if (errpos
) *errpos
= expr
;
2877 if (expr
[0] != ':') return URA_EXTRA_TEXT
;
2885 // ////////////////////////////////////////////////////////////////////////// //
2886 static const char *error_messages_asm
[5] = {
2890 "extra text after instruction",
2895 static const char *error_messages_expr
[14] = {
2897 "unexpected end of expression",
2899 "unbalanced parens",
2903 "term expected", /*FIXME: better message!*/
2905 "invalid operand type", /*FIXME: better message! this is string/number conflict*/
2906 "unknown macro argument", /*FIXME: better message! */
2908 "type mismatch", /* in comparisons */
2909 "operand text too long",
2913 const char *urasm_errormsg (int errcode
) {
2914 if (errcode
>= 0) return "";
2915 if (errcode
< URA_EXPR_ERR
) {
2916 errcode
= -(errcode
-URA_EXPR_ERR
);
2917 if (errcode
>= UR_EXPRERR_EOS
&& errcode
<= UR_EXPRERR_TOOLONG
) {
2918 return error_messages_expr
[errcode
];
2920 return "unknown error";
2922 if (errcode
< -5) return "unknown error";
2923 return error_messages_asm
[(-errcode
)-1];