liburasm: fixed bug with colons
[urasm.git] / src / liburasm / liburasm.c
blob0a376769563b72985bc6c59a79a77b1ad527a435
1 /* coded by Ketmar // Invisible Vector (ketmar@ketmar.no-ip.org)
2 * Understanding is not required. Only obedience.
4 * URASM Z80 assembler/disassembler core v0.1.2 (with ZXNext support)
6 * This program is free software. It comes without any warranty, to
7 * the extent permitted by applicable law. You can redistribute it
8 * and/or modify it under the terms of the Do What The Fuck You Want
9 * To Public License, Version 2, as published by Sam Hocevar. See
10 * http://sam.zoy.org/wtfpl/COPYING for more details.
12 #include <setjmp.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
17 #include "liburasm.h"
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",
41 /* ZXNext */
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"
49 // various things...
50 const char *URA_REGS8[8] = {"B","C","D","E","H","L","(HL)","A"};
51 const char *URA_REGS16[4] = {"BC","DE","HL","SP"};
52 const char *URA_REGS16A[4] = {"BC","DE","HL","AF"};
53 const char *URA_COND[8] = {"NZ","Z","NC","C","PO","PE","P","M"};
56 // the longest matches must come first (for disassembler)
57 // solid-masked must come first (for disassembler)
58 // assembler searches the table from the last command
59 // disassembler searches the table from the first command
60 // heh, i spent a whole night creating this shit! %-)
61 const urasm_cmdinfo_t URASM_COMMANDS[URASM_MAX_COMMAND] = {
62 {.mnemo=UT_NOPX, .code=0x000000DDUL, .mask=0x00000000UL, .ops={UO_NONE, UO_NONE, UO_NONE}},
63 {.mnemo=UT_NOPY, .code=0x000000FDUL, .mask=0x00000000UL, .ops={UO_NONE, UO_NONE, UO_NONE}},
64 // DD/CB opcodes (special)
65 // RLC (IX+d)
66 {.mnemo=UT_RLC, .code=0x0600CBDDUL, .mask=0xFF00FFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
67 // RRC (IX+d)
68 {.mnemo=UT_RRC, .code=0x0E00CBDDUL, .mask=0xFF00FFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
69 // RL (IX+d)
70 {.mnemo=UT_RL, .code=0x1600CBDDUL, .mask=0xFF00FFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
71 // RR (IX+d)
72 {.mnemo=UT_RR, .code=0x1E00CBDDUL, .mask=0xFF00FFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
73 // SLA (IX+d)
74 {.mnemo=UT_SLA, .code=0x2600CBDDUL, .mask=0xFF00FFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
75 // SRA (IX+d)
76 {.mnemo=UT_SRA, .code=0x2E00CBDDUL, .mask=0xFF00FFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
77 // SLL (IX+d)
78 {.mnemo=UT_SLL, .code=0x3600CBDDUL, .mask=0xFF00FFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
79 // SLI (IX+d)
80 {.mnemo=UT_SLI, .code=0x3600CBDDUL, .mask=0xFF00FFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
81 // SRL (IX+d)
82 {.mnemo=UT_SRL, .code=0x3E00CBDDUL, .mask=0xFF00FFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
83 // RES n,(IX+d)
84 {.mnemo=UT_RES, .code=0x8600CBDDUL, .mask=0xC700FFFFUL, .ops={UO_BITN, UO_MIX, UO_NONE}},
85 // SET n,(IX+d)
86 {.mnemo=UT_SET, .code=0xC600CBDDUL, .mask=0xC700FFFFUL, .ops={UO_BITN, UO_MIX, UO_NONE}},
87 // FD/CB opcodes (special)
88 // RLC (IY+d)
89 {.mnemo=UT_RLC, .code=0x0600CBFDUL, .mask=0xFF00FFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
90 // RRC (IY+d)
91 {.mnemo=UT_RRC, .code=0x0E00CBFDUL, .mask=0xFF00FFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
92 // RL (IY+d)
93 {.mnemo=UT_RL, .code=0x1600CBFDUL, .mask=0xFF00FFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
94 // RR (IY+d)
95 {.mnemo=UT_RR, .code=0x1E00CBFDUL, .mask=0xFF00FFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
96 // SLA (IY+d)
97 {.mnemo=UT_SLA, .code=0x2600CBFDUL, .mask=0xFF00FFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
98 // SRA (IY+d)
99 {.mnemo=UT_SRA, .code=0x2E00CBFDUL, .mask=0xFF00FFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
100 // SLL (IY+d)
101 {.mnemo=UT_SLL, .code=0x3600CBFDUL, .mask=0xFF00FFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
102 // SLI (IY+d)
103 {.mnemo=UT_SLI, .code=0x3600CBFDUL, .mask=0xFF00FFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
104 // SRL (IY+d)
105 {.mnemo=UT_SRL, .code=0x3E00CBFDUL, .mask=0xFF00FFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
106 // RES n,(IY+d)
107 {.mnemo=UT_RES, .code=0x8600CBFDUL, .mask=0xC700FFFFUL, .ops={UO_BITN, UO_MIY, UO_NONE}},
108 // SET n,(IY+d)
109 {.mnemo=UT_SET, .code=0xC600CBFDUL, .mask=0xC700FFFFUL, .ops={UO_BITN, UO_MIY, UO_NONE}},
111 // DD/CB opcodes
112 // RLC (IX+d),r8
113 {.mnemo=UT_RLC, .code=0x0000CBDDUL, .mask=0xF800FFFFUL, .ops={UO_MIX, UO_R8_NOM, UO_NONE}},
114 // RRC (IX+d),r8
115 {.mnemo=UT_RRC, .code=0x0800CBDDUL, .mask=0xF800FFFFUL, .ops={UO_MIX, UO_R8_NOM, UO_NONE}},
116 // RL (IX+d),r8
117 {.mnemo=UT_RL, .code=0x1000CBDDUL, .mask=0xF800FFFFUL, .ops={UO_MIX, UO_R8_NOM, UO_NONE}},
118 // RR (IX+d),r8
119 {.mnemo=UT_RR, .code=0x1800CBDDUL, .mask=0xF800FFFFUL, .ops={UO_MIX, UO_R8_NOM, UO_NONE}},
120 // SLA (IX+d),r8
121 {.mnemo=UT_SLA, .code=0x2000CBDDUL, .mask=0xF800FFFFUL, .ops={UO_MIX, UO_R8_NOM, UO_NONE}},
122 // SRA (IX+d),r8
123 {.mnemo=UT_SRA, .code=0x2800CBDDUL, .mask=0xF800FFFFUL, .ops={UO_MIX, UO_R8_NOM, UO_NONE}},
124 // SLL (IX+d),r8
125 {.mnemo=UT_SLL, .code=0x3000CBDDUL, .mask=0xF800FFFFUL, .ops={UO_MIX, UO_R8_NOM, UO_NONE}},
126 // SLI (IX+d),r8
127 {.mnemo=UT_SLI, .code=0x3000CBDDUL, .mask=0xF800FFFFUL, .ops={UO_MIX, UO_R8_NOM, UO_NONE}},
128 // SRL (IX+d),r8
129 {.mnemo=UT_SRL, .code=0x3800CBDDUL, .mask=0xF800FFFFUL, .ops={UO_MIX, UO_R8_NOM, UO_NONE}},
130 // BIT n,(IX+d)
131 {.mnemo=UT_BIT, .code=0x4600CBDDUL, .mask=0xC700FFFFUL, .ops={UO_BITN, UO_MIX, UO_NONE}},
132 // BIT n,(IX+d),r8
133 {.mnemo=UT_BIT, .code=0x4000CBDDUL, .mask=0xC000FFFFUL, .ops={UO_BITN, UO_MIX, UO_R8_NOM}},
134 // RES n,(IX+d),r8
135 {.mnemo=UT_RES, .code=0x8000CBDDUL, .mask=0xC000FFFFUL, .ops={UO_BITN, UO_MIX, UO_R8_NOM}},
136 // SET n,(IX+d),r8
137 {.mnemo=UT_SET, .code=0xC000CBDDUL, .mask=0xC000FFFFUL, .ops={UO_BITN, UO_MIX, UO_R8_NOM}},
138 // FD/CB opcodes
139 // RLC (IY+d),r8
140 {.mnemo=UT_RLC, .code=0x0000CBFDUL, .mask=0xF800FFFFUL, .ops={UO_MIY, UO_R8_NOM, UO_NONE}},
141 // RRC (IY+d),r8
142 {.mnemo=UT_RRC, .code=0x0800CBFDUL, .mask=0xF800FFFFUL, .ops={UO_MIY, UO_R8_NOM, UO_NONE}},
143 // RL (IY+d),r8
144 {.mnemo=UT_RL, .code=0x1000CBFDUL, .mask=0xF800FFFFUL, .ops={UO_MIY, UO_R8_NOM, UO_NONE}},
145 // RR (IY+d),r8
146 {.mnemo=UT_RR, .code=0x1800CBFDUL, .mask=0xF800FFFFUL, .ops={UO_MIY, UO_R8_NOM, UO_NONE}},
147 // SLA (IY+d),r8
148 {.mnemo=UT_SLA, .code=0x2000CBFDUL, .mask=0xF800FFFFUL, .ops={UO_MIY, UO_R8_NOM, UO_NONE}},
149 // SRA (IY+d),r8
150 {.mnemo=UT_SRA, .code=0x2800CBFDUL, .mask=0xF800FFFFUL, .ops={UO_MIY, UO_R8_NOM, UO_NONE}},
151 // SLL (IY+d),r8
152 {.mnemo=UT_SLL, .code=0x3000CBFDUL, .mask=0xF800FFFFUL, .ops={UO_MIY, UO_R8_NOM, UO_NONE}},
153 // SLI (IY+d),r8
154 {.mnemo=UT_SLI, .code=0x3000CBFDUL, .mask=0xF800FFFFUL, .ops={UO_MIY, UO_R8_NOM, UO_NONE}},
155 // SRL (IY+d),r8
156 {.mnemo=UT_SRL, .code=0x3800CBFDUL, .mask=0xF800FFFFUL, .ops={UO_MIY, UO_R8_NOM, UO_NONE}},
157 // BIT n,(IY+d)
158 {.mnemo=UT_BIT, .code=0x4600CBFDUL, .mask=0xC700FFFFUL, .ops={UO_BITN, UO_MIY, UO_NONE}},
159 // BIT n,(IY+d),r8
160 {.mnemo=UT_BIT, .code=0x4000CBFDUL, .mask=0xC000FFFFUL, .ops={UO_BITN, UO_MIY, UO_R8_NOM}},
161 // RES n,(IY+d),r8
162 {.mnemo=UT_RES, .code=0x8000CBFDUL, .mask=0xC000FFFFUL, .ops={UO_BITN, UO_MIY, UO_R8_NOM}},
163 // SET n,(IY+d),r8
164 {.mnemo=UT_SET, .code=0xC000CBFDUL, .mask=0xC000FFFFUL, .ops={UO_BITN, UO_MIY, UO_R8_NOM}},
165 // standard CB opcodes
166 // RLC r8
167 {.mnemo=UT_RLC, .code=0x00CBUL, .mask=0xF8FFUL, .ops={UO_R8, UO_NONE, UO_NONE}},
168 // RRC r8
169 {.mnemo=UT_RRC, .code=0x08CBUL, .mask=0xF8FFUL, .ops={UO_R8, UO_NONE, UO_NONE}},
170 // RL r8
171 {.mnemo=UT_RL, .code=0x10CBUL, .mask=0xF8FFUL, .ops={UO_R8, UO_NONE, UO_NONE}},
172 // RR r8
173 {.mnemo=UT_RR, .code=0x18CBUL, .mask=0xF8FFUL, .ops={UO_R8, UO_NONE, UO_NONE}},
174 // SLA r8
175 {.mnemo=UT_SLA, .code=0x20CBUL, .mask=0xF8FFUL, .ops={UO_R8, UO_NONE, UO_NONE}},
176 // SRA r8
177 {.mnemo=UT_SRA, .code=0x28CBUL, .mask=0xF8FFUL, .ops={UO_R8, UO_NONE, UO_NONE}},
178 // SLL r8
179 {.mnemo=UT_SLL, .code=0x30CBUL, .mask=0xF8FFUL, .ops={UO_R8, UO_NONE, UO_NONE}},
180 // SLI r8
181 {.mnemo=UT_SLI, .code=0x30CBUL, .mask=0xF8FFUL, .ops={UO_R8, UO_NONE, UO_NONE}},
182 // SRL r8
183 {.mnemo=UT_SRL, .code=0x38CBUL, .mask=0xF8FFUL, .ops={UO_R8, UO_NONE, UO_NONE}},
184 // BIT n,r8
185 {.mnemo=UT_BIT, .code=0x40CBUL, .mask=0xC0FFUL, .ops={UO_BITN, UO_R8, UO_NONE}},
186 // RES n,r8
187 {.mnemo=UT_RES, .code=0x80CBUL, .mask=0xC0FFUL, .ops={UO_BITN, UO_R8, UO_NONE}},
188 // SET n,r8
189 {.mnemo=UT_SET, .code=0xC0CBUL, .mask=0xC0FFUL, .ops={UO_BITN, UO_R8, UO_NONE}},
191 // some ED opcodes
192 // traps
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}},
227 /* ADD RR,A*/
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}},
231 /* ADD RR,nnnn*/
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}},
235 /* PUSH nnnn*/
236 {.mnemo=UT_PUSH, .code=0x8AEDUL, .mask=0xFFFFUL, .ops={UO_IMM16BE, UO_NONE, UO_NEXT}},
237 /* TEST nn */
238 {.mnemo=UT_TEST, .code=0x27EDUL, .mask=0xFFFFUL, .ops={UO_IMM8, UO_NONE, UO_NEXT}},
239 /* NEXTREG nn,nn*/
240 {.mnemo=UT_NEXTREG, .code=0x91EDUL, .mask=0xFFFFUL, .ops={UO_IMM8, UO_IMM8, UO_NEXT}},
241 /* NEXTREG nn,A*/
242 {.mnemo=UT_NEXTREG, .code=0x92EDUL, .mask=0xFFFFUL, .ops={UO_IMM8, UO_R8_A, UO_NEXT}},
243 /* BSXX RR,B*/
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}},
249 /* JP (C) */
250 {.mnemo=UT_JP, .code=0x98EDUL, .mask=0xFFFFUL, .ops={UO_PORTC, UO_NONE, UO_NEXT}},
252 // ED w/o operands
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}},
256 // IN (C)
257 {.mnemo=UT_IN, .code=0x70EDUL, .mask=0xFFFFUL, .ops={UO_PORTC, UO_NONE, UO_NONE}},
258 // OUT (C),0
259 {.mnemo=UT_OUT, .code=0x71EDUL, .mask=0xFFFFUL, .ops={UO_PORTC, UO_IM0, UO_NONE}},
261 // LD I,A
262 {.mnemo=UT_LD, .code=0x47EDUL, .mask=0xFFFFUL, .ops={UO_R8_I, UO_R8_A, UO_NONE}},
263 // LD A,I
264 {.mnemo=UT_LD, .code=0x57EDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_I, UO_NONE}},
265 // LD R,A
266 {.mnemo=UT_LD, .code=0x4FEDUL, .mask=0xFFFFUL, .ops={UO_R8_R, UO_R8_A, UO_NONE}},
267 // LD A,R
268 {.mnemo=UT_LD, .code=0x5FEDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_R, UO_NONE}},
269 // IM 0/1
270 //(.mnemo=UT_IM, .code=0x4EEDUL, .mask=0xFFFFUL, .ops={UO_IM01, UO_NONE, UO_NONE}},
272 // ED w/o operands
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}},
276 // SBC HL,r16
277 {.mnemo=UT_SBC, .code=0x42EDUL, .mask=0xCFFFUL, .ops={UO_R16HL, UO_R16, UO_NONE}},
278 // ADC HL,r16
279 {.mnemo=UT_ADC, .code=0x4AEDUL, .mask=0xCFFFUL, .ops={UO_R16HL, UO_R16, UO_NONE}},
280 // LD (nnnn),r16
281 {.mnemo=UT_LD, .code=0x43EDUL, .mask=0xCFFFUL, .ops={UO_MEM16, UO_R16, UO_NONE}},
282 // LD r16,(nnnn)
283 {.mnemo=UT_LD, .code=0x4BEDUL, .mask=0xCFFFUL, .ops={UO_R16, UO_MEM16, UO_NONE}},
285 // ED w/o operands
286 {.mnemo=UT_NEG, .code=0x44EDUL, .mask=0xC7FFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
288 // IN r8,(C)
289 {.mnemo=UT_IN, .code=0x40EDUL, .mask=0xC7FFUL, .ops={UO_2R8_NOM, UO_PORTC, UO_NONE}},
290 // OUT (C),r8
291 {.mnemo=UT_OUT, .code=0x41EDUL, .mask=0xC7FFUL, .ops={UO_PORTC, UO_2R8_NOM, UO_NONE}},
293 // IM 2
294 {.mnemo=UT_IM, .code=0x5EEDUL, .mask=0xDFFFUL, .ops={UO_IM2, UO_NONE, UO_NONE}},
295 // IM 1
296 {.mnemo=UT_IM, .code=0x56EDUL, .mask=0xDFFFUL, .ops={UO_IM1, UO_NONE, UO_NONE}},
297 // IM 0
298 {.mnemo=UT_IM, .code=0x46EDUL, .mask=0xD7FFUL, .ops={UO_IM0, UO_NONE, UO_NONE}},
300 // LD SP,IX
301 {.mnemo=UT_LD, .code=0xF9DDUL, .mask=0xFFFFUL, .ops={UO_R16SP, UO_R16IX, UO_NONE}},
302 // LD SP,IY
303 {.mnemo=UT_LD, .code=0xF9FDUL, .mask=0xFFFFUL, .ops={UO_R16SP, UO_R16IY, UO_NONE}},
305 // EX (SP),IX
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}},
309 // EX (SP),IY
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}},
314 // JP (IX)
315 {.mnemo=UT_JP, .code=0xE9DDUL, .mask=0xFFFFUL, .ops={UO_MIX0, UO_NONE, UO_NONE}},
316 // JP (IY)
317 {.mnemo=UT_JP, .code=0xE9FDUL, .mask=0xFFFFUL, .ops={UO_MIY0, UO_NONE, UO_NONE}},
318 // JP IX
319 {.mnemo=UT_JP, .code=0xE9DDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_NONE, UO_NONE}},
320 // JP IY
321 {.mnemo=UT_JP, .code=0xE9FDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_NONE, UO_NONE}},
323 // POP IX
324 {.mnemo=UT_POP, .code=0xE1DDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_NONE, UO_NONE}},
325 // PUSH IX
326 {.mnemo=UT_PUSH, .code=0xE5DDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_NONE, UO_NONE}},
327 // POP IY
328 {.mnemo=UT_POP, .code=0xE1FDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_NONE, UO_NONE}},
329 // PUSH IY
330 {.mnemo=UT_PUSH, .code=0xE5FDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_NONE, UO_NONE}},
332 // ADD A,(IX+d)
333 {.mnemo=UT_ADD, .code=0x86DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIX, UO_NONE}},
334 // ADD (IX+d)
335 {.mnemo=UT_ADD, .code=0x86DDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
336 // ADC A,(IX+d)
337 {.mnemo=UT_ADC, .code=0x8EDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIX, UO_NONE}},
338 // ADC (IX+d)
339 {.mnemo=UT_ADC, .code=0x8EDDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
340 // SUB (IX+d)
341 {.mnemo=UT_SUB, .code=0x96DDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
342 // SUB A,(IX+d)
343 {.mnemo=UT_SUB, .code=0x96DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIX, UO_NONE}},
344 // SBC A,(IX+d)
345 {.mnemo=UT_SBC, .code=0x9EDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIX, UO_NONE}},
346 // SBC (IX+d)
347 {.mnemo=UT_SBC, .code=0x9EDDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
348 // AND (IX+d)
349 {.mnemo=UT_AND, .code=0xA6DDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
350 // AND A,(IX+d)
351 {.mnemo=UT_AND, .code=0xA6DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIX, UO_NONE}},
352 // XOR (IX+d)
353 {.mnemo=UT_XOR, .code=0xAEDDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
354 // XOR A,(IX+d)
355 {.mnemo=UT_XOR, .code=0xAEDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIX, UO_NONE}},
356 // OR (IX+d)
357 {.mnemo=UT_OR, .code=0xB6DDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
358 // OR A,(IX+d)
359 {.mnemo=UT_OR, .code=0xB6DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIX, UO_NONE}},
360 // CP (IX+d)
361 {.mnemo=UT_CP, .code=0xBEDDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
362 // CP A,(IX+d)
363 {.mnemo=UT_CP, .code=0xBEDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIX, UO_NONE}},
364 // ADD A,(IY+d)
365 {.mnemo=UT_ADD, .code=0x86FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIY, UO_NONE}},
366 // ADD (IY+d)
367 {.mnemo=UT_ADD, .code=0x86FDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
368 // ADC A,(IY+d)
369 {.mnemo=UT_ADC, .code=0x8EFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIY, UO_NONE}},
370 // ADC (IY+d)
371 {.mnemo=UT_ADC, .code=0x8EFDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
372 // SUB (IY+d)
373 {.mnemo=UT_SUB, .code=0x96FDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
374 // SUB A,(IY+d)
375 {.mnemo=UT_SUB, .code=0x96FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIY, UO_NONE}},
376 // SBC A,(IY+d)
377 {.mnemo=UT_SBC, .code=0x9EFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIY, UO_NONE}},
378 // SBC (IY+d)
379 {.mnemo=UT_SBC, .code=0x9EFDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
380 // AND (IY+d)
381 {.mnemo=UT_AND, .code=0xA6FDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
382 // AND A,(IY+d)
383 {.mnemo=UT_AND, .code=0xA6FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIY, UO_NONE}},
384 // XOR (IY+d)
385 {.mnemo=UT_XOR, .code=0xAEFDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
386 // XOR A,(IY+d)
387 {.mnemo=UT_XOR, .code=0xAEFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIY, UO_NONE}},
388 // OR (IY+d)
389 {.mnemo=UT_OR, .code=0xB6FDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
390 // OR A,(IY+d)
391 {.mnemo=UT_OR, .code=0xB6FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIY, UO_NONE}},
392 // CP (IY+d)
393 {.mnemo=UT_CP, .code=0xBEFDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
394 // CP A,(IY+d)
395 {.mnemo=UT_CP, .code=0xBEFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIY, UO_NONE}},
396 // ADD A,XH
397 {.mnemo=UT_ADD, .code=0x84DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XH, UO_NONE}},
398 // ADD XH
399 {.mnemo=UT_ADD, .code=0x84DDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_NONE, UO_NONE}},
400 // ADC A,XH
401 {.mnemo=UT_ADC, .code=0x8CDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XH, UO_NONE}},
402 // ADC XH
403 {.mnemo=UT_ADC, .code=0x8CDDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_NONE, UO_NONE}},
404 // SUB XH
405 {.mnemo=UT_SUB, .code=0x94DDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_NONE, UO_NONE}},
406 // SUB A,XH
407 {.mnemo=UT_SUB, .code=0x94DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XH, UO_NONE}},
408 // SBC A,XH
409 {.mnemo=UT_SBC, .code=0x9CDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XH, UO_NONE}},
410 // SBC XH
411 {.mnemo=UT_SBC, .code=0x9CDDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_NONE, UO_NONE}},
412 // AND XH
413 {.mnemo=UT_AND, .code=0xA4DDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_NONE, UO_NONE}},
414 // AND A,XH
415 {.mnemo=UT_AND, .code=0xA4DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XH, UO_NONE}},
416 // XOR XH
417 {.mnemo=UT_XOR, .code=0xACDDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_NONE, UO_NONE}},
418 // XOR A,XH
419 {.mnemo=UT_XOR, .code=0xACDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XH, UO_NONE}},
420 // OR XH
421 {.mnemo=UT_OR, .code=0xB4DDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_NONE, UO_NONE}},
422 // OR A,XH
423 {.mnemo=UT_OR, .code=0xB4DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XH, UO_NONE}},
424 // CP XH
425 {.mnemo=UT_CP, .code=0xBCDDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_NONE, UO_NONE}},
426 // CP A,XH
427 {.mnemo=UT_CP, .code=0xBCDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XH, UO_NONE}},
428 // ADD A,XL
429 {.mnemo=UT_ADD, .code=0x85DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XL, UO_NONE}},
430 // ADD XL
431 {.mnemo=UT_ADD, .code=0x85DDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_NONE, UO_NONE}},
432 // ADC A,XL
433 {.mnemo=UT_ADC, .code=0x8DDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XL, UO_NONE}},
434 // ADC XL
435 {.mnemo=UT_ADC, .code=0x8DDDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_NONE, UO_NONE}},
436 // SUB XL
437 {.mnemo=UT_SUB, .code=0x95DDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_NONE, UO_NONE}},
438 // SUB A,XL
439 {.mnemo=UT_SUB, .code=0x95DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XL, UO_NONE}},
440 // SBC A,XL
441 {.mnemo=UT_SBC, .code=0x9DDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XL, UO_NONE}},
442 // SBC XL
443 {.mnemo=UT_SBC, .code=0x9DDDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_NONE, UO_NONE}},
444 // AND XL
445 {.mnemo=UT_AND, .code=0xA5DDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_NONE, UO_NONE}},
446 // AND A,XL
447 {.mnemo=UT_AND, .code=0xA5DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XL, UO_NONE}},
448 // XOR XL
449 {.mnemo=UT_XOR, .code=0xADDDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_NONE, UO_NONE}},
450 // XOR A,XL
451 {.mnemo=UT_XOR, .code=0xADDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XL, UO_NONE}},
452 // OR XL
453 {.mnemo=UT_OR, .code=0xB5DDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_NONE, UO_NONE}},
454 // OR A,XL
455 {.mnemo=UT_OR, .code=0xB5DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XL, UO_NONE}},
456 // CP XL
457 {.mnemo=UT_CP, .code=0xBDDDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_NONE, UO_NONE}},
458 // CP A,XL
459 {.mnemo=UT_CP, .code=0xBDDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XL, UO_NONE}},
460 // ADD A,YH
461 {.mnemo=UT_ADD, .code=0x84FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YH, UO_NONE}},
462 // ADD YH
463 {.mnemo=UT_ADD, .code=0x84FDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_NONE, UO_NONE}},
464 // ADC A,YH
465 {.mnemo=UT_ADC, .code=0x8CFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YH, UO_NONE}},
466 // ADC YH
467 {.mnemo=UT_ADC, .code=0x8CFDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_NONE, UO_NONE}},
468 // SUB YH
469 {.mnemo=UT_SUB, .code=0x94FDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_NONE, UO_NONE}},
470 // SUB A,YH
471 {.mnemo=UT_SUB, .code=0x94FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YH, UO_NONE}},
472 // SBC A,YH
473 {.mnemo=UT_SBC, .code=0x9CFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YH, UO_NONE}},
474 // SBC YH
475 {.mnemo=UT_SBC, .code=0x9CFDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_NONE, UO_NONE}},
476 // AND YH
477 {.mnemo=UT_AND, .code=0xA4FDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_NONE, UO_NONE}},
478 // AND A,YH
479 {.mnemo=UT_AND, .code=0xA4FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YH, UO_NONE}},
480 // XOR YH
481 {.mnemo=UT_XOR, .code=0xACFDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_NONE, UO_NONE}},
482 // XOR A,YH
483 {.mnemo=UT_XOR, .code=0xACFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YH, UO_NONE}},
484 // OR YH
485 {.mnemo=UT_OR, .code=0xB4FDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_NONE, UO_NONE}},
486 // OR A,YH
487 {.mnemo=UT_OR, .code=0xB4FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YH, UO_NONE}},
488 // CP YH
489 {.mnemo=UT_CP, .code=0xBCFDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_NONE, UO_NONE}},
490 // CP A,YH
491 {.mnemo=UT_CP, .code=0xBCFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YH, UO_NONE}},
492 // ADD A,YL
493 {.mnemo=UT_ADD, .code=0x85FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YL, UO_NONE}},
494 // ADD YL
495 {.mnemo=UT_ADD, .code=0x85FDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_NONE, UO_NONE}},
496 // ADC A,YL
497 {.mnemo=UT_ADC, .code=0x8DFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YL, UO_NONE}},
498 // ADC YL
499 {.mnemo=UT_ADC, .code=0x8DFDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_NONE, UO_NONE}},
500 // SUB YL
501 {.mnemo=UT_SUB, .code=0x95FDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_NONE, UO_NONE}},
502 // SUB A,YL
503 {.mnemo=UT_SUB, .code=0x95FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YL, UO_NONE}},
504 // SBC A,YL
505 {.mnemo=UT_SBC, .code=0x9DFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YL, UO_NONE}},
506 // SBC YL
507 {.mnemo=UT_SBC, .code=0x9DFDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_NONE, UO_NONE}},
508 // AND YL
509 {.mnemo=UT_AND, .code=0xA5FDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_NONE, UO_NONE}},
510 // AND A,YL
511 {.mnemo=UT_AND, .code=0xA5FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YL, UO_NONE}},
512 // XOR YL
513 {.mnemo=UT_XOR, .code=0xADFDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_NONE, UO_NONE}},
514 // XOR A,YL
515 {.mnemo=UT_XOR, .code=0xADFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YL, UO_NONE}},
516 // OR YL
517 {.mnemo=UT_OR, .code=0xB5FDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_NONE, UO_NONE}},
518 // OR A,YL
519 {.mnemo=UT_OR, .code=0xB5FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YL, UO_NONE}},
520 // CP YL
521 {.mnemo=UT_CP, .code=0xBDFDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_NONE, UO_NONE}},
522 // CP A,YL
523 {.mnemo=UT_CP, .code=0xBDFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YL, UO_NONE}},
525 // LD XH,XH
526 {.mnemo=UT_LD, .code=0x64DDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_R8_XH, UO_NONE}},
527 // LD XH,XL
528 {.mnemo=UT_LD, .code=0x65DDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_R8_XL, UO_NONE}},
529 // LD XL,XH
530 {.mnemo=UT_LD, .code=0x6CDDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_R8_XH, UO_NONE}},
531 // LD XL,XL
532 {.mnemo=UT_LD, .code=0x6DDDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_R8_XL, UO_NONE}},
533 // LD YH,YH
534 {.mnemo=UT_LD, .code=0x64FDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_R8_YH, UO_NONE}},
535 // LD YH,YL
536 {.mnemo=UT_LD, .code=0x65FDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_R8_YL, UO_NONE}},
537 // LD YL,YH
538 {.mnemo=UT_LD, .code=0x6CFDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_R8_YH, UO_NONE}},
539 // LD YL,YL
540 {.mnemo=UT_LD, .code=0x6DFDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_R8_YL, UO_NONE}},
542 // LD (nnnn),IX
543 {.mnemo=UT_LD, .code=0x22DDUL, .mask=0xFFFFUL, .ops={UO_MEM16, UO_R16IX, UO_NONE}},
544 // LD IX,(nnnn)
545 {.mnemo=UT_LD, .code=0x2ADDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_MEM16, UO_NONE}},
546 // LD (nnnn),IY
547 {.mnemo=UT_LD, .code=0x22FDUL, .mask=0xFFFFUL, .ops={UO_MEM16, UO_R16IY, UO_NONE}},
548 // LD IY,(nnnn)
549 {.mnemo=UT_LD, .code=0x2AFDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_MEM16, UO_NONE}},
551 // LD IX,nnnn
552 {.mnemo=UT_LD, .code=0x21DDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_IMM16, UO_NONE}},
553 // LD IY,nnnn
554 {.mnemo=UT_LD, .code=0x21FDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_IMM16, UO_NONE}},
556 // INC IX
557 {.mnemo=UT_INC, .code=0x23DDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_NONE, UO_NONE}},
558 // DEC IX
559 {.mnemo=UT_DEC, .code=0x2BDDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_NONE, UO_NONE}},
560 // INC IY
561 {.mnemo=UT_INC, .code=0x23FDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_NONE, UO_NONE}},
562 // DEC IY
563 {.mnemo=UT_DEC, .code=0x2BFDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_NONE, UO_NONE}},
565 // INC (IX+d)
566 {.mnemo=UT_INC, .code=0x34DDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
567 // DEC (IX+d)
568 {.mnemo=UT_DEC, .code=0x35DDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
569 // LD (IX+d),nn
570 {.mnemo=UT_LD, .code=0x36DDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_IMM8, UO_NONE}},
571 // INC (IY+d)
572 {.mnemo=UT_INC, .code=0x34FDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
573 // DEC (IY+d)
574 {.mnemo=UT_DEC, .code=0x35FDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
575 // LD (IY+d),nn
576 {.mnemo=UT_LD, .code=0x36FDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_IMM8, UO_NONE}},
578 // INC XH
579 {.mnemo=UT_INC, .code=0x24DDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_NONE, UO_NONE}},
580 // DEC XH
581 {.mnemo=UT_DEC, .code=0x25DDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_NONE, UO_NONE}},
582 // INC XL
583 {.mnemo=UT_INC, .code=0x2CDDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_NONE, UO_NONE}},
584 // DEC XL
585 {.mnemo=UT_DEC, .code=0x2DDDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_NONE, UO_NONE}},
586 // INC YH
587 {.mnemo=UT_INC, .code=0x24FDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_NONE, UO_NONE}},
588 // DEC YH
589 {.mnemo=UT_DEC, .code=0x25FDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_NONE, UO_NONE}},
590 // INC YL
591 {.mnemo=UT_INC, .code=0x2CFDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_NONE, UO_NONE}},
592 // DEC YL
593 {.mnemo=UT_DEC, .code=0x2DFDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_NONE, UO_NONE}},
595 // LD XH,nn
596 {.mnemo=UT_LD, .code=0x26DDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_IMM8, UO_NONE}},
597 // LD XL,nn
598 {.mnemo=UT_LD, .code=0x2EDDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_IMM8, UO_NONE}},
599 // LD YH,nn
600 {.mnemo=UT_LD, .code=0x26FDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_IMM8, UO_NONE}},
601 // LD YL,nn
602 {.mnemo=UT_LD, .code=0x2EFDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_IMM8, UO_NONE}},
604 // ADD IX,BC
605 {.mnemo=UT_ADD, .code=0x09DDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_R16BC, UO_NONE}},
606 // ADD IX,DE
607 {.mnemo=UT_ADD, .code=0x19DDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_R16DE, UO_NONE}},
608 // ADD IX,IX
609 {.mnemo=UT_ADD, .code=0x29DDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_R16IX, UO_NONE}},
610 // ADD IX,SP
611 {.mnemo=UT_ADD, .code=0x39DDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_R16SP, UO_NONE}},
612 // ADD IY,BC
613 {.mnemo=UT_ADD, .code=0x09FDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_R16BC, UO_NONE}},
614 // ADD IY,DE
615 {.mnemo=UT_ADD, .code=0x19FDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_R16DE, UO_NONE}},
616 // ADD IY,IY
617 {.mnemo=UT_ADD, .code=0x29FDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_R16IY, UO_NONE}},
618 // ADD IY,SP
619 {.mnemo=UT_ADD, .code=0x39FDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_R16SP, UO_NONE}},
621 // LD XH,r8
622 {.mnemo=UT_LD, .code=0x60DDUL, .mask=0xF8FFUL, .ops={UO_R8_XH, UO_R8_NOM, UO_NONE}},
623 // LD XL,r8
624 {.mnemo=UT_LD, .code=0x68DDUL, .mask=0xF8FFUL, .ops={UO_R8_XL, UO_R8_NOM, UO_NONE}},
625 // LD (IX+d),r8
626 {.mnemo=UT_LD, .code=0x70DDUL, .mask=0xF8FFUL, .ops={UO_MIX, UO_R8_NOM, UO_NONE}},
627 // LD YH,r8
628 {.mnemo=UT_LD, .code=0x60FDUL, .mask=0xF8FFUL, .ops={UO_R8_YH, UO_R8_NOM, UO_NONE}},
629 // LD YL,r8
630 {.mnemo=UT_LD, .code=0x68FDUL, .mask=0xF8FFUL, .ops={UO_R8_YL, UO_R8_NOM, UO_NONE}},
631 // LD (IY+d),r8
632 {.mnemo=UT_LD, .code=0x70FDUL, .mask=0xF8FFUL, .ops={UO_MIY, UO_R8_NOM, UO_NONE}},
634 // LD r8,XH
635 {.mnemo=UT_LD, .code=0x44DDUL, .mask=0xC7FFUL, .ops={UO_2R8_NOM, UO_R8_XH, UO_NONE}},
636 // LD r8,XL
637 {.mnemo=UT_LD, .code=0x45DDUL, .mask=0xC7FFUL, .ops={UO_2R8_NOM, UO_R8_XL, UO_NONE}},
638 // LD r8,(IX+d)
639 {.mnemo=UT_LD, .code=0x46DDUL, .mask=0xC7FFUL, .ops={UO_2R8_NOM, UO_MIX, UO_NONE}},
641 // LD r8,YH
642 {.mnemo=UT_LD, .code=0x44FDUL, .mask=0xC7FFUL, .ops={UO_2R8_NOM, UO_R8_YH, UO_NONE}},
643 // LD r8,YL
644 {.mnemo=UT_LD, .code=0x45FDUL, .mask=0xC7FFUL, .ops={UO_2R8_NOM, UO_R8_YL, UO_NONE}},
645 // LD r8,(IY+d)
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}},
663 // LD SP,HL
664 {.mnemo=UT_LD, .code=0xF9UL, .mask=0xFFUL, .ops={UO_R16SP, UO_R16HL, UO_NONE}},
665 // EX AF,AF'
666 {.mnemo=UT_EX, .code=0x08UL, .mask=0xFFUL, .ops={UO_R16AF, UO_R16AFX, UO_NONE}},
667 // EX AF',AF (ditto)
668 {.mnemo=UT_EX, .code=0x08UL, .mask=0xFFUL, .ops={UO_R16AFX, UO_R16AF, UO_NONE}},
669 // EX (SP),HL
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}},
673 // EX DE,HL
674 {.mnemo=UT_EX, .code=0xEBUL, .mask=0xFFUL, .ops={UO_R16DE, UO_R16HL, UO_NONE}},
675 // EX HL,DE (ditto)
676 {.mnemo=UT_EX, .code=0xEBUL, .mask=0xFFUL, .ops={UO_R16HL, UO_R16DE, UO_NONE}},
677 // JP (HL)
678 {.mnemo=UT_JP, .code=0xE9UL, .mask=0xFFUL, .ops={UO_MHL, UO_NONE, UO_NONE}},
679 // JP HL
680 {.mnemo=UT_JP, .code=0xE9UL, .mask=0xFFUL, .ops={UO_R16HL, UO_NONE, UO_NONE}},
681 // JP nnnn
682 {.mnemo=UT_JP, .code=0xC3UL, .mask=0xFFUL, .ops={UO_ADDR16, UO_NONE, UO_NONE}},
683 // CALL nnnn
684 {.mnemo=UT_CALL, .code=0xCDUL, .mask=0xFFUL, .ops={UO_ADDR16, UO_NONE, UO_NONE}},
685 // OUT (n),A
686 {.mnemo=UT_OUT, .code=0xD3UL, .mask=0xFFUL, .ops={UO_PORTIMM, UO_R8_A, UO_NONE}},
687 // IN A,(n)
688 {.mnemo=UT_IN, .code=0xDBUL, .mask=0xFFUL, .ops={UO_R8_A, UO_PORTIMM, UO_NONE}},
690 // ADD A,nn
691 {.mnemo=UT_ADD, .code=0xC6UL, .mask=0xFFUL, .ops={UO_R8_A, UO_IMM8, UO_NONE}},
692 // ADD nn (ditto)
693 {.mnemo=UT_ADD, .code=0xC6UL, .mask=0xFFUL, .ops={UO_IMM8, UO_NONE, UO_NONE}},
694 // ADC A,nn
695 {.mnemo=UT_ADC, .code=0xCEUL, .mask=0xFFUL, .ops={UO_R8_A, UO_IMM8, UO_NONE}},
696 // ADC nn (ditto)
697 {.mnemo=UT_ADC, .code=0xCEUL, .mask=0xFFUL, .ops={UO_IMM8, UO_NONE, UO_NONE}},
698 // SUB nn
699 {.mnemo=UT_SUB, .code=0xD6UL, .mask=0xFFUL, .ops={UO_IMM8, UO_NONE, UO_NONE}},
700 // SUB A,nn (ditto)
701 {.mnemo=UT_SUB, .code=0xD6UL, .mask=0xFFUL, .ops={UO_R8_A, UO_IMM8, UO_NONE}},
702 // SBC A,nn
703 {.mnemo=UT_SBC, .code=0xDEUL, .mask=0xFFUL, .ops={UO_R8_A, UO_IMM8, UO_NONE}},
704 // SBC nn (ditto)
705 {.mnemo=UT_SBC, .code=0xDEUL, .mask=0xFFUL, .ops={UO_IMM8, UO_NONE, UO_NONE}},
706 // AND nn
707 {.mnemo=UT_AND, .code=0xE6UL, .mask=0xFFUL, .ops={UO_IMM8, UO_NONE, UO_NONE}},
708 // AND A,nn (ditto)
709 {.mnemo=UT_AND, .code=0xE6UL, .mask=0xFFUL, .ops={UO_R8_A, UO_IMM8, UO_NONE}},
710 // XOR nn
711 {.mnemo=UT_XOR, .code=0xEEUL, .mask=0xFFUL, .ops={UO_IMM8, UO_NONE, UO_NONE}},
712 // XOR A,nn (ditto)
713 {.mnemo=UT_XOR, .code=0xEEUL, .mask=0xFFUL, .ops={UO_R8_A, UO_IMM8, UO_NONE}},
714 // OR nn
715 {.mnemo=UT_OR, .code=0xF6UL, .mask=0xFFUL, .ops={UO_IMM8, UO_NONE, UO_NONE}},
716 // OR A,nn (ditto)
717 {.mnemo=UT_OR, .code=0xF6UL, .mask=0xFFUL, .ops={UO_R8_A, UO_IMM8, UO_NONE}},
718 // CP nn
719 {.mnemo=UT_CP, .code=0xFEUL, .mask=0xFFUL, .ops={UO_IMM8, UO_NONE, UO_NONE}},
720 // CP A,nn (ditto)
721 {.mnemo=UT_CP, .code=0xFEUL, .mask=0xFFUL, .ops={UO_R8_A, UO_IMM8, UO_NONE}},
722 // LD (BC),A
723 {.mnemo=UT_LD, .code=0x02UL, .mask=0xFFUL, .ops={UO_MBC, UO_R8_A, UO_NONE}},
724 // LD (DE),A
725 {.mnemo=UT_LD, .code=0x12UL, .mask=0xFFUL, .ops={UO_MDE, UO_R8_A, UO_NONE}},
726 // LD A,(BC)
727 {.mnemo=UT_LD, .code=0x0AUL, .mask=0xFFUL, .ops={UO_R8_A, UO_MBC, UO_NONE}},
728 // LD A,(DE)
729 {.mnemo=UT_LD, .code=0x1AUL, .mask=0xFFUL, .ops={UO_R8_A, UO_MDE, UO_NONE}},
730 // LD (nnnn),HL
731 {.mnemo=UT_LD, .code=0x22UL, .mask=0xFFUL, .ops={UO_MEM16, UO_R16HL, UO_NONE}},
732 // LD HL,(nnnn)
733 {.mnemo=UT_LD, .code=0x2AUL, .mask=0xFFUL, .ops={UO_R16HL, UO_MEM16, UO_NONE}},
734 // LD (nnnn),A
735 {.mnemo=UT_LD, .code=0x32UL, .mask=0xFFUL, .ops={UO_MEM16, UO_R8_A, UO_NONE}},
736 // LD A,(nnnn)
737 {.mnemo=UT_LD, .code=0x3AUL, .mask=0xFFUL, .ops={UO_R8_A, UO_MEM16, UO_NONE}},
738 // DJNZ d
739 {.mnemo=UT_DJNZ, .code=0x10UL, .mask=0xFFUL, .ops={UO_ADDR8, UO_NONE, UO_NONE}},
740 // JR d
741 {.mnemo=UT_JR, .code=0x18UL, .mask=0xFFUL, .ops={UO_ADDR8, UO_NONE, UO_NONE}},
743 // ADD HL,r16
744 {.mnemo=UT_ADD, .code=0x09UL, .mask=0xCFUL, .ops={UO_R16HL, UO_R16, UO_NONE}},
746 // ADD A,r8
747 {.mnemo=UT_ADD, .code=0x80UL, .mask=0xF8UL, .ops={UO_R8_A, UO_R8, UO_NONE}},
748 // ADD r8
749 {.mnemo=UT_ADD, .code=0x80UL, .mask=0xF8UL, .ops={UO_R8, UO_NONE, UO_NONE}},
750 // ADC A,r8
751 {.mnemo=UT_ADC, .code=0x88UL, .mask=0xF8UL, .ops={UO_R8_A, UO_R8, UO_NONE}},
752 // ADC r8
753 {.mnemo=UT_ADC, .code=0x88UL, .mask=0xF8UL, .ops={UO_R8, UO_NONE, UO_NONE}},
754 // SUB r8
755 {.mnemo=UT_SUB, .code=0x90UL, .mask=0xF8UL, .ops={UO_R8, UO_NONE, UO_NONE}},
756 // SUB A,r8
757 {.mnemo=UT_SUB, .code=0x90UL, .mask=0xF8UL, .ops={UO_R8_A, UO_R8, UO_NONE}},
758 // SBC A,r8
759 {.mnemo=UT_SBC, .code=0x98UL, .mask=0xF8UL, .ops={UO_R8_A, UO_R8, UO_NONE}},
760 // SBC r8
761 {.mnemo=UT_SBC, .code=0x98UL, .mask=0xF8UL, .ops={UO_R8, UO_NONE, UO_NONE}},
762 // AND r8
763 {.mnemo=UT_AND, .code=0xA0UL, .mask=0xF8UL, .ops={UO_R8, UO_NONE, UO_NONE}},
764 // AND A,r8
765 {.mnemo=UT_AND, .code=0xA0UL, .mask=0xF8UL, .ops={UO_R8_A, UO_R8, UO_NONE}},
766 // XOR r8
767 {.mnemo=UT_XOR, .code=0xA8UL, .mask=0xF8UL, .ops={UO_R8, UO_NONE, UO_NONE}},
768 // XOR A,r8
769 {.mnemo=UT_XOR, .code=0xA8UL, .mask=0xF8UL, .ops={UO_R8_A, UO_R8, UO_NONE}},
770 // OR r8
771 {.mnemo=UT_OR, .code=0xB0UL, .mask=0xF8UL, .ops={UO_R8, UO_NONE, UO_NONE}},
772 // OR A,r8
773 {.mnemo=UT_OR, .code=0xB0UL, .mask=0xF8UL, .ops={UO_R8_A, UO_R8, UO_NONE}},
774 // CP r8
775 {.mnemo=UT_CP, .code=0xB8UL, .mask=0xF8UL, .ops={UO_R8, UO_NONE, UO_NONE}},
776 // CP A,r8
777 {.mnemo=UT_CP, .code=0xB8UL, .mask=0xF8UL, .ops={UO_R8_A, UO_R8, UO_NONE}},
779 // JR cc,d
780 {.mnemo=UT_JR, .code=0x20UL, .mask=0xE7UL, .ops={UO_JRCOND, UO_ADDR8, UO_NONE}},
782 // POP r16
783 {.mnemo=UT_POP, .code=0xC1UL, .mask=0xCFUL, .ops={UO_R16A, UO_NONE, UO_NONE}},
784 // PUSH r16
785 {.mnemo=UT_PUSH, .code=0xC5UL, .mask=0xCFUL, .ops={UO_R16A, UO_NONE, UO_NONE}},
786 // RET cc
787 {.mnemo=UT_RET, .code=0xC0UL, .mask=0xC7UL, .ops={UO_COND, UO_NONE, UO_NONE}},
788 // JP cc,nnnn
789 {.mnemo=UT_JP, .code=0xC2UL, .mask=0xC7UL, .ops={UO_COND, UO_ADDR16, UO_NONE}},
790 // CALL cc,nnnn
791 {.mnemo=UT_CALL, .code=0xC4UL, .mask=0xC7UL, .ops={UO_COND, UO_ADDR16, UO_NONE}},
792 // RST n
793 {.mnemo=UT_RST, .code=0xC7UL, .mask=0xC7UL, .ops={UO_RSTDEST, UO_NONE, UO_NONE}},
795 // INC r8
796 {.mnemo=UT_INC, .code=0x04UL, .mask=0xC7UL, .ops={UO_2R8, UO_NONE, UO_NONE}},
797 // DEC r8
798 {.mnemo=UT_DEC, .code=0x05UL, .mask=0xC7UL, .ops={UO_2R8, UO_NONE, UO_NONE}},
799 // LD r8,nn
800 {.mnemo=UT_LD, .code=0x06UL, .mask=0xC7UL, .ops={UO_2R8, UO_IMM8, UO_NONE}},
802 // LD r16,nnnn
803 {.mnemo=UT_LD, .code=0x01UL, .mask=0xCFUL, .ops={UO_R16, UO_IMM16, UO_NONE}},
804 // INC r16
805 {.mnemo=UT_INC, .code=0x03UL, .mask=0xCFUL, .ops={UO_R16, UO_NONE, UO_NONE}},
806 // DEC r16
807 {.mnemo=UT_DEC, .code=0x0BUL, .mask=0xCFUL, .ops={UO_R16, UO_NONE, UO_NONE}},
809 // LD r8,r8
810 {.mnemo=UT_LD, .code=0x40UL, .mask=0xC0UL, .ops={UO_2R8, UO_R8, UO_NONE}},
812 // syntetics
813 // LD BC,BC
814 {.mnemo=UT_LD, .code=0x4940UL, .mask=0xFFFFUL, .ops={UO_R16BC, UO_R16BC, UO_NONE}},
815 // LD BC,DE
816 {.mnemo=UT_LD, .code=0x4B42UL, .mask=0xFFFFUL, .ops={UO_R16BC, UO_R16DE, UO_NONE}},
817 // LD BC,HL
818 {.mnemo=UT_LD, .code=0x4D44UL, .mask=0xFFFFUL, .ops={UO_R16BC, UO_R16HL, UO_NONE}},
819 // LD DE,BC
820 {.mnemo=UT_LD, .code=0x5950UL, .mask=0xFFFFUL, .ops={UO_R16DE, UO_R16BC, UO_NONE}},
821 // LD DE,DE
822 {.mnemo=UT_LD, .code=0x5B52UL, .mask=0xFFFFUL, .ops={UO_R16DE, UO_R16DE, UO_NONE}},
823 // LD DE,HL
824 {.mnemo=UT_LD, .code=0x5D54UL, .mask=0xFFFFUL, .ops={UO_R16DE, UO_R16HL, UO_NONE}},
825 // LD HL,BC
826 {.mnemo=UT_LD, .code=0x6960UL, .mask=0xFFFFUL, .ops={UO_R16HL, UO_R16BC, UO_NONE}},
827 // LD HL,DE
828 {.mnemo=UT_LD, .code=0x6B62UL, .mask=0xFFFFUL, .ops={UO_R16HL, UO_R16DE, UO_NONE}},
829 // LD HL,HL
830 {.mnemo=UT_LD, .code=0x6D64UL, .mask=0xFFFFUL, .ops={UO_R16HL, UO_R16HL, UO_NONE}},
834 // instructions unaffected by DD/FF prefixes
835 // this table used by disassembler (we don't want to eat prefixes)
836 const unsigned char URASM_DDFD_INSENSITIVE[256] = {
837 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
838 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
839 1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,
840 1,1,1,1,0,0,0,1,1,0,1,1,1,1,1,1,
841 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
842 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
843 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
844 0,0,0,0,0,0,1,0,1,1,1,1,0,0,0,1,
845 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
846 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
847 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
848 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
849 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,
850 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
851 1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,
852 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
854 0xff,0xbf,0xff,0xbf,0x81,0x81,0xf1,0xbf,0xf1,0xf1,0xf1,0xf1,0x00,0x00,0x02,0xf1,
855 0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xff,0xef,0xff,0xff,0xab,0xbf,0xff,0xbf,
859 #define IS_DD_SENSITIVE(c) URASM_DDFD_INSENSITIVE[(c)&0xff]
861 static inline int IS_DD_SENSITIVE (uint8_t opc) {
862 return URASM_DDFD_INSENSITIVE[opc/8]&(0x80>>(opc%8));
867 #if 0
868 const unsigned char URASM_DDFD_HAS_DISP[256] = {
870 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
871 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
872 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
873 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
874 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
875 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
876 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
877 1,1,1,1,1,1,0,1,0,0,0,0,0,0,1,0,
878 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
879 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
880 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
881 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
882 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
883 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
884 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
885 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
887 0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x00,0x02,0x02,0x02,0x02,0x02,0x02,0xfd,0x02,
888 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
891 static inline int HAS_DDFD_DISP (uint8_t opc) {
892 return URASM_DDFD_HAS_DISP[opc/8]&(0x80>>(opc%8));
894 #endif
897 static __attribute__((always_inline)) inline const char *label_by_addr (uint16_t addr) {
898 if (!urasm_label_by_addr) return NULL;
899 return urasm_label_by_addr(addr);
903 static __attribute__((always_inline)) inline char ur_toupper (char ch) {
904 return (ch >= 'a' && ch <= 'z' ? ch-'a'+'A' : ch);
908 static __attribute__((always_inline)) inline char ur_isalpha (char ch) {
909 return
910 (ch >= 'A' && ch <= 'Z') ||
911 (ch >= 'a' && ch <= 'z');
915 static __attribute__((always_inline)) inline char ur_isalnum (char ch) {
916 return
917 (ch >= 'A' && ch <= 'Z') ||
918 (ch >= 'a' && ch <= 'z') ||
919 (ch >= '0' && ch <= '9');
923 static __attribute__((always_inline)) inline char ur_isspace (char ch) {
924 return (ch != 0 && ((ch&0xff) <= 32 || ch == 127));
928 static inline int dig2n (char ch, int base) {
929 if (ch < '0') return -1;
930 if (base <= 10) {
931 if (ch > '0'+base) return -1;
932 return ch-'0';
934 if (ch >= '0' && ch <= '9') return ch-'0';
935 if (ch >= 'a' && ch <= 'z') ch = ch-'a'+10;
936 else if (ch >= 'A' && ch <= 'Z') ch = ch-'A'+10;
937 else return -1;
938 if (ch >= base) return -1;
939 return ch;
943 /******************************************************************************/
944 /* disassembler */
945 /******************************************************************************/
947 /* opc: opcode */
948 /* nextW: next 2 bytes (after opcode) */
949 /* idx: I? displacement */
950 static void ua_op2str (char *res, int op, uint16_t addr, uint8_t opc, uint16_t nextW, int idx) {
951 const char *lbl;
952 int add, ismem = 0;
953 switch (op) {
954 case UO_NONE: case UO_NEXT: strcpy(res, ""); break;
955 case UO_IMM8:
956 if (!urasm_disasm_decimal) sprintf(res, "#%02X", nextW&0xFFU); else sprintf(res, "%u", nextW&0xFFU);
957 break;
958 case UO_IMM16:
959 if (!urasm_disasm_decimal) sprintf(res, "#%04X", nextW); else sprintf(res, "%u", nextW);
960 break;
961 case UO_IMM16BE:
962 nextW = (uint16_t)(((nextW>>8)&0xffu)|((nextW<<8)&0xff00u));
963 if (!urasm_disasm_decimal) sprintf(res, "#%04X", nextW); else sprintf(res, "%u", nextW);
964 break;
965 case UO_ADDR8:
966 addr += 2; nextW &= 0xFFU;
967 add = (nextW < 128 ? nextW : ((int)nextW)-256);
968 addr += add;
969 nextW = addr;
970 /* fallthru */
971 case UO_ADDR16:
972 dolabel:
973 lbl = label_by_addr(nextW);
974 if (lbl) { strcpy(res, lbl); break; }
975 lbl = label_by_addr(nextW-1);
976 if (lbl) { sprintf(res, "%s-1", lbl); break; }
977 lbl = label_by_addr(nextW-2);
978 if (lbl) { sprintf(res, "%s-2", lbl); break; }
979 lbl = label_by_addr(nextW+1);
980 if (lbl) { sprintf(res, "%s+1", lbl); break; }
981 lbl = label_by_addr(nextW+2);
982 if (lbl) { sprintf(res, "%s+2", lbl); break; }
983 if (!urasm_disasm_decimal) sprintf(res, "#%04X", nextW); else sprintf(res, "%u", nextW);
984 break;
985 case UO_MEM16:
986 ismem = 1;
987 strcpy(res, "("); ++res;
988 goto dolabel;
989 case UO_R8:
990 case UO_R8_NOM:
991 strcpy(res, URA_REGS8[opc&0x07UL]);
992 break;
993 case UO_2R8:
994 case UO_2R8_NOM:
995 strcpy(res, URA_REGS8[(opc>>3)&0x07UL]);
996 break;
997 case UO_PORTC: strcpy(res, "(C)"); break;
998 case UO_PORTIMM:
999 if (!urasm_disasm_decimal) sprintf(res, "(#%02X)", nextW&0xFFU); else sprintf(res, "(%u)", nextW&0xFFU);
1000 break;
1001 case UO_R8_XH: strcpy(res, "XH"); break;
1002 case UO_R8_XL: strcpy(res, "XL"); break;
1003 case UO_R8_YH: strcpy(res, "YH"); break;
1004 case UO_R8_YL: strcpy(res, "YL"); break;
1005 case UO_R8_A: strcpy(res, "A"); break;
1006 case UO_R8_B: strcpy(res, "B"); break;
1007 case UO_R8_R: strcpy(res, "R"); break;
1008 case UO_R8_I: strcpy(res, "I"); break;
1009 case UO_R16: strcpy(res, URA_REGS16[(opc>>4)&0x03UL]); break;
1010 case UO_R16A: strcpy(res, URA_REGS16A[(opc>>4)&0x03UL]); break;
1011 case UO_R16AF: strcpy(res, "AF"); break;
1012 case UO_R16AFX: strcpy(res, "AF'"); break;
1013 case UO_R16BC: strcpy(res, "BC"); break;
1014 case UO_R16DE: strcpy(res, "DE"); break;
1015 case UO_R16HL: strcpy(res, "HL"); break;
1016 case UO_R16IX: strcpy(res, "IX"); break;
1017 case UO_R16IY: strcpy(res, "IY"); break;
1018 case UO_R16SP: strcpy(res, "SP"); break;
1019 case UO_MSP: strcpy(res, "(SP)"); break;
1020 case UO_MBC: strcpy(res, "(BC)"); break;
1021 case UO_MDE: strcpy(res, "(DE)"); break;
1022 case UO_MHL: strcpy(res, "(HL)"); break;
1023 case UO_MIX0: strcpy(res, "(IX)"); break;
1024 case UO_MIY0: strcpy(res, "(IY)"); break;
1025 case UO_MIX:
1026 if (idx) {
1027 sprintf(res, "(IX%s%d)", (idx < 0 ? "" : "+"), idx);
1028 } else {
1029 strcpy(res, "(IX)");
1031 break;
1032 case UO_MIY:
1033 if (idx) {
1034 sprintf(res, "(IY%s%d)", (idx < 0 ? "" : "+"), idx);
1035 } else {
1036 strcpy(res, "(IY)");
1038 break;
1039 case UO_JRCOND: strcpy(res, URA_COND[(opc>>3)&0x03U]); break;
1040 case UO_COND: strcpy(res, URA_COND[(opc>>3)&0x07U]); break;
1041 case UO_BITN: sprintf(res, "%u", (opc>>3)&0x07U); break;
1042 case UO_RSTDEST:
1043 if (!urasm_disasm_decimal) sprintf(res, "#%02X", opc&0x38U); else sprintf(res, "%u", opc&0x38U);
1044 break;
1045 case UO_IM0: strcpy(res, "0"); break;
1046 case UO_IM1: strcpy(res, "1"); break;
1047 case UO_IM2: strcpy(res, "2"); break;
1048 default: strcpy(res, ""); break; /* we'll never come here */
1050 if (ismem) strcat(res, ")");
1054 /* find the corresponding record in URASM_COMMANDS */
1055 int urasm_disasm_opfind (uint16_t addr) {
1056 uint8_t buf[8];
1057 uint32_t ci, f, c;
1058 uint8_t opc;
1059 int bpos, opn, op;
1060 if (!urasm_getbyte) return -1;
1061 for (f = 0; f < 8; ++f) buf[f] = urasm_getbyte(addr+f);
1062 if (buf[0] == 0xDDU || buf[0] == 0xFDU) {
1063 /* dummy prefix */
1064 if (IS_DD_SENSITIVE(buf[1])) return (buf[0] == 0xDDU ? 0 : 1);
1066 ci = ((uint32_t)buf[0]) | (((uint32_t)buf[1])<<8) | (((uint32_t)buf[2])<<16) | (((uint32_t)buf[3])<<24);
1067 for (opn = 0; opn < URASM_MAX_COMMAND; ++opn) {
1068 /* find command */
1069 for (; opn < URASM_MAX_COMMAND && (ci&URASM_COMMANDS[opn].mask) != URASM_COMMANDS[opn].code; ++opn) {}
1070 if (!urasm_allow_zxnext && URASM_COMMANDS[opn].ops[2] == UO_NEXT) opn = URASM_MAX_COMMAND; /* skip ZXNext if not allowed */
1071 if (opn >= URASM_MAX_COMMAND) {
1072 if (buf[0] == 0xEDU) return -2;
1073 return -1;
1075 /* skip prefixes, determine command length */
1076 f = URASM_COMMANDS[opn].mask; c = URASM_COMMANDS[opn].code;
1077 for (bpos = 0; ; ++bpos) {
1078 uint8_t b;
1079 if ((f&0xFFUL) != 0xFFUL) break;
1080 b = c&0xFFUL;
1081 if (b != 0xFDU && b != 0xDDU && b != 0xEDU && b != 0xCBU) break;
1082 f >>= 8; c >>= 8;
1084 /* are there any operands? */
1085 if (URASM_COMMANDS[opn].ops[0] == UO_NONE) return opn;
1086 /* is this CB-prefixed? */
1087 if (((URASM_COMMANDS[opn].code&0xFFFFUL) == 0xCBDDUL) ||
1088 ((URASM_COMMANDS[opn].code&0xFFFFUL) == 0xCBFDUL)) ++bpos; /* skip displacement */
1089 opc = buf[bpos];
1090 /* do operands */
1091 for (f = 0; f <= 3; ++f) {
1092 if (f == 3) return opn;
1093 op = URASM_COMMANDS[opn].ops[f];
1094 if (op == UO_NONE || op == UO_NEXT) return opn;
1095 /* check for valid operand */
1096 if (op == UO_R8_NOM) {
1097 if ((opc&0x07U) == 6) break; /* bad (HL) */
1099 if (op == UO_2R8_NOM) {
1100 if (((opc>>3)&0x07U) == 6) break; /* bad (HL) */
1104 return -1;
1108 /* length of the corresponding instruction */
1109 int urasm_disasm_oplen (int idx) {
1110 int res = 0, f, op;
1111 uint32_t m, c;
1112 if (idx == -2) return 2;
1113 if (idx < 0 || idx >= URASM_MAX_COMMAND) return 1;
1114 if (idx < 2) return 1;
1115 m = URASM_COMMANDS[idx].mask; c = URASM_COMMANDS[idx].code;
1116 /* I?/CB? */
1118 if (((m&0xFFFFUL) == 0xFFFFUL) &&
1119 ((c&0xFF00UL) == 0xCBUL) && ((c&0xFFUL) == 0xDDUL || (c&0xFFUL) == 0xFDUL)) return 4;
1121 /* skip prefixes, determine command length */
1122 for (;;) {
1123 uint8_t b;
1124 if ((m&0xFFUL) != 0xFFUL) break;
1125 b = c&0xFFUL;
1126 if (b != 0xFDU && b != 0xDDU && b != 0xEDU && b != 0xCBU) break;
1127 m >>= 8; c >>= 8; ++res;
1129 /* is this CB-prefixed? */
1130 if (((URASM_COMMANDS[idx].code&0xFFFFUL) == 0xCBDDUL) ||
1131 ((URASM_COMMANDS[idx].code&0xFFFFUL) == 0xCBFDUL)) m >>= 8;
1132 /* count opcodes */
1133 while (m != 0) { m >>= 8; ++res; }
1134 /* process operands */
1135 for (f = 0; f <= 2; ++f) {
1136 op = URASM_COMMANDS[idx].ops[f];
1137 if (op == UO_NONE || op == UO_NEXT) break;
1138 switch (op) {
1139 /* command with displacement */
1140 case UO_MIX: case UO_MIY: ++res; break;
1141 /* command has immediate operand */
1142 case UO_IMM8: case UO_ADDR8: case UO_PORTIMM: ++res; break;
1143 case UO_IMM16: case UO_IMM16BE: case UO_ADDR16: case UO_MEM16: res += 2; break;
1146 return res;
1150 extern int urasm_disasm_opdisasm_ex (char *dstr, uint16_t addr, const uint8_t mem[8]) {
1151 int res, idx = 0;
1152 uint32_t ci, f, c;
1153 uint8_t opc;
1154 int bpos, opn, op;
1155 uint16_t nextW;
1156 char opstr[129];
1157 if (!dstr) return -1;
1158 if (mem[0] == 0xDDU || mem[0] == 0xFDU) {
1159 /* dummy prefix */
1160 if (IS_DD_SENSITIVE(mem[1])) {
1161 strcpy(dstr, URASM_TOKENS[mem[0]==0xDDU ? UT_NOPX : UT_NOPY]);
1162 return 1;
1164 /* take possible I? displacement */
1165 idx = (int8_t)mem[2];
1167 ci = ((uint32_t)mem[0]) | (((uint32_t)mem[1])<<8) | (((uint32_t)mem[2])<<16) | (((uint32_t)mem[3])<<24);
1168 for (opn = 0; opn < URASM_MAX_COMMAND; ++opn) {
1169 res = 0; dstr[0] = '\0';
1170 /* find command */
1171 for (; opn < URASM_MAX_COMMAND && (ci&URASM_COMMANDS[opn].mask) != URASM_COMMANDS[opn].code; ++opn) {}
1172 if (!urasm_allow_zxnext && URASM_COMMANDS[opn].ops[2] == UO_NEXT) opn = URASM_MAX_COMMAND; /* skip ZXNext if not allowed */
1173 if (opn >= URASM_MAX_COMMAND) {
1174 if (mem[0] == 0xEDU) {
1175 if (!urasm_disasm_decimal) sprintf(opstr, "#%02X,#%02X", mem[0], mem[1]); else sprintf(opstr, "%u,%u", mem[0], mem[1]);
1176 /*if (!urasm_disasm_decimal) sprintf(opstr, "#%04X", (uint16_t)buf[0]|(((uint16_t)buf[1])<<8));
1177 else sprintf(opstr, "%u", (uint16_t)buf[0]|(((uint16_t)buf[1])<<8));*/
1178 sprintf(dstr, "DB\t%s", opstr);
1179 return 2;
1181 if (!urasm_disasm_decimal) sprintf(opstr, "#%02X", mem[0]); else sprintf(opstr, "%u", mem[0]);
1182 sprintf(dstr, "DB\t%s", opstr);
1183 return 1;
1185 /* skip prefixes, determine command length */
1186 f = URASM_COMMANDS[opn].mask; c = URASM_COMMANDS[opn].code;
1187 for (bpos = 0; ; ++bpos) {
1188 uint8_t b;
1189 if ((f&0xFFUL) != 0xFFUL) break;
1190 b = c&0xFFUL;
1191 if (b != 0xFDU && b != 0xDDU && b != 0xEDU && b != 0xCBU) break;
1192 f >>= 8; c >>= 8; ++res;
1194 /* is this CB-prefixed? */
1195 if (((URASM_COMMANDS[opn].code&0xFFFFUL) == 0xCBDDUL) ||
1196 ((URASM_COMMANDS[opn].code&0xFFFFUL) == 0xCBFDUL)) f >>= 8;
1197 while (f != 0) { f >>= 8; ++res; }
1198 /* copy mnemonics */
1199 strcpy(dstr, URASM_TOKENS[URASM_COMMANDS[opn].mnemo]);
1200 /* are there any operands? */
1201 if (URASM_COMMANDS[opn].ops[0] == UO_NONE) return res;
1202 /* is this CB-prefixed? */
1203 if (((URASM_COMMANDS[opn].code&0xFFFFUL) == 0xCBDDUL) ||
1204 ((URASM_COMMANDS[opn].code&0xFFFFUL) == 0xCBFDUL)) ++bpos; /* skip displacement */
1205 else {
1206 if ((URASM_COMMANDS[opn].ops[0] == UO_MIX || URASM_COMMANDS[opn].ops[0] == UO_MIY) &&
1207 URASM_COMMANDS[opn].ops[1] == UO_IMM8 &&
1208 (URASM_COMMANDS[opn].ops[2] == UO_NONE || URASM_COMMANDS[opn].ops[2] == UO_NEXT)) ++bpos; /* skip displacement */
1210 opc = mem[bpos++];
1211 nextW = (uint16_t)mem[bpos] | (((uint16_t)mem[bpos+1])<<8);
1212 /* do operands */
1213 for (f = 0; f <= 3; ++f) {
1214 if (f == 3) {
1215 //printf("OPN=%d\n", opn);
1216 return res;
1218 op = URASM_COMMANDS[opn].ops[f];
1219 if (op == UO_NONE || op == UO_NEXT) {
1220 //printf("OPN=%d\n", opn);
1221 return res;
1223 /* check for valid operand */
1224 if (op == UO_R8_NOM) {
1225 if ((opc&0x07U) == 6) break; /* bad (HL) */
1227 if (op == UO_2R8_NOM) {
1228 if (((opc>>3)&0x07U) == 6) break; /* bad (HL) */
1230 /* command with displacement? */
1231 if (op == UO_MIX || op == UO_MIY) ++res;
1232 /* command has immediate operand? */
1233 if (op == UO_IMM8 || op == UO_ADDR8 || op == UO_PORTIMM) ++res;
1234 if (op == UO_IMM16 || op == UO_IMM16BE || op == UO_ADDR16 || op == UO_MEM16) res += 2;
1235 /* add delimiter */
1236 strcat(dstr, (f == 0 ? urasm_disasm_mnemo_delimiter : urasm_disasm_operand_delimiter));
1237 /* decode operand */
1238 ua_op2str(opstr, op, addr, opc, nextW, idx);
1239 strcat(dstr, opstr);
1242 return -1;
1246 int urasm_disasm_opdisasm (char *dstr, uint16_t addr) {
1247 uint8_t mem[8];
1248 if (!urasm_getbyte) return -1;
1249 for (unsigned f = 0; f < 8; ++f) mem[f] = urasm_getbyte((uint16_t)((addr+f)&0xffffu));
1250 return urasm_disasm_opdisasm_ex(dstr, addr, mem);
1254 ///////////////////////////////////////////////////////////////////////////////
1255 // assembler
1257 /* returns 0 if label name conflicts with reserved word */
1258 /* (or if the label is just a bad one) */
1259 int urasm_is_valid_name (const char *lbl) {
1260 int f, hasNA = 0;
1261 char ch, buf[6];
1262 if (!lbl || !lbl[0]) return 0;
1263 if (lbl[0] == '@') {
1264 ch = lbl[1];
1265 } else {
1266 ch = lbl[0];
1268 if (ch >= '0' && ch <= '9') return 0;
1269 if (!ur_isalpha(ch) && ch != '.' && ch != '_' && ch != '@') return 0;
1270 for (f = 1; lbl[f]; ++f) {
1271 ch = lbl[f];
1272 if (ch >= '0' && ch <= '9') continue;
1273 if (!ur_isalpha(ch)) {
1274 hasNA = 1;
1275 if (ch != '$' && ch != '.' && ch != '_' && ch != '@') return 0;
1278 if (hasNA || f > 4) return 1;
1279 for (f = 0; lbl[f]; ++f) buf[f] = ur_toupper(lbl[f]); buf[f] = '\0';
1280 for (f = 0; f < (!urasm_allow_zxnext ? URASM_MAX_NORMAL_TOKEN : URASM_MAX_TOKEN); ++f) if (!strcmp(buf, URASM_TOKENS[f])) return 0;
1281 for (f = 0; f < 8; ++f) if (!strcmp(buf, URA_REGS8[f])) return 0;
1282 for (f = 0; f < 4; ++f) if (!strcmp(buf, URA_REGS16[f])) return 0;
1283 for (f = 0; f < 4; ++f) if (!strcmp(buf, URA_REGS16A[f])) return 0;
1284 for (f = 0; f < 8; ++f) if (!strcmp(buf, URA_COND[f])) return 0;
1285 if (!strcmp(buf, "AFX")) return 0;
1286 if (!strcmp(buf, "IXH")) return 0;
1287 if (!strcmp(buf, "IXL")) return 0;
1288 if (!strcmp(buf, "IYH")) return 0;
1289 if (!strcmp(buf, "IYL")) return 0;
1290 if (!strcmp(buf, "IX")) return 0;
1291 if (!strcmp(buf, "IY")) return 0;
1292 if (!strcmp(buf, "XH")) return 0;
1293 if (!strcmp(buf, "HX")) return 0;
1294 if (!strcmp(buf, "XL")) return 0;
1295 if (!strcmp(buf, "LX")) return 0;
1296 if (!strcmp(buf, "YH")) return 0;
1297 if (!strcmp(buf, "HY")) return 0;
1298 if (!strcmp(buf, "YL")) return 0;
1299 if (!strcmp(buf, "LY")) return 0;
1300 if (!strcmp(buf, "R")) return 0;
1301 if (!strcmp(buf, "I")) return 0;
1302 return 1;
1306 ///////////////////////////////////////////////////////////////////////////////
1307 // scanner / parser
1309 // parse and calculate expression
1310 static inline const char *skip_blanks (const char *expr) {
1311 while (*expr && ur_isspace(*expr)) ++expr;
1312 return expr;
1316 ///////////////////////////////////////////////////////////////////////////////
1317 // expression parser
1318 urasm_getval_fn urasm_getval = NULL;
1319 urasm_expand_fn urasm_expand = NULL;
1322 typedef struct ur_function_s {
1323 struct ur_function_s *next;
1324 char *name;
1325 urasm_func_fn fn;
1326 } ur_function_t;
1328 static ur_function_t *fnlist = NULL;
1330 static void atexit_func_finalize (void) {
1331 while (fnlist != NULL) {
1332 ur_function_t *f = fnlist;
1333 fnlist = f->next;
1334 free(f->name);
1335 free(f);
1340 void urasm_expr_register_func (const char *name, urasm_func_fn fn) {
1341 if (name != NULL && name[0]) {
1342 static int atexitset = 0;
1343 ur_function_t *p, *c;
1344 if (!atexitset) { atexit(atexit_func_finalize); atexitset = 1; }
1345 for (p = NULL, c = fnlist; c != NULL; p = c, c = c->next) {
1346 if (strcasecmp(name, c->name) == 0) {
1347 /* replace or remove */
1348 if (fn == NULL) {
1349 /* remove */
1350 if (p == NULL) fnlist = c->next; else p->next = c->next;
1351 free(c->name);
1352 free(c);
1353 } else {
1354 /* replace */
1355 c->fn = fn;
1357 return;
1360 if (fn != NULL) {
1361 /* add new */
1362 c = malloc(sizeof(*c));
1363 c->name = strdup(name);
1364 c->fn = fn;
1365 c->next = fnlist;
1366 fnlist = c;
1372 urasm_func_fn urasm_expr_find_func (const char *name) {
1373 if (name != NULL && name[0]) {
1374 for (ur_function_t *c = fnlist; c != NULL; c = c->next) if (strcasecmp(name, c->name) == 0) return c->fn;
1376 return NULL;
1380 ///////////////////////////////////////////////////////////////////////////////
1381 typedef struct {
1382 const char *expr; /* can be changed */
1383 uint16_t addr; /* current address */
1384 int defined; /* !0: all used labels are defined */
1385 int error; /* !0: error */
1386 const char *errpos; /* will be set on error, has no meaning otherwise */
1387 jmp_buf errJP;
1388 int logic_done;
1389 int32_t logic_res;
1390 } expr_info_t;
1393 /* do math; op0 is the result */
1394 typedef void (*expr_doit_fn) (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei);
1396 enum {
1397 optype_none,
1398 optype_unary,
1399 optype_math,
1400 optype_bitwise,
1401 optype_shift,
1402 optype_logic,
1403 optype_comparison,
1406 typedef struct {
1407 char sn; /* short name or 0 */
1408 const char *ln; /* long name or NULL if `sn`!=0 */
1409 int prio; /* priority */
1410 expr_doit_fn doer;
1411 int type;
1412 } expr_operator_t;
1415 ///////////////////////////////////////////////////////////////////////////////
1416 // math ops
1417 /* returns !0 is passed string is not NULL, and longer than 2 chars */
1418 static inline __attribute__((always_inline)) __attribute__((pure))
1419 int ur_is_long_str (const char *s) { return (s && s[0] && s[1] && s[2]); }
1421 #define EERROR(code) longjmp(ei->errJP, code)
1423 #define CHECKVALNOTSTR(_v,_vkill) do { \
1424 if ((_v)->str != NULL) { \
1425 if (ur_is_long_str((_v)->str)) { \
1426 if ((_vkill) != NULL) urasm_exprval_clear((_vkill)); \
1427 EERROR(UR_EXPRERR_TYPE); \
1429 free((_v)->str); \
1430 (_v)->str = NULL; \
1432 } while (0)
1434 #define CHECKARGSNOTSTR do { \
1435 CHECKVALNOTSTR(op0, op1); \
1436 CHECKVALNOTSTR(op1, op1); \
1437 } while (0)
1440 #define PROPAGATE_FIXUP do { \
1441 if (op0->fixuptype == UR_FIXUP_NONE) { \
1442 op0->fixuptype = op1->fixuptype; \
1443 } else if (op0->fixuptype == UR_FIXUP_WORD) { \
1444 if (op1->fixuptype != UR_FIXUP_NONE) op0->fixuptype = op1->fixuptype; \
1445 } else if (op1->fixuptype != UR_FIXUP_NONE && op0->fixuptype != op1->fixuptype) { \
1446 urasm_exprval_clear(op1);\
1447 urasm_exprval_clear(op0); \
1448 EERROR(UR_EXPRERR_FIXUP); \
1450 } while (0)
1453 static void mdo_bitnot (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) {
1454 op0->val = ~op0->val;
1455 op0->fixuptype = UR_FIXUP_NONE;
1457 static void mdo_lognot (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) {
1458 op0->val = !op0->val;
1459 op0->fixuptype = UR_FIXUP_NONE;
1461 static void mdo_uminus (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) {
1462 op0->val = -op0->val;
1463 op0->fixuptype = UR_FIXUP_NONE;
1465 static void mdo_uplus (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) {
1468 static void mdo_bitand (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) {
1469 op0->val &= op1->val;
1470 if (op1->val == 0) op0->fixuptype = UR_FIXUP_NONE;
1471 else if (op0->fixuptype != UR_FIXUP_NONE) {
1472 switch (op1->val) {
1473 case 0x00ff: op0->fixuptype = (op0->fixuptype == UR_FIXUP_WORD ? UR_FIXUP_LOBYTE : UR_FIXUP_NONE); break;
1474 case 0xff00: op0->fixuptype = (op0->fixuptype == UR_FIXUP_WORD ? UR_FIXUP_HIBYTE : UR_FIXUP_NONE); break;
1476 } else {
1477 PROPAGATE_FIXUP;
1480 static void mdo_bitor (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { op0->val |= op1->val; op0->fixuptype = UR_FIXUP_NONE; }
1481 static void mdo_bitxor (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { op0->val ^= op1->val; op0->fixuptype = UR_FIXUP_NONE; }
1482 static void mdo_shl (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { op0->val <<= op1->val; op0->fixuptype = UR_FIXUP_NONE; }
1483 static void mdo_shr (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { op0->val >>= op1->val; }
1484 static void mdo_shru (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { *(uint32_t *)&op0->val >>= op1->val; }
1485 static void mdo_mul (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { op0->val *= op1->val; op0->fixuptype = UR_FIXUP_NONE; }
1486 static void mdo_div (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { if (op1->val == 0) EERROR(UR_EXPRERR_DIV0); op0->val /= op1->val; op0->fixuptype = UR_FIXUP_NONE; }
1487 static void mdo_mod (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { if (op1->val == 0) EERROR(UR_EXPRERR_DIV0); op0->val %= op1->val; op0->fixuptype = UR_FIXUP_NONE; }
1488 static void mdo_add (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { op0->val += op1->val; PROPAGATE_FIXUP; }
1489 static void mdo_sub (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { op0->val -= op1->val; PROPAGATE_FIXUP; }
1491 static int mdo_compare (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) {
1492 const int isnum0 = !ur_is_long_str(op0->str);
1493 const int isnum1 = !ur_is_long_str(op1->str);
1494 //fprintf(stderr, "mdo_compare: num0=%d; num1=%d (%s) (%s)\n", isnum0, isnum1, op0->str, op1->str);
1495 if (isnum0 != isnum1) EERROR(UR_EXPRERR_TYPES);
1496 if (isnum0) {
1497 return
1498 op0->val < op1->val ? -1 :
1499 op0->val > op1->val ? 1 :
1501 } else {
1502 return strcmp(op0->str, op1->str);
1506 static void mdo_set_int (urasm_exprval_t *op0, const int32_t v) {
1507 urasm_exprval_clear(op0);
1508 op0->val = v;
1511 static void mdo_cmp_ls (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { mdo_set_int(op0, (mdo_compare(op0, op1, ei) < 0)); }
1512 static void mdo_cmp_gt (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { mdo_set_int(op0, (mdo_compare(op0, op1, ei) > 0)); }
1513 static void mdo_cmp_eq (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { mdo_set_int(op0, (mdo_compare(op0, op1, ei) == 0)); }
1514 static void mdo_cmp_ne (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { mdo_set_int(op0, (mdo_compare(op0, op1, ei) != 0)); }
1515 static void mdo_cmp_le (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { mdo_set_int(op0, (mdo_compare(op0, op1, ei) <= 0)); }
1516 static void mdo_cmp_ge (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { mdo_set_int(op0, (mdo_compare(op0, op1, ei) >= 0)); }
1518 static void mdo_log_and (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) {
1519 ei->logic_res = op0->val = (op0->val && op1->val);
1520 if (!op0->val) ei->logic_done = 1;
1521 op0->fixuptype = UR_FIXUP_NONE;
1524 static void mdo_log_or (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) {
1525 ei->logic_res = op0->val = (op0->val || op1->val);
1526 if (op0->val) ei->logic_done = 1;
1527 op0->fixuptype = UR_FIXUP_NONE;
1531 // priority level 1 -- opertiors line "." and "[]", function calls
1532 // priority level 2 -- unary opertiors like "!" and "~"
1533 // short forms must be put before long
1534 // priorities must be sorted
1535 static const expr_operator_t operators_old[] = {
1536 // unaries
1537 { '~', NULL, 2, mdo_bitnot, optype_unary },
1538 { '!', NULL, 2, mdo_lognot, optype_unary },
1539 { '-', NULL, 2, mdo_uminus, optype_unary },
1540 { '+', NULL, 2, mdo_uplus, optype_unary },
1541 // shifts
1542 { 0, "<<", 3, mdo_shl, optype_shift },
1543 { 0, ">>", 3, mdo_shr, optype_shift },
1544 { 0, ">>>", 3, mdo_shru, optype_shift },
1545 // bitwise and
1546 { '&', NULL, 4, mdo_bitand, optype_bitwise },
1547 // bitwise or and xor
1548 { '|', NULL, 5, mdo_bitor, optype_bitwise },
1549 { '^', NULL, 5, mdo_bitxor, optype_bitwise },
1550 // mul/div/mod
1551 { '*', NULL, 6, mdo_mul, optype_math },
1552 { '/', NULL, 6, mdo_div, optype_math },
1553 { '%', NULL, 6, mdo_mod, optype_math },
1554 // add/subtract
1555 { '+', NULL, 7, mdo_add, optype_math },
1556 { '-', NULL, 7, mdo_sub, optype_math },
1557 // logic and
1558 { 0, "&&", 8, mdo_log_and, optype_logic },
1559 // logic or
1560 { 0, "||", 9, mdo_log_or, optype_logic },
1561 // comparisons
1562 { '<', NULL, 10, mdo_cmp_ls, optype_comparison },
1563 { '>', NULL, 10, mdo_cmp_gt, optype_comparison },
1564 { '=', NULL, 10, mdo_cmp_eq, optype_comparison },
1565 { 0, "==", 10, mdo_cmp_eq, optype_comparison },
1566 { 0, "!=", 10, mdo_cmp_ne, optype_comparison },
1567 { 0, "<>", 10, mdo_cmp_ne, optype_comparison },
1568 { 0, "<=", 10, mdo_cmp_le, optype_comparison },
1569 { 0, ">=", 10, mdo_cmp_ge, optype_comparison },
1570 // no more
1571 { 0, NULL, -1, NULL, optype_none },
1573 // new C-like priorities
1574 static const expr_operator_t operators_new[] = {
1575 // unaries
1576 { '~', NULL, 2, mdo_bitnot, optype_unary },
1577 { '!', NULL, 2, mdo_lognot, optype_unary },
1578 { '-', NULL, 2, mdo_uminus, optype_unary },
1579 { '+', NULL, 2, mdo_uplus, optype_unary },
1580 // shifts
1581 { 0, "<<", 3, mdo_shl, optype_shift },
1582 { 0, ">>", 3, mdo_shr, optype_shift },
1583 { 0, ">>>", 3, mdo_shru, optype_shift },
1584 // bitwise and
1585 { '&', NULL, 4, mdo_bitand, optype_bitwise },
1586 // bitwise or and xor
1587 { '|', NULL, 5, mdo_bitor, optype_bitwise },
1588 { '^', NULL, 5, mdo_bitxor, optype_bitwise },
1589 // mul/div/mod
1590 { '*', NULL, 6, mdo_mul, optype_math },
1591 { '/', NULL, 6, mdo_div, optype_math },
1592 { '%', NULL, 6, mdo_mod, optype_math },
1593 // add/subtract
1594 { '+', NULL, 7, mdo_add, optype_math },
1595 { '-', NULL, 7, mdo_sub, optype_math },
1596 // comparisons
1597 { '<', NULL, 8, mdo_cmp_ls, optype_comparison },
1598 { '>', NULL, 8, mdo_cmp_gt, optype_comparison },
1599 { '=', NULL, 8, mdo_cmp_eq, optype_comparison },
1600 { 0, "==", 8, mdo_cmp_eq, optype_comparison },
1601 { 0, "!=", 8, mdo_cmp_ne, optype_comparison },
1602 { 0, "<>", 8, mdo_cmp_ne, optype_comparison },
1603 { 0, "<=", 8, mdo_cmp_le, optype_comparison },
1604 { 0, ">=", 8, mdo_cmp_ge, optype_comparison },
1605 // logic and
1606 { 0, "&&", 9, mdo_log_and, optype_logic },
1607 // logic or
1608 { 0, "||", 10, mdo_log_or, optype_logic },
1609 // no more
1610 { 0, NULL, -1, NULL, optype_none },
1612 #define UNARY_PRIO (2)
1614 #define MAX_PRIO (10)
1615 #define PRIO_LAND (8)
1616 #define PRIO_LOR (9)
1618 static int max_prio_old = 0;
1619 static int prio_land_old = 0;
1620 static int prio_lor_old = 0;
1622 static int max_prio = 0;
1623 static int prio_land = 0;
1624 static int prio_lor = 0;
1626 int urasm_use_old_priorities = 0;
1628 static inline __attribute__((always_inline)) int get_max_prio () { return (!urasm_use_old_priorities ? max_prio : max_prio_old); }
1629 static inline __attribute__((always_inline)) int get_land_prio () { return (!urasm_use_old_priorities ? prio_land : prio_land_old); }
1630 static inline __attribute__((always_inline)) int get_lor_prio () { return (!urasm_use_old_priorities ? prio_lor : prio_lor_old); }
1632 static __attribute((constructor)) void init_priorities (void) {
1633 if (max_prio_old) return;
1634 // old priorities
1635 for (const expr_operator_t *op = operators_old; op->prio >= 0; ++op) {
1636 if (max_prio_old < op->prio) max_prio_old = op->prio;
1637 if (op->doer == &mdo_log_and) prio_land_old = op->prio;
1638 else if (op->doer == &mdo_log_or) prio_lor_old = op->prio;
1640 // new priorities
1641 for (const expr_operator_t *op = operators_new; op->prio >= 0; ++op) {
1642 if (max_prio < op->prio) max_prio = op->prio;
1643 if (op->doer == &mdo_log_and) prio_land = op->prio;
1644 else if (op->doer == &mdo_log_or) prio_lor = op->prio;
1649 /******************************************************************************/
1650 /* expression parser engine */
1651 /******************************************************************************/
1652 static void expression (urasm_exprval_t *res, expr_info_t *ei);
1655 #define SKIP_BLANKS { ei->errpos = ei->expr = skip_blanks(ei->expr); }
1657 #define PSEMITCHAR(_ch) do { \
1658 if (!doinglen) res->str[len++] = (_ch); else ++len; \
1659 } while (0)
1661 // qch skipped
1662 static const char *parse_string (urasm_exprval_t *res, char qch, const char *expr, int *error, int *lenp) {
1663 int doinglen = 2;
1664 if (lenp) *lenp = 0;
1665 if (*error) return expr;
1666 if (!expr[0]) { *error = 1; return expr; }
1667 //memset(buf, 0, sizeof(buf));
1668 for (;;) {
1669 int len = 0, n, f, base;
1670 const char *a = expr;
1671 --doinglen;
1672 for (; *a; ++a) {
1673 if (*a == '\\') {
1674 if (!a[1]) break;
1675 switch (*(++a)) {
1676 case 'a': PSEMITCHAR('\a'); break;
1677 case 'b': PSEMITCHAR('\b'); break;
1678 case 'e': PSEMITCHAR('\x1b'); break;
1679 case 'f': PSEMITCHAR('\f'); break;
1680 case 'n': PSEMITCHAR('\n'); break;
1681 case 'r': PSEMITCHAR('\r'); break;
1682 case 't': PSEMITCHAR('\t'); break;
1683 case 'v': PSEMITCHAR('\v'); break;
1684 case 'z': PSEMITCHAR('\0'); break;
1685 case 'x': case 'X': /* hex */
1686 ++a; /* skip 'x' */
1687 base = 16; f = 2;
1688 donum: for (n = 0; f > 0; --f) {
1689 char ch = dig2n(*a++, base);
1690 if (ch < 0) { --a; break; }
1691 n *= base;
1692 n += ch;
1694 PSEMITCHAR(n);
1695 --a; /* return to the last digit, 'for' will skip it */
1696 break;
1697 case '0': /* octal */
1698 base = 8; f = 4;
1699 goto donum;
1700 case '1' ... '9': /* decimal */
1701 base = 10; f = 3;
1702 goto donum;
1703 default: PSEMITCHAR(a[0]); break; /* others */
1705 } else {
1706 if (*a == qch) { ++a; break; }
1707 PSEMITCHAR(*a);
1710 if (doinglen) {
1711 res->str = calloc(len+1, 1);
1712 if (lenp) *lenp = len;
1713 } else {
1714 return a;
1720 static int try_suffix_base (const char *s, char sfx, int base) {
1721 if (!s || !s[0]) return 0;
1722 while (*s == '_') ++s; /* just in case */
1723 if (dig2n(*s++, base) < 0) return 0;
1724 /* we don't need to check for zero here, because `dig2n()` will do this for us */
1725 for (;;) {
1726 const char ch = *s++;
1727 if (ch != '_' && dig2n(ch, base) < 0) {
1728 return (ur_toupper(ch) == sfx && (!ch || dig2n(*s, 16) < 0));
1734 /*TODO: make suffix detector one-pass */
1735 static int check_number_base_sfx (const char *s) {
1736 if (!s || !s[0]) return 0;
1737 while (*s == '_') ++s; /* just in case */
1738 /* check suffixes (suffix char must be passed as uppercase) */
1739 if (try_suffix_base(s, 'H', 16)) return 16;
1740 if (try_suffix_base(s, 'B', 2)) return 2;
1741 if (try_suffix_base(s, 'O', 8)) return 9;
1742 return 0;
1746 static int check_number_base_char (char ch) {
1747 switch (ur_toupper(ch)) {
1748 case 'X': case 'H': return 16;
1749 case 'B': return 2;
1750 case 'O': return 8;
1751 case 'D': return 10;
1752 default: break;
1754 return 0;
1758 static const char *parse_number (urasm_exprval_t *res, const char *expr, int *error) {
1759 int prefixed = 1;
1760 if (*error) return expr;
1761 if (!expr[0]) { *error = 1; return expr; }
1762 const char *estart = expr;
1763 /* detect suffix first */
1764 int base = check_number_base_sfx(expr);
1765 if (base) {
1766 /* the suffix is ok */
1767 prefixed = 0; /* note that it is suffixed number, not prefixed */
1768 } else {
1769 /* no good suffix, check prefixes */
1770 switch (*expr) {
1771 case '0': /* this allows "0habcd" as hex number too; why not? */
1772 base = check_number_base_char(expr[1]);
1773 if (base) expr += 2; else base = 8;
1774 break;
1775 case '%': base = 2; ++expr; break;
1776 case '#': case '$': base = 16; ++expr; break;
1777 case '1' ... '9': base = 10; break;
1778 case '&':
1779 base = check_number_base_char(expr[1]);
1780 if (base) { expr += 2; break; }
1781 /* fallthru */
1782 default: *error = 1; return estart;
1785 /* parse number (ignore underscores) */
1786 while (*expr && *expr == '_') ++expr;
1787 if (dig2n(*expr, base) < 0) { *error = 1; return estart; }
1788 int n = 0;
1789 for (;;) {
1790 char ch = *expr++;
1791 if (ch == '_') continue;
1792 int d = dig2n(ch, base);
1793 if (d < 0) { res->val = n; return expr-prefixed; } /* `prefixed` set to 1 if there's no suffix */
1794 n *= base;
1795 /* this check is UB in standards-compliant C. because standard was created by morons. */
1796 if (n < 0) { *error = 1; return estart; }
1797 n += d;
1802 static void get_addr (const char *lbl, urasm_exprval_t *res, expr_info_t *ei) {
1803 int defined = 0, found = 0;
1804 int32_t val = 0;
1805 if (urasm_label_by_name == NULL) EERROR(UR_EXPRERR_LABEL);
1806 res->fixuptype = UR_FIXUP_NONE;
1807 val = urasm_label_by_name(lbl, ei->addr, &defined, &found, &res->fixuptype);
1808 if (!found) EERROR(UR_EXPRERR_LABEL);
1809 if (!defined) ei->defined = 0;
1810 res->val = val;
1814 // !0: invalid label
1815 static int read_label_name (char *buf, expr_info_t *ei) {
1816 int pos = 0;
1817 for (;;) {
1818 if (pos >= 128) return -3;
1819 char ch = ei->expr[0];
1820 if (!ch) break;
1821 if (ur_isalnum(ch) || ch == '$' || ch == '.' || ch == '_' || ch == '@') {
1822 buf[pos++] = ch;
1823 ++(ei->expr);
1824 } else {
1825 break;
1828 if (pos < 1) return -2;
1829 buf[pos] = '\0';
1830 if (!urasm_is_valid_name(buf)) return -1;
1831 return 0;
1835 static void term (urasm_exprval_t *res, expr_info_t *ei) {
1836 char ch, lbl[130];
1837 int tmp = 0, len;
1838 if (res->str != NULL) { free(res->str); res->str = NULL; }
1839 SKIP_BLANKS
1840 ch = (res->pos = ei->errpos = ei->expr)[0];
1841 if (!ch) EERROR(UR_EXPRERR_EOS);
1842 switch (ch) {
1843 case '[': case '(':
1844 ++(ei->expr);
1845 ch = (ch == '[' ? ']' : ')');
1846 expression(res, ei);
1847 if (ei->expr[0] != ch) EERROR(UR_EXPRERR_PARENS);
1848 ++(ei->expr);
1849 break;
1850 case '0' ... '9': case '#': case '%':
1851 donumber:
1852 ei->expr = parse_number(res, ei->expr, &tmp);
1853 if (tmp) EERROR(UR_EXPRERR_NUMBER);
1854 break;
1855 case '$':
1856 if (dig2n(ei->expr[1], 16) >= 0) goto donumber;
1857 res->val = ei->addr;
1858 res->fixuptype = UR_FIXUP_WORD;
1859 ++(ei->expr);
1860 break;
1861 case '&':
1862 if (ur_toupper(ei->expr[1]) == 'H' && dig2n(ei->expr[2], 16) >= 0) goto donumber;
1863 if (ur_toupper(ei->expr[1]) == 'X' && dig2n(ei->expr[2], 16) >= 0) goto donumber;
1864 if (ur_toupper(ei->expr[1]) == 'O' && dig2n(ei->expr[2], 8) >= 0) goto donumber;
1865 if (ur_toupper(ei->expr[1]) == 'B' && dig2n(ei->expr[2], 2) >= 0) goto donumber;
1866 if (ur_toupper(ei->expr[1]) == 'D' && dig2n(ei->expr[2], 10) >= 0) goto donumber;
1867 goto dodefault;
1868 case '"': /* char or 2 chars */
1869 case '\'': /* char or 2 reversed chars */
1870 res->val = 0;
1871 ei->expr = parse_string(res, ch, ei->expr+1, &tmp, &len);
1872 if (tmp) EERROR(UR_EXPRERR_STRING);
1873 if (len == 1) {
1874 res->val = (unsigned char)res->str[0];
1875 } else if (len >= 2) {
1876 res->val = ((unsigned char)res->str[0])<<(ch == '"' ? 0 : 8);
1877 res->val |= ((unsigned char)res->str[1])<<(ch == '"' ? 8 : 0);
1879 break;
1880 case ';':
1881 case ':':
1882 EERROR(UR_EXPRERR_TERM);
1883 case ')':
1884 case ']':
1885 return;
1886 case '=':
1887 case '*':
1888 if (urasm_getval != NULL) {
1889 ei->expr = urasm_getval(res, ei->expr, ei->addr, ei->logic_done, &ei->defined, &ei->error);
1890 if (ei->error != UR_EXPRERR_NONE) EERROR(ei->error);
1891 } else {
1892 EERROR(UR_EXPRERR_MARG);
1894 break;
1895 default:
1896 dodefault:
1897 if (read_label_name(lbl, ei)) EERROR(UR_EXPRERR_LABEL);
1898 SKIP_BLANKS
1899 if (ei->expr[0] == '(') {
1900 /* function call */
1901 urasm_func_fn fn = urasm_expr_find_func(lbl);
1902 const char *e;
1903 if (fn == NULL) EERROR(UR_EXPRERR_FUNC);
1904 ++(ei->expr); /* skip '(' */
1905 e = fn(res, ei->expr, ei->addr, ei->logic_done, &ei->defined, &ei->error);
1906 if (ei->error != UR_EXPRERR_NONE) EERROR(ei->error);
1907 else if (e == NULL) EERROR(UR_EXPRERR_FUNC);
1908 else ei->expr = e;
1909 } else {
1910 /* just a label */
1911 if (!ei->logic_done) get_addr(lbl, res, ei);
1913 break;
1918 static const expr_operator_t *get_operator (int prio, expr_info_t *ei) {
1919 const char opc = ei->expr[0];
1920 int oplen = 1;
1921 const expr_operator_t *res = NULL;
1922 for (const expr_operator_t *op = (!urasm_use_old_priorities ? operators_new : operators_old); op->prio >= 0; ++op) {
1923 if (op->sn) {
1924 //fprintf(stderr, "get_operator: prio=%d; sn=%c; opc=%c\n", prio, op->sn, opc);
1925 if (op->prio == prio && oplen <= 1 && opc == op->sn) { res = op; oplen = 1; }
1926 } else {
1927 const int l = (int)strlen(op->ln);
1928 if (l > oplen && strncmp(ei->expr, op->ln, l) == 0) { res = op; oplen = l; }
1931 if (res && res->prio != prio) res = NULL;
1932 //if (res) fprintf(stderr, "res: prio=%d; sn='%c' \"%s\" (%d : %.*s)\n", prio, res->sn, res->ln, oplen, (unsigned)oplen, ei->expr);
1933 if (res) ei->expr += oplen; /* eat operator */
1934 return res;
1938 #define CHECKNOTSTR do { \
1939 if (ur_is_long_str(res->str) || ur_is_long_str(o1.str)) { \
1940 urasm_exprval_clear(&o1); \
1941 urasm_exprval_clear(res); \
1942 EERROR(UR_EXPRERR_TYPE); \
1944 } while (0)
1947 static void expr_do (int prio, urasm_exprval_t *res, expr_info_t *ei) {
1948 const expr_operator_t *op;
1949 urasm_exprval_t o1;
1950 SKIP_BLANKS
1951 if (ei->expr[0] == ')' || ei->expr[0] == ']') return;
1952 if (prio <= 0) { term(res, ei); return; }
1953 urasm_exprval_init(&o1);
1954 //fprintf(stderr, "expr_do: prio=%d <%s>\n", prio, ei->expr);
1955 if (prio == UNARY_PRIO) {
1956 //fprintf(stderr, "expr_do: prio=%d <%s>\n", prio, ei->expr);
1957 int wasIt = 0;
1958 for (;;) {
1959 SKIP_BLANKS
1960 ei->errpos = ei->expr;
1961 if (!(op = get_operator(prio, ei))) break;
1962 //fprintf(stderr, "UNARY: op=%c\n", op->sn);
1963 //expression(res, ei);
1964 if (op->sn == '-' || op->sn == '+') {
1965 expr_do(prio-1, res, ei); /* left-associative */
1966 } else {
1967 expr_do(prio, res, ei); /* right-associative */
1969 if (!ei->logic_done) {
1970 CHECKNOTSTR;
1971 op->doer(res, &o1, ei);
1972 } else {
1973 res->fixuptype = UR_FIXUP_NONE;
1974 res->val = ei->logic_res;
1976 wasIt = 1;
1977 if (op->sn == '-' || op->sn == '+') break;
1979 if (!wasIt) expr_do(prio-1, res, ei); /* left-associative */
1980 return;
1982 /* first operand */
1983 expr_do(prio-1, res, ei); /* first operand, left-associative */
1984 /* go on */
1985 for (;;) {
1986 SKIP_BLANKS
1987 ei->errpos = ei->expr;
1988 if (!ei->expr[0] || ei->expr[0] == ';' || ei->expr[0] == ':' || ei->expr[0] == ')' || ei->expr[0] == ']') break;
1989 //fprintf(stderr, "BINARY: prio=%d; expr=<%s>\n", prio, ei->expr);
1990 if (!(op = get_operator(prio, ei))) break;
1991 if (!ei->logic_done) {
1992 if (prio == get_land_prio()) {
1993 /* && */
1994 if (!res->val) { ei->logic_done = 1; ei->logic_res = 0; }
1995 } else if (prio == get_lor_prio()) {
1996 /* || */
1997 if (res->val) { ei->logic_done = 1; ei->logic_res = res->val; }
2000 //fprintf(stderr, "BINARY:000: prio=%d; expr=<%s>; op=%c(%s)\n", prio, ei->expr, op->sn, op->ln);
2001 expr_do(prio-1, &o1, ei); /* second operand, left-associative */
2002 //fprintf(stderr, "BINARY:001: prio=%d; expr=<%s>; op=%c(%s)\n", prio, ei->expr, op->sn, op->ln);
2003 if (!ei->logic_done) {
2004 if (op->type != optype_comparison) {
2005 CHECKNOTSTR;
2007 //fprintf(stderr, "DOER:BEFORE: op=%c(%s); prio=%d; val=%d (%d : %d)\n", op->sn, op->ln, op->prio, res->val, ei->logic_done, ei->logic_res);
2008 op->doer(res, &o1, ei);
2009 //fprintf(stderr, "DOER:AFTER: val=%d (%d : %d)\n", res->val, ei->logic_done, ei->logic_res);
2010 urasm_exprval_clear(&o1);
2011 } else {
2012 res->fixuptype = UR_FIXUP_NONE;
2013 res->val = ei->logic_res;
2019 static void expression (urasm_exprval_t *res, expr_info_t *ei) {
2020 SKIP_BLANKS
2021 ei->errpos = ei->expr;
2022 if (!ei->expr[0]) EERROR(UR_EXPRERR_EOS);
2023 expr_do(get_max_prio(), res, ei);
2024 SKIP_BLANKS
2028 const char *urasm_expr_ex (urasm_exprval_t *res, const char *expr, uint16_t addr, int *donteval, int *defined, int *error) {
2029 expr_info_t ei;
2030 int jr;
2031 urasm_exprval_clear(res);
2032 if (error) *error = 0;
2033 if (!expr) { if (error) *error = UR_EXPRERR_EOS; return NULL; }
2034 if (res->str != NULL) { free(res->str); res->str = NULL; }
2035 ei.expr = expr;
2036 ei.addr = addr;
2037 ei.defined = (defined ? *defined : 1);
2038 ei.error = 0;
2039 ei.logic_done = (donteval ? *donteval : 0);
2040 ei.logic_res = 0;
2041 jr = setjmp(ei.errJP);
2042 if (jr) {
2043 urasm_exprval_clear(res);
2044 if (error) *error = ei.error;
2045 return ei.errpos;
2047 expression(res, &ei);
2048 if (defined) *defined = ei.defined;
2049 if (donteval) *donteval = ei.logic_done;
2050 return ei.expr;
2054 const char *urasm_expr (int32_t *res, const char *expr, uint16_t addr, int *defined, int *fixuptype, int *error) {
2055 urasm_exprval_t r;
2056 const char *ret;
2057 int err;
2058 if (defined) *defined = 1;
2059 if (fixuptype) *fixuptype = UR_FIXUP_NONE;
2060 urasm_exprval_init(&r);
2061 ret = urasm_expr_ex(&r, expr, addr, NULL, defined, &err);
2062 if (error) *error = err;
2063 if (!err) {
2064 if (fixuptype) *fixuptype = r.fixuptype;
2065 if (ur_is_long_str(r.str)) {
2066 if (error) *error = UR_EXPRERR_TYPE;
2067 ret = r.pos;
2068 } else if (res) {
2069 *res = r.val;
2071 } else {
2072 if (res) *res = 0;
2074 urasm_exprval_clear(&r);
2075 return ret;
2079 void urasm_exprval_init (urasm_exprval_t *res) {
2080 if (res != NULL) {
2081 memset(res, 0, sizeof(*res));
2082 res->fixuptype = UR_FIXUP_NONE;
2087 void urasm_exprval_clear (urasm_exprval_t *res) {
2088 if (res != NULL) {
2089 if (res->str != NULL) {
2090 free(res->str);
2091 res->str = NULL;
2093 res->val = 0;
2094 res->fixuptype = UR_FIXUP_NONE;
2099 void urasm_exprval_setint (urasm_exprval_t *res, int32_t v) {
2100 if (res->str) { free(res->str); res->str = NULL; }
2101 res->val = v;
2105 /* sets val as in double quotes */
2106 void urasm_exprval_tostr (urasm_exprval_t *res, const char *str) {
2107 if (!str) {
2108 urasm_exprval_setint(res, 0);
2109 } else {
2110 const size_t slen = strlen(str);
2111 res->str = realloc(res->str, slen+1);
2112 strcpy(res->str, str);
2113 if (slen == 1) {
2114 res->val = (unsigned char)res->str[0];
2115 } else {
2116 res->val = (unsigned char)res->str[0];
2117 res->val |= ((unsigned char)res->str[1])<<8;
2123 /* sets val as in single quotes */
2124 void urasm_exprval_tostr_rev (urasm_exprval_t *res, const char *str) {
2125 if (!str) {
2126 urasm_exprval_setint(res, 0);
2127 } else {
2128 const size_t slen = strlen(str);
2129 res->str = realloc(res->str, slen+1);
2130 strcpy(res->str, str);
2131 if (slen == 1) {
2132 res->val = (unsigned char)res->str[0];
2133 } else {
2134 res->val = ((unsigned char)res->str[0])<<8;
2135 res->val |= (unsigned char)res->str[1];
2141 ///////////////////////////////////////////////////////////////////////////////
2142 // operand parser
2144 const char *urasm_skip_operand (const char *expr, int *seenarg) {
2145 if (seenarg) *seenarg = 0;
2146 if (!expr) return NULL;
2147 expr = skip_blanks(expr);
2148 if (!expr[0] || expr[0] == ';') return NULL;
2149 if (expr[0] == ':' || expr[0] == ',') return expr; /* colon or comma, nothing to do here */
2150 if (seenarg) *seenarg = 1;
2151 char inQ = 0;
2152 int parens = 0;
2153 const char *oe = expr;
2154 for (; *expr; ++expr) {
2155 const char ch = *expr;
2156 if (inQ) {
2157 if (ch == inQ) inQ = 0;
2158 else if (ch == '\\' && expr[1]) ++expr;
2159 } else {
2160 if (ch == '"' || ch == '`') inQ = ch;
2161 else if (ch == '\'' && (expr == oe || !ur_isalnum(expr[-1]))) inQ = ch;
2162 else if (ch == '(') ++parens;
2163 else if (ch == ')') { if (--parens < 0) parens = 0; }
2164 else if (ch == ';') break;
2165 else if (parens == 0 && (ch == ',' || ch == ':')) break;
2168 return expr;
2172 /* error is `UR_EXPRERR_XXX` */
2173 const char *urasm_next_operand (urasm_operand_t *op, const char *expr, uint16_t addr, int *error) {
2174 const char *oe;
2175 char opstr[256];
2176 char inQ = 0;
2177 int parens = 0;
2178 int f;
2179 *error = UR_EXPRERR_NONE;
2180 memset(op, 0, sizeof(urasm_operand_t));
2181 op->defined = 1;
2182 if (!expr) return NULL;
2183 expr = skip_blanks(expr);
2184 if (!expr[0] || expr[0] == ';') return NULL;
2185 if (expr[0] == ':') return expr;
2186 op->parsed = 1;
2187 op->fixuptype = UR_FIXUP_NONE;
2188 /* skip operand */
2189 for (oe = expr; *expr; ++expr) {
2190 const char ch = *expr;
2191 if (inQ) {
2192 if (ch == inQ) inQ = 0;
2193 else if (ch == '\\' && expr[1]) ++expr;
2194 } else {
2195 if (ch == '"' || ch == '`') inQ = ch;
2196 else if (ch == '\'' && (oe == expr || !ur_isalnum(expr[-1]))) inQ = ch;
2197 else if (ch == '(') ++parens;
2198 else if (ch == ')') { if (--parens < 0) parens = 0; }
2199 else if (ch == ';') break;
2200 else if (parens == 0 && (ch == ',' || ch == ':')) break;
2203 if (expr-oe > 255) { *error = UR_EXPRERR_TOOLONG; return oe; }
2204 memset(opstr, 0, sizeof(opstr));
2205 memcpy(opstr, oe, expr-oe);
2206 while (opstr[0] && ur_isspace(opstr[strlen(opstr)-1])) opstr[strlen(opstr)-1] = '\0';
2207 if (!opstr[0]) { *error = UR_EXPRERR_EOS; return oe; }
2208 /* determine operand type */
2209 if (opstr[0] == '=' && urasm_expand != NULL) {
2210 if (urasm_expand(opstr, (int)sizeof(opstr)-1) != 0) { *error = UR_EXPRERR_MARG; return oe; }
2211 //fprintf(stderr, "exp: [%s]\n", opstr);
2213 if (ur_isalpha(opstr[0]) && urasm_is_valid_name(opstr)) {
2214 goto doexpression;
2216 if (opstr[0] == '(') {
2217 /* memref */
2218 op->mem = 1; op->special = 1;
2219 if (!opstr[1] || opstr[strlen(opstr)-1] != ')') { *error = UR_EXPRERR_PARENS; return oe; }
2220 /* operand w/o "()" */
2221 opstr[strlen(opstr)-1] = '\0';
2222 memmove(opstr, opstr+1, sizeof(opstr)-1);
2223 /* trim spaces */
2224 while (opstr[0] && ur_isspace(opstr[0])) memmove(opstr, opstr+1, sizeof(opstr)-1);
2225 while (opstr[0] && ur_isspace(opstr[strlen(opstr)-1])) opstr[strlen(opstr)-1] = '\0';
2226 /* empty brackets? */
2227 if (!opstr[0]) { *error = UR_EXPRERR_TERM; return oe; }
2228 for (f = 0; opstr[f]; ++f) op->s[f] = ur_toupper(opstr[f]);
2229 if (!strcmp(op->s, "C")) {
2230 op->special = 1; op->mem = 0; strcpy(op->s, "(C)");
2231 return expr;
2233 if (!strcmp(op->s, "HL")) return expr;
2234 if (!strcmp(op->s, "DE")) return expr;
2235 if (!strcmp(op->s, "BC")) return expr;
2236 if (!strcmp(op->s, "SP")) return expr;
2237 if (op->s[0] == 'I' && (op->s[1] == 'X' || op->s[1] == 'Y')) {
2238 /* memref: IX or IY */
2239 op->ixy = op->s[1]=='X' ? 0xDDU : 0xFDU;
2240 op->v = 0;
2241 memmove(opstr, opstr+1, sizeof(opstr)-1);
2242 opstr[0] = '0';
2243 while (opstr[1] && ur_isspace(opstr[1])) memmove(opstr+1, opstr+2, sizeof(opstr)-2);
2244 if (!opstr[1]) return expr;
2245 if (opstr[1] != '+' && opstr[1] != '-') { *error = UR_EXPRERR_NUMBER; return oe; }
2246 /* opstr must be an expression */
2247 const char *t = urasm_expr(&op->v, opstr, addr, &op->defined, NULL, error);
2248 if (*error) return oe;
2249 if (t[0]) { *error = UR_EXPRERR_TOOLONG; return oe; }
2250 if (op->defined && (op->v < -128 || op->v > 127)) { *error = UR_EXPRERR_NUMBER; return oe; }
2251 return expr;
2253 op->special = 0;
2254 } else {
2255 if (!strcasecmp(opstr, "af'")) goto registerop;
2256 for (f = 0; ur_isalpha(opstr[f]); ++f) {}
2257 if (!opstr[f]) {
2258 registerop:
2259 for (f = 0; opstr[f]; ++f) opstr[f] = ur_toupper(opstr[f]);
2260 strcpy(op->s, opstr);
2261 op->special = 1;
2262 return skip_blanks(expr);
2265 /* this must be an expression */
2266 doexpression:
2267 strcpy(op->s, opstr);
2269 urasm_exprval_t e;
2270 const char *t;
2271 int donteval = 0;
2272 urasm_exprval_init(&e);
2273 t = urasm_expr_ex(&e, opstr, addr, &donteval, &op->defined, error);
2274 op->v = e.val;
2275 op->fixuptype = e.fixuptype;
2276 urasm_exprval_clear(&e);
2277 //const char *t = urasm_expr(&op->v, opstr, addr, &op->defined, error);
2278 if (*error) { op->parsed = 0; return oe; }
2279 if (t == NULL || t[0]) { op->parsed = 0; *error = UR_EXPRERR_EOS; return oe; }
2281 return skip_blanks(expr);
2285 ///////////////////////////////////////////////////////////////////////////////
2286 // assembler
2288 // for regsters & conditions: op->v will be set to reg number
2289 int urasm_is_valid_operand (urasm_operand_t *op, uint16_t addr, unsigned optype) {
2290 int i;
2291 if (optype == UO_NONE || optype == UO_NEXT) return (op->s[0] == '\0');
2292 if (!op->s[0]) return 0;
2293 switch (optype) {
2294 case UO_IMM8:
2295 if (op->special || op->mem) return 0;
2296 if (op->defined && (op->v < -128 || op->v > 255)) return 0;
2297 return 1;
2298 case UO_IMM16:
2299 if (op->special || op->mem) return 0;
2300 if (op->defined && (op->v < -32768 || op->v > 65535)) return 0;
2301 return 1;
2302 case UO_IMM16BE:
2303 if (op->special || op->mem) return 0;
2304 if (op->defined && (op->v < -32768 || op->v > 65535)) return 0;
2305 return 1;
2306 case UO_ADDR16:
2307 if (op->special || op->mem) return 0;
2308 if (op->defined && (op->v < -32768 || op->v > 65535)) return 0;
2309 if (op->v < 0) op->v = 65536+op->v;
2310 return 1;
2311 case UO_ADDR8:
2312 if (op->special || op->mem) return 0;
2313 if (op->defined && (op->v < -32768 || op->v > 65535)) return 0;
2314 if (!op->defined) op->v = addr;
2315 if (op->v < 0) op->v = 65536+op->v;
2316 i = op->v-((int)addr+2);
2317 if (i < -128 || i > 127) return 0;
2318 op->v = i&0xff;
2319 return 1;
2320 case UO_MEM16:
2321 if (op->special || !op->mem) return 0;
2322 if (op->defined && (op->v < -32768 || op->v > 65535)) return 0;
2323 if (op->v < 0) op->v = 65536+op->v;
2324 return 1;
2325 case UO_R8: case UO_2R8:
2326 if (op->mem && !strcmp(op->s, "HL")) { /*strcpy(op->s, "M");*/ op->v = 6; return 1; }
2327 /* fallthru */
2328 case UO_R8_NOM: case UO_2R8_NOM:
2329 if (!op->special || op->mem || op->s[1]) return 0;
2330 switch (op->s[0]) {
2331 case 'B': op->v = 0; break;
2332 case 'C': op->v = 1; break;
2333 case 'D': op->v = 2; break;
2334 case 'E': op->v = 3; break;
2335 case 'H': op->v = 4; break;
2336 case 'L': op->v = 5; break;
2337 case 'A': op->v = 7; break;
2338 default: return 0;
2340 return 1;
2341 case UO_PORTC:
2342 if (!op->special || op->mem) return 0;
2343 return strcmp(op->s, "(C)")==0;
2344 case UO_PORTIMM: /* mem, 'cause (n) */
2345 if (op->special || !op->mem) return 0;
2346 op->mem = 0;
2347 if (op->defined && (op->v < 0 || op->v > 255)) return 0;
2348 return 1;
2349 case UO_R8_XH:
2350 if (!op->special || op->mem) return 0;
2351 if (!strcmp(op->s, "XH") || !strcmp(op->s, "HX") || !strcmp(op->s, "IXH")) return 1;
2352 return 0;
2353 case UO_R8_XL:
2354 if (!op->special || op->mem) return 0;
2355 if (!strcmp(op->s, "XL") || !strcmp(op->s, "LX") || !strcmp(op->s, "IXL")) return 1;
2356 return 0;
2357 case UO_R8_YH:
2358 if (!op->special || op->mem) return 0;
2359 if (!strcmp(op->s, "YH") || !strcmp(op->s, "HY") || !strcmp(op->s, "IYH")) return 1;
2360 return 0;
2361 case UO_R8_YL:
2362 if (!op->special || op->mem) return 0;
2363 if (!strcmp(op->s, "YL") || !strcmp(op->s, "LY") || !strcmp(op->s, "IYL")) return 1;
2364 return 0;
2365 case UO_R8_A:
2366 if (!op->special || op->mem) return 0;
2367 if (!strcmp(op->s, "A")) return 1;
2368 return 0;
2369 case UO_R8_B:
2370 if (!op->special || op->mem) return 0;
2371 if (!strcmp(op->s, "B")) return 1;
2372 return 0;
2373 case UO_R8_R:
2374 if (!op->special || op->mem) return 0;
2375 if (!strcmp(op->s, "R")) return 1;
2376 return 0;
2377 case UO_R8_I:
2378 if (!op->special || op->mem) return 0;
2379 if (!strcmp(op->s, "I")) return 1;
2380 return 0;
2381 case UO_R16:
2382 if (!op->special || op->mem || !op->s[1] || op->s[2]) return 0;
2383 if (!strcmp(op->s, "BC")) { op->v = 0; return 1; }
2384 if (!strcmp(op->s, "DE")) { op->v = 1; return 1; }
2385 if (!strcmp(op->s, "HL")) { op->v = 2; return 1; }
2386 if (!strcmp(op->s, "SP")) { op->v = 3; return 1; }
2387 return 0;
2388 case UO_R16A:
2389 if (!op->special || op->mem || !op->s[1] || op->s[2]) return 0;
2390 if (!strcmp(op->s, "BC")) { op->v = 0; return 1; }
2391 if (!strcmp(op->s, "DE")) { op->v = 1; return 1; }
2392 if (!strcmp(op->s, "HL")) { op->v = 2; return 1; }
2393 if (!strcmp(op->s, "AF")) { op->v = 3; return 1; }
2394 return 0;
2395 case UO_R16AF:
2396 if (!op->special || op->mem || strcmp(op->s, "AF")) return 0;
2397 op->v = 3;
2398 return 1;
2399 case UO_R16AFX:
2400 if (!op->special || op->mem || (strcmp(op->s, "AF'") && strcmp(op->s, "AFX"))) return 0;
2401 op->v = 3;
2402 return 1;
2403 case UO_R16BC:
2404 if (!op->special || op->mem || strcmp(op->s, "BC")) return 0;
2405 op->v = 0;
2406 return 1;
2407 case UO_R16DE:
2408 if (!op->special || op->mem || strcmp(op->s, "DE")) return 0;
2409 op->v = 1;
2410 return 1;
2411 case UO_R16HL:
2412 if (!op->special || op->mem || strcmp(op->s, "HL")) return 0;
2413 op->v = 2;
2414 return 1;
2415 case UO_R16IX:
2416 if (!op->special || op->mem || strcmp(op->s, "IX")) return 0;
2417 op->v = 2;
2418 return 1;
2419 case UO_R16IY:
2420 if (!op->special || op->mem || strcmp(op->s, "IY")) return 0;
2421 op->v = 2;
2422 return 1;
2423 case UO_R16SP:
2424 if (!op->special || op->mem || strcmp(op->s, "SP")) return 0;
2425 op->v = 3;
2426 return 1;
2427 case UO_MSP:
2428 if (!op->special || !op->mem || strcmp(op->s, "SP")) return 0;
2429 op->v = 3;
2430 return 1;
2431 case UO_MBC:
2432 if (!op->special || !op->mem || strcmp(op->s, "BC")) return 0;
2433 op->v = 0;
2434 return 1;
2435 case UO_MDE:
2436 if (!op->special || !op->mem || strcmp(op->s, "DE")) return 0;
2437 op->v = 1;
2438 return 1;
2439 case UO_MHL:
2440 if (!op->special || !op->mem || strcmp(op->s, "HL")) return 0;
2441 op->v = 2;
2442 return 1;
2443 case UO_MIX:
2444 if (!op->special || !op->mem || op->ixy != 0xDDU) return 0;
2445 if (op->defined && (op->v < -128 || op->v > 127)) return 0;
2446 return 1;
2447 case UO_MIY:
2448 if (!op->special || !op->mem || op->ixy != 0xFDU) return 0;
2449 if (op->defined && (op->v < -128 || op->v > 127)) return 0;
2450 return 1;
2451 case UO_MIX0:
2452 if (!op->special || !op->mem || op->ixy != 0xDDU) return 0;
2453 if (op->defined && op->v != 0) return 0;
2454 return 1;
2455 case UO_MIY0:
2456 if (!op->special || !op->mem || op->ixy != 0xFDU) return 0;
2457 if (op->defined && op->v != 0) return 0;
2458 return 1;
2459 case UO_JRCOND:
2460 if (!op->special || op->mem || ur_is_long_str(op->s)) return 0;
2461 if (!strcmp(op->s, "NZ")) { op->v = 0; return 1; }
2462 if (!strcmp(op->s, "Z")) { op->v = 1; return 1; }
2463 if (!strcmp(op->s, "NC")) { op->v = 2; return 1; }
2464 if (!strcmp(op->s, "C")) { op->v = 3; return 1; }
2465 return 0;
2466 case UO_COND:
2467 if (!op->special || op->mem || ur_is_long_str(op->s)) return 0;
2468 if (!strcmp(op->s, "NZ")) { op->v = 0; return 1; }
2469 if (!strcmp(op->s, "Z")) { op->v = 1; return 1; }
2470 if (!strcmp(op->s, "NC")) { op->v = 2; return 1; }
2471 if (!strcmp(op->s, "C")) { op->v = 3; return 1; }
2472 if (!strcmp(op->s, "PO")) { op->v = 4; return 1; }
2473 if (!strcmp(op->s, "PE")) { op->v = 5; return 1; }
2474 if (!strcmp(op->s, "P")) { op->v = 6; return 1; }
2475 if (!strcmp(op->s, "M")) { op->v = 7; return 1; }
2476 return 0;
2477 case UO_BITN:
2478 if (op->special || op->mem) return 0;
2479 if (op->defined && (op->v < 0 || op->v > 7)) return 0;
2480 return 1;
2481 case UO_RSTDEST:
2482 if (op->special || op->mem) return 0;
2483 if (op->defined && (op->v < 0 || op->v > 0x38 || (op->v&7))) return 0;
2484 op->v >>= 3;
2485 return 1;
2486 case UO_IM0:
2487 if (op->special || op->mem) return 0;
2488 if (op->defined && op->v != 0) return 0;
2489 return 1;
2490 case UO_IM1:
2491 if (op->special || op->mem) return 0;
2492 if (op->defined && op->v != 1) return 0;
2493 return 1;
2494 case UO_IM2:
2495 if (op->special || op->mem) return 0;
2496 if (op->defined && op->v != 2) return 0;
2497 return 1;
2499 return 0;
2503 // mem size should be at least 7 bytes
2504 // returns size of the assembled code
2505 // result <0 on error
2506 // understands comments
2507 int urasm_opasm (const char *expr, uint16_t destaddr, uint16_t addr, const char **errpos) {
2508 uint8_t buf[8];
2509 int len = 0;
2510 const char *oe;
2511 char mnem[16];
2512 int tkn;
2513 urasm_operand_t ops[3];
2514 const urasm_cmdinfo_t *cm;
2515 uint32_t code, mask;
2516 int opcPos; /* opcode will be placed here */
2517 int ret;
2519 int doOperand (int idx) {
2520 const urasm_operand_t *op = ops+idx;
2521 switch (cm->ops[idx]) {
2522 case UO_IMM8:
2523 if (op->fixuptype != UR_FIXUP_NONE && urasm_fixup_operand != NULL) {
2524 if (op->fixuptype == UR_FIXUP_WORD) return UR_EXPRERR_FIXUP+URA_EXPR_ERR;
2525 urasm_fixup_operand(op, (destaddr+len)&0xffff, (destaddr+len)&0xffff, op->fixuptype, 1);
2527 /* fallthru */
2528 case UO_PORTIMM:
2529 case UO_ADDR8:
2530 buf[len++] = op->v&0xFFU;
2531 break;
2532 case UO_IMM16:
2533 case UO_ADDR16:
2534 case UO_MEM16:
2535 if (op->fixuptype != UR_FIXUP_NONE && urasm_fixup_operand != NULL) {
2536 urasm_fixup_operand(op, (destaddr+len)&0xffff, (destaddr+len)&0xffff, op->fixuptype, 2);
2538 buf[len++] = op->v&0xFFU;
2539 buf[len++] = ((op->v&0xFFFFU)>>8)&0xFFU;
2540 break;
2541 case UO_IMM16BE:
2542 /*FIXME: this is prolly not right*/
2543 if (op->fixuptype != UR_FIXUP_NONE && urasm_fixup_operand != NULL) {
2544 switch (op->fixuptype) {
2545 case UR_FIXUP_WORD:
2546 urasm_fixup_operand(op, (destaddr+len)&0xffff, (destaddr+len)&0xffff, UR_FIXUP_HIBYTE, 1);
2547 urasm_fixup_operand(op, (destaddr+len+1)&0xffff, (destaddr+len+1)&0xffff, UR_FIXUP_LOBYTE, 1);
2548 break;
2549 case UR_FIXUP_LOBYTE:
2550 urasm_fixup_operand(op, (destaddr+len)&0xffff, (destaddr+len)&0xffff, UR_FIXUP_HIBYTE, 1);
2551 break;
2552 case UR_FIXUP_HIBYTE:
2553 urasm_fixup_operand(op, (destaddr+len+1)&0xffff, (destaddr+len+1)&0xffff, UR_FIXUP_LOBYTE, 1);
2554 break;
2555 default: break;
2558 buf[len++] = ((op->v&0xFFFFU)>>8)&0xFFU;
2559 buf[len++] = op->v&0xFFU;
2560 break;
2561 case UO_R8:
2562 case UO_R8_NOM:
2563 code |= op->v&0xFFU;
2564 break;
2565 case UO_JRCOND:
2566 case UO_COND:
2567 case UO_BITN:
2568 case UO_RSTDEST:
2569 case UO_2R8:
2570 case UO_2R8_NOM:
2571 code |= (op->v&0xFFU)<<3;
2572 break;
2573 case UO_R16:
2574 case UO_R16A:
2575 code |= (op->v&0xFFU)<<4;
2576 break;
2577 case UO_MIX:
2578 case UO_MIY:
2579 buf[len++] = op->v;
2580 break;
2582 return 0;
2585 /* <0: error; 0: ok; >0: last operand (ops[opix].parsed != 0: non-empty one) */
2586 int parseOperand (int opidx) {
2587 int error = 0;
2588 const char *oe = expr;
2589 expr = urasm_next_operand(ops+opidx, expr, addr, &error);
2590 if (error) {
2591 if (errpos) *errpos = oe;
2592 //return URA_BAD_OPERAND;
2593 return -error+URA_EXPR_ERR;
2595 if (!expr || !expr[0] || expr[0] == ';' || expr[0] == ':') return 1;
2596 if (*expr != ',') { if (errpos) *errpos = oe; return URA_BAD_OPERAND; }
2597 ++expr;
2598 return 0;
2601 int genCode (void) {
2602 int operr = 0;
2603 for (int pos = URASM_MAX_COMMAND-1; pos >= 0; --pos) {
2604 int f;
2605 if (tkn != URASM_COMMANDS[pos].mnemo) continue;
2606 for (f = 0; f < 3; ++f) {
2607 if (!urasm_is_valid_operand(&ops[f], addr, URASM_COMMANDS[pos].ops[f])) break;
2609 if (f < 3) continue;
2610 /* command found, generate code */
2611 len = 0; cm = URASM_COMMANDS+pos;
2612 code = cm->code; mask = cm->mask;
2613 if ((code&0xFFFFUL) == 0xCBDDUL || (code&0xFFFFUL) == 0xCBFDUL) {
2614 /* special commands */
2615 /* emit unmasked code */
2616 buf[0] = (code&0xFFU); buf[1] = 0xCBU;
2617 for (f = 0; f < 3; ++f) {
2618 if (cm->ops[f] == UO_MIX || cm->ops[f] == UO_MIY) {
2619 if (ops[f].defined && (ops[f].v < -128 || ops[f].v > 127)) f = -1;
2620 else if (ops[f].defined) buf[2] = ops[f].v;
2621 break;
2624 if (f < 0) continue; /* not me */
2625 len = 4;
2626 code >>= 24; mask >>= 24;
2627 if ((mask&0xFFUL) != 0xFFUL) {
2628 for (f = 0; f < 3; ++f) if (cm->ops[f] != UO_MIX && cm->ops[f] != UO_MIY) {
2629 if ((operr = doOperand(f)) != 0) goto badi;
2632 buf[3] = code;
2633 /* that's all */
2634 for (f = 0; f < len; ++f) { urasm_putbyte(destaddr++, buf[f]); ++addr; }
2635 return len;
2636 } else {
2637 /* normal commands */
2638 /* emit unmasked code */
2639 while ((mask&0xFFUL) == 0xFFUL) {
2640 buf[len++] = code&0xFFUL;
2641 code >>= 8; mask >>= 8;
2643 //ASSERT((code&0xFFFFFF00UL) == 0);
2644 if (mask == 0) {
2645 //ASSERT(len > 0);
2646 code = buf[--len];
2648 opcPos = len++;
2649 if ((operr = doOperand(0)) != 0) goto badi;
2650 if ((operr = doOperand(1)) != 0) goto badi;
2651 if ((operr = doOperand(2)) != 0) goto badi;
2652 buf[opcPos] = code;
2653 /* that's all */
2654 for (f = 0; f < len; ++f) { urasm_putbyte(destaddr++, buf[f]); ++addr; }
2655 return len;
2658 badi:
2659 if (errpos) *errpos = oe;
2660 return (operr < 0 ? operr : URA_BAD_INSTRUCTION);
2663 int doPushPop (void) {
2664 int f, len;
2665 for (f = len = 0; ; ++f) {
2666 int doQuit = 0;
2667 const char *oe = expr;
2668 int res = parseOperand(0);
2669 if (res < 0) return res;
2670 if (res > 0) {
2671 if (f == 0 && !ops[0].parsed) { *errpos = oe; return URA_BAD_INSTRUCTION; }
2672 doQuit = 1;
2674 code = (tkn == UT_POP ? 0xC1U : 0xC5U);
2675 if (urasm_is_valid_operand(ops, addr, UO_R16A)) {
2676 code |= (ops[0].v&0xFFU)<<4;
2677 urasm_putbyte(destaddr++, code);
2678 ++addr;
2679 ++len;
2680 } else if (urasm_is_valid_operand(ops, addr, UO_R16IX)) {
2681 code |= (ops[0].v&0xFFU)<<4;
2682 urasm_putbyte(destaddr++, 0xDDU);
2683 urasm_putbyte(destaddr++, code);
2684 addr += 2;
2685 len += 2;
2686 } else if (urasm_is_valid_operand(ops, addr, UO_R16IY)) {
2687 code |= (ops[0].v&0xFFU)<<4;
2688 urasm_putbyte(destaddr++, 0xFDU);
2689 urasm_putbyte(destaddr++, code);
2690 addr += 2;
2691 len += 2;
2692 } else if (urasm_allow_zxnext && code == 0xC5U && urasm_is_valid_operand(ops, addr, UO_IMM16BE)) {
2693 /* ZXNext PUSH nnnn */
2694 urasm_putbyte(destaddr++, 0xEDU);
2695 urasm_putbyte(destaddr++, 0x8AU);
2696 /*FIXME: this is prolly not right*/
2697 if (ops[0].fixuptype != UR_FIXUP_NONE && urasm_fixup_operand != NULL) {
2698 switch (ops[0].fixuptype) {
2699 case UR_FIXUP_WORD:
2700 urasm_fixup_operand(&ops[0], (destaddr+len)&0xffff, (destaddr+len)&0xffff, UR_FIXUP_HIBYTE, 1);
2701 urasm_fixup_operand(&ops[0], (destaddr+len+1)&0xffff, (destaddr+len+1)&0xffff, UR_FIXUP_LOBYTE, 1);
2702 break;
2703 case UR_FIXUP_LOBYTE:
2704 urasm_fixup_operand(&ops[0], (destaddr+len)&0xffff, (destaddr+len)&0xffff, UR_FIXUP_HIBYTE, 1);
2705 break;
2706 case UR_FIXUP_HIBYTE:
2707 urasm_fixup_operand(&ops[0], (destaddr+len+1)&0xffff, (destaddr+len+1)&0xffff, UR_FIXUP_LOBYTE, 1);
2708 break;
2709 default: break;
2712 urasm_putbyte(destaddr++, ((ops[0].v&0xFFFFU)>>8)&0xFFU);
2713 urasm_putbyte(destaddr++, ops[0].v&0xFFU);
2714 addr += 4;
2715 len += 4;
2716 } else {
2717 if (errpos) *errpos = oe;
2718 return URA_BAD_OPERAND;
2720 if (doQuit) break;
2722 if (expr) {
2723 expr = skip_blanks(expr);
2724 if (expr[0] && expr[0] != ';') {
2725 if (errpos) *errpos = expr;
2726 if (expr[0] != ':') return URA_EXTRA_TEXT;
2729 return len;
2732 int dorep (int opcnt) {
2733 int f, len;
2734 memset(ops, 0, sizeof(ops));
2735 for (f = len = 0; ; ++f) {
2736 int doQuit = 0, res;
2737 const char *oe;
2738 for (int c = 0; c < opcnt; ++c) {
2739 oe = expr;
2740 res = parseOperand(c);
2741 if (res < 0) return res;
2742 if (res > 0) {
2743 if (c != opcnt-1 || !ops[c].parsed) { *errpos = oe; return URA_BAD_INSTRUCTION; }
2744 doQuit = 1;
2747 if ((res = genCode()) < 0) return res;
2748 addr += res;
2749 len += res;
2750 if (doQuit) break;
2752 if (expr) {
2753 expr = skip_blanks(expr);
2754 if (expr[0] && expr[0] != ';') {
2755 if (errpos) *errpos = expr;
2756 if (expr[0] != ':') return URA_EXTRA_TEXT;
2759 return len;
2762 if (errpos) *errpos = NULL;
2763 if (!urasm_putbyte || !expr) return URA_GENERIC;
2765 expr = skip_blanks(expr);
2766 if (!expr[0] || expr[0] == ';') return 0;
2767 if (expr[0] == ':') { if (errpos) *errpos = expr; return 0; }
2768 for (oe = expr; *expr && !ur_isspace(*expr) && *expr != ':' && *expr != ';'; ++expr) {}
2769 if (urasm_allow_zxnext) {
2770 if (expr-oe > 7) { if (errpos) *errpos = oe; return URA_BAD_MNEMO; } /* bad mnemonics */
2771 } else {
2772 if (expr-oe > 4) { if (errpos) *errpos = oe; return URA_BAD_MNEMO; } /* bad mnemonics */
2775 memset(mnem, 0, sizeof(mnem));
2776 memcpy(mnem, oe, expr-oe);
2777 for (int f = 0; mnem[f]; ++f) mnem[f] = ur_toupper(mnem[f]);
2778 /* find it */
2779 for (tkn = 0; tkn < URASM_MAX_TOKEN; ++tkn) if (!strcmp(mnem, URASM_TOKENS[tkn])) break;
2780 if (tkn >= URASM_MAX_TOKEN) { if (errpos) *errpos = oe; return URA_BAD_MNEMO; } /* unknown mnemonics */
2782 expr = skip_blanks(expr);
2783 if (expr[0] == ',') { if (errpos) *errpos = oe; return URA_BAD_OPERAND; }
2784 /* special for PUSH and POP */
2785 if (tkn == UT_POP || tkn == UT_PUSH) return doPushPop();
2786 /* special for LD */
2787 if (tkn == UT_LD /*|| tkn == UT_ADD || tkn == UT_ADC || tkn == UT_SBC*/) return dorep(2);
2788 /* special for RR/RL */
2789 if (tkn == UT_RL || tkn == UT_RR || tkn == UT_INC || tkn == UT_DEC ||
2790 tkn == UT_SRL || tkn == UT_SRA || tkn == UT_SLI || tkn == UT_SLL || tkn == UT_SLA) return dorep(1);
2792 memset(ops, 0, sizeof(ops));
2793 for (int f = 0; f < 3; ++f) {
2794 int res = parseOperand(f);
2795 if (res > 0) break;
2796 if (res < 0) return res;
2799 ret = genCode();
2801 if (ret >= 0 && expr) {
2802 expr = skip_blanks(expr);
2803 if (expr[0] && expr[0] != ';') {
2804 if (errpos) *errpos = expr;
2805 if (expr[0] != ':') return URA_EXTRA_TEXT;
2809 return ret;
2813 // ////////////////////////////////////////////////////////////////////////// //
2814 static const char *error_messages_asm[5] = {
2815 "generic error",
2816 "bad mnemonics",
2817 "bad operand",
2818 "extra text after instruction",
2819 "bad instruction",
2823 static const char *error_messages_expr[14] = {
2824 "", /* none */
2825 "unexpected end of expression",
2826 "division by zero",
2827 "unbalanced parens",
2828 "number expected",
2829 "string expected",
2830 "unknown label",
2831 "term expected", /*FIXME: better message!*/
2832 "unknown function",
2833 "invalid operand type", /*FIXME: better message! this is string/number conflict*/
2834 "unknown macro argument", /*FIXME: better message! */
2835 "invalid fixup",
2836 "type mismatch", /* in comparisons */
2837 "operand text too long",
2841 const char *urasm_errormsg (int errcode) {
2842 if (errcode >= 0) return "";
2843 if (errcode < URA_EXPR_ERR) {
2844 errcode = -(errcode-URA_EXPR_ERR);
2845 if (errcode >= UR_EXPRERR_EOS && errcode <= UR_EXPRERR_TOOLONG) {
2846 return error_messages_expr[errcode-1];
2848 return "unknown error";
2849 } else {
2850 if (errcode < -5) return "unknown error";
2851 return error_messages_asm[(-errcode)-1];