emu: added useless `inline`
[zymosis.git] / src / liburasm / liburasm.c
blob432e2271563243d0a59334a528e3de84a32c48f5
1 /* coded by Ketmar // Invisible Vector (ketmar@ketmar.no-ip.org)
2 * Understanding is not required. Only obedience.
4 * URASM Z80 assembler/disassembler core v0.1.3 (with ZXNext support)
6 * This program is free software. It comes without any warranty, to
7 * the extent permitted by applicable law. You can redistribute it
8 * and/or modify it under the terms of the Do What The Fuck You Want
9 * To Public License, Version 2, as published by Sam Hocevar. See
10 * http://sam.zoy.org/wtfpl/COPYING for more details.
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 the whole night creating this shit! %-)
61 const urasm_cmdinfo_t URASM_COMMANDS[URASM_MAX_COMMAND] = {
62 {.mnemo=UT_NOPX, .code=0x000000DDUL, .mask=0x00000000UL, .ops={UO_NONE, UO_NONE, UO_NONE}},
63 {.mnemo=UT_NOPY, .code=0x000000FDUL, .mask=0x00000000UL, .ops={UO_NONE, UO_NONE, UO_NONE}},
64 // DD/CB opcodes (special)
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_NOHL, UO_NONE}},
623 // LD XL,r8
624 {.mnemo=UT_LD, .code=0x68DDUL, .mask=0xF8FFUL, .ops={UO_R8_XL, UO_R8_NOM_NOHL, 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_NOHL, UO_NONE}},
629 // LD YL,r8
630 {.mnemo=UT_LD, .code=0x68FDUL, .mask=0xF8FFUL, .ops={UO_R8_YL, UO_R8_NOM_NOHL, 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_NOHL, UO_R8_XH, UO_NONE}},
636 // LD r8,XL
637 {.mnemo=UT_LD, .code=0x45DDUL, .mask=0xC7FFUL, .ops={UO_2R8_NOM_NOHL, 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_NOHL, UO_R8_YH, UO_NONE}},
643 // LD r8,YL
644 {.mnemo=UT_LD, .code=0x45FDUL, .mask=0xC7FFUL, .ops={UO_2R8_NOM_NOHL, 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}},
832 // LD BC,IX
833 {.mnemo=UT_LD, .code=0x4DDD44DDUL, .mask=0xFFFFFFFFUL, .ops={UO_R16BC, UO_R16IX, UO_NONE}},
834 // LD BC,IY
835 {.mnemo=UT_LD, .code=0x4DFD44FDUL, .mask=0xFFFFFFFFUL, .ops={UO_R16BC, UO_R16IY, UO_NONE}},
836 // LD DE,IX
837 {.mnemo=UT_LD, .code=0x5DDD54DDUL, .mask=0xFFFFFFFFUL, .ops={UO_R16DE, UO_R16IX, UO_NONE}},
838 // LD DE,IY
839 {.mnemo=UT_LD, .code=0x5DFD54FDUL, .mask=0xFFFFFFFFUL, .ops={UO_R16DE, UO_R16IY, UO_NONE}},
840 // LD IX,BC
841 {.mnemo=UT_LD, .code=0x69DD60DDUL, .mask=0xFFFFFFFFUL, .ops={UO_R16IX, UO_R16BC, UO_NONE}},
842 // LD IY,BC
843 {.mnemo=UT_LD, .code=0x69FD60FDUL, .mask=0xFFFFFFFFUL, .ops={UO_R16IY, UO_R16BC, UO_NONE}},
844 // LD IX,DE
845 {.mnemo=UT_LD, .code=0x6BDD62DDUL, .mask=0xFFFFFFFFUL, .ops={UO_R16IX, UO_R16DE, UO_NONE}},
846 // LD IY,DE
847 {.mnemo=UT_LD, .code=0x6BFD62FDUL, .mask=0xFFFFFFFFUL, .ops={UO_R16IY, UO_R16DE, UO_NONE}},
851 // instructions unaffected by DD/FF prefixes
852 // this table used by disassembler (we don't want to eat prefixes)
853 const unsigned char URASM_DDFD_INSENSITIVE[256] = {
854 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
855 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
856 1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,
857 1,1,1,1,0,0,0,1,1,0,1,1,1,1,1,1,
858 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
859 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
860 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
861 0,0,0,0,0,0,1,0,1,1,1,1,0,0,0,1,
862 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
863 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
864 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
865 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
866 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,
867 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
868 1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,
869 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
871 0xff,0xbf,0xff,0xbf,0x81,0x81,0xf1,0xbf,0xf1,0xf1,0xf1,0xf1,0x00,0x00,0x02,0xf1,
872 0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xff,0xef,0xff,0xff,0xab,0xbf,0xff,0xbf,
876 #define IS_DD_SENSITIVE(c) URASM_DDFD_INSENSITIVE[(c)&0xff]
878 static inline int IS_DD_SENSITIVE (uint8_t opc) {
879 return URASM_DDFD_INSENSITIVE[opc/8]&(0x80>>(opc%8));
884 #if 0
885 const unsigned char URASM_DDFD_HAS_DISP[256] = {
887 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
888 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
889 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
890 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
891 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
892 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
893 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
894 1,1,1,1,1,1,0,1,0,0,0,0,0,0,1,0,
895 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
896 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
897 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
898 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
899 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
900 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
901 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
902 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
904 0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x00,0x02,0x02,0x02,0x02,0x02,0x02,0xfd,0x02,
905 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
908 static inline int HAS_DDFD_DISP (uint8_t opc) {
909 return URASM_DDFD_HAS_DISP[opc/8]&(0x80>>(opc%8));
911 #endif
914 static __attribute__((always_inline)) inline const char *label_by_addr (uint16_t addr) {
915 if (!urasm_label_by_addr) return NULL;
916 return urasm_label_by_addr(addr);
920 static __attribute__((always_inline)) inline char ur_toupper (char ch) {
921 return (ch >= 'a' && ch <= 'z' ? ch-'a'+'A' : ch);
925 static __attribute__((always_inline)) inline char ur_isalpha (char ch) {
926 return
927 (ch >= 'A' && ch <= 'Z') ||
928 (ch >= 'a' && ch <= 'z');
932 static __attribute__((always_inline)) inline char ur_isalnum (char ch) {
933 return
934 (ch >= 'A' && ch <= 'Z') ||
935 (ch >= 'a' && ch <= 'z') ||
936 (ch >= '0' && ch <= '9');
940 static __attribute__((always_inline)) inline char ur_isspace (char ch) {
941 return (ch != 0 && ((ch&0xff) <= 32 || ch == 127));
945 static inline int dig2n (char ch, int base) {
946 if (ch < '0') return -1;
947 if (base <= 10) {
948 if (ch > '0'+base) return -1;
949 return ch-'0';
951 if (ch >= '0' && ch <= '9') return ch-'0';
952 if (ch >= 'a' && ch <= 'z') ch = ch-'a'+10;
953 else if (ch >= 'A' && ch <= 'Z') ch = ch-'A'+10;
954 else return -1;
955 if (ch >= base) return -1;
956 return ch;
960 /******************************************************************************/
961 /* disassembler */
962 /******************************************************************************/
964 /* opc: opcode */
965 /* nextW: next 2 bytes (after opcode) */
966 /* idx: I? displacement */
967 static void ua_op2str (char *res, int op, uint16_t addr, uint8_t opc, uint16_t nextW, int idx) {
968 const char *lbl;
969 int add, ismem = 0;
970 switch (op) {
971 case UO_NONE: case UO_NEXT: strcpy(res, ""); break;
972 case UO_IMM8:
973 if (!urasm_disasm_decimal) sprintf(res, "#%02X", nextW&0xFFU); else sprintf(res, "%u", nextW&0xFFU);
974 break;
975 case UO_IMM16:
976 if (!urasm_disasm_decimal) sprintf(res, "#%04X", nextW); else sprintf(res, "%u", nextW);
977 break;
978 case UO_IMM16BE:
979 nextW = (uint16_t)(((nextW>>8)&0xffu)|((nextW<<8)&0xff00u));
980 if (!urasm_disasm_decimal) sprintf(res, "#%04X", nextW); else sprintf(res, "%u", nextW);
981 break;
982 case UO_ADDR8:
983 addr += 2; nextW &= 0xFFU;
984 add = (nextW < 128 ? nextW : ((int)nextW)-256);
985 addr += add;
986 nextW = addr;
987 /* fallthru */
988 case UO_ADDR16:
989 dolabel:
990 lbl = label_by_addr(nextW);
991 if (lbl) { strcpy(res, lbl); break; }
992 lbl = label_by_addr(nextW-1);
993 if (lbl) { sprintf(res, "%s-1", lbl); break; }
994 lbl = label_by_addr(nextW-2);
995 if (lbl) { sprintf(res, "%s-2", lbl); break; }
996 lbl = label_by_addr(nextW+1);
997 if (lbl) { sprintf(res, "%s+1", lbl); break; }
998 lbl = label_by_addr(nextW+2);
999 if (lbl) { sprintf(res, "%s+2", lbl); break; }
1000 if (!urasm_disasm_decimal) sprintf(res, "#%04X", nextW); else sprintf(res, "%u", nextW);
1001 break;
1002 case UO_MEM16:
1003 ismem = 1;
1004 strcpy(res, "("); ++res;
1005 goto dolabel;
1006 case UO_R8:
1007 case UO_R8_NOM:
1008 case UO_R8_NOM_NOHL:
1009 strcpy(res, URA_REGS8[opc&0x07UL]);
1010 break;
1011 case UO_2R8:
1012 case UO_2R8_NOM:
1013 case UO_2R8_NOM_NOHL:
1014 strcpy(res, URA_REGS8[(opc>>3)&0x07UL]);
1015 break;
1016 case UO_PORTC: strcpy(res, "(C)"); break;
1017 case UO_PORTIMM:
1018 if (!urasm_disasm_decimal) sprintf(res, "(#%02X)", nextW&0xFFU); else sprintf(res, "(%u)", nextW&0xFFU);
1019 break;
1020 case UO_R8_XH: strcpy(res, "XH"); break;
1021 case UO_R8_XL: strcpy(res, "XL"); break;
1022 case UO_R8_YH: strcpy(res, "YH"); break;
1023 case UO_R8_YL: strcpy(res, "YL"); break;
1024 case UO_R8_A: strcpy(res, "A"); break;
1025 case UO_R8_B: strcpy(res, "B"); break;
1026 case UO_R8_R: strcpy(res, "R"); break;
1027 case UO_R8_I: strcpy(res, "I"); break;
1028 case UO_R16: strcpy(res, URA_REGS16[(opc>>4)&0x03UL]); break;
1029 case UO_R16A: strcpy(res, URA_REGS16A[(opc>>4)&0x03UL]); break;
1030 case UO_R16AF: strcpy(res, "AF"); break;
1031 case UO_R16AFX: strcpy(res, "AF'"); break;
1032 case UO_R16BC: strcpy(res, "BC"); break;
1033 case UO_R16DE: strcpy(res, "DE"); break;
1034 case UO_R16HL: strcpy(res, "HL"); break;
1035 case UO_R16IX: strcpy(res, "IX"); break;
1036 case UO_R16IY: strcpy(res, "IY"); break;
1037 case UO_R16SP: strcpy(res, "SP"); break;
1038 case UO_MSP: strcpy(res, "(SP)"); break;
1039 case UO_MBC: strcpy(res, "(BC)"); break;
1040 case UO_MDE: strcpy(res, "(DE)"); break;
1041 case UO_MHL: strcpy(res, "(HL)"); break;
1042 case UO_MIX0: strcpy(res, "(IX)"); break;
1043 case UO_MIY0: strcpy(res, "(IY)"); break;
1044 case UO_MIX:
1045 if (idx) {
1046 sprintf(res, "(IX%s%d)", (idx < 0 ? "" : "+"), idx);
1047 } else {
1048 strcpy(res, "(IX)");
1050 break;
1051 case UO_MIY:
1052 if (idx) {
1053 sprintf(res, "(IY%s%d)", (idx < 0 ? "" : "+"), idx);
1054 } else {
1055 strcpy(res, "(IY)");
1057 break;
1058 case UO_JRCOND: strcpy(res, URA_COND[(opc>>3)&0x03U]); break;
1059 case UO_COND: strcpy(res, URA_COND[(opc>>3)&0x07U]); break;
1060 case UO_BITN: sprintf(res, "%u", (opc>>3)&0x07U); break;
1061 case UO_RSTDEST:
1062 if (!urasm_disasm_decimal) sprintf(res, "#%02X", opc&0x38U); else sprintf(res, "%u", opc&0x38U);
1063 break;
1064 case UO_IM0: strcpy(res, "0"); break;
1065 case UO_IM1: strcpy(res, "1"); break;
1066 case UO_IM2: strcpy(res, "2"); break;
1067 default: strcpy(res, ""); break; /* we'll never come here */
1069 if (ismem) strcat(res, ")");
1073 /* common code for two disasm functions */
1074 static inline int is_opc_invalid_op (int op, uint8_t opc) {
1075 switch (op) {
1076 case UO_R8_NOM:
1077 return ((opc&0x07U) == 6); /* bad (HL) */
1078 case UO_R8_NOM_NOHL:
1079 opc &= 0x07;
1080 return (opc >= 4 && opc <= 6); /* bad H,L,(HL) */
1081 case UO_2R8_NOM:
1082 return (((opc>>3)&0x07U) == 6); /* bad (HL) */
1083 case UO_2R8_NOM_NOHL:
1084 opc = (opc>>3)&0x07U;
1085 return (opc >= 4 && opc <= 6); /* bad H,L,(HL) */
1087 return 0;
1091 /* find the corresponding record in URASM_COMMANDS */
1092 int urasm_disasm_opfind (uint16_t addr) {
1093 uint8_t buf[8];
1094 uint32_t ci, f, c;
1095 uint8_t opc;
1096 int bpos, opn, op;
1097 if (!urasm_getbyte) return -1;
1098 for (f = 0; f < 8; ++f) buf[f] = urasm_getbyte(addr+f);
1099 if (buf[0] == 0xDDU || buf[0] == 0xFDU) {
1100 /* dummy prefix */
1101 if (IS_DD_SENSITIVE(buf[1])) return (buf[0] == 0xDDU ? 0 : 1);
1103 ci = ((uint32_t)buf[0]) | (((uint32_t)buf[1])<<8) | (((uint32_t)buf[2])<<16) | (((uint32_t)buf[3])<<24);
1104 for (opn = 0; opn < URASM_MAX_COMMAND; ++opn) {
1105 /* find command */
1106 for (; opn < URASM_MAX_COMMAND && (ci&URASM_COMMANDS[opn].mask) != URASM_COMMANDS[opn].code; ++opn) {}
1107 if (!urasm_allow_zxnext && URASM_COMMANDS[opn].ops[2] == UO_NEXT) opn = URASM_MAX_COMMAND; /* skip ZXNext if not allowed */
1108 if (opn >= URASM_MAX_COMMAND) {
1109 if (buf[0] == 0xEDU) return -2;
1110 return -1;
1112 /* skip prefixes, determine command length */
1113 f = URASM_COMMANDS[opn].mask; c = URASM_COMMANDS[opn].code;
1114 for (bpos = 0; ; ++bpos) {
1115 uint8_t b;
1116 if ((f&0xFFUL) != 0xFFUL) break;
1117 b = c&0xFFUL;
1118 if (b != 0xFDU && b != 0xDDU && b != 0xEDU && b != 0xCBU) break;
1119 f >>= 8; c >>= 8;
1121 /* are there any operands? */
1122 if (URASM_COMMANDS[opn].ops[0] == UO_NONE) return opn;
1123 /* is this CB-prefixed? */
1124 if (((URASM_COMMANDS[opn].code&0xFFFFUL) == 0xCBDDUL) ||
1125 ((URASM_COMMANDS[opn].code&0xFFFFUL) == 0xCBFDUL)) ++bpos; /* skip displacement */
1126 opc = buf[bpos];
1127 /* do operands */
1128 for (f = 0; f <= 3; ++f) {
1129 if (f == 3) return opn;
1130 op = URASM_COMMANDS[opn].ops[f];
1131 if (op == UO_NONE || op == UO_NEXT) return opn;
1132 /* check for valid operand */
1133 if (is_opc_invalid_op(op, opc)) break;
1136 return -1;
1140 /* length of the corresponding instruction */
1141 int urasm_disasm_oplen (int idx) {
1142 int res = 0, f, op;
1143 uint32_t m, c;
1144 if (idx == -2) return 2;
1145 if (idx < 0 || idx >= URASM_MAX_COMMAND) return 1;
1146 if (idx < 2) return 1;
1147 m = URASM_COMMANDS[idx].mask; c = URASM_COMMANDS[idx].code;
1148 /* I?/CB? */
1150 if (((m&0xFFFFUL) == 0xFFFFUL) &&
1151 ((c&0xFF00UL) == 0xCBUL) && ((c&0xFFUL) == 0xDDUL || (c&0xFFUL) == 0xFDUL)) return 4;
1153 /* skip prefixes, determine command length */
1154 for (;;) {
1155 uint8_t b;
1156 if ((m&0xFFUL) != 0xFFUL) break;
1157 b = c&0xFFUL;
1158 if (b != 0xFDU && b != 0xDDU && b != 0xEDU && b != 0xCBU) break;
1159 m >>= 8; c >>= 8; ++res;
1161 /* is this CB-prefixed? */
1162 if (((URASM_COMMANDS[idx].code&0xFFFFUL) == 0xCBDDUL) ||
1163 ((URASM_COMMANDS[idx].code&0xFFFFUL) == 0xCBFDUL)) m >>= 8;
1164 /* count opcodes */
1165 while (m != 0) { m >>= 8; ++res; }
1166 /* process operands */
1167 for (f = 0; f <= 2; ++f) {
1168 op = URASM_COMMANDS[idx].ops[f];
1169 if (op == UO_NONE || op == UO_NEXT) break;
1170 switch (op) {
1171 /* command with displacement */
1172 case UO_MIX: case UO_MIY: ++res; break;
1173 /* command has immediate operand */
1174 case UO_IMM8: case UO_ADDR8: case UO_PORTIMM: ++res; break;
1175 case UO_IMM16: case UO_IMM16BE: case UO_ADDR16: case UO_MEM16: res += 2; break;
1178 return res;
1182 extern int urasm_disasm_opdisasm_ex (char *dstr, uint16_t addr, const uint8_t mem[8]) {
1183 int res, idx = 0;
1184 uint32_t ci, f, c;
1185 uint8_t opc;
1186 int bpos, opn, op;
1187 uint16_t nextW;
1188 char opstr[129];
1189 if (!dstr) return -1;
1190 if (mem[0] == 0xDDU || mem[0] == 0xFDU) {
1191 /* dummy prefix */
1192 if (IS_DD_SENSITIVE(mem[1])) {
1193 strcpy(dstr, URASM_TOKENS[mem[0]==0xDDU ? UT_NOPX : UT_NOPY]);
1194 return 1;
1196 /* take possible I? displacement */
1197 idx = (int8_t)mem[2];
1199 ci = ((uint32_t)mem[0]) | (((uint32_t)mem[1])<<8) | (((uint32_t)mem[2])<<16) | (((uint32_t)mem[3])<<24);
1200 for (opn = 0; opn < URASM_MAX_COMMAND; ++opn) {
1201 res = 0; dstr[0] = '\0';
1202 /* find command */
1203 for (; opn < URASM_MAX_COMMAND && (ci&URASM_COMMANDS[opn].mask) != URASM_COMMANDS[opn].code; ++opn) {}
1204 if (!urasm_allow_zxnext && URASM_COMMANDS[opn].ops[2] == UO_NEXT) opn = URASM_MAX_COMMAND; /* skip ZXNext if not allowed */
1205 if (opn >= URASM_MAX_COMMAND) {
1206 if (mem[0] == 0xEDU) {
1207 if (!urasm_disasm_decimal) sprintf(opstr, "#%02X,#%02X", mem[0], mem[1]); else sprintf(opstr, "%u,%u", mem[0], mem[1]);
1208 /*if (!urasm_disasm_decimal) sprintf(opstr, "#%04X", (uint16_t)buf[0]|(((uint16_t)buf[1])<<8));
1209 else sprintf(opstr, "%u", (uint16_t)buf[0]|(((uint16_t)buf[1])<<8));*/
1210 sprintf(dstr, "DB\t%s", opstr);
1211 return 2;
1213 if (!urasm_disasm_decimal) sprintf(opstr, "#%02X", mem[0]); else sprintf(opstr, "%u", mem[0]);
1214 sprintf(dstr, "DB\t%s", opstr);
1215 return 1;
1217 /* skip prefixes, determine command length */
1218 f = URASM_COMMANDS[opn].mask; c = URASM_COMMANDS[opn].code;
1219 for (bpos = 0; ; ++bpos) {
1220 uint8_t b;
1221 if ((f&0xFFUL) != 0xFFUL) break;
1222 b = c&0xFFUL;
1223 if (b != 0xFDU && b != 0xDDU && b != 0xEDU && b != 0xCBU) break;
1224 f >>= 8; c >>= 8; ++res;
1226 /* is this CB-prefixed? */
1227 if (((URASM_COMMANDS[opn].code&0xFFFFUL) == 0xCBDDUL) ||
1228 ((URASM_COMMANDS[opn].code&0xFFFFUL) == 0xCBFDUL)) f >>= 8;
1229 while (f != 0) { f >>= 8; ++res; }
1230 /* copy mnemonics */
1231 strcpy(dstr, URASM_TOKENS[URASM_COMMANDS[opn].mnemo]);
1232 /* are there any operands? */
1233 if (URASM_COMMANDS[opn].ops[0] == UO_NONE) return res;
1234 /* is this CB-prefixed? */
1235 if (((URASM_COMMANDS[opn].code&0xFFFFUL) == 0xCBDDUL) ||
1236 ((URASM_COMMANDS[opn].code&0xFFFFUL) == 0xCBFDUL)) ++bpos; /* skip displacement */
1237 else {
1238 if ((URASM_COMMANDS[opn].ops[0] == UO_MIX || URASM_COMMANDS[opn].ops[0] == UO_MIY) &&
1239 URASM_COMMANDS[opn].ops[1] == UO_IMM8 &&
1240 (URASM_COMMANDS[opn].ops[2] == UO_NONE || URASM_COMMANDS[opn].ops[2] == UO_NEXT)) ++bpos; /* skip displacement */
1242 opc = mem[bpos++];
1243 nextW = (uint16_t)mem[bpos] | (((uint16_t)mem[bpos+1])<<8);
1244 /* do operands */
1245 for (f = 0; f <= 3; ++f) {
1246 if (f == 3) {
1247 //printf("OPN=%d\n", opn);
1248 return res;
1250 op = URASM_COMMANDS[opn].ops[f];
1251 if (op == UO_NONE || op == UO_NEXT) {
1252 //printf("OPN=%d\n", opn);
1253 return res;
1255 /* check for valid operand */
1256 if (is_opc_invalid_op(op, opc)) break;
1257 /* command with displacement? */
1258 if (op == UO_MIX || op == UO_MIY) ++res;
1259 /* command has immediate operand? */
1260 if (op == UO_IMM8 || op == UO_ADDR8 || op == UO_PORTIMM) ++res;
1261 if (op == UO_IMM16 || op == UO_IMM16BE || op == UO_ADDR16 || op == UO_MEM16) res += 2;
1262 /* add delimiter */
1263 strcat(dstr, (f == 0 ? urasm_disasm_mnemo_delimiter : urasm_disasm_operand_delimiter));
1264 /* decode operand */
1265 ua_op2str(opstr, op, addr, opc, nextW, idx);
1266 strcat(dstr, opstr);
1269 return -1;
1273 int urasm_disasm_opdisasm (char *dstr, uint16_t addr) {
1274 uint8_t mem[8];
1275 if (!urasm_getbyte) return -1;
1276 for (unsigned f = 0; f < 8; ++f) mem[f] = urasm_getbyte((uint16_t)((addr+f)&0xffffu));
1277 return urasm_disasm_opdisasm_ex(dstr, addr, mem);
1281 ///////////////////////////////////////////////////////////////////////////////
1282 // assembler
1284 /* returns 0 if label name conflicts with reserved word */
1285 /* (or if the label is just a bad one) */
1286 int urasm_is_valid_name (const char *lbl) {
1287 int f, hasNA = 0;
1288 char ch, buf[6];
1289 if (!lbl || !lbl[0]) return 0;
1290 if (lbl[0] == '@') {
1291 ch = lbl[1];
1292 } else {
1293 ch = lbl[0];
1295 if (ch >= '0' && ch <= '9') return 0;
1296 if (!ur_isalpha(ch) && ch != '.' && ch != '_' && ch != '@') return 0;
1297 for (f = 1; lbl[f]; ++f) {
1298 ch = lbl[f];
1299 if (ch >= '0' && ch <= '9') continue;
1300 if (!ur_isalpha(ch)) {
1301 hasNA = 1;
1302 if (ch != '$' && ch != '.' && ch != '_' && ch != '@') return 0;
1305 if (hasNA || f > 4) return 1;
1306 for (f = 0; lbl[f]; ++f) buf[f] = ur_toupper(lbl[f]); buf[f] = '\0';
1307 for (f = 0; f < (!urasm_allow_zxnext ? URASM_MAX_NORMAL_TOKEN : URASM_MAX_TOKEN); ++f) if (!strcmp(buf, URASM_TOKENS[f])) return 0;
1308 for (f = 0; f < 8; ++f) if (!strcmp(buf, URA_REGS8[f])) return 0;
1309 for (f = 0; f < 4; ++f) if (!strcmp(buf, URA_REGS16[f])) return 0;
1310 for (f = 0; f < 4; ++f) if (!strcmp(buf, URA_REGS16A[f])) return 0;
1311 for (f = 0; f < 8; ++f) if (!strcmp(buf, URA_COND[f])) return 0;
1312 if (!strcmp(buf, "AFX")) return 0;
1313 if (!strcmp(buf, "IXH")) return 0;
1314 if (!strcmp(buf, "IXL")) return 0;
1315 if (!strcmp(buf, "IYH")) return 0;
1316 if (!strcmp(buf, "IYL")) return 0;
1317 if (!strcmp(buf, "IX")) return 0;
1318 if (!strcmp(buf, "IY")) return 0;
1319 if (!strcmp(buf, "XH")) return 0;
1320 if (!strcmp(buf, "HX")) return 0;
1321 if (!strcmp(buf, "XL")) return 0;
1322 if (!strcmp(buf, "LX")) return 0;
1323 if (!strcmp(buf, "YH")) return 0;
1324 if (!strcmp(buf, "HY")) return 0;
1325 if (!strcmp(buf, "YL")) return 0;
1326 if (!strcmp(buf, "LY")) return 0;
1327 if (!strcmp(buf, "R")) return 0;
1328 if (!strcmp(buf, "I")) return 0;
1329 return 1;
1333 ///////////////////////////////////////////////////////////////////////////////
1334 // scanner / parser
1336 // parse and calculate expression
1337 static inline const char *skip_blanks (const char *expr) {
1338 while (*expr && ur_isspace(*expr)) ++expr;
1339 return expr;
1343 ///////////////////////////////////////////////////////////////////////////////
1344 // expression parser
1345 urasm_getval_fn urasm_getval = NULL;
1346 urasm_expand_fn urasm_expand = NULL;
1349 typedef struct ur_function_s {
1350 struct ur_function_s *next;
1351 char *name;
1352 urasm_func_fn fn;
1353 } ur_function_t;
1355 static ur_function_t *fnlist = NULL;
1357 static void atexit_func_finalize (void) {
1358 while (fnlist != NULL) {
1359 ur_function_t *f = fnlist;
1360 fnlist = f->next;
1361 free(f->name);
1362 free(f);
1367 void urasm_expr_register_func (const char *name, urasm_func_fn fn) {
1368 if (name != NULL && name[0]) {
1369 static int atexitset = 0;
1370 ur_function_t *p, *c;
1371 if (!atexitset) { atexit(atexit_func_finalize); atexitset = 1; }
1372 for (p = NULL, c = fnlist; c != NULL; p = c, c = c->next) {
1373 if (strcasecmp(name, c->name) == 0) {
1374 /* replace or remove */
1375 if (fn == NULL) {
1376 /* remove */
1377 if (p == NULL) fnlist = c->next; else p->next = c->next;
1378 free(c->name);
1379 free(c);
1380 } else {
1381 /* replace */
1382 c->fn = fn;
1384 return;
1387 if (fn != NULL) {
1388 /* add new */
1389 c = malloc(sizeof(*c));
1390 c->name = strdup(name);
1391 c->fn = fn;
1392 c->next = fnlist;
1393 fnlist = c;
1399 urasm_func_fn urasm_expr_find_func (const char *name) {
1400 if (name != NULL && name[0]) {
1401 for (ur_function_t *c = fnlist; c != NULL; c = c->next) if (strcasecmp(name, c->name) == 0) return c->fn;
1403 return NULL;
1407 ///////////////////////////////////////////////////////////////////////////////
1408 typedef struct {
1409 const char *expr; /* can be changed */
1410 uint16_t addr; /* current address */
1411 int defined; /* !0: all used labels are defined */
1412 int error; /* !0: error */
1413 const char *errpos; /* will be set on error, has no meaning otherwise */
1414 jmp_buf errJP;
1415 int logic_done;
1416 int32_t logic_res;
1417 } expr_info_t;
1420 /* do math; op0 is the result */
1421 typedef void (*expr_doit_fn) (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei);
1423 enum {
1424 optype_none,
1425 optype_unary,
1426 optype_math,
1427 optype_bitwise,
1428 optype_shift,
1429 optype_logic,
1430 optype_comparison,
1433 typedef struct {
1434 char sn; /* short name or 0 */
1435 const char *ln; /* long name or NULL if `sn`!=0 */
1436 int prio; /* priority */
1437 expr_doit_fn doer;
1438 int type;
1439 } expr_operator_t;
1442 ///////////////////////////////////////////////////////////////////////////////
1443 // math ops
1444 /* returns !0 is passed string is not NULL, and longer than 2 chars */
1445 static inline __attribute__((always_inline)) __attribute__((pure))
1446 int ur_is_long_str (const char *s) { return (s && s[0] && s[1] && s[2]); }
1448 #define EERROR(code) longjmp(ei->errJP, code)
1450 #define CHECKVALNOTSTR(_v,_vkill) do { \
1451 if ((_v)->str != NULL) { \
1452 if (ur_is_long_str((_v)->str)) { \
1453 if ((_vkill) != NULL) urasm_exprval_clear((_vkill)); \
1454 EERROR(UR_EXPRERR_TYPE); \
1456 free((_v)->str); \
1457 (_v)->str = NULL; \
1459 } while (0)
1461 #define CHECKARGSNOTSTR do { \
1462 CHECKVALNOTSTR(op0, op1); \
1463 CHECKVALNOTSTR(op1, op1); \
1464 } while (0)
1467 #define PROPAGATE_FIXUP do { \
1468 if (op0->fixuptype == UR_FIXUP_NONE) { \
1469 op0->fixuptype = op1->fixuptype; \
1470 } else if (op0->fixuptype == UR_FIXUP_WORD) { \
1471 if (op1->fixuptype != UR_FIXUP_NONE) op0->fixuptype = op1->fixuptype; \
1472 } else if (op1->fixuptype != UR_FIXUP_NONE && op0->fixuptype != op1->fixuptype) { \
1473 urasm_exprval_clear(op1);\
1474 urasm_exprval_clear(op0); \
1475 EERROR(UR_EXPRERR_FIXUP); \
1477 } while (0)
1480 static void mdo_bitnot (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) {
1481 op0->val = ~op0->val;
1482 op0->fixuptype = UR_FIXUP_NONE;
1484 static void mdo_lognot (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) {
1485 op0->val = !op0->val;
1486 op0->fixuptype = UR_FIXUP_NONE;
1488 static void mdo_uminus (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) {
1489 op0->val = -op0->val;
1490 op0->fixuptype = UR_FIXUP_NONE;
1492 static void mdo_uplus (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) {
1495 static void mdo_bitand (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) {
1496 op0->val &= op1->val;
1497 if (op1->val == 0) op0->fixuptype = UR_FIXUP_NONE;
1498 else if (op0->fixuptype != UR_FIXUP_NONE) {
1499 switch (op1->val) {
1500 case 0x00ff: op0->fixuptype = (op0->fixuptype == UR_FIXUP_WORD ? UR_FIXUP_LOBYTE : UR_FIXUP_NONE); break;
1501 case 0xff00: op0->fixuptype = (op0->fixuptype == UR_FIXUP_WORD ? UR_FIXUP_HIBYTE : UR_FIXUP_NONE); break;
1503 } else {
1504 PROPAGATE_FIXUP;
1507 static void mdo_bitor (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { op0->val |= op1->val; op0->fixuptype = UR_FIXUP_NONE; }
1508 static void mdo_bitxor (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { op0->val ^= op1->val; op0->fixuptype = UR_FIXUP_NONE; }
1509 static void mdo_shl (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { op0->val <<= op1->val; op0->fixuptype = UR_FIXUP_NONE; }
1510 static void mdo_shr (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { op0->val >>= op1->val; }
1511 static void mdo_shru (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { *(uint32_t *)&op0->val >>= op1->val; }
1512 static void mdo_mul (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { op0->val *= op1->val; op0->fixuptype = UR_FIXUP_NONE; }
1513 static void mdo_div (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { if (op1->val == 0) EERROR(UR_EXPRERR_DIV0); op0->val /= op1->val; op0->fixuptype = UR_FIXUP_NONE; }
1514 static void mdo_mod (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { if (op1->val == 0) EERROR(UR_EXPRERR_DIV0); op0->val %= op1->val; op0->fixuptype = UR_FIXUP_NONE; }
1515 static void mdo_add (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { op0->val += op1->val; PROPAGATE_FIXUP; }
1516 static void mdo_sub (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { op0->val -= op1->val; PROPAGATE_FIXUP; }
1518 static int mdo_compare (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) {
1519 const int isnum0 = !ur_is_long_str(op0->str);
1520 const int isnum1 = !ur_is_long_str(op1->str);
1521 //fprintf(stderr, "mdo_compare: num0=%d; num1=%d (%s) (%s)\n", isnum0, isnum1, op0->str, op1->str);
1522 if (isnum0 != isnum1) EERROR(UR_EXPRERR_TYPES);
1523 if (isnum0) {
1524 return
1525 op0->val < op1->val ? -1 :
1526 op0->val > op1->val ? 1 :
1528 } else {
1529 return strcmp(op0->str, op1->str);
1533 static void mdo_set_int (urasm_exprval_t *op0, const int32_t v) {
1534 urasm_exprval_clear(op0);
1535 op0->val = v;
1538 static void mdo_cmp_ls (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { mdo_set_int(op0, (mdo_compare(op0, op1, ei) < 0)); }
1539 static void mdo_cmp_gt (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { mdo_set_int(op0, (mdo_compare(op0, op1, ei) > 0)); }
1540 static void mdo_cmp_eq (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { mdo_set_int(op0, (mdo_compare(op0, op1, ei) == 0)); }
1541 static void mdo_cmp_ne (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { mdo_set_int(op0, (mdo_compare(op0, op1, ei) != 0)); }
1542 static void mdo_cmp_le (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { mdo_set_int(op0, (mdo_compare(op0, op1, ei) <= 0)); }
1543 static void mdo_cmp_ge (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) { mdo_set_int(op0, (mdo_compare(op0, op1, ei) >= 0)); }
1545 static void mdo_log_and (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) {
1546 ei->logic_res = op0->val = (op0->val && op1->val);
1547 if (!op0->val) ei->logic_done = 1;
1548 op0->fixuptype = UR_FIXUP_NONE;
1551 static void mdo_log_or (urasm_exprval_t *op0, urasm_exprval_t *op1, expr_info_t *ei) {
1552 ei->logic_res = op0->val = (op0->val || op1->val);
1553 if (op0->val) ei->logic_done = 1;
1554 op0->fixuptype = UR_FIXUP_NONE;
1558 // priority level 1 -- opertiors line "." and "[]", function calls
1559 // priority level 2 -- unary opertiors like "!" and "~"
1560 // short forms must be put before long
1561 // priorities must be sorted
1562 static const expr_operator_t operators_old[] = {
1563 // unaries
1564 { '~', NULL, 2, mdo_bitnot, optype_unary },
1565 { '!', NULL, 2, mdo_lognot, optype_unary },
1566 { '-', NULL, 2, mdo_uminus, optype_unary },
1567 { '+', NULL, 2, mdo_uplus, optype_unary },
1568 // shifts
1569 { 0, "<<", 3, mdo_shl, optype_shift },
1570 { 0, ">>", 3, mdo_shr, optype_shift },
1571 { 0, ">>>", 3, mdo_shru, optype_shift },
1572 // bitwise and
1573 { '&', NULL, 4, mdo_bitand, optype_bitwise },
1574 // bitwise or and xor
1575 { '|', NULL, 5, mdo_bitor, optype_bitwise },
1576 { '^', NULL, 5, mdo_bitxor, optype_bitwise },
1577 // mul/div/mod
1578 { '*', NULL, 6, mdo_mul, optype_math },
1579 { '/', NULL, 6, mdo_div, optype_math },
1580 { '%', NULL, 6, mdo_mod, optype_math },
1581 // add/subtract
1582 { '+', NULL, 7, mdo_add, optype_math },
1583 { '-', NULL, 7, mdo_sub, optype_math },
1584 // logic and
1585 { 0, "&&", 8, mdo_log_and, optype_logic },
1586 // logic or
1587 { 0, "||", 9, mdo_log_or, optype_logic },
1588 // comparisons
1589 { '<', NULL, 10, mdo_cmp_ls, optype_comparison },
1590 { '>', NULL, 10, mdo_cmp_gt, optype_comparison },
1591 { '=', NULL, 10, mdo_cmp_eq, optype_comparison },
1592 { 0, "==", 10, mdo_cmp_eq, optype_comparison },
1593 { 0, "!=", 10, mdo_cmp_ne, optype_comparison },
1594 { 0, "<>", 10, mdo_cmp_ne, optype_comparison },
1595 { 0, "<=", 10, mdo_cmp_le, optype_comparison },
1596 { 0, ">=", 10, mdo_cmp_ge, optype_comparison },
1597 // no more
1598 { 0, NULL, -1, NULL, optype_none },
1600 // new C-like priorities
1601 static const expr_operator_t operators_new[] = {
1602 // unaries
1603 { '~', NULL, 2, mdo_bitnot, optype_unary },
1604 { '!', NULL, 2, mdo_lognot, optype_unary },
1605 { '-', NULL, 2, mdo_uminus, optype_unary },
1606 { '+', NULL, 2, mdo_uplus, optype_unary },
1607 // shifts
1608 { 0, "<<", 3, mdo_shl, optype_shift },
1609 { 0, ">>", 3, mdo_shr, optype_shift },
1610 { 0, ">>>", 3, mdo_shru, optype_shift },
1611 // bitwise and
1612 { '&', NULL, 4, mdo_bitand, optype_bitwise },
1613 // bitwise or and xor
1614 { '|', NULL, 5, mdo_bitor, optype_bitwise },
1615 { '^', NULL, 5, mdo_bitxor, optype_bitwise },
1616 // mul/div/mod
1617 { '*', NULL, 6, mdo_mul, optype_math },
1618 { '/', NULL, 6, mdo_div, optype_math },
1619 { '%', NULL, 6, mdo_mod, optype_math },
1620 // add/subtract
1621 { '+', NULL, 7, mdo_add, optype_math },
1622 { '-', NULL, 7, mdo_sub, optype_math },
1623 // comparisons
1624 { '<', NULL, 8, mdo_cmp_ls, optype_comparison },
1625 { '>', NULL, 8, mdo_cmp_gt, optype_comparison },
1626 { '=', NULL, 8, mdo_cmp_eq, optype_comparison },
1627 { 0, "==", 8, mdo_cmp_eq, optype_comparison },
1628 { 0, "!=", 8, mdo_cmp_ne, optype_comparison },
1629 { 0, "<>", 8, mdo_cmp_ne, optype_comparison },
1630 { 0, "<=", 8, mdo_cmp_le, optype_comparison },
1631 { 0, ">=", 8, mdo_cmp_ge, optype_comparison },
1632 // logic and
1633 { 0, "&&", 9, mdo_log_and, optype_logic },
1634 // logic or
1635 { 0, "||", 10, mdo_log_or, optype_logic },
1636 // no more
1637 { 0, NULL, -1, NULL, optype_none },
1639 #define UNARY_PRIO (2)
1641 #define MAX_PRIO (10)
1642 #define PRIO_LAND (8)
1643 #define PRIO_LOR (9)
1645 static int max_prio_old = 0;
1646 static int prio_land_old = 0;
1647 static int prio_lor_old = 0;
1649 static int max_prio = 0;
1650 static int prio_land = 0;
1651 static int prio_lor = 0;
1653 int urasm_use_old_priorities = 0;
1654 int urasm_allow_hex_castrates = 0;
1656 static inline __attribute__((always_inline)) int get_max_prio () { return (!urasm_use_old_priorities ? max_prio : max_prio_old); }
1657 static inline __attribute__((always_inline)) int get_land_prio () { return (!urasm_use_old_priorities ? prio_land : prio_land_old); }
1658 static inline __attribute__((always_inline)) int get_lor_prio () { return (!urasm_use_old_priorities ? prio_lor : prio_lor_old); }
1660 static __attribute((constructor)) void init_priorities (void) {
1661 if (max_prio_old) return;
1662 // old priorities
1663 for (const expr_operator_t *op = operators_old; op->prio >= 0; ++op) {
1664 if (max_prio_old < op->prio) max_prio_old = op->prio;
1665 if (op->doer == &mdo_log_and) prio_land_old = op->prio;
1666 else if (op->doer == &mdo_log_or) prio_lor_old = op->prio;
1668 // new priorities
1669 for (const expr_operator_t *op = operators_new; op->prio >= 0; ++op) {
1670 if (max_prio < op->prio) max_prio = op->prio;
1671 if (op->doer == &mdo_log_and) prio_land = op->prio;
1672 else if (op->doer == &mdo_log_or) prio_lor = op->prio;
1677 /******************************************************************************/
1678 /* expression parser engine */
1679 /******************************************************************************/
1680 static void expression (urasm_exprval_t *res, expr_info_t *ei);
1683 #define SKIP_BLANKS { ei->errpos = ei->expr = skip_blanks(ei->expr); }
1685 #define PSEMITCHAR(_ch) do { \
1686 if (!doinglen) res->str[len++] = (_ch); else ++len; \
1687 } while (0)
1689 // qch skipped
1690 static const char *parse_string (urasm_exprval_t *res, char qch, const char *expr, int *error, int *lenp) {
1691 int doinglen = 2;
1692 if (lenp) *lenp = 0;
1693 if (*error) return expr;
1694 if (!expr[0]) { *error = 1; return expr; }
1695 //memset(buf, 0, sizeof(buf));
1696 for (;;) {
1697 int len = 0, n, f, base;
1698 const char *a = expr;
1699 --doinglen;
1700 for (; *a; ++a) {
1701 if (*a == '\\') {
1702 if (!a[1]) break;
1703 switch (*(++a)) {
1704 case 'a': PSEMITCHAR('\a'); break;
1705 case 'b': PSEMITCHAR('\b'); break;
1706 case 'e': PSEMITCHAR('\x1b'); break;
1707 case 'f': PSEMITCHAR('\f'); break;
1708 case 'n': PSEMITCHAR('\n'); break;
1709 case 'r': PSEMITCHAR('\r'); break;
1710 case 't': PSEMITCHAR('\t'); break;
1711 case 'v': PSEMITCHAR('\v'); break;
1712 case 'z': PSEMITCHAR('\0'); break;
1713 case 'x': case 'X': /* hex */
1714 ++a; /* skip 'x' */
1715 base = 16; f = 2;
1716 donum: for (n = 0; f > 0; --f) {
1717 char ch = dig2n(*a++, base);
1718 if (ch < 0) { --a; break; }
1719 n *= base;
1720 n += ch;
1722 PSEMITCHAR(n);
1723 --a; /* return to the last digit, 'for' will skip it */
1724 break;
1725 case '0': /* octal */
1726 base = 8; f = 4;
1727 goto donum;
1728 case '1' ... '9': /* decimal */
1729 base = 10; f = 3;
1730 goto donum;
1731 default: PSEMITCHAR(a[0]); break; /* others */
1733 } else {
1734 if (*a == qch) { ++a; break; }
1735 PSEMITCHAR(*a);
1738 if (doinglen) {
1739 res->str = calloc(len+1, 1);
1740 if (lenp) *lenp = len;
1741 } else {
1742 return a;
1748 static int try_suffix_base (const char *s, char sfx, int base) {
1749 if (!s || !s[0]) return 0;
1750 while (*s == '_') ++s; /* just in case */
1751 if (dig2n(*s++, base) < 0) return 0;
1752 /* we don't need to check for zero here, because `dig2n()` will do this for us */
1753 for (;;) {
1754 const char ch = *s++;
1755 if (ch != '_' && dig2n(ch, base) < 0) {
1756 return (ch && ur_toupper(ch) == sfx && dig2n(*s, 16) < 0);
1762 /*TODO: make suffix detector one-pass */
1763 static int check_number_base_sfx (const char *s) {
1764 if (!s || !s[0]) return 0;
1765 while (*s == '_') ++s; /* just in case */
1766 /* check suffixes (suffix char must be passed as uppercase) */
1767 if (try_suffix_base(s, 'H', 16)) return 16;
1768 if (try_suffix_base(s, 'B', 2)) return 2;
1769 if (try_suffix_base(s, 'O', 8)) return 8;
1770 if (try_suffix_base(s, 'D', 10)) return 10;
1771 return 0;
1775 static int check_number_base_char (char ch) {
1776 switch (ur_toupper(ch)) {
1777 case 'X': case 'H': return 16;
1778 case 'B': return 2;
1779 case 'O': return 8;
1780 case 'D': return 10;
1781 default: break;
1783 return 0;
1787 static const char *parse_number (urasm_exprval_t *res, const char *expr, int *error) {
1788 int prefixed = 1;
1789 if (*error) return expr;
1790 if (!expr[0]) { *error = 1; return expr; }
1791 const char *estart = expr;
1792 /* detect suffix first */
1793 int base = check_number_base_sfx(expr);
1794 if (base) {
1795 /* the suffix is ok */
1796 prefixed = 0; /* note that it is suffixed number, not prefixed */
1797 } else {
1798 /* no good suffix, check prefixes */
1799 switch (*expr) {
1800 case '0': /* this allows "0habcd" as hex number too; why not? */
1801 base = check_number_base_char(expr[1]);
1802 if (base) expr += 2; else base = 8;
1803 break;
1804 case '%': base = 2; ++expr; break;
1805 case '#': case '$': base = 16; ++expr; break;
1806 case '1' ... '9': base = 10; break;
1807 case '&':
1808 base = check_number_base_char(expr[1]);
1809 // check for ambiguity
1810 if (urasm_allow_hex_castrates && base == 2) {
1811 // '&b10' can be either binary, or hex; parse it as hex if castrates are allowed
1812 base = 16;
1814 if (base) { expr += 2; break; }
1815 // some assemblers are using lone '&' for hex numbers, let's support it too
1816 // note that there is an ambiguity: '&b10' can be either binary, or hex
1817 // currently, it will be parsed as binary
1818 if (urasm_allow_hex_castrates && dig2n(expr[1], 16) >= 0) { base = 16; ++expr; break; }
1819 /* fallthru */
1820 default: *error = 1; return estart;
1823 /* parse number (ignore underscores) */
1824 while (*expr && *expr == '_') ++expr;
1825 if (dig2n(*expr, base) < 0) { *error = 1; return estart; }
1826 int n = 0;
1827 for (;;) {
1828 char ch = *expr++;
1829 if (ch == '_') continue;
1830 int d = dig2n(ch, base);
1831 if (d < 0) { res->val = n; return expr-prefixed; } /* `prefixed` set to 1 if there's no suffix */
1832 n *= base;
1833 /* this check is UB in standards-compliant C, because standard was created by morons */
1834 if (n < 0) { *error = 1; return estart; }
1835 n += d;
1840 static void get_addr (const char *lbl, urasm_exprval_t *res, expr_info_t *ei) {
1841 int defined = 0, found = 0;
1842 int32_t val = 0;
1843 if (urasm_label_by_name == NULL) EERROR(UR_EXPRERR_LABEL);
1844 res->fixuptype = UR_FIXUP_NONE;
1845 val = urasm_label_by_name(lbl, ei->addr, &defined, &found, &res->fixuptype);
1846 if (!found) EERROR(UR_EXPRERR_LABEL);
1847 if (!defined) ei->defined = 0;
1848 res->val = val;
1852 // !0: invalid label
1853 static int read_label_name (char *buf, expr_info_t *ei) {
1854 int pos = 0;
1855 for (;;) {
1856 if (pos >= 128) return -3;
1857 char ch = ei->expr[0];
1858 if (!ch) break;
1859 if (ur_isalnum(ch) || ch == '$' || ch == '.' || ch == '_' || ch == '@') {
1860 buf[pos++] = ch;
1861 ++(ei->expr);
1862 } else {
1863 break;
1866 if (pos < 1) return -2;
1867 buf[pos] = '\0';
1868 if (!urasm_is_valid_name(buf)) return -1;
1869 return 0;
1873 static void term (urasm_exprval_t *res, expr_info_t *ei) {
1874 char ch, lbl[130];
1875 int tmp = 0, len;
1876 if (res->str != NULL) { free(res->str); res->str = NULL; }
1877 SKIP_BLANKS
1878 ch = (res->pos = ei->errpos = ei->expr)[0];
1879 if (!ch) EERROR(UR_EXPRERR_EOS);
1880 switch (ch) {
1881 case '[': case '(':
1882 ++(ei->expr);
1883 ch = (ch == '[' ? ']' : ')');
1884 expression(res, ei);
1885 if (ei->expr[0] != ch) EERROR(UR_EXPRERR_PARENS);
1886 ++(ei->expr);
1887 break;
1888 case '0' ... '9': case '#': case '%':
1889 donumber:
1890 ei->expr = parse_number(res, ei->expr, &tmp);
1891 if (tmp) EERROR(UR_EXPRERR_NUMBER);
1892 break;
1893 case '$':
1894 if (dig2n(ei->expr[1], 16) >= 0) goto donumber;
1895 res->val = ei->addr;
1896 res->fixuptype = UR_FIXUP_WORD;
1897 ++(ei->expr);
1898 break;
1899 case '&':
1900 if (ur_toupper(ei->expr[1]) == 'H' && dig2n(ei->expr[2], 16) >= 0) goto donumber;
1901 if (ur_toupper(ei->expr[1]) == 'X' && dig2n(ei->expr[2], 16) >= 0) goto donumber;
1902 if (ur_toupper(ei->expr[1]) == 'O' && dig2n(ei->expr[2], 8) >= 0) goto donumber;
1903 if (ur_toupper(ei->expr[1]) == 'B' && dig2n(ei->expr[2], 2) >= 0) goto donumber;
1904 if (ur_toupper(ei->expr[1]) == 'D' && dig2n(ei->expr[2], 10) >= 0) goto donumber;
1905 // some assemblers are using lone '&' for hex numbers, let's support it too
1906 if (urasm_allow_hex_castrates && dig2n(ei->expr[1], 16) >= 0) goto donumber;
1907 goto dodefault;
1908 case '"': /* char or 2 chars */
1909 case '\'': /* char or 2 reversed chars */
1910 res->val = 0;
1911 ei->expr = parse_string(res, ch, ei->expr+1, &tmp, &len);
1912 if (tmp) EERROR(UR_EXPRERR_STRING);
1913 if (len == 1) {
1914 res->val = (unsigned char)res->str[0];
1915 } else if (len >= 2) {
1916 res->val = ((unsigned char)res->str[0])<<(ch == '"' ? 0 : 8);
1917 res->val |= ((unsigned char)res->str[1])<<(ch == '"' ? 8 : 0);
1919 break;
1920 case ';':
1921 case ':':
1922 EERROR(UR_EXPRERR_TERM);
1923 case ')':
1924 case ']':
1925 return;
1926 case '=':
1927 case '*':
1928 if (urasm_getval != NULL) {
1929 ei->expr = urasm_getval(res, ei->expr, ei->addr, ei->logic_done, &ei->defined, &ei->error);
1930 if (ei->error != UR_EXPRERR_NONE) EERROR(ei->error);
1931 } else {
1932 EERROR(UR_EXPRERR_MARG);
1934 break;
1935 default:
1936 dodefault:
1937 if (read_label_name(lbl, ei)) EERROR(UR_EXPRERR_LABEL);
1938 SKIP_BLANKS
1939 if (ei->expr[0] == '(') {
1940 /* function call */
1941 urasm_func_fn fn = urasm_expr_find_func(lbl);
1942 const char *e;
1943 if (fn == NULL) EERROR(UR_EXPRERR_FUNC);
1944 ++(ei->expr); /* skip '(' */
1945 e = fn(res, ei->expr, ei->addr, ei->logic_done, &ei->defined, &ei->error);
1946 if (ei->error != UR_EXPRERR_NONE) EERROR(ei->error);
1947 else if (e == NULL) EERROR(UR_EXPRERR_FUNC);
1948 else ei->expr = e;
1949 } else {
1950 /* just a label */
1951 if (!ei->logic_done) get_addr(lbl, res, ei);
1953 break;
1958 static const expr_operator_t *get_operator (int prio, expr_info_t *ei) {
1959 const char opc = ei->expr[0];
1960 int oplen = 1;
1961 const expr_operator_t *res = NULL;
1962 for (const expr_operator_t *op = (!urasm_use_old_priorities ? operators_new : operators_old); op->prio >= 0; ++op) {
1963 if (op->sn) {
1964 //fprintf(stderr, "get_operator: prio=%d; sn=%c; opc=%c\n", prio, op->sn, opc);
1965 if (op->prio == prio && oplen <= 1 && opc == op->sn) { res = op; oplen = 1; }
1966 } else {
1967 const int l = (int)strlen(op->ln);
1968 if (l > oplen && strncmp(ei->expr, op->ln, l) == 0) { res = op; oplen = l; }
1971 if (res && res->prio != prio) res = NULL;
1972 //if (res) fprintf(stderr, "res: prio=%d; sn='%c' \"%s\" (%d : %.*s)\n", prio, res->sn, res->ln, oplen, (unsigned)oplen, ei->expr);
1973 if (res) ei->expr += oplen; /* eat operator */
1974 return res;
1978 #define CHECKNOTSTR do { \
1979 if (ur_is_long_str(res->str) || ur_is_long_str(o1.str)) { \
1980 urasm_exprval_clear(&o1); \
1981 urasm_exprval_clear(res); \
1982 EERROR(UR_EXPRERR_TYPE); \
1984 } while (0)
1987 static void expr_do (int prio, urasm_exprval_t *res, expr_info_t *ei) {
1988 const expr_operator_t *op;
1989 urasm_exprval_t o1;
1990 SKIP_BLANKS
1991 if (ei->expr[0] == ')' || ei->expr[0] == ']') return;
1992 if (prio <= 0) { term(res, ei); return; }
1993 urasm_exprval_init(&o1);
1994 //fprintf(stderr, "expr_do: prio=%d <%s>\n", prio, ei->expr);
1995 if (prio == UNARY_PRIO) {
1996 //fprintf(stderr, "expr_do: prio=%d <%s>\n", prio, ei->expr);
1997 int wasIt = 0;
1998 for (;;) {
1999 SKIP_BLANKS
2000 ei->errpos = ei->expr;
2001 if (!(op = get_operator(prio, ei))) break;
2002 //fprintf(stderr, "UNARY: op=%c\n", op->sn);
2003 //expression(res, ei);
2004 if (op->sn == '-' || op->sn == '+') {
2005 expr_do(prio-1, res, ei); /* left-associative */
2006 } else {
2007 expr_do(prio, res, ei); /* right-associative */
2009 if (!ei->logic_done) {
2010 CHECKNOTSTR;
2011 op->doer(res, &o1, ei);
2012 } else {
2013 res->fixuptype = UR_FIXUP_NONE;
2014 res->val = ei->logic_res;
2016 wasIt = 1;
2017 if (op->sn == '-' || op->sn == '+') break;
2019 if (!wasIt) expr_do(prio-1, res, ei); /* left-associative */
2020 return;
2022 /* first operand */
2023 expr_do(prio-1, res, ei); /* first operand, left-associative */
2024 /* go on */
2025 for (;;) {
2026 SKIP_BLANKS
2027 ei->errpos = ei->expr;
2028 if (!ei->expr[0] || ei->expr[0] == ';' || ei->expr[0] == ':' || ei->expr[0] == ')' || ei->expr[0] == ']') break;
2029 //fprintf(stderr, "BINARY: prio=%d; expr=<%s>\n", prio, ei->expr);
2030 if (!(op = get_operator(prio, ei))) break;
2031 if (!ei->logic_done) {
2032 if (prio == get_land_prio()) {
2033 /* && */
2034 if (!res->val) { ei->logic_done = 1; ei->logic_res = 0; }
2035 } else if (prio == get_lor_prio()) {
2036 /* || */
2037 if (res->val) { ei->logic_done = 1; ei->logic_res = res->val; }
2040 //fprintf(stderr, "BINARY:000: prio=%d; expr=<%s>; op=%c(%s)\n", prio, ei->expr, op->sn, op->ln);
2041 expr_do(prio-1, &o1, ei); /* second operand, left-associative */
2042 //fprintf(stderr, "BINARY:001: prio=%d; expr=<%s>; op=%c(%s)\n", prio, ei->expr, op->sn, op->ln);
2043 if (!ei->logic_done) {
2044 if (op->type != optype_comparison) {
2045 CHECKNOTSTR;
2047 //fprintf(stderr, "DOER:BEFORE: op=%c(%s); prio=%d; val=%d (%d : %d)\n", op->sn, op->ln, op->prio, res->val, ei->logic_done, ei->logic_res);
2048 op->doer(res, &o1, ei);
2049 //fprintf(stderr, "DOER:AFTER: val=%d (%d : %d)\n", res->val, ei->logic_done, ei->logic_res);
2050 urasm_exprval_clear(&o1);
2051 } else {
2052 res->fixuptype = UR_FIXUP_NONE;
2053 res->val = ei->logic_res;
2059 static void expression (urasm_exprval_t *res, expr_info_t *ei) {
2060 SKIP_BLANKS
2061 ei->errpos = ei->expr;
2062 if (!ei->expr[0]) EERROR(UR_EXPRERR_EOS);
2063 expr_do(get_max_prio(), res, ei);
2064 SKIP_BLANKS
2068 const char *urasm_expr_ex (urasm_exprval_t *res, const char *expr, uint16_t addr, int *donteval, int *defined, int *error) {
2069 expr_info_t ei;
2070 int jr;
2071 urasm_exprval_clear(res);
2072 if (error) *error = 0;
2073 if (!expr) { if (error) *error = UR_EXPRERR_EOS; return NULL; }
2074 if (res->str != NULL) { free(res->str); res->str = NULL; }
2075 ei.expr = expr;
2076 ei.addr = addr;
2077 ei.defined = (defined ? *defined : 1);
2078 ei.error = 0;
2079 ei.logic_done = (donteval ? *donteval : 0);
2080 ei.logic_res = 0;
2081 jr = setjmp(ei.errJP);
2082 if (jr) {
2083 urasm_exprval_clear(res);
2084 if (error) *error = ei.error;
2085 return ei.errpos;
2087 expression(res, &ei);
2088 if (defined) *defined = ei.defined;
2089 if (donteval) *donteval = ei.logic_done;
2090 return ei.expr;
2094 const char *urasm_expr (int32_t *res, const char *expr, uint16_t addr, int *defined, int *fixuptype, int *error) {
2095 urasm_exprval_t r;
2096 const char *ret;
2097 int err;
2098 if (defined) *defined = 1;
2099 if (fixuptype) *fixuptype = UR_FIXUP_NONE;
2100 urasm_exprval_init(&r);
2101 ret = urasm_expr_ex(&r, expr, addr, NULL, defined, &err);
2102 if (error) *error = err;
2103 if (!err) {
2104 if (fixuptype) *fixuptype = r.fixuptype;
2105 if (ur_is_long_str(r.str)) {
2106 if (error) *error = UR_EXPRERR_TYPE;
2107 ret = r.pos;
2108 } else if (res) {
2109 *res = r.val;
2111 } else {
2112 if (res) *res = 0;
2114 urasm_exprval_clear(&r);
2115 return ret;
2119 void urasm_exprval_init (urasm_exprval_t *res) {
2120 if (res != NULL) {
2121 memset(res, 0, sizeof(*res));
2122 res->fixuptype = UR_FIXUP_NONE;
2127 void urasm_exprval_clear (urasm_exprval_t *res) {
2128 if (res != NULL) {
2129 if (res->str != NULL) {
2130 free(res->str);
2131 res->str = NULL;
2133 res->val = 0;
2134 res->fixuptype = UR_FIXUP_NONE;
2139 void urasm_exprval_setint (urasm_exprval_t *res, int32_t v) {
2140 if (res->str) { free(res->str); res->str = NULL; }
2141 res->val = v;
2145 /* sets val as in double quotes */
2146 void urasm_exprval_tostr (urasm_exprval_t *res, const char *str) {
2147 if (!str) {
2148 urasm_exprval_setint(res, 0);
2149 } else {
2150 const size_t slen = strlen(str);
2151 res->str = realloc(res->str, slen+1);
2152 strcpy(res->str, str);
2153 if (slen == 1) {
2154 res->val = (unsigned char)res->str[0];
2155 } else {
2156 res->val = (unsigned char)res->str[0];
2157 res->val |= ((unsigned char)res->str[1])<<8;
2163 /* sets val as in single quotes */
2164 void urasm_exprval_tostr_rev (urasm_exprval_t *res, const char *str) {
2165 if (!str) {
2166 urasm_exprval_setint(res, 0);
2167 } else {
2168 const size_t slen = strlen(str);
2169 res->str = realloc(res->str, slen+1);
2170 strcpy(res->str, str);
2171 if (slen == 1) {
2172 res->val = (unsigned char)res->str[0];
2173 } else {
2174 res->val = ((unsigned char)res->str[0])<<8;
2175 res->val |= (unsigned char)res->str[1];
2181 ///////////////////////////////////////////////////////////////////////////////
2182 // operand parser
2184 const char *urasm_skip_operand (const char *expr, int *seenarg) {
2185 if (seenarg) *seenarg = 0;
2186 if (!expr) return NULL;
2187 expr = skip_blanks(expr);
2188 if (!expr[0] || expr[0] == ';') return NULL;
2189 if (expr[0] == ':' || expr[0] == ',') return expr; /* colon or comma, nothing to do here */
2190 if (seenarg) *seenarg = 1;
2191 char inQ = 0;
2192 int parens = 0;
2193 const char *oe = expr;
2194 for (; *expr; ++expr) {
2195 const char ch = *expr;
2196 if (inQ) {
2197 if (ch == inQ) inQ = 0;
2198 else if (ch == '\\' && expr[1]) ++expr;
2199 } else {
2200 if (ch == '"' || ch == '`') inQ = ch;
2201 else if (ch == '\'' && (expr == oe || !ur_isalnum(expr[-1]))) inQ = ch;
2202 else if (ch == '(') ++parens;
2203 else if (ch == ')') { if (--parens < 0) parens = 0; }
2204 else if (ch == ';') break;
2205 else if (parens == 0 && (ch == ',' || ch == ':')) break;
2208 return expr;
2212 /* error is `UR_EXPRERR_XXX` */
2213 const char *urasm_next_operand (urasm_operand_t *op, const char *expr, uint16_t addr, int *error) {
2214 const char *oe;
2215 char opstr[256];
2216 char inQ = 0;
2217 int parens = 0;
2218 int f;
2219 *error = UR_EXPRERR_NONE;
2220 memset(op, 0, sizeof(urasm_operand_t));
2221 op->defined = 1;
2222 if (!expr) return NULL;
2223 expr = skip_blanks(expr);
2224 if (!expr[0] || expr[0] == ';') return NULL;
2225 if (expr[0] == ':') return expr;
2226 op->parsed = 1;
2227 op->fixuptype = UR_FIXUP_NONE;
2228 /* skip operand */
2229 for (oe = expr; *expr; ++expr) {
2230 const char ch = *expr;
2231 if (inQ) {
2232 if (ch == inQ) inQ = 0;
2233 else if (ch == '\\' && expr[1]) ++expr;
2234 } else {
2235 if (ch == '"' || ch == '`') inQ = ch;
2236 else if (ch == '\'' && (oe == expr || !ur_isalnum(expr[-1]))) inQ = ch;
2237 else if (ch == '(') ++parens;
2238 else if (ch == ')') { if (--parens < 0) parens = 0; }
2239 else if (ch == ';') break;
2240 else if (parens == 0 && (ch == ',' || ch == ':')) break;
2243 if (expr-oe > 255) { *error = UR_EXPRERR_TOOLONG; return oe; }
2244 memset(opstr, 0, sizeof(opstr));
2245 memcpy(opstr, oe, expr-oe);
2246 while (opstr[0] && ur_isspace(opstr[strlen(opstr)-1])) opstr[strlen(opstr)-1] = '\0';
2247 if (!opstr[0]) { *error = UR_EXPRERR_EOS; return oe; }
2248 /* determine operand type */
2249 if (opstr[0] == '=' && urasm_expand != NULL) {
2250 if (urasm_expand(opstr, (int)sizeof(opstr)-1) != 0) { *error = UR_EXPRERR_MARG; return oe; }
2251 //fprintf(stderr, "exp: [%s]\n", opstr);
2253 if (ur_isalpha(opstr[0]) && urasm_is_valid_name(opstr)) {
2254 goto doexpression;
2256 if (opstr[0] == '(') {
2257 /* memref */
2258 op->mem = 1; op->special = 1;
2259 if (!opstr[1] || opstr[strlen(opstr)-1] != ')') { *error = UR_EXPRERR_PARENS; return oe; }
2260 /* operand w/o "()" */
2261 opstr[strlen(opstr)-1] = '\0';
2262 memmove(opstr, opstr+1, sizeof(opstr)-1);
2263 /* trim spaces */
2264 while (opstr[0] && ur_isspace(opstr[0])) memmove(opstr, opstr+1, sizeof(opstr)-1);
2265 while (opstr[0] && ur_isspace(opstr[strlen(opstr)-1])) opstr[strlen(opstr)-1] = '\0';
2266 /* empty brackets? */
2267 if (!opstr[0]) { *error = UR_EXPRERR_TERM; return oe; }
2268 for (f = 0; opstr[f]; ++f) op->s[f] = ur_toupper(opstr[f]);
2269 if (!strcmp(op->s, "C")) {
2270 op->special = 1; op->mem = 0; strcpy(op->s, "(C)");
2271 return expr;
2273 if (!strcmp(op->s, "HL")) return expr;
2274 if (!strcmp(op->s, "DE")) return expr;
2275 if (!strcmp(op->s, "BC")) return expr;
2276 if (!strcmp(op->s, "SP")) return expr;
2277 if (op->s[0] == 'I' && (op->s[1] == 'X' || op->s[1] == 'Y')) {
2278 /* memref: IX or IY */
2279 op->ixy = op->s[1]=='X' ? 0xDDU : 0xFDU;
2280 op->v = 0;
2281 memmove(opstr, opstr+1, sizeof(opstr)-1);
2282 opstr[0] = '0';
2283 while (opstr[1] && ur_isspace(opstr[1])) memmove(opstr+1, opstr+2, sizeof(opstr)-2);
2284 if (!opstr[1]) return expr;
2285 if (opstr[1] != '+' && opstr[1] != '-') { *error = UR_EXPRERR_NUMBER; return oe; }
2286 /* opstr must be an expression */
2287 const char *t = urasm_expr(&op->v, opstr, addr, &op->defined, NULL, error);
2288 if (*error) return oe;
2289 if (t[0]) { *error = UR_EXPRERR_TOOLONG; return oe; }
2290 if (op->defined && (op->v < -128 || op->v > 127)) { *error = UR_EXPRERR_NUMBER; return oe; }
2291 return expr;
2293 op->special = 0;
2294 } else {
2295 if (!strcasecmp(opstr, "af'")) goto registerop;
2296 for (f = 0; ur_isalpha(opstr[f]); ++f) {}
2297 if (!opstr[f]) {
2298 registerop:
2299 for (f = 0; opstr[f]; ++f) opstr[f] = ur_toupper(opstr[f]);
2300 strcpy(op->s, opstr);
2301 op->special = 1;
2302 return skip_blanks(expr);
2305 /* this must be an expression */
2306 doexpression:
2307 strcpy(op->s, opstr);
2309 urasm_exprval_t e;
2310 const char *t;
2311 int donteval = 0;
2312 urasm_exprval_init(&e);
2313 t = urasm_expr_ex(&e, opstr, addr, &donteval, &op->defined, error);
2314 op->v = e.val;
2315 op->fixuptype = e.fixuptype;
2316 urasm_exprval_clear(&e);
2317 //const char *t = urasm_expr(&op->v, opstr, addr, &op->defined, error);
2318 if (*error) { op->parsed = 0; return oe; }
2319 if (t == NULL || t[0]) { op->parsed = 0; *error = UR_EXPRERR_EOS; return oe; }
2321 return skip_blanks(expr);
2325 ///////////////////////////////////////////////////////////////////////////////
2326 // assembler
2328 // for regsters & conditions: op->v will be set to reg number
2329 int urasm_is_valid_operand (urasm_operand_t *op, uint16_t addr, unsigned optype) {
2330 int i;
2331 if (optype == UO_NONE || optype == UO_NEXT) return (op->s[0] == '\0');
2332 if (!op->s[0]) return 0;
2333 switch (optype) {
2334 case UO_IMM8:
2335 if (op->special || op->mem) return 0;
2336 if (op->defined && (op->v < -128 || op->v > 255)) return 0;
2337 return 1;
2338 case UO_IMM16:
2339 if (op->special || op->mem) return 0;
2340 if (op->defined && (op->v < -32768 || op->v > 65535)) return 0;
2341 return 1;
2342 case UO_IMM16BE:
2343 if (op->special || op->mem) return 0;
2344 if (op->defined && (op->v < -32768 || op->v > 65535)) return 0;
2345 return 1;
2346 case UO_ADDR16:
2347 if (op->special || op->mem) return 0;
2348 if (op->defined && (op->v < -32768 || op->v > 65535)) return 0;
2349 if (op->v < 0) op->v = 65536+op->v;
2350 return 1;
2351 case UO_ADDR8:
2352 if (op->special || op->mem) return 0;
2353 if (op->defined && (op->v < -32768 || op->v > 65535)) return 0;
2354 if (!op->defined) op->v = addr;
2355 if (op->v < 0) op->v = 65536+op->v;
2356 i = op->v-((int)addr+2);
2357 if (i < -128 || i > 127) return 0;
2358 op->v = i&0xff;
2359 return 1;
2360 case UO_MEM16:
2361 if (op->special || !op->mem) return 0;
2362 if (op->defined && (op->v < -32768 || op->v > 65535)) return 0;
2363 if (op->v < 0) op->v = 65536+op->v;
2364 return 1;
2365 case UO_R8: case UO_2R8:
2366 if (op->mem && !strcmp(op->s, "HL")) { /*strcpy(op->s, "M");*/ op->v = 6; return 1; }
2367 /* fallthru */
2368 case UO_R8_NOM: case UO_2R8_NOM:
2369 if (!op->special || op->mem || op->s[1]) return 0;
2370 switch (op->s[0]) {
2371 case 'B': op->v = 0; break;
2372 case 'C': op->v = 1; break;
2373 case 'D': op->v = 2; break;
2374 case 'E': op->v = 3; break;
2375 case 'H': op->v = 4; break;
2376 case 'L': op->v = 5; break;
2377 case 'A': op->v = 7; break;
2378 default: return 0;
2380 return 1;
2381 case UO_R8_NOM_NOHL: case UO_2R8_NOM_NOHL:
2382 if (!op->special || op->mem || op->s[1]) return 0;
2383 switch (op->s[0]) {
2384 case 'B': op->v = 0; break;
2385 case 'C': op->v = 1; break;
2386 case 'D': op->v = 2; break;
2387 case 'E': op->v = 3; break;
2388 case 'A': op->v = 7; break;
2389 default: return 0;
2391 return 1;
2392 case UO_PORTC:
2393 if (!op->special || op->mem) return 0;
2394 return strcmp(op->s, "(C)")==0;
2395 case UO_PORTIMM: /* mem, 'cause (n) */
2396 if (op->special || !op->mem) return 0;
2397 op->mem = 0;
2398 if (op->defined && (op->v < 0 || op->v > 255)) return 0;
2399 return 1;
2400 case UO_R8_XH:
2401 if (!op->special || op->mem) return 0;
2402 if (!strcmp(op->s, "XH") || !strcmp(op->s, "HX") || !strcmp(op->s, "IXH")) return 1;
2403 return 0;
2404 case UO_R8_XL:
2405 if (!op->special || op->mem) return 0;
2406 if (!strcmp(op->s, "XL") || !strcmp(op->s, "LX") || !strcmp(op->s, "IXL")) return 1;
2407 return 0;
2408 case UO_R8_YH:
2409 if (!op->special || op->mem) return 0;
2410 if (!strcmp(op->s, "YH") || !strcmp(op->s, "HY") || !strcmp(op->s, "IYH")) return 1;
2411 return 0;
2412 case UO_R8_YL:
2413 if (!op->special || op->mem) return 0;
2414 if (!strcmp(op->s, "YL") || !strcmp(op->s, "LY") || !strcmp(op->s, "IYL")) return 1;
2415 return 0;
2416 case UO_R8_A:
2417 if (!op->special || op->mem) return 0;
2418 if (!strcmp(op->s, "A")) return 1;
2419 return 0;
2420 case UO_R8_B:
2421 if (!op->special || op->mem) return 0;
2422 if (!strcmp(op->s, "B")) return 1;
2423 return 0;
2424 case UO_R8_R:
2425 if (!op->special || op->mem) return 0;
2426 if (!strcmp(op->s, "R")) return 1;
2427 return 0;
2428 case UO_R8_I:
2429 if (!op->special || op->mem) return 0;
2430 if (!strcmp(op->s, "I")) return 1;
2431 return 0;
2432 case UO_R16:
2433 if (!op->special || op->mem || !op->s[1] || op->s[2]) return 0;
2434 if (!strcmp(op->s, "BC")) { op->v = 0; return 1; }
2435 if (!strcmp(op->s, "DE")) { op->v = 1; return 1; }
2436 if (!strcmp(op->s, "HL")) { op->v = 2; return 1; }
2437 if (!strcmp(op->s, "SP")) { op->v = 3; return 1; }
2438 return 0;
2439 case UO_R16A:
2440 if (!op->special || op->mem || !op->s[1] || op->s[2]) return 0;
2441 if (!strcmp(op->s, "BC")) { op->v = 0; return 1; }
2442 if (!strcmp(op->s, "DE")) { op->v = 1; return 1; }
2443 if (!strcmp(op->s, "HL")) { op->v = 2; return 1; }
2444 if (!strcmp(op->s, "AF")) { op->v = 3; return 1; }
2445 return 0;
2446 case UO_R16AF:
2447 if (!op->special || op->mem || strcmp(op->s, "AF")) return 0;
2448 op->v = 3;
2449 return 1;
2450 case UO_R16AFX:
2451 if (!op->special || op->mem || (strcmp(op->s, "AF'") && strcmp(op->s, "AFX"))) return 0;
2452 op->v = 3;
2453 return 1;
2454 case UO_R16BC:
2455 if (!op->special || op->mem || strcmp(op->s, "BC")) return 0;
2456 op->v = 0;
2457 return 1;
2458 case UO_R16DE:
2459 if (!op->special || op->mem || strcmp(op->s, "DE")) return 0;
2460 op->v = 1;
2461 return 1;
2462 case UO_R16HL:
2463 if (!op->special || op->mem || strcmp(op->s, "HL")) return 0;
2464 op->v = 2;
2465 return 1;
2466 case UO_R16IX:
2467 if (!op->special || op->mem || strcmp(op->s, "IX")) return 0;
2468 op->v = 2;
2469 return 1;
2470 case UO_R16IY:
2471 if (!op->special || op->mem || strcmp(op->s, "IY")) return 0;
2472 op->v = 2;
2473 return 1;
2474 case UO_R16SP:
2475 if (!op->special || op->mem || strcmp(op->s, "SP")) return 0;
2476 op->v = 3;
2477 return 1;
2478 case UO_MSP:
2479 if (!op->special || !op->mem || strcmp(op->s, "SP")) return 0;
2480 op->v = 3;
2481 return 1;
2482 case UO_MBC:
2483 if (!op->special || !op->mem || strcmp(op->s, "BC")) return 0;
2484 op->v = 0;
2485 return 1;
2486 case UO_MDE:
2487 if (!op->special || !op->mem || strcmp(op->s, "DE")) return 0;
2488 op->v = 1;
2489 return 1;
2490 case UO_MHL:
2491 if (!op->special || !op->mem || strcmp(op->s, "HL")) return 0;
2492 op->v = 2;
2493 return 1;
2494 case UO_MIX:
2495 if (!op->special || !op->mem || op->ixy != 0xDDU) return 0;
2496 if (op->defined && (op->v < -128 || op->v > 127)) return 0;
2497 return 1;
2498 case UO_MIY:
2499 if (!op->special || !op->mem || op->ixy != 0xFDU) return 0;
2500 if (op->defined && (op->v < -128 || op->v > 127)) return 0;
2501 return 1;
2502 case UO_MIX0:
2503 if (!op->special || !op->mem || op->ixy != 0xDDU) return 0;
2504 if (op->defined && op->v != 0) return 0;
2505 return 1;
2506 case UO_MIY0:
2507 if (!op->special || !op->mem || op->ixy != 0xFDU) return 0;
2508 if (op->defined && op->v != 0) return 0;
2509 return 1;
2510 case UO_JRCOND:
2511 if (!op->special || op->mem || ur_is_long_str(op->s)) return 0;
2512 if (!strcmp(op->s, "NZ")) { op->v = 0; return 1; }
2513 if (!strcmp(op->s, "Z")) { op->v = 1; return 1; }
2514 if (!strcmp(op->s, "NC")) { op->v = 2; return 1; }
2515 if (!strcmp(op->s, "C")) { op->v = 3; return 1; }
2516 return 0;
2517 case UO_COND:
2518 if (!op->special || op->mem || ur_is_long_str(op->s)) return 0;
2519 if (!strcmp(op->s, "NZ")) { op->v = 0; return 1; }
2520 if (!strcmp(op->s, "Z")) { op->v = 1; return 1; }
2521 if (!strcmp(op->s, "NC")) { op->v = 2; return 1; }
2522 if (!strcmp(op->s, "C")) { op->v = 3; return 1; }
2523 if (!strcmp(op->s, "PO")) { op->v = 4; return 1; }
2524 if (!strcmp(op->s, "PE")) { op->v = 5; return 1; }
2525 if (!strcmp(op->s, "P")) { op->v = 6; return 1; }
2526 if (!strcmp(op->s, "M")) { op->v = 7; return 1; }
2527 return 0;
2528 case UO_BITN:
2529 if (op->special || op->mem) return 0;
2530 if (op->defined && (op->v < 0 || op->v > 7)) return 0;
2531 return 1;
2532 case UO_RSTDEST:
2533 if (op->special || op->mem) return 0;
2534 if (op->defined && (op->v < 0 || op->v > 0x38 || (op->v&7))) return 0;
2535 op->v >>= 3;
2536 return 1;
2537 case UO_IM0:
2538 if (op->special || op->mem) return 0;
2539 if (op->defined && op->v != 0) return 0;
2540 return 1;
2541 case UO_IM1:
2542 if (op->special || op->mem) return 0;
2543 if (op->defined && op->v != 1) return 0;
2544 return 1;
2545 case UO_IM2:
2546 if (op->special || op->mem) return 0;
2547 if (op->defined && op->v != 2) return 0;
2548 return 1;
2550 return 0;
2554 // mem size should be at least 7 bytes
2555 // returns size of the assembled code
2556 // result <0 on error
2557 // understands comments
2558 int urasm_opasm (const char *expr, uint16_t destaddr, uint16_t addr, const char **errpos) {
2559 uint8_t buf[8];
2560 int len = 0;
2561 const char *oe;
2562 char mnem[16];
2563 int tkn;
2564 urasm_operand_t ops[3];
2565 const urasm_cmdinfo_t *cm;
2566 uint32_t code, mask;
2567 int opcPos; /* opcode will be placed here */
2568 int ret;
2570 int doOperand (int idx) {
2571 const urasm_operand_t *op = ops+idx;
2572 switch (cm->ops[idx]) {
2573 case UO_IMM8:
2574 if (op->fixuptype != UR_FIXUP_NONE && urasm_fixup_operand != NULL) {
2575 if (op->fixuptype == UR_FIXUP_WORD) return URA_EXPR_ERR-UR_EXPRERR_FIXUP;
2576 urasm_fixup_operand(op, (destaddr+len)&0xffff, (destaddr+len)&0xffff, op->fixuptype, 1);
2578 /* fallthru */
2579 case UO_PORTIMM:
2580 case UO_ADDR8:
2581 buf[len++] = op->v&0xFFU;
2582 break;
2583 case UO_IMM16:
2584 case UO_ADDR16:
2585 case UO_MEM16:
2586 if (op->fixuptype != UR_FIXUP_NONE && urasm_fixup_operand != NULL) {
2587 urasm_fixup_operand(op, (destaddr+len)&0xffff, (destaddr+len)&0xffff, op->fixuptype, 2);
2589 buf[len++] = op->v&0xFFU;
2590 buf[len++] = ((op->v&0xFFFFU)>>8)&0xFFU;
2591 break;
2592 case UO_IMM16BE:
2593 /*FIXME: this is prolly not right*/
2594 if (op->fixuptype != UR_FIXUP_NONE && urasm_fixup_operand != NULL) {
2595 switch (op->fixuptype) {
2596 case UR_FIXUP_WORD:
2597 urasm_fixup_operand(op, (destaddr+len)&0xffff, (destaddr+len)&0xffff, UR_FIXUP_HIBYTE, 1);
2598 urasm_fixup_operand(op, (destaddr+len+1)&0xffff, (destaddr+len+1)&0xffff, UR_FIXUP_LOBYTE, 1);
2599 break;
2600 case UR_FIXUP_LOBYTE:
2601 urasm_fixup_operand(op, (destaddr+len)&0xffff, (destaddr+len)&0xffff, UR_FIXUP_HIBYTE, 1);
2602 break;
2603 case UR_FIXUP_HIBYTE:
2604 urasm_fixup_operand(op, (destaddr+len+1)&0xffff, (destaddr+len+1)&0xffff, UR_FIXUP_LOBYTE, 1);
2605 break;
2606 default: break;
2609 buf[len++] = ((op->v&0xFFFFU)>>8)&0xFFU;
2610 buf[len++] = op->v&0xFFU;
2611 break;
2612 case UO_R8:
2613 case UO_R8_NOM:
2614 case UO_R8_NOM_NOHL:
2615 code |= op->v&0xFFU;
2616 break;
2617 case UO_JRCOND:
2618 case UO_COND:
2619 case UO_BITN:
2620 case UO_RSTDEST:
2621 case UO_2R8:
2622 case UO_2R8_NOM:
2623 case UO_2R8_NOM_NOHL:
2624 code |= (op->v&0xFFU)<<3;
2625 break;
2626 case UO_R16:
2627 case UO_R16A:
2628 code |= (op->v&0xFFU)<<4;
2629 break;
2630 case UO_MIX:
2631 case UO_MIY:
2632 buf[len++] = op->v;
2633 break;
2635 return 0;
2638 /* <0: error; 0: ok; >0: last operand (ops[opix].parsed != 0: non-empty one) */
2639 int parseOperand (int opidx) {
2640 int error = 0;
2641 const char *oe = expr;
2642 expr = urasm_next_operand(ops+opidx, expr, addr, &error);
2643 if (error) {
2644 if (errpos) *errpos = oe;
2645 //return URA_BAD_OPERAND;
2646 return -error+URA_EXPR_ERR;
2648 if (!expr || !expr[0] || expr[0] == ';' || expr[0] == ':') return 1;
2649 if (*expr != ',') { if (errpos) *errpos = oe; return URA_BAD_OPERAND; }
2650 ++expr;
2651 return 0;
2654 int genCode (void) {
2655 int operr = 0;
2656 /* special macro for ADD DE,HL */
2657 if (tkn == UT_ADD &&
2658 urasm_is_valid_operand(&ops[0], addr, UO_R16DE) &&
2659 urasm_is_valid_operand(&ops[1], addr, UO_R16HL) &&
2660 urasm_is_valid_operand(&ops[2], addr, UO_NONE))
2662 // generate:
2663 // EX DE,HL
2664 // ADD HL,DE
2665 // EX DE,HL
2666 buf[0] = 0xEBU;
2667 buf[1] = 0x19U;
2668 buf[2] = 0xEBU;
2669 for (unsigned n = 0; n < 3; ++n) urasm_putbyte(destaddr++, buf[n]);
2670 addr += 3;
2671 return 3;
2673 /* hack for invalid instructions */
2674 for (int pos = URASM_MAX_COMMAND-1; pos >= 0; --pos) {
2675 int f;
2676 if (tkn != URASM_COMMANDS[pos].mnemo) continue;
2677 if (!urasm_allow_zxnext && URASM_COMMANDS[pos].ops[2] == UO_NEXT) continue;
2678 for (f = 0; f < 3; ++f) {
2679 if (!urasm_is_valid_operand(&ops[f], addr, URASM_COMMANDS[pos].ops[f])) break;
2681 if (f < 3) continue;
2682 /* command found, generate code */
2683 len = 0; cm = URASM_COMMANDS+pos;
2684 code = cm->code; mask = cm->mask;
2685 if ((code&0xFFFFUL) == 0xCBDDUL || (code&0xFFFFUL) == 0xCBFDUL) {
2686 /* special commands */
2687 /* emit unmasked code */
2688 buf[0] = (code&0xFFU); buf[1] = 0xCBU;
2689 for (f = 0; f < 3; ++f) {
2690 if (cm->ops[f] == UO_MIX || cm->ops[f] == UO_MIY) {
2691 if (ops[f].defined && (ops[f].v < -128 || ops[f].v > 127)) f = -1;
2692 else if (ops[f].defined) buf[2] = ops[f].v;
2693 break;
2696 if (f < 0) continue; /* not me */
2697 len = 4;
2698 code >>= 24; mask >>= 24;
2699 if ((mask&0xFFUL) != 0xFFUL) {
2700 for (f = 0; f < 3; ++f) if (cm->ops[f] != UO_MIX && cm->ops[f] != UO_MIY) {
2701 if ((operr = doOperand(f)) != 0) goto badi;
2704 buf[3] = code;
2705 /* that's all */
2706 for (f = 0; f < len; ++f) { urasm_putbyte(destaddr++, buf[f]); ++addr; }
2707 return len;
2708 } else {
2709 /* normal commands */
2710 /* emit unmasked code */
2711 while ((mask&0xFFUL) == 0xFFUL) {
2712 buf[len++] = code&0xFFUL;
2713 code >>= 8; mask >>= 8;
2715 //ASSERT((code&0xFFFFFF00UL) == 0);
2716 if (mask == 0) {
2717 //ASSERT(len > 0);
2718 code = buf[--len];
2720 opcPos = len++;
2721 if ((operr = doOperand(0)) != 0) goto badi;
2722 if ((operr = doOperand(1)) != 0) goto badi;
2723 if ((operr = doOperand(2)) != 0) goto badi;
2724 buf[opcPos] = code;
2725 /* that's all */
2726 for (f = 0; f < len; ++f) { urasm_putbyte(destaddr++, buf[f]); ++addr; }
2727 return len;
2730 badi:
2731 if (errpos) *errpos = oe;
2732 return (operr < 0 ? operr : URA_BAD_INSTRUCTION);
2735 int doPushPop (void) {
2736 int f, len;
2737 for (f = len = 0; ; ++f) {
2738 int doQuit = 0;
2739 const char *oe = expr;
2740 int res = parseOperand(0);
2741 if (res < 0) return res;
2742 if (res > 0) {
2743 if (f == 0 && !ops[0].parsed) { *errpos = oe; return URA_BAD_INSTRUCTION; }
2744 doQuit = 1;
2746 code = (tkn == UT_POP ? 0xC1U : 0xC5U);
2747 if (urasm_is_valid_operand(ops, addr, UO_R16A)) {
2748 code |= (ops[0].v&0xFFU)<<4;
2749 urasm_putbyte(destaddr++, code);
2750 ++addr;
2751 ++len;
2752 } else if (urasm_is_valid_operand(ops, addr, UO_R16IX)) {
2753 code |= (ops[0].v&0xFFU)<<4;
2754 urasm_putbyte(destaddr++, 0xDDU);
2755 urasm_putbyte(destaddr++, code);
2756 addr += 2;
2757 len += 2;
2758 } else if (urasm_is_valid_operand(ops, addr, UO_R16IY)) {
2759 code |= (ops[0].v&0xFFU)<<4;
2760 urasm_putbyte(destaddr++, 0xFDU);
2761 urasm_putbyte(destaddr++, code);
2762 addr += 2;
2763 len += 2;
2764 } else if (urasm_allow_zxnext && code == 0xC5U && urasm_is_valid_operand(ops, addr, UO_IMM16BE)) {
2765 /* ZXNext PUSH nnnn */
2766 urasm_putbyte(destaddr++, 0xEDU);
2767 urasm_putbyte(destaddr++, 0x8AU);
2768 /*FIXME: this is prolly not right*/
2769 if (ops[0].fixuptype != UR_FIXUP_NONE && urasm_fixup_operand != NULL) {
2770 switch (ops[0].fixuptype) {
2771 case UR_FIXUP_WORD:
2772 urasm_fixup_operand(&ops[0], (destaddr+len)&0xffff, (destaddr+len)&0xffff, UR_FIXUP_HIBYTE, 1);
2773 urasm_fixup_operand(&ops[0], (destaddr+len+1)&0xffff, (destaddr+len+1)&0xffff, UR_FIXUP_LOBYTE, 1);
2774 break;
2775 case UR_FIXUP_LOBYTE:
2776 urasm_fixup_operand(&ops[0], (destaddr+len)&0xffff, (destaddr+len)&0xffff, UR_FIXUP_HIBYTE, 1);
2777 break;
2778 case UR_FIXUP_HIBYTE:
2779 urasm_fixup_operand(&ops[0], (destaddr+len+1)&0xffff, (destaddr+len+1)&0xffff, UR_FIXUP_LOBYTE, 1);
2780 break;
2781 default: break;
2784 urasm_putbyte(destaddr++, ((ops[0].v&0xFFFFU)>>8)&0xFFU);
2785 urasm_putbyte(destaddr++, ops[0].v&0xFFU);
2786 addr += 4;
2787 len += 4;
2788 } else {
2789 if (errpos) *errpos = oe;
2790 return URA_BAD_OPERAND;
2792 if (doQuit) break;
2794 if (expr) {
2795 expr = skip_blanks(expr);
2796 if (expr[0] && expr[0] != ';') {
2797 if (errpos) *errpos = expr;
2798 if (expr[0] != ':') return URA_EXTRA_TEXT;
2801 return len;
2804 int dorep (int opcnt) {
2805 int f, len;
2806 memset(ops, 0, sizeof(ops));
2807 for (f = len = 0; ; ++f) {
2808 int doQuit = 0, res;
2809 const char *oe;
2810 for (int c = 0; c < opcnt; ++c) {
2811 oe = expr;
2812 res = parseOperand(c);
2813 if (res < 0) return res;
2814 if (res > 0) {
2815 if (c != opcnt-1 || !ops[c].parsed) { *errpos = oe; return URA_BAD_INSTRUCTION; }
2816 doQuit = 1;
2819 if ((res = genCode()) < 0) return res;
2820 addr += res;
2821 len += res;
2822 if (doQuit) break;
2824 if (expr) {
2825 expr = skip_blanks(expr);
2826 if (expr[0] && expr[0] != ';') {
2827 if (errpos) *errpos = expr;
2828 if (expr[0] != ':') return URA_EXTRA_TEXT;
2831 return len;
2834 if (errpos) *errpos = NULL;
2835 if (!urasm_putbyte || !expr) return URA_GENERIC;
2837 expr = skip_blanks(expr);
2838 if (!expr[0] || expr[0] == ';') return 0;
2839 if (expr[0] == ':') { if (errpos) *errpos = expr; return 0; }
2840 for (oe = expr; *expr && !ur_isspace(*expr) && *expr != ':' && *expr != ';'; ++expr) {}
2841 if (urasm_allow_zxnext) {
2842 if (expr-oe > 7) { if (errpos) *errpos = oe; return URA_BAD_MNEMO; } /* bad mnemonics */
2843 } else {
2844 if (expr-oe > 4) { if (errpos) *errpos = oe; return URA_BAD_MNEMO; } /* bad mnemonics */
2847 memset(mnem, 0, sizeof(mnem));
2848 memcpy(mnem, oe, expr-oe);
2849 for (int f = 0; mnem[f]; ++f) mnem[f] = ur_toupper(mnem[f]);
2850 /* find it */
2851 for (tkn = 0; tkn < URASM_MAX_TOKEN; ++tkn) if (!strcmp(mnem, URASM_TOKENS[tkn])) break;
2852 if (tkn >= URASM_MAX_TOKEN) { if (errpos) *errpos = oe; return URA_BAD_MNEMO; } /* unknown mnemonics */
2854 expr = skip_blanks(expr);
2855 if (expr[0] == ',') { if (errpos) *errpos = oe; return URA_BAD_OPERAND; }
2856 /* special for PUSH and POP */
2857 if (tkn == UT_POP || tkn == UT_PUSH) return doPushPop();
2858 /* special for LD */
2859 if (tkn == UT_LD /*|| tkn == UT_ADD || tkn == UT_ADC || tkn == UT_SBC*/) return dorep(2);
2860 /* special for RR/RL */
2861 if (tkn == UT_RL || tkn == UT_RR || tkn == UT_INC || tkn == UT_DEC ||
2862 tkn == UT_SRL || tkn == UT_SRA || tkn == UT_SLI || tkn == UT_SLL || tkn == UT_SLA) return dorep(1);
2864 memset(ops, 0, sizeof(ops));
2865 for (int f = 0; f < 3; ++f) {
2866 int res = parseOperand(f);
2867 if (res > 0) break;
2868 if (res < 0) return res;
2871 ret = genCode();
2873 if (ret >= 0 && expr) {
2874 expr = skip_blanks(expr);
2875 if (expr[0] && expr[0] != ';') {
2876 if (errpos) *errpos = expr;
2877 if (expr[0] != ':') return URA_EXTRA_TEXT;
2881 return ret;
2885 // ////////////////////////////////////////////////////////////////////////// //
2886 static const char *error_messages_asm[5] = {
2887 "generic error",
2888 "bad mnemonics",
2889 "bad operand",
2890 "extra text after instruction",
2891 "bad instruction",
2895 static const char *error_messages_expr[14] = {
2896 "", /* none */
2897 "unexpected end of expression",
2898 "division by zero",
2899 "unbalanced parens",
2900 "number expected",
2901 "string expected",
2902 "unknown label",
2903 "term expected", /*FIXME: better message!*/
2904 "unknown function",
2905 "invalid operand type", /*FIXME: better message! this is string/number conflict*/
2906 "unknown macro argument", /*FIXME: better message! */
2907 "invalid fixup",
2908 "type mismatch", /* in comparisons */
2909 "operand text too long",
2913 const char *urasm_errormsg (int errcode) {
2914 if (errcode >= 0) return "";
2915 if (errcode < URA_EXPR_ERR) {
2916 errcode = -(errcode-URA_EXPR_ERR);
2917 if (errcode >= UR_EXPRERR_EOS && errcode <= UR_EXPRERR_TOOLONG) {
2918 return error_messages_expr[errcode];
2920 return "unknown error";
2921 } else {
2922 if (errcode < -5) return "unknown error";
2923 return error_messages_asm[(-errcode)-1];