added '<<' and '>>'
[urasm.git] / src / liburasm / liburasm.c
blob4dae91b7d3a123a81b8c1be234ab6575e25e80f4
1 /* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar)
2 * Understanding is not required. Only obedience.
4 * URASM Z80 assembler/disassembler core v0.0.0a
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 #ifdef __cplusplus
13 extern "C" {
14 #endif
16 #include <ctype.h>
17 #include <setjmp.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
22 #include "liburasm.h"
25 int urDisDecimal = 0;
26 URFindLabelByAddr urFindLabelByAddr = NULL;
27 URFindLabelByName urFindLabelByName = NULL;
28 URGetByte urGetByte = NULL;
29 URPutByte urPutByte = NULL;
30 URIsLabelDefinedOrKnown urIsLabelDefinedOrKnown = NULL;
33 const char *URASM_TOKENS[URASM_MAX_TOKEN] = {
34 "ADC", "ADD", "AND", "BIT", "CALL","CCF", "CP", "CPD",
35 "CPDR","CPI", "CPIR","CPL", "DAA", "DEC", "DI", "DJNZ",
36 "EI", "EX", "EXX", "HALT","IM", "IN", "INC", "IND",
37 "INDR","INI", "INIR","JP", "JR", "LD", "LDD", "LDDR",
38 "LDI", "LDIR","NEG", "NOP", "OR", "OTDR","OTIR","OUT",
39 "OUTD","OUTI","POP", "PUSH","RES", "RET", "RETI","RETN",
40 "RL", "RLA", "RLC", "RLCA","RLD", "RR", "RRA", "RRC",
41 "RRCA","RRD", "RST", "SBC", "SCF", "SET", "SLA", "SLI",
42 "SLL", "SRA", "SRL", "SUB", "XOR", "XSLT","NOPX","NOPY"
45 // various things...
46 const char *URA_REGS8[8] = {"B","C","D","E","H","L","(HL)","A"};
47 const char *URA_REGS16[4] = {"BC","DE","HL","SP"};
48 const char *URA_REGS16A[4] = {"BC","DE","HL","AF"};
49 const char *URA_COND[8] = {"NZ","Z","NC","C","PO","PE","P","M"};
52 // the longest matches must come first (for disassembler)
53 // solid-masked must come first (for disassembler)
54 // assembler searches the table from the last command
55 // disassembler searches the table from the first command
56 // heh, i spent a whole night creating this shit! %-)
57 const URAsmCmdInfo URASM_COMMANDS[URASM_MAX_COMMAND+1] = {
58 {.mnemo=UT_NOPX, .code=0x000000DDUL, .mask=0x00000000UL, .ops={UO_NONE, UO_NONE, UO_NONE}},
59 {.mnemo=UT_NOPY, .code=0x000000FDUL, .mask=0x00000000UL, .ops={UO_NONE, UO_NONE, UO_NONE}},
60 // DD/CB opcodes (special)
61 // RLC (IX+d)
62 {.mnemo=UT_RLC, .code=0x0600CBDDUL, .mask=0xFF00FFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
63 // RRC (IX+d)
64 {.mnemo=UT_RRC, .code=0x0E00CBDDUL, .mask=0xFF00FFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
65 // RL (IX+d)
66 {.mnemo=UT_RL, .code=0x1600CBDDUL, .mask=0xFF00FFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
67 // RR (IX+d)
68 {.mnemo=UT_RR, .code=0x1E00CBDDUL, .mask=0xFF00FFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
69 // SLA (IX+d)
70 {.mnemo=UT_SLA, .code=0x2600CBDDUL, .mask=0xFF00FFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
71 // SRA (IX+d)
72 {.mnemo=UT_SRA, .code=0x2E00CBDDUL, .mask=0xFF00FFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
73 // SLL (IX+d)
74 {.mnemo=UT_SLL, .code=0x3600CBDDUL, .mask=0xFF00FFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
75 // SLI (IX+d)
76 {.mnemo=UT_SLI, .code=0x3600CBDDUL, .mask=0xFF00FFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
77 // SRL (IX+d)
78 {.mnemo=UT_SRL, .code=0x3E00CBDDUL, .mask=0xFF00FFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
79 // RES n,(IX+d)
80 {.mnemo=UT_RES, .code=0x8600CBDDUL, .mask=0xC700FFFFUL, .ops={UO_BITN, UO_MIX, UO_NONE}},
81 // SET n,(IX+d)
82 {.mnemo=UT_SET, .code=0xC600CBDDUL, .mask=0xC700FFFFUL, .ops={UO_BITN, UO_MIX, UO_NONE}},
83 // FD/CB opcodes (special)
84 // RLC (IY+d)
85 {.mnemo=UT_RLC, .code=0x0600CBFDUL, .mask=0xFF00FFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
86 // RRC (IY+d)
87 {.mnemo=UT_RRC, .code=0x0E00CBFDUL, .mask=0xFF00FFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
88 // RL (IY+d)
89 {.mnemo=UT_RL, .code=0x1600CBFDUL, .mask=0xFF00FFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
90 // RR (IY+d)
91 {.mnemo=UT_RR, .code=0x1E00CBFDUL, .mask=0xFF00FFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
92 // SLA (IY+d)
93 {.mnemo=UT_SLA, .code=0x2600CBFDUL, .mask=0xFF00FFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
94 // SRA (IY+d)
95 {.mnemo=UT_SRA, .code=0x2E00CBFDUL, .mask=0xFF00FFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
96 // SLL (IY+d)
97 {.mnemo=UT_SLL, .code=0x3600CBFDUL, .mask=0xFF00FFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
98 // SLI (IY+d)
99 {.mnemo=UT_SLI, .code=0x3600CBFDUL, .mask=0xFF00FFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
100 // SRL (IY+d)
101 {.mnemo=UT_SRL, .code=0x3E00CBFDUL, .mask=0xFF00FFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
102 // RES n,(IY+d)
103 {.mnemo=UT_RES, .code=0x8600CBFDUL, .mask=0xC700FFFFUL, .ops={UO_BITN, UO_MIY, UO_NONE}},
104 // SET n,(IY+d)
105 {.mnemo=UT_SET, .code=0xC600CBFDUL, .mask=0xC700FFFFUL, .ops={UO_BITN, UO_MIY, UO_NONE}},
107 // DD/CB opcodes
108 // RLC (IX+d),r8
109 {.mnemo=UT_RLC, .code=0x0000CBDDUL, .mask=0xF800FFFFUL, .ops={UO_MIX, UO_R8_NOM, UO_NONE}},
110 // RRC (IX+d),r8
111 {.mnemo=UT_RRC, .code=0x0800CBDDUL, .mask=0xF800FFFFUL, .ops={UO_MIX, UO_R8_NOM, UO_NONE}},
112 // RL (IX+d),r8
113 {.mnemo=UT_RL, .code=0x1000CBDDUL, .mask=0xF800FFFFUL, .ops={UO_MIX, UO_R8_NOM, UO_NONE}},
114 // RR (IX+d),r8
115 {.mnemo=UT_RR, .code=0x1800CBDDUL, .mask=0xF800FFFFUL, .ops={UO_MIX, UO_R8_NOM, UO_NONE}},
116 // SLA (IX+d),r8
117 {.mnemo=UT_SLA, .code=0x2000CBDDUL, .mask=0xF800FFFFUL, .ops={UO_MIX, UO_R8_NOM, UO_NONE}},
118 // SRA (IX+d),r8
119 {.mnemo=UT_SRA, .code=0x2800CBDDUL, .mask=0xF800FFFFUL, .ops={UO_MIX, UO_R8_NOM, UO_NONE}},
120 // SLL (IX+d),r8
121 {.mnemo=UT_SLL, .code=0x3000CBDDUL, .mask=0xF800FFFFUL, .ops={UO_MIX, UO_R8_NOM, UO_NONE}},
122 // SLI (IX+d),r8
123 {.mnemo=UT_SLI, .code=0x3000CBDDUL, .mask=0xF800FFFFUL, .ops={UO_MIX, UO_R8_NOM, UO_NONE}},
124 // SRL (IX+d),r8
125 {.mnemo=UT_SRL, .code=0x3800CBDDUL, .mask=0xF800FFFFUL, .ops={UO_MIX, UO_R8_NOM, UO_NONE}},
126 // BIT n,(IX+d)
127 {.mnemo=UT_BIT, .code=0x4600CBDDUL, .mask=0xC700FFFFUL, .ops={UO_BITN, UO_MIX, UO_NONE}},
128 // BIT n,(IX+d),r8
129 {.mnemo=UT_BIT, .code=0x4000CBDDUL, .mask=0xC000FFFFUL, .ops={UO_BITN, UO_MIX, UO_R8_NOM}},
130 // RES n,(IX+d),r8
131 {.mnemo=UT_RES, .code=0x8000CBDDUL, .mask=0xC000FFFFUL, .ops={UO_BITN, UO_MIX, UO_R8_NOM}},
132 // SET n,(IX+d),r8
133 {.mnemo=UT_SET, .code=0xC000CBDDUL, .mask=0xC000FFFFUL, .ops={UO_BITN, UO_MIX, UO_R8_NOM}},
134 // FD/CB opcodes
135 // RLC (IY+d),r8
136 {.mnemo=UT_RLC, .code=0x0000CBFDUL, .mask=0xF800FFFFUL, .ops={UO_MIY, UO_R8_NOM, UO_NONE}},
137 // RRC (IY+d),r8
138 {.mnemo=UT_RRC, .code=0x0800CBFDUL, .mask=0xF800FFFFUL, .ops={UO_MIY, UO_R8_NOM, UO_NONE}},
139 // RL (IY+d),r8
140 {.mnemo=UT_RL, .code=0x1000CBFDUL, .mask=0xF800FFFFUL, .ops={UO_MIY, UO_R8_NOM, UO_NONE}},
141 // RR (IY+d),r8
142 {.mnemo=UT_RR, .code=0x1800CBFDUL, .mask=0xF800FFFFUL, .ops={UO_MIY, UO_R8_NOM, UO_NONE}},
143 // SLA (IY+d),r8
144 {.mnemo=UT_SLA, .code=0x2000CBFDUL, .mask=0xF800FFFFUL, .ops={UO_MIY, UO_R8_NOM, UO_NONE}},
145 // SRA (IY+d),r8
146 {.mnemo=UT_SRA, .code=0x2800CBFDUL, .mask=0xF800FFFFUL, .ops={UO_MIY, UO_R8_NOM, UO_NONE}},
147 // SLL (IY+d),r8
148 {.mnemo=UT_SLL, .code=0x3000CBFDUL, .mask=0xF800FFFFUL, .ops={UO_MIY, UO_R8_NOM, UO_NONE}},
149 // SLI (IY+d),r8
150 {.mnemo=UT_SLI, .code=0x3000CBFDUL, .mask=0xF800FFFFUL, .ops={UO_MIY, UO_R8_NOM, UO_NONE}},
151 // SRL (IY+d),r8
152 {.mnemo=UT_SRL, .code=0x3800CBFDUL, .mask=0xF800FFFFUL, .ops={UO_MIY, UO_R8_NOM, UO_NONE}},
153 // BIT n,(IY+d)
154 {.mnemo=UT_BIT, .code=0x4600CBFDUL, .mask=0xC700FFFFUL, .ops={UO_BITN, UO_MIY, UO_NONE}},
155 // BIT n,(IY+d),r8
156 {.mnemo=UT_BIT, .code=0x4000CBFDUL, .mask=0xC000FFFFUL, .ops={UO_BITN, UO_MIY, UO_R8_NOM}},
157 // RES n,(IY+d),r8
158 {.mnemo=UT_RES, .code=0x8000CBFDUL, .mask=0xC000FFFFUL, .ops={UO_BITN, UO_MIY, UO_R8_NOM}},
159 // SET n,(IY+d),r8
160 {.mnemo=UT_SET, .code=0xC000CBFDUL, .mask=0xC000FFFFUL, .ops={UO_BITN, UO_MIY, UO_R8_NOM}},
161 // standard CB opcodes
162 // RLC r8
163 {.mnemo=UT_RLC, .code=0x00CBUL, .mask=0xF8FFUL, .ops={UO_R8, UO_NONE, UO_NONE}},
164 // RRC r8
165 {.mnemo=UT_RRC, .code=0x08CBUL, .mask=0xF8FFUL, .ops={UO_R8, UO_NONE, UO_NONE}},
166 // RL r8
167 {.mnemo=UT_RL, .code=0x10CBUL, .mask=0xF8FFUL, .ops={UO_R8, UO_NONE, UO_NONE}},
168 // RR r8
169 {.mnemo=UT_RR, .code=0x18CBUL, .mask=0xF8FFUL, .ops={UO_R8, UO_NONE, UO_NONE}},
170 // SLA r8
171 {.mnemo=UT_SLA, .code=0x20CBUL, .mask=0xF8FFUL, .ops={UO_R8, UO_NONE, UO_NONE}},
172 // SRA r8
173 {.mnemo=UT_SRA, .code=0x28CBUL, .mask=0xF8FFUL, .ops={UO_R8, UO_NONE, UO_NONE}},
174 // SLL r8
175 {.mnemo=UT_SLL, .code=0x30CBUL, .mask=0xF8FFUL, .ops={UO_R8, UO_NONE, UO_NONE}},
176 // SLI r8
177 {.mnemo=UT_SLI, .code=0x30CBUL, .mask=0xF8FFUL, .ops={UO_R8, UO_NONE, UO_NONE}},
178 // SRL r8
179 {.mnemo=UT_SRL, .code=0x38CBUL, .mask=0xF8FFUL, .ops={UO_R8, UO_NONE, UO_NONE}},
180 // BIT n,r8
181 {.mnemo=UT_BIT, .code=0x40CBUL, .mask=0xC0FFUL, .ops={UO_BITN, UO_R8, UO_NONE}},
182 // RES n,r8
183 {.mnemo=UT_RES, .code=0x80CBUL, .mask=0xC0FFUL, .ops={UO_BITN, UO_R8, UO_NONE}},
184 // SET n,r8
185 {.mnemo=UT_SET, .code=0xC0CBUL, .mask=0xC0FFUL, .ops={UO_BITN, UO_R8, UO_NONE}},
187 // some ED opcodes
188 // traps
189 {.mnemo=UT_XSLT, .code=0xFBEDUL, .mask=0xFFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
190 // ED string instructions
191 {.mnemo=UT_LDI, .code=0xA0EDUL, .mask=0xFFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
192 {.mnemo=UT_LDIR, .code=0xB0EDUL, .mask=0xFFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
193 {.mnemo=UT_CPI, .code=0xA1EDUL, .mask=0xFFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
194 {.mnemo=UT_CPIR, .code=0xB1EDUL, .mask=0xFFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
195 {.mnemo=UT_INI, .code=0xA2EDUL, .mask=0xFFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
196 {.mnemo=UT_INIR, .code=0xB2EDUL, .mask=0xFFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
197 {.mnemo=UT_OUTI, .code=0xA3EDUL, .mask=0xFFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
198 {.mnemo=UT_OTIR, .code=0xB3EDUL, .mask=0xFFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
199 {.mnemo=UT_LDD, .code=0xA8EDUL, .mask=0xFFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
200 {.mnemo=UT_LDDR, .code=0xB8EDUL, .mask=0xFFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
201 {.mnemo=UT_CPD, .code=0xA9EDUL, .mask=0xFFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
202 {.mnemo=UT_CPDR, .code=0xB9EDUL, .mask=0xFFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
203 {.mnemo=UT_IND, .code=0xAAEDUL, .mask=0xFFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
204 {.mnemo=UT_INDR, .code=0xBAEDUL, .mask=0xFFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
205 {.mnemo=UT_OUTD, .code=0xABEDUL, .mask=0xFFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
206 {.mnemo=UT_OTDR, .code=0xBBEDUL, .mask=0xFFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
208 // ED w/o operands
209 {.mnemo=UT_RRD, .code=0x67EDUL, .mask=0xFFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
210 {.mnemo=UT_RLD, .code=0x6FEDUL, .mask=0xFFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
212 // IN (C)
213 {.mnemo=UT_IN, .code=0x70EDUL, .mask=0xFFFFUL, .ops={UO_PORTC, UO_NONE, UO_NONE}},
214 // OUT (C),0
215 {.mnemo=UT_OUT, .code=0x71EDUL, .mask=0xFFFFUL, .ops={UO_PORTC, UO_IM0, UO_NONE}},
217 // LD I,A
218 {.mnemo=UT_LD, .code=0x47EDUL, .mask=0xFFFFUL, .ops={UO_R8_I, UO_R8_A, UO_NONE}},
219 // LD A,I
220 {.mnemo=UT_LD, .code=0x57EDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_I, UO_NONE}},
221 // LD R,A
222 {.mnemo=UT_LD, .code=0x4FEDUL, .mask=0xFFFFUL, .ops={UO_R8_R, UO_R8_A, UO_NONE}},
223 // LD A,R
224 {.mnemo=UT_LD, .code=0x5FEDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_R, UO_NONE}},
225 // IM 0/1
226 //(.mnemo=UT_IM, .code=0x4EEDUL, .mask=0xFFFFUL, .ops={UO_IM01, UO_NONE, UO_NONE}},
228 // ED w/o operands
229 {.mnemo=UT_RETN, .code=0x45EDUL, .mask=0xCFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
230 {.mnemo=UT_RETI, .code=0x4DEDUL, .mask=0xCFFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
232 // SBC HL,r16
233 {.mnemo=UT_SBC, .code=0x42EDUL, .mask=0xCFFFUL, .ops={UO_R16HL, UO_R16, UO_NONE}},
234 // ADC HL,r16
235 {.mnemo=UT_ADC, .code=0x4AEDUL, .mask=0xCFFFUL, .ops={UO_R16HL, UO_R16, UO_NONE}},
236 // LD (nnnn),r16
237 {.mnemo=UT_LD, .code=0x43EDUL, .mask=0xCFFFUL, .ops={UO_MEM16, UO_R16, UO_NONE}},
238 // LD r16,(nnnn)
239 {.mnemo=UT_LD, .code=0x4BEDUL, .mask=0xCFFFUL, .ops={UO_R16, UO_MEM16, UO_NONE}},
241 // ED w/o operands
242 {.mnemo=UT_NEG, .code=0x44EDUL, .mask=0xC7FFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
244 // IN r8,(C)
245 {.mnemo=UT_IN, .code=0x40EDUL, .mask=0xC7FFUL, .ops={UO_2R8_NOM, UO_PORTC, UO_NONE}},
246 // OUT (C),r8
247 {.mnemo=UT_OUT, .code=0x41EDUL, .mask=0xC7FFUL, .ops={UO_PORTC, UO_2R8_NOM, UO_NONE}},
249 // IM 2
250 {.mnemo=UT_IM, .code=0x5EEDUL, .mask=0xDFFFUL, .ops={UO_IM2, UO_NONE, UO_NONE}},
251 // IM 1
252 {.mnemo=UT_IM, .code=0x56EDUL, .mask=0xDFFFUL, .ops={UO_IM1, UO_NONE, UO_NONE}},
253 // IM 0
254 {.mnemo=UT_IM, .code=0x46EDUL, .mask=0xD7FFUL, .ops={UO_IM0, UO_NONE, UO_NONE}},
256 // LD SP,IX
257 {.mnemo=UT_LD, .code=0xF9DDUL, .mask=0xFFFFUL, .ops={UO_R16SP, UO_R16IX, UO_NONE}},
258 // LD SP,IY
259 {.mnemo=UT_LD, .code=0xF9FDUL, .mask=0xFFFFUL, .ops={UO_R16SP, UO_R16IY, UO_NONE}},
261 // EX (SP),IX
262 {.mnemo=UT_EX, .code=0xE3DDUL, .mask=0xFFFFUL, .ops={UO_MSP, UO_R16IX, UO_NONE}},
263 // EX IX,(SP) (ditto)
264 {.mnemo=UT_EX, .code=0xE3DDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_MSP, UO_NONE}},
265 // EX (SP),IY
266 {.mnemo=UT_EX, .code=0xE3FDUL, .mask=0xFFFFUL, .ops={UO_MSP, UO_R16IY, UO_NONE}},
267 // EX IY,(SP) (ditto)
268 {.mnemo=UT_EX, .code=0xE3FDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_MSP, UO_NONE}},
270 // JP (IX)
271 {.mnemo=UT_JP, .code=0xE9DDUL, .mask=0xFFFFUL, .ops={UO_MIX0, UO_NONE, UO_NONE}},
272 // JP (IY)
273 {.mnemo=UT_JP, .code=0xE9FDUL, .mask=0xFFFFUL, .ops={UO_MIY0, UO_NONE, UO_NONE}},
274 // JP IX
275 {.mnemo=UT_JP, .code=0xE9DDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_NONE, UO_NONE}},
276 // JP IY
277 {.mnemo=UT_JP, .code=0xE9FDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_NONE, UO_NONE}},
279 // POP IX
280 {.mnemo=UT_POP, .code=0xE1DDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_NONE, UO_NONE}},
281 // PUSH IX
282 {.mnemo=UT_PUSH, .code=0xE5DDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_NONE, UO_NONE}},
283 // POP IY
284 {.mnemo=UT_POP, .code=0xE1FDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_NONE, UO_NONE}},
285 // PUSH IY
286 {.mnemo=UT_PUSH, .code=0xE5FDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_NONE, UO_NONE}},
288 // ADD A,(IX+d)
289 {.mnemo=UT_ADD, .code=0x86DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIX, UO_NONE}},
290 // ADD (IX+d)
291 {.mnemo=UT_ADD, .code=0x86DDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
292 // ADC A,(IX+d)
293 {.mnemo=UT_ADC, .code=0x8EDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIX, UO_NONE}},
294 // ADC (IX+d)
295 {.mnemo=UT_ADC, .code=0x8EDDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
296 // SUB (IX+d)
297 {.mnemo=UT_SUB, .code=0x96DDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
298 // SUB A,(IX+d)
299 {.mnemo=UT_SUB, .code=0x96DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIX, UO_NONE}},
300 // SBC A,(IX+d)
301 {.mnemo=UT_SBC, .code=0x9EDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIX, UO_NONE}},
302 // SBC (IX+d)
303 {.mnemo=UT_SBC, .code=0x9EDDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
304 // AND (IX+d)
305 {.mnemo=UT_AND, .code=0xA6DDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
306 // AND A,(IX+d)
307 {.mnemo=UT_AND, .code=0xA6DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIX, UO_NONE}},
308 // XOR (IX+d)
309 {.mnemo=UT_XOR, .code=0xAEDDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
310 // XOR A,(IX+d)
311 {.mnemo=UT_XOR, .code=0xAEDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIX, UO_NONE}},
312 // OR (IX+d)
313 {.mnemo=UT_OR, .code=0xB6DDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
314 // OR A,(IX+d)
315 {.mnemo=UT_OR, .code=0xB6DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIX, UO_NONE}},
316 // CP (IX+d)
317 {.mnemo=UT_CP, .code=0xBEDDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
318 // CP A,(IX+d)
319 {.mnemo=UT_CP, .code=0xBEDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIX, UO_NONE}},
320 // ADD A,(IY+d)
321 {.mnemo=UT_ADD, .code=0x86FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIY, UO_NONE}},
322 // ADD (IY+d)
323 {.mnemo=UT_ADD, .code=0x86FDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
324 // ADC A,(IY+d)
325 {.mnemo=UT_ADC, .code=0x8EFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIY, UO_NONE}},
326 // ADC (IY+d)
327 {.mnemo=UT_ADC, .code=0x8EFDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
328 // SUB (IY+d)
329 {.mnemo=UT_SUB, .code=0x96FDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
330 // SUB A,(IY+d)
331 {.mnemo=UT_SUB, .code=0x96FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIY, UO_NONE}},
332 // SBC A,(IY+d)
333 {.mnemo=UT_SBC, .code=0x9EFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIY, UO_NONE}},
334 // SBC (IY+d)
335 {.mnemo=UT_SBC, .code=0x9EFDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
336 // AND (IY+d)
337 {.mnemo=UT_AND, .code=0xA6FDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
338 // AND A,(IY+d)
339 {.mnemo=UT_AND, .code=0xA6FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIY, UO_NONE}},
340 // XOR (IY+d)
341 {.mnemo=UT_XOR, .code=0xAEFDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
342 // XOR A,(IY+d)
343 {.mnemo=UT_XOR, .code=0xAEFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIY, UO_NONE}},
344 // OR (IY+d)
345 {.mnemo=UT_OR, .code=0xB6FDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
346 // OR A,(IY+d)
347 {.mnemo=UT_OR, .code=0xB6FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIY, UO_NONE}},
348 // CP (IY+d)
349 {.mnemo=UT_CP, .code=0xBEFDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
350 // CP A,(IY+d)
351 {.mnemo=UT_CP, .code=0xBEFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_MIY, UO_NONE}},
352 // ADD A,XH
353 {.mnemo=UT_ADD, .code=0x84DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XH, UO_NONE}},
354 // ADD XH
355 {.mnemo=UT_ADD, .code=0x84DDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_NONE, UO_NONE}},
356 // ADC A,XH
357 {.mnemo=UT_ADC, .code=0x8CDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XH, UO_NONE}},
358 // ADC XH
359 {.mnemo=UT_ADC, .code=0x8CDDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_NONE, UO_NONE}},
360 // SUB XH
361 {.mnemo=UT_SUB, .code=0x94DDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_NONE, UO_NONE}},
362 // SUB A,XH
363 {.mnemo=UT_SUB, .code=0x94DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XH, UO_NONE}},
364 // SBC A,XH
365 {.mnemo=UT_SBC, .code=0x9CDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XH, UO_NONE}},
366 // SBC XH
367 {.mnemo=UT_SBC, .code=0x9CDDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_NONE, UO_NONE}},
368 // AND XH
369 {.mnemo=UT_AND, .code=0xA4DDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_NONE, UO_NONE}},
370 // AND A,XH
371 {.mnemo=UT_AND, .code=0xA4DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XH, UO_NONE}},
372 // XOR XH
373 {.mnemo=UT_XOR, .code=0xACDDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_NONE, UO_NONE}},
374 // XOR A,XH
375 {.mnemo=UT_XOR, .code=0xACDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XH, UO_NONE}},
376 // OR XH
377 {.mnemo=UT_OR, .code=0xB4DDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_NONE, UO_NONE}},
378 // OR A,XH
379 {.mnemo=UT_OR, .code=0xB4DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XH, UO_NONE}},
380 // CP XH
381 {.mnemo=UT_CP, .code=0xBCDDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_NONE, UO_NONE}},
382 // CP A,XH
383 {.mnemo=UT_CP, .code=0xBCDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XH, UO_NONE}},
384 // ADD A,XL
385 {.mnemo=UT_ADD, .code=0x85DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XL, UO_NONE}},
386 // ADD XL
387 {.mnemo=UT_ADD, .code=0x85DDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_NONE, UO_NONE}},
388 // ADC A,XL
389 {.mnemo=UT_ADC, .code=0x8DDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XL, UO_NONE}},
390 // ADC XL
391 {.mnemo=UT_ADC, .code=0x8DDDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_NONE, UO_NONE}},
392 // SUB XL
393 {.mnemo=UT_SUB, .code=0x95DDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_NONE, UO_NONE}},
394 // SUB A,XL
395 {.mnemo=UT_SUB, .code=0x95DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XL, UO_NONE}},
396 // SBC A,XL
397 {.mnemo=UT_SBC, .code=0x9DDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XL, UO_NONE}},
398 // SBC XL
399 {.mnemo=UT_SBC, .code=0x9DDDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_NONE, UO_NONE}},
400 // AND XL
401 {.mnemo=UT_AND, .code=0xA5DDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_NONE, UO_NONE}},
402 // AND A,XL
403 {.mnemo=UT_AND, .code=0xA5DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XL, UO_NONE}},
404 // XOR XL
405 {.mnemo=UT_XOR, .code=0xADDDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_NONE, UO_NONE}},
406 // XOR A,XL
407 {.mnemo=UT_XOR, .code=0xADDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XL, UO_NONE}},
408 // OR XL
409 {.mnemo=UT_OR, .code=0xB5DDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_NONE, UO_NONE}},
410 // OR A,XL
411 {.mnemo=UT_OR, .code=0xB5DDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XL, UO_NONE}},
412 // CP XL
413 {.mnemo=UT_CP, .code=0xBDDDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_NONE, UO_NONE}},
414 // CP A,XL
415 {.mnemo=UT_CP, .code=0xBDDDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_XL, UO_NONE}},
416 // ADD A,YH
417 {.mnemo=UT_ADD, .code=0x84FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YH, UO_NONE}},
418 // ADD YH
419 {.mnemo=UT_ADD, .code=0x84FDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_NONE, UO_NONE}},
420 // ADC A,YH
421 {.mnemo=UT_ADC, .code=0x8CFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YH, UO_NONE}},
422 // ADC YH
423 {.mnemo=UT_ADC, .code=0x8CFDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_NONE, UO_NONE}},
424 // SUB YH
425 {.mnemo=UT_SUB, .code=0x94FDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_NONE, UO_NONE}},
426 // SUB A,YH
427 {.mnemo=UT_SUB, .code=0x94FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YH, UO_NONE}},
428 // SBC A,YH
429 {.mnemo=UT_SBC, .code=0x9CFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YH, UO_NONE}},
430 // SBC YH
431 {.mnemo=UT_SBC, .code=0x9CFDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_NONE, UO_NONE}},
432 // AND YH
433 {.mnemo=UT_AND, .code=0xA4FDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_NONE, UO_NONE}},
434 // AND A,YH
435 {.mnemo=UT_AND, .code=0xA4FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YH, UO_NONE}},
436 // XOR YH
437 {.mnemo=UT_XOR, .code=0xACFDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_NONE, UO_NONE}},
438 // XOR A,YH
439 {.mnemo=UT_XOR, .code=0xACFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YH, UO_NONE}},
440 // OR YH
441 {.mnemo=UT_OR, .code=0xB4FDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_NONE, UO_NONE}},
442 // OR A,YH
443 {.mnemo=UT_OR, .code=0xB4FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YH, UO_NONE}},
444 // CP YH
445 {.mnemo=UT_CP, .code=0xBCFDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_NONE, UO_NONE}},
446 // CP A,YH
447 {.mnemo=UT_CP, .code=0xBCFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YH, UO_NONE}},
448 // ADD A,YL
449 {.mnemo=UT_ADD, .code=0x85FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YL, UO_NONE}},
450 // ADD YL
451 {.mnemo=UT_ADD, .code=0x85FDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_NONE, UO_NONE}},
452 // ADC A,YL
453 {.mnemo=UT_ADC, .code=0x8DFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YL, UO_NONE}},
454 // ADC YL
455 {.mnemo=UT_ADC, .code=0x8DFDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_NONE, UO_NONE}},
456 // SUB YL
457 {.mnemo=UT_SUB, .code=0x95FDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_NONE, UO_NONE}},
458 // SUB A,YL
459 {.mnemo=UT_SUB, .code=0x95FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YL, UO_NONE}},
460 // SBC A,YL
461 {.mnemo=UT_SBC, .code=0x9DFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YL, UO_NONE}},
462 // SBC YL
463 {.mnemo=UT_SBC, .code=0x9DFDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_NONE, UO_NONE}},
464 // AND YL
465 {.mnemo=UT_AND, .code=0xA5FDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_NONE, UO_NONE}},
466 // AND A,YL
467 {.mnemo=UT_AND, .code=0xA5FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YL, UO_NONE}},
468 // XOR YL
469 {.mnemo=UT_XOR, .code=0xADFDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_NONE, UO_NONE}},
470 // XOR A,YL
471 {.mnemo=UT_XOR, .code=0xADFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YL, UO_NONE}},
472 // OR YL
473 {.mnemo=UT_OR, .code=0xB5FDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_NONE, UO_NONE}},
474 // OR A,YL
475 {.mnemo=UT_OR, .code=0xB5FDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YL, UO_NONE}},
476 // CP YL
477 {.mnemo=UT_CP, .code=0xBDFDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_NONE, UO_NONE}},
478 // CP A,YL
479 {.mnemo=UT_CP, .code=0xBDFDUL, .mask=0xFFFFUL, .ops={UO_R8_A, UO_R8_YL, UO_NONE}},
481 // LD XH,XH
482 {.mnemo=UT_LD, .code=0x64DDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_R8_XH, UO_NONE}},
483 // LD XH,XL
484 {.mnemo=UT_LD, .code=0x65DDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_R8_XL, UO_NONE}},
485 // LD XL,XH
486 {.mnemo=UT_LD, .code=0x6CDDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_R8_XH, UO_NONE}},
487 // LD XL,XL
488 {.mnemo=UT_LD, .code=0x6DDDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_R8_XL, UO_NONE}},
489 // LD YH,YH
490 {.mnemo=UT_LD, .code=0x64FDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_R8_YH, UO_NONE}},
491 // LD YH,YL
492 {.mnemo=UT_LD, .code=0x65FDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_R8_YL, UO_NONE}},
493 // LD YL,YH
494 {.mnemo=UT_LD, .code=0x6CFDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_R8_YH, UO_NONE}},
495 // LD YL,YL
496 {.mnemo=UT_LD, .code=0x6DFDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_R8_YL, UO_NONE}},
498 // LD (nnnn),IX
499 {.mnemo=UT_LD, .code=0x22DDUL, .mask=0xFFFFUL, .ops={UO_MEM16, UO_R16IX, UO_NONE}},
500 // LD IX,(nnnn)
501 {.mnemo=UT_LD, .code=0x2ADDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_MEM16, UO_NONE}},
502 // LD (nnnn),IY
503 {.mnemo=UT_LD, .code=0x22FDUL, .mask=0xFFFFUL, .ops={UO_MEM16, UO_R16IY, UO_NONE}},
504 // LD IY,(nnnn)
505 {.mnemo=UT_LD, .code=0x2AFDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_MEM16, UO_NONE}},
507 // LD IX,nnnn
508 {.mnemo=UT_LD, .code=0x21DDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_IMM16, UO_NONE}},
509 // LD IY,nnnn
510 {.mnemo=UT_LD, .code=0x21FDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_IMM16, UO_NONE}},
512 // INC IX
513 {.mnemo=UT_INC, .code=0x23DDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_NONE, UO_NONE}},
514 // DEC IX
515 {.mnemo=UT_DEC, .code=0x2BDDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_NONE, UO_NONE}},
516 // INC IY
517 {.mnemo=UT_INC, .code=0x23FDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_NONE, UO_NONE}},
518 // DEC IY
519 {.mnemo=UT_DEC, .code=0x2BFDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_NONE, UO_NONE}},
521 // INC (IX+d)
522 {.mnemo=UT_INC, .code=0x34DDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
523 // DEC (IX+d)
524 {.mnemo=UT_DEC, .code=0x35DDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_NONE, UO_NONE}},
525 // LD (IX+d),nn
526 {.mnemo=UT_LD, .code=0x36DDUL, .mask=0xFFFFUL, .ops={UO_MIX, UO_IMM8, UO_NONE}},
527 // INC (IY+d)
528 {.mnemo=UT_INC, .code=0x34FDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
529 // DEC (IY+d)
530 {.mnemo=UT_DEC, .code=0x35FDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_NONE, UO_NONE}},
531 // LD (IY+d),nn
532 {.mnemo=UT_LD, .code=0x36FDUL, .mask=0xFFFFUL, .ops={UO_MIY, UO_IMM8, UO_NONE}},
534 // INC XH
535 {.mnemo=UT_INC, .code=0x24DDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_NONE, UO_NONE}},
536 // DEC XH
537 {.mnemo=UT_DEC, .code=0x25DDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_NONE, UO_NONE}},
538 // INC XL
539 {.mnemo=UT_INC, .code=0x2CDDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_NONE, UO_NONE}},
540 // DEC XL
541 {.mnemo=UT_DEC, .code=0x2DDDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_NONE, UO_NONE}},
542 // INC YH
543 {.mnemo=UT_INC, .code=0x24FDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_NONE, UO_NONE}},
544 // DEC YH
545 {.mnemo=UT_DEC, .code=0x25FDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_NONE, UO_NONE}},
546 // INC YL
547 {.mnemo=UT_INC, .code=0x2CFDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_NONE, UO_NONE}},
548 // DEC YL
549 {.mnemo=UT_DEC, .code=0x2DFDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_NONE, UO_NONE}},
551 // LD XH,nn
552 {.mnemo=UT_LD, .code=0x26DDUL, .mask=0xFFFFUL, .ops={UO_R8_XH, UO_IMM8, UO_NONE}},
553 // LD XL,nn
554 {.mnemo=UT_LD, .code=0x2EDDUL, .mask=0xFFFFUL, .ops={UO_R8_XL, UO_IMM8, UO_NONE}},
555 // LD YH,nn
556 {.mnemo=UT_LD, .code=0x26FDUL, .mask=0xFFFFUL, .ops={UO_R8_YH, UO_IMM8, UO_NONE}},
557 // LD YL,nn
558 {.mnemo=UT_LD, .code=0x2EFDUL, .mask=0xFFFFUL, .ops={UO_R8_YL, UO_IMM8, UO_NONE}},
560 // ADD IX,BC
561 {.mnemo=UT_ADD, .code=0x09DDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_R16BC, UO_NONE}},
562 // ADD IX,DE
563 {.mnemo=UT_ADD, .code=0x19DDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_R16DE, UO_NONE}},
564 // ADD IX,IX
565 {.mnemo=UT_ADD, .code=0x29DDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_R16IX, UO_NONE}},
566 // ADD IX,SP
567 {.mnemo=UT_ADD, .code=0x39DDUL, .mask=0xFFFFUL, .ops={UO_R16IX, UO_R16SP, UO_NONE}},
568 // ADD IY,BC
569 {.mnemo=UT_ADD, .code=0x09FDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_R16BC, UO_NONE}},
570 // ADD IY,DE
571 {.mnemo=UT_ADD, .code=0x19FDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_R16DE, UO_NONE}},
572 // ADD IY,IY
573 {.mnemo=UT_ADD, .code=0x29FDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_R16IY, UO_NONE}},
574 // ADD IY,SP
575 {.mnemo=UT_ADD, .code=0x39FDUL, .mask=0xFFFFUL, .ops={UO_R16IY, UO_R16SP, UO_NONE}},
577 // LD XH,r8
578 {.mnemo=UT_LD, .code=0x60DDUL, .mask=0xF8FFUL, .ops={UO_R8_XH, UO_R8_NOM, UO_NONE}},
579 // LD XL,r8
580 {.mnemo=UT_LD, .code=0x68DDUL, .mask=0xF8FFUL, .ops={UO_R8_XL, UO_R8_NOM, UO_NONE}},
581 // LD (IX+d),r8
582 {.mnemo=UT_LD, .code=0x70DDUL, .mask=0xF8FFUL, .ops={UO_MIX, UO_R8_NOM, UO_NONE}},
583 // LD YH,r8
584 {.mnemo=UT_LD, .code=0x60FDUL, .mask=0xF8FFUL, .ops={UO_R8_YH, UO_R8_NOM, UO_NONE}},
585 // LD YL,r8
586 {.mnemo=UT_LD, .code=0x68FDUL, .mask=0xF8FFUL, .ops={UO_R8_YL, UO_R8_NOM, UO_NONE}},
587 // LD (IY+d),r8
588 {.mnemo=UT_LD, .code=0x70FDUL, .mask=0xF8FFUL, .ops={UO_MIY, UO_R8_NOM, UO_NONE}},
590 // LD r8,XH
591 {.mnemo=UT_LD, .code=0x44DDUL, .mask=0xC7FFUL, .ops={UO_2R8_NOM, UO_R8_XH, UO_NONE}},
592 // LD r8,XL
593 {.mnemo=UT_LD, .code=0x45DDUL, .mask=0xC7FFUL, .ops={UO_2R8_NOM, UO_R8_XL, UO_NONE}},
594 // LD r8,(IX+d)
595 {.mnemo=UT_LD, .code=0x46DDUL, .mask=0xC7FFUL, .ops={UO_2R8_NOM, UO_MIX, UO_NONE}},
597 // LD r8,YH
598 {.mnemo=UT_LD, .code=0x44FDUL, .mask=0xC7FFUL, .ops={UO_2R8_NOM, UO_R8_YH, UO_NONE}},
599 // LD r8,YL
600 {.mnemo=UT_LD, .code=0x45FDUL, .mask=0xC7FFUL, .ops={UO_2R8_NOM, UO_R8_YL, UO_NONE}},
601 // LD r8,(IY+d)
602 {.mnemo=UT_LD, .code=0x46FDUL, .mask=0xC7FFUL, .ops={UO_2R8_NOM, UO_MIY, UO_NONE}},
604 // instructions w/o operands or with unchangeable operands
605 {.mnemo=UT_NOP, .code=0x00UL, .mask=0xFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
606 {.mnemo=UT_RLCA, .code=0x07UL, .mask=0xFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
607 {.mnemo=UT_RRCA, .code=0x0FUL, .mask=0xFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
608 {.mnemo=UT_RLA, .code=0x17UL, .mask=0xFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
609 {.mnemo=UT_RRA, .code=0x1FUL, .mask=0xFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
610 {.mnemo=UT_DAA, .code=0x27UL, .mask=0xFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
611 {.mnemo=UT_CPL, .code=0x2FUL, .mask=0xFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
612 {.mnemo=UT_SCF, .code=0x37UL, .mask=0xFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
613 {.mnemo=UT_CCF, .code=0x3FUL, .mask=0xFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
614 {.mnemo=UT_HALT, .code=0x76UL, .mask=0xFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
615 {.mnemo=UT_RET, .code=0xC9UL, .mask=0xFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
616 {.mnemo=UT_EXX, .code=0xD9UL, .mask=0xFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
617 {.mnemo=UT_DI, .code=0xF3UL, .mask=0xFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
618 {.mnemo=UT_EI, .code=0xFBUL, .mask=0xFFUL, .ops={UO_NONE, UO_NONE, UO_NONE}},
619 // LD SP,HL
620 {.mnemo=UT_LD, .code=0xF9UL, .mask=0xFFUL, .ops={UO_R16SP, UO_R16HL, UO_NONE}},
621 // EX AF,AF'
622 {.mnemo=UT_EX, .code=0x08UL, .mask=0xFFUL, .ops={UO_R16AF, UO_R16AFX, UO_NONE}},
623 // EX AF',AF (ditto)
624 {.mnemo=UT_EX, .code=0x08UL, .mask=0xFFUL, .ops={UO_R16AFX, UO_R16AF, UO_NONE}},
625 // EX (SP),HL
626 {.mnemo=UT_EX, .code=0xE3UL, .mask=0xFFUL, .ops={UO_MSP, UO_R16HL, UO_NONE}},
627 // EX HL,(SP) (ditto)
628 {.mnemo=UT_EX, .code=0xE3UL, .mask=0xFFUL, .ops={UO_R16HL, UO_MSP, UO_NONE}},
629 // EX DE,HL
630 {.mnemo=UT_EX, .code=0xEBUL, .mask=0xFFUL, .ops={UO_R16DE, UO_R16HL, UO_NONE}},
631 // EX HL,DE (ditto)
632 {.mnemo=UT_EX, .code=0xEBUL, .mask=0xFFUL, .ops={UO_R16HL, UO_R16DE, UO_NONE}},
633 // JP (HL)
634 {.mnemo=UT_JP, .code=0xE9UL, .mask=0xFFUL, .ops={UO_MHL, UO_NONE, UO_NONE}},
635 // JP HL
636 {.mnemo=UT_JP, .code=0xE9UL, .mask=0xFFUL, .ops={UO_R16HL, UO_NONE, UO_NONE}},
637 // JP nnnn
638 {.mnemo=UT_JP, .code=0xC3UL, .mask=0xFFUL, .ops={UO_ADDR16, UO_NONE, UO_NONE}},
639 // CALL nnnn
640 {.mnemo=UT_CALL, .code=0xCDUL, .mask=0xFFUL, .ops={UO_ADDR16, UO_NONE, UO_NONE}},
641 // OUT (n),A
642 {.mnemo=UT_OUT, .code=0xD3UL, .mask=0xFFUL, .ops={UO_PORTIMM, UO_R8_A, UO_NONE}},
643 // IN A,(n)
644 {.mnemo=UT_IN, .code=0xDBUL, .mask=0xFFUL, .ops={UO_R8_A, UO_PORTIMM, UO_NONE}},
646 // ADD A,nn
647 {.mnemo=UT_ADD, .code=0xC6UL, .mask=0xFFUL, .ops={UO_R8_A, UO_IMM8, UO_NONE}},
648 // ADD nn (ditto)
649 {.mnemo=UT_ADD, .code=0xC6UL, .mask=0xFFUL, .ops={UO_IMM8, UO_NONE, UO_NONE}},
650 // ADC A,nn
651 {.mnemo=UT_ADC, .code=0xCEUL, .mask=0xFFUL, .ops={UO_R8_A, UO_IMM8, UO_NONE}},
652 // ADC nn (ditto)
653 {.mnemo=UT_ADC, .code=0xCEUL, .mask=0xFFUL, .ops={UO_IMM8, UO_NONE, UO_NONE}},
654 // SUB nn
655 {.mnemo=UT_SUB, .code=0xD6UL, .mask=0xFFUL, .ops={UO_IMM8, UO_NONE, UO_NONE}},
656 // SUB A,nn (ditto)
657 {.mnemo=UT_SUB, .code=0xD6UL, .mask=0xFFUL, .ops={UO_R8_A, UO_IMM8, UO_NONE}},
658 // SBC A,nn
659 {.mnemo=UT_SBC, .code=0xDEUL, .mask=0xFFUL, .ops={UO_R8_A, UO_IMM8, UO_NONE}},
660 // SBC nn (ditto)
661 {.mnemo=UT_SBC, .code=0xDEUL, .mask=0xFFUL, .ops={UO_IMM8, UO_NONE, UO_NONE}},
662 // AND nn
663 {.mnemo=UT_AND, .code=0xE6UL, .mask=0xFFUL, .ops={UO_IMM8, UO_NONE, UO_NONE}},
664 // AND A,nn (ditto)
665 {.mnemo=UT_AND, .code=0xE6UL, .mask=0xFFUL, .ops={UO_R8_A, UO_IMM8, UO_NONE}},
666 // XOR nn
667 {.mnemo=UT_XOR, .code=0xEEUL, .mask=0xFFUL, .ops={UO_IMM8, UO_NONE, UO_NONE}},
668 // XOR A,nn (ditto)
669 {.mnemo=UT_XOR, .code=0xEEUL, .mask=0xFFUL, .ops={UO_R8_A, UO_IMM8, UO_NONE}},
670 // OR nn
671 {.mnemo=UT_OR, .code=0xF6UL, .mask=0xFFUL, .ops={UO_IMM8, UO_NONE, UO_NONE}},
672 // OR A,nn (ditto)
673 {.mnemo=UT_OR, .code=0xF6UL, .mask=0xFFUL, .ops={UO_R8_A, UO_IMM8, UO_NONE}},
674 // CP nn
675 {.mnemo=UT_CP, .code=0xFEUL, .mask=0xFFUL, .ops={UO_IMM8, UO_NONE, UO_NONE}},
676 // CP A,nn (ditto)
677 {.mnemo=UT_CP, .code=0xFEUL, .mask=0xFFUL, .ops={UO_R8_A, UO_IMM8, UO_NONE}},
678 // LD (BC),A
679 {.mnemo=UT_LD, .code=0x02UL, .mask=0xFFUL, .ops={UO_MBC, UO_R8_A, UO_NONE}},
680 // LD (DE),A
681 {.mnemo=UT_LD, .code=0x12UL, .mask=0xFFUL, .ops={UO_MDE, UO_R8_A, UO_NONE}},
682 // LD A,(BC)
683 {.mnemo=UT_LD, .code=0x0AUL, .mask=0xFFUL, .ops={UO_R8_A, UO_MBC, UO_NONE}},
684 // LD A,(DE)
685 {.mnemo=UT_LD, .code=0x1AUL, .mask=0xFFUL, .ops={UO_R8_A, UO_MDE, UO_NONE}},
686 // LD (nnnn),HL
687 {.mnemo=UT_LD, .code=0x22UL, .mask=0xFFUL, .ops={UO_MEM16, UO_R16HL, UO_NONE}},
688 // LD HL,(nnnn)
689 {.mnemo=UT_LD, .code=0x2AUL, .mask=0xFFUL, .ops={UO_R16HL, UO_MEM16, UO_NONE}},
690 // LD (nnnn),A
691 {.mnemo=UT_LD, .code=0x32UL, .mask=0xFFUL, .ops={UO_MEM16, UO_R8_A, UO_NONE}},
692 // LD A,(nnnn)
693 {.mnemo=UT_LD, .code=0x3AUL, .mask=0xFFUL, .ops={UO_R8_A, UO_MEM16, UO_NONE}},
694 // DJNZ d
695 {.mnemo=UT_DJNZ, .code=0x10UL, .mask=0xFFUL, .ops={UO_ADDR8, UO_NONE, UO_NONE}},
696 // JR d
697 {.mnemo=UT_JR, .code=0x18UL, .mask=0xFFUL, .ops={UO_ADDR8, UO_NONE, UO_NONE}},
699 // ADD HL,r16
700 {.mnemo=UT_ADD, .code=0x09UL, .mask=0xCFUL, .ops={UO_R16HL, UO_R16, UO_NONE}},
702 // ADD A,r8
703 {.mnemo=UT_ADD, .code=0x80UL, .mask=0xF8UL, .ops={UO_R8_A, UO_R8, UO_NONE}},
704 // ADD r8
705 {.mnemo=UT_ADD, .code=0x80UL, .mask=0xF8UL, .ops={UO_R8, UO_NONE, UO_NONE}},
706 // ADC A,r8
707 {.mnemo=UT_ADC, .code=0x88UL, .mask=0xF8UL, .ops={UO_R8_A, UO_R8, UO_NONE}},
708 // ADC r8
709 {.mnemo=UT_ADC, .code=0x88UL, .mask=0xF8UL, .ops={UO_R8, UO_NONE, UO_NONE}},
710 // SUB r8
711 {.mnemo=UT_SUB, .code=0x90UL, .mask=0xF8UL, .ops={UO_R8, UO_NONE, UO_NONE}},
712 // SUB A,r8
713 {.mnemo=UT_SUB, .code=0x90UL, .mask=0xF8UL, .ops={UO_R8_A, UO_R8, UO_NONE}},
714 // SBC A,r8
715 {.mnemo=UT_SBC, .code=0x98UL, .mask=0xF8UL, .ops={UO_R8_A, UO_R8, UO_NONE}},
716 // SBC r8
717 {.mnemo=UT_SBC, .code=0x98UL, .mask=0xF8UL, .ops={UO_R8, UO_NONE, UO_NONE}},
718 // AND r8
719 {.mnemo=UT_AND, .code=0xA0UL, .mask=0xF8UL, .ops={UO_R8, UO_NONE, UO_NONE}},
720 // AND A,r8
721 {.mnemo=UT_AND, .code=0xA0UL, .mask=0xF8UL, .ops={UO_R8_A, UO_R8, UO_NONE}},
722 // XOR r8
723 {.mnemo=UT_XOR, .code=0xA8UL, .mask=0xF8UL, .ops={UO_R8, UO_NONE, UO_NONE}},
724 // XOR A,r8
725 {.mnemo=UT_XOR, .code=0xA8UL, .mask=0xF8UL, .ops={UO_R8_A, UO_R8, UO_NONE}},
726 // OR r8
727 {.mnemo=UT_OR, .code=0xB0UL, .mask=0xF8UL, .ops={UO_R8, UO_NONE, UO_NONE}},
728 // OR A,r8
729 {.mnemo=UT_OR, .code=0xB0UL, .mask=0xF8UL, .ops={UO_R8_A, UO_R8, UO_NONE}},
730 // CP r8
731 {.mnemo=UT_CP, .code=0xB8UL, .mask=0xF8UL, .ops={UO_R8, UO_NONE, UO_NONE}},
732 // CP A,r8
733 {.mnemo=UT_CP, .code=0xB8UL, .mask=0xF8UL, .ops={UO_R8_A, UO_R8, UO_NONE}},
735 // JR cc,d
736 {.mnemo=UT_JR, .code=0x20UL, .mask=0xE7UL, .ops={UO_JRCOND, UO_ADDR8, UO_NONE}},
738 // POP r16
739 {.mnemo=UT_POP, .code=0xC1UL, .mask=0xCFUL, .ops={UO_R16A, UO_NONE, UO_NONE}},
740 // PUSH r16
741 {.mnemo=UT_PUSH, .code=0xC5UL, .mask=0xCFUL, .ops={UO_R16A, UO_NONE, UO_NONE}},
742 // RET cc
743 {.mnemo=UT_RET, .code=0xC0UL, .mask=0xC7UL, .ops={UO_COND, UO_NONE, UO_NONE}},
744 // JP cc,nnnn
745 {.mnemo=UT_JP, .code=0xC2UL, .mask=0xC7UL, .ops={UO_COND, UO_ADDR16, UO_NONE}},
746 // CALL cc,nnnn
747 {.mnemo=UT_CALL, .code=0xC4UL, .mask=0xC7UL, .ops={UO_COND, UO_ADDR16, UO_NONE}},
748 // RST n
749 {.mnemo=UT_RST, .code=0xC7UL, .mask=0xC7UL, .ops={UO_RSTDEST, UO_NONE, UO_NONE}},
751 // INC r8
752 {.mnemo=UT_INC, .code=0x04UL, .mask=0xC7UL, .ops={UO_2R8, UO_NONE, UO_NONE}},
753 // DEC r8
754 {.mnemo=UT_DEC, .code=0x05UL, .mask=0xC7UL, .ops={UO_2R8, UO_NONE, UO_NONE}},
755 // LD r8,nn
756 {.mnemo=UT_LD, .code=0x06UL, .mask=0xC7UL, .ops={UO_2R8, UO_IMM8, UO_NONE}},
758 // LD r16,nnnn
759 {.mnemo=UT_LD, .code=0x01UL, .mask=0xCFUL, .ops={UO_R16, UO_IMM16, UO_NONE}},
760 // INC r16
761 {.mnemo=UT_INC, .code=0x03UL, .mask=0xCFUL, .ops={UO_R16, UO_NONE, UO_NONE}},
762 // DEC r16
763 {.mnemo=UT_DEC, .code=0x0BUL, .mask=0xCFUL, .ops={UO_R16, UO_NONE, UO_NONE}},
765 // LD r8,r8
766 {.mnemo=UT_LD, .code=0x40UL, .mask=0xC0UL, .ops={UO_2R8, UO_R8, UO_NONE}},
768 // syntetics
769 // LD BC,BC
770 {.mnemo=UT_LD, .code=0x4940UL, .mask=0xFFFFUL, .ops={UO_R16BC, UO_R16BC, UO_NONE}},
771 // LD BC,DE
772 {.mnemo=UT_LD, .code=0x4B42UL, .mask=0xFFFFUL, .ops={UO_R16BC, UO_R16DE, UO_NONE}},
773 // LD BC,HL
774 {.mnemo=UT_LD, .code=0x4D44UL, .mask=0xFFFFUL, .ops={UO_R16BC, UO_R16HL, UO_NONE}},
775 // LD DE,BC
776 {.mnemo=UT_LD, .code=0x5950UL, .mask=0xFFFFUL, .ops={UO_R16DE, UO_R16BC, UO_NONE}},
777 // LD DE,DE
778 {.mnemo=UT_LD, .code=0x5B52UL, .mask=0xFFFFUL, .ops={UO_R16DE, UO_R16DE, UO_NONE}},
779 // LD DE,HL
780 {.mnemo=UT_LD, .code=0x5D54UL, .mask=0xFFFFUL, .ops={UO_R16DE, UO_R16HL, UO_NONE}},
781 // LD HL,BC
782 {.mnemo=UT_LD, .code=0x6960UL, .mask=0xFFFFUL, .ops={UO_R16HL, UO_R16BC, UO_NONE}},
783 // LD HL,DE
784 {.mnemo=UT_LD, .code=0x6B62UL, .mask=0xFFFFUL, .ops={UO_R16HL, UO_R16DE, UO_NONE}},
785 // LD HL,HL
786 {.mnemo=UT_LD, .code=0x6D64UL, .mask=0xFFFFUL, .ops={UO_R16HL, UO_R16HL, UO_NONE}},
790 // instructions unaffected by DD/FF prefixes
791 // this table used by disassembler (we don't want to eat prefixes)
792 const unsigned char URASM_DDFD_INSENSITIVE[256] = {
793 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
794 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
795 1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,
796 1,1,1,1,0,0,0,1,1,0,1,1,1,1,1,1,
797 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
798 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
799 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
800 0,0,0,0,0,0,1,0,1,1,1,1,0,0,0,1,
801 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
802 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
803 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
804 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
805 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,
806 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
807 1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,
808 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
810 0xff,0xbf,0xff,0xbf,0x81,0x81,0xf1,0xbf,0xf1,0xf1,0xf1,0xf1,0x00,0x00,0x02,0xf1,
811 0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xff,0xef,0xff,0xff,0xab,0xbf,0xff,0xbf,
815 #define isDDSensitive(c) URASM_DDFD_INSENSITIVE[(c)&0xff]
817 static inline int isDDSensitive (uint8_t opc) {
818 return URASM_DDFD_INSENSITIVE[opc/8]&(0x80>>(opc%8));
823 #if 0
824 const unsigned char URASM_DDFD_HAS_DISP[256] = {
826 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
827 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
828 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
829 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
830 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
831 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
832 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
833 1,1,1,1,1,1,0,1,0,0,0,0,0,0,1,0,
834 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
835 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
836 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
837 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
838 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
839 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
840 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
841 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
843 0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x00,0x02,0x02,0x02,0x02,0x02,0x02,0xfd,0x02,
844 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
847 static inline int hasDDFDDisp (uint8_t opc) {
848 return URASM_DDFD_HAS_DISP[opc/8]&(0x80>>(opc%8));
850 #endif
853 static const char *findLabelByAddr (uint16_t addr) {
854 if (!urFindLabelByAddr) return NULL;
855 return urFindLabelByAddr(addr);
859 ///////////////////////////////////////////////////////////////////////////////
860 // disassembler
862 // opc: opcode
863 // nextW: next 2 bytes (after opcode)
864 // idx: I? displacement
865 static void uaOp2Str (char *res, int op, uint16_t addr, uint8_t opc, uint16_t nextW, int idx) {
866 const char *lbl;
867 int add, ismem = 0;
869 switch (op) {
870 case UO_NONE: strcpy(res, ""); break;
871 case UO_IMM8:
872 if (!urDisDecimal) sprintf(res, "#%02X", nextW&0xFFU); else sprintf(res, "%u", nextW&0xFFU);
873 break;
874 case UO_IMM16:
875 if (!urDisDecimal) sprintf(res, "#%04X", nextW); else sprintf(res, "%u", nextW);
876 break;
877 case UO_ADDR8:
878 addr += 2; nextW &= 0xFFU;
879 add = nextW<128 ? nextW : ((int)nextW)-256;
880 addr += add;
881 nextW = addr;
882 /* fallthru */
883 case UO_ADDR16:
884 dolabel:
885 lbl = findLabelByAddr(nextW);
886 if (lbl) { strcpy(res, lbl); break; }
887 lbl = findLabelByAddr(nextW-1);
888 if (lbl) { sprintf(res, "%s-1", lbl); break; }
889 lbl = findLabelByAddr(nextW-2);
890 if (lbl) { sprintf(res, "%s-2", lbl); break; }
891 lbl = findLabelByAddr(nextW+1);
892 if (lbl) { sprintf(res, "%s+1", lbl); break; }
893 lbl = findLabelByAddr(nextW+2);
894 if (lbl) { sprintf(res, "%s+2", lbl); break; }
895 if (!urDisDecimal) sprintf(res, "#%04X", nextW); else sprintf(res, "%u", nextW);
896 break;
897 case UO_MEM16:
898 ismem = 1;
899 strcpy(res, "("); ++res;
900 goto dolabel;
901 case UO_R8:
902 case UO_R8_NOM:
903 strcpy(res, URA_REGS8[opc&0x07UL]);
904 break;
905 case UO_2R8:
906 case UO_2R8_NOM:
907 strcpy(res, URA_REGS8[(opc>>3)&0x07UL]);
908 break;
909 case UO_PORTC: strcpy(res, "(C)"); break;
910 case UO_PORTIMM:
911 if (!urDisDecimal) sprintf(res, "(#%02X)", nextW&0xFFU); else sprintf(res, "(%u)", nextW&0xFFU);
912 break;
913 case UO_R8_XH: strcpy(res, "XH"); break;
914 case UO_R8_XL: strcpy(res, "XL"); break;
915 case UO_R8_YH: strcpy(res, "YH"); break;
916 case UO_R8_YL: strcpy(res, "YL"); break;
917 case UO_R8_A: strcpy(res, "A"); break;
918 case UO_R8_R: strcpy(res, "R"); break;
919 case UO_R8_I: strcpy(res, "I"); break;
920 case UO_R16: strcpy(res, URA_REGS16[(opc>>4)&0x03UL]); break;
921 case UO_R16A: strcpy(res, URA_REGS16A[(opc>>4)&0x03UL]); break;
922 case UO_R16AF: strcpy(res, "AF"); break;
923 case UO_R16AFX: strcpy(res, "AF'"); break;
924 case UO_R16BC: strcpy(res, "BC"); break;
925 case UO_R16DE: strcpy(res, "DE"); break;
926 case UO_R16HL: strcpy(res, "HL"); break;
927 case UO_R16IX: strcpy(res, "IX"); break;
928 case UO_R16IY: strcpy(res, "IY"); break;
929 case UO_R16SP: strcpy(res, "SP"); break;
930 case UO_MSP: strcpy(res, "(SP)"); break;
931 case UO_MBC: strcpy(res, "(BC)"); break;
932 case UO_MDE: strcpy(res, "(DE)"); break;
933 case UO_MHL: strcpy(res, "(HL)"); break;
934 case UO_MIX0: strcpy(res, "(IX)"); break;
935 case UO_MIY0: strcpy(res, "(IY)"); break;
936 case UO_MIX:
937 sprintf(res, "(IX%c%d)", idx<0?'-':'+', idx);
938 break;
939 case UO_MIY:
940 sprintf(res, "(IY%c%d)", idx<0?'-':'+', idx);
941 break;
942 case UO_JRCOND: strcpy(res, URA_COND[(opc>>3)&0x03U]); break;
943 case UO_COND: strcpy(res, URA_COND[(opc>>3)&0x07U]); break;
944 case UO_BITN: sprintf(res, "%u", (opc>>3)&0x07U); break;
945 case UO_RSTDEST:
946 if (!urDisDecimal) sprintf(res, "#%02X", opc&0x38U); else sprintf(res, "%u", opc&0x38U);
947 break;
948 case UO_IM0: strcpy(res, "0"); break;
949 case UO_IM1: strcpy(res, "1"); break;
950 case UO_IM2: strcpy(res, "2"); break;
951 default: strcpy(res, ""); break; // we'll never come here
953 if (ismem) strcat(res, ")");
957 // find the corresponding record in URASM_COMMANDS
958 int urDisassembleFind (uint16_t addr) {
959 uint8_t buf[8];
960 uint32_t ci, f, c;
961 uint8_t opc;
962 int bpos, opn, op;
964 if (!urGetByte) return -1;
965 for (f = 0; f < 8; ++f) buf[f] = urGetByte(addr+f);
966 if (buf[0] == 0xDDU || buf[0] == 0xFDU) {
967 // dummy prefix
968 if (isDDSensitive(buf[1])) return buf[0]==0xDDU ? 0 : 1;
970 ci = ((uint32_t)buf[0]) | (((uint32_t)buf[1])<<8) | (((uint32_t)buf[2])<<16) | (((uint32_t)buf[3])<<24);
971 for (opn = 0; opn <= URASM_MAX_COMMAND; ++opn) {
972 // find command
973 for (; opn <= URASM_MAX_COMMAND && (ci&URASM_COMMANDS[opn].mask) != URASM_COMMANDS[opn].code; ++opn) ;
974 if (opn > URASM_MAX_COMMAND) {
975 if (buf[0] == 0xEDU) return -2;
976 return -1;
978 // skip prefixes, determine command length
979 f = URASM_COMMANDS[opn].mask; c = URASM_COMMANDS[opn].code;
980 for (bpos = 0; ; ++bpos) {
981 uint8_t b;
982 if ((f&0xFFUL) != 0xFFUL) break;
983 b = c&0xFFUL;
984 if (b != 0xFDU && b != 0xDDU && b != 0xEDU && b != 0xCBU) break;
985 f >>= 8; c >>= 8;
987 // are there any operands?
988 if (URASM_COMMANDS[opn].ops[0] == UO_NONE) return opn;
989 // is this CB-prefixed?
990 if (((URASM_COMMANDS[opn].code&0xFFFFUL) == 0xCBDDUL) ||
991 ((URASM_COMMANDS[opn].code&0xFFFFUL) == 0xCBFDUL)) ++bpos; // skip displacement
992 opc = buf[bpos];
993 // do operands
994 for (f = 0; f <= 3; ++f) {
995 if (f == 3) return opn;
996 op = URASM_COMMANDS[opn].ops[f];
997 if (op == UO_NONE) return opn;
998 // check for valid operand
999 if (op == UO_R8_NOM) {
1000 if ((opc&0x07U) == 6) break; // bad (HL)
1002 if (op == UO_2R8_NOM) {
1003 if (((opc>>3)&0x07U) == 6) break; // bad (HL)
1007 return -1;
1011 // length of the corresponding instruction
1012 int urDisassembleLength (int idx) {
1013 int res = 0, f, op;
1014 uint32_t m, c;
1016 if (idx == -2) return 2;
1017 if (idx < 0 || idx > URASM_MAX_COMMAND) return 1;
1018 if (idx < 2) return 1;
1019 m = URASM_COMMANDS[idx].mask; c = URASM_COMMANDS[idx].code;
1020 // I?/CB?
1022 if (((m&0xFFFFUL) == 0xFFFFUL) &&
1023 ((c&0xFF00UL) == 0xCBUL) && ((c&0xFFUL) == 0xDDUL || (c&0xFFUL) == 0xFDUL)) return 4;
1025 // skip prefixes, determine command length
1026 for (;;) {
1027 uint8_t b;
1028 if ((m&0xFFUL) != 0xFFUL) break;
1029 b = c&0xFFUL;
1030 if (b != 0xFDU && b != 0xDDU && b != 0xEDU && b != 0xCBU) break;
1031 m >>= 8; c >>= 8; ++res;
1033 // is this CB-prefixed?
1034 if (((URASM_COMMANDS[idx].code&0xFFFFUL) == 0xCBDDUL) ||
1035 ((URASM_COMMANDS[idx].code&0xFFFFUL) == 0xCBFDUL)) m >>= 8;
1036 // count opcodes
1037 while (m != 0) { m >>= 8; ++res; }
1038 // process operands
1039 for (f = 0; f <= 2; ++f) {
1040 op = URASM_COMMANDS[idx].ops[f];
1041 if (op == UO_NONE) break;
1042 switch (op) {
1043 // command with displacement
1044 case UO_MIX: case UO_MIY: ++res; break;
1045 // command has immediate operand
1046 case UO_IMM8: case UO_ADDR8: case UO_PORTIMM: ++res; break;
1047 case UO_IMM16: case UO_ADDR16: case UO_MEM16: res += 2; break;
1050 return res;
1054 int urDisassembleOne (char *dstr, uint16_t addr) {
1055 uint8_t buf[8];
1056 int res, idx = 0;
1057 uint32_t ci, f, c;
1058 uint8_t opc;
1059 int bpos, opn, op;
1060 uint16_t nextW;
1061 char opstr[129];
1063 if (!urGetByte) return -1;
1064 for (f = 0; f < 8; ++f) buf[f] = urGetByte(addr+f);
1065 if (buf[0] == 0xDDU || buf[0] == 0xFDU) {
1066 // dummy prefix
1067 if (isDDSensitive(buf[1])) {
1068 strcpy(dstr, URASM_TOKENS[buf[0]==0xDDU ? UT_NOPX : UT_NOPY]);
1069 return 1;
1071 // take possible I? displacement
1072 idx = (int8_t)buf[2];
1074 ci = ((uint32_t)buf[0]) | (((uint32_t)buf[1])<<8) | (((uint32_t)buf[2])<<16) | (((uint32_t)buf[3])<<24);
1076 for (opn = 0; opn <= URASM_MAX_COMMAND; ++opn) {
1077 res = 0; dstr[0] = '\0';
1078 // find command
1079 for (; opn <= URASM_MAX_COMMAND && (ci&URASM_COMMANDS[opn].mask) != URASM_COMMANDS[opn].code; ++opn) ;
1080 if (opn > URASM_MAX_COMMAND) {
1081 if (buf[0] == 0xEDU) {
1082 if (!urDisDecimal) sprintf(opstr, "#%02X,#%02X", buf[0], buf[1]); else sprintf(opstr, "%u,%u", buf[0], buf[1]);
1083 /*if (!urDisDecimal) sprintf(opstr, "#%04X", (uint16_t)buf[0]|(((uint16_t)buf[1])<<8));
1084 else sprintf(opstr, "%u", (uint16_t)buf[0]|(((uint16_t)buf[1])<<8));*/
1085 sprintf(dstr, "DB\t%s", opstr);
1086 return 2;
1088 if (!urDisDecimal) sprintf(opstr, "#%02X", buf[0]); else sprintf(opstr, "%u", buf[0]);
1089 sprintf(dstr, "DB\t%s", opstr);
1090 return 1;
1092 // skip prefixes, determine command length
1093 f = URASM_COMMANDS[opn].mask; c = URASM_COMMANDS[opn].code;
1094 for (bpos = 0; ; ++bpos) {
1095 uint8_t b;
1096 if ((f&0xFFUL) != 0xFFUL) break;
1097 b = c&0xFFUL;
1098 if (b != 0xFDU && b != 0xDDU && b != 0xEDU && b != 0xCBU) break;
1099 f >>= 8; c >>= 8; ++res;
1101 // is this CB-prefixed?
1102 if (((URASM_COMMANDS[opn].code&0xFFFFUL) == 0xCBDDUL) ||
1103 ((URASM_COMMANDS[opn].code&0xFFFFUL) == 0xCBFDUL)) f >>= 8;
1104 while (f != 0) { f >>= 8; ++res; }
1105 // copy mnemonics
1106 strcpy(dstr, URASM_TOKENS[URASM_COMMANDS[opn].mnemo]);
1107 // are there any operands?
1108 if (URASM_COMMANDS[opn].ops[0] == UO_NONE) return res;
1109 // is this CB-prefixed?
1110 if (((URASM_COMMANDS[opn].code&0xFFFFUL) == 0xCBDDUL) ||
1111 ((URASM_COMMANDS[opn].code&0xFFFFUL) == 0xCBFDUL)) ++bpos; // skip displacement
1112 else {
1113 if ((URASM_COMMANDS[opn].ops[0] == UO_MIX || URASM_COMMANDS[opn].ops[0] == UO_MIY) &&
1114 URASM_COMMANDS[opn].ops[1] == UO_IMM8 &&
1115 URASM_COMMANDS[opn].ops[2] == UO_NONE) ++bpos; // skip displacement
1117 opc = buf[bpos++];
1118 nextW = (uint16_t)buf[bpos] | (((uint16_t)buf[bpos+1])<<8);
1119 // do operands
1120 for (f = 0; f <= 3; ++f) {
1121 if (f == 3) {
1122 //printf("OPN=%d\n", opn);
1123 return res;
1125 op = URASM_COMMANDS[opn].ops[f];
1126 if (op == UO_NONE) {
1127 //printf("OPN=%d\n", opn);
1128 return res;
1130 // check for valid operand
1131 if (op == UO_R8_NOM) {
1132 if ((opc&0x07U) == 6) break; // bad (HL)
1134 if (op == UO_2R8_NOM) {
1135 if (((opc>>3)&0x07U) == 6) break; // bad (HL)
1137 // command with displacement?
1138 if (op == UO_MIX || op == UO_MIY) ++res;
1139 // command has immediate operand?
1140 if (op == UO_IMM8 || op == UO_ADDR8 || op == UO_PORTIMM) ++res;
1141 if (op == UO_IMM16 || op == UO_ADDR16 || op == UO_MEM16) res += 2;
1142 // add delimiter
1143 strcat(dstr, f==0?"\t":",");
1144 // decode operand
1145 uaOp2Str(opstr, op, addr, opc, nextW, idx);
1146 strcat(dstr, opstr);
1149 return -1;
1153 ///////////////////////////////////////////////////////////////////////////////
1154 // assembler
1156 // returns false if label name conflicts with reserved word
1157 // (or if label is just invalid one)
1158 int urIsValidLabelName (const char *lbl) {
1159 int f, hasNA = 0;
1160 char ch, buf[6];
1162 if (!lbl || !lbl[0]) return 0;
1163 if (lbl[0] == '@') {
1164 ch = lbl[1];
1165 } else {
1166 ch = lbl[0];
1168 if (isdigit(ch)) return 0;
1169 if (!isalpha(ch) && ch != '.' && ch != '_' && ch != '@') return 0;
1170 for (f = 1; lbl[f]; ++f) {
1171 ch = lbl[f];
1172 if (isdigit(ch)) continue;
1173 if (!isalpha(ch)) {
1174 hasNA = 1;
1175 if (ch != '$' && ch != '.' && ch != '_' && ch != '@') return 0;
1178 if (hasNA || f > 4) return 1;
1179 for (f = 0; lbl[f]; ++f) buf[f] = toupper(lbl[f]); buf[f] = '\0';
1180 for (f = 0; f < URASM_MAX_TOKEN; ++f) if (!strcmp(buf, URASM_TOKENS[f])) return 0;
1181 for (f = 0; f < 8; ++f) if (!strcmp(buf, URA_REGS8[f])) return 0;
1182 for (f = 0; f < 4; ++f) if (!strcmp(buf, URA_REGS16[f])) return 0;
1183 for (f = 0; f < 4; ++f) if (!strcmp(buf, URA_REGS16A[f])) return 0;
1184 for (f = 0; f < 8; ++f) if (!strcmp(buf, URA_COND[f])) return 0;
1185 if (!strcmp(buf, "AFX")) return 0;
1186 if (!strcmp(buf, "IXH")) return 0;
1187 if (!strcmp(buf, "IXL")) return 0;
1188 if (!strcmp(buf, "IYH")) return 0;
1189 if (!strcmp(buf, "IYL")) return 0;
1190 if (!strcmp(buf, "IX")) return 0;
1191 if (!strcmp(buf, "IY")) return 0;
1192 if (!strcmp(buf, "XH")) return 0;
1193 if (!strcmp(buf, "HX")) return 0;
1194 if (!strcmp(buf, "XL")) return 0;
1195 if (!strcmp(buf, "LX")) return 0;
1196 if (!strcmp(buf, "YH")) return 0;
1197 if (!strcmp(buf, "HY")) return 0;
1198 if (!strcmp(buf, "YL")) return 0;
1199 if (!strcmp(buf, "LY")) return 0;
1200 if (!strcmp(buf, "R")) return 0;
1201 if (!strcmp(buf, "I")) return 0;
1202 return 1;
1206 ///////////////////////////////////////////////////////////////////////////////
1207 // scanner / parser
1209 // parse and calculate expression
1210 static const char *skipBlanks (const char *expr) {
1211 while (*expr && isspace(*expr)) ++expr;
1212 return expr;
1216 static inline int dig2n (char ch, int base) {
1217 if (ch < '0') return -1;
1218 if (base <= 10) {
1219 if (ch > '0'+base) return -1;
1220 return ch-'0';
1222 ch = toupper(ch);
1223 if (ch > '9' && ch < 'A') return -1;
1224 ch -= '0'+(ch>'9'?7:0);
1225 if (ch >= base) return -1;
1226 return ch;
1230 ///////////////////////////////////////////////////////////////////////////////
1231 // expression parser
1232 typedef struct {
1233 const char *expr; /* can be changed */
1234 uint16_t addr; /* current address */
1235 int defined; /* !0: all used labels are defined */
1236 int error; /* !0: error */
1237 const char *errpos; /* will be set on error, has no meaning otherwise */
1238 jmp_buf errJP;
1239 int logDone;
1240 int32_t logRes;
1241 } ExprInfo;
1243 typedef struct {
1244 int32_t val; /* for now */
1245 } ExprOp;
1248 /* do math; op0 is the result */
1249 typedef void (*ExprDoItFn) (ExprOp *op0, ExprOp *op1, ExprInfo *ei);
1251 typedef struct {
1252 char sn; /* short name or 0 */
1253 const char *ln; /* long name or NULL if `sn`!=0 */
1254 int prio; /* priority */
1255 ExprDoItFn doer;
1256 } ExprOperator;
1259 ///////////////////////////////////////////////////////////////////////////////
1260 // math ops
1261 #define ERR_EOS 1
1262 #define ERR_DIV0 2
1263 #define ERR_PARENS 3
1264 #define ERR_NUMBER 4
1265 #define ERR_STRING 5
1266 #define ERR_LABEL 6
1267 #define ERR_TERM 7
1268 #define ERR_FUNC 8
1270 #define EERROR(code) longjmp(ei->errJP, code)
1272 static void mdoBitNot (ExprOp *op0, ExprOp *op1, ExprInfo *ei) { op0->val = ~op0->val; }
1273 static void mdoLogNot (ExprOp *op0, ExprOp *op1, ExprInfo *ei) { op0->val = !op0->val; }
1274 static void mdoBitAnd (ExprOp *op0, ExprOp *op1, ExprInfo *ei) { op0->val &= op1->val; }
1275 static void mdoBitOr (ExprOp *op0, ExprOp *op1, ExprInfo *ei) { op0->val |= op1->val; }
1276 static void mdoBitXor (ExprOp *op0, ExprOp *op1, ExprInfo *ei) { op0->val ^= op1->val; }
1277 static void mdoLShift (ExprOp *op0, ExprOp *op1, ExprInfo *ei) { op0->val <<= op1->val; }
1278 static void mdoRShift (ExprOp *op0, ExprOp *op1, ExprInfo *ei) { op0->val >>= op1->val; }
1279 static void mdoMul (ExprOp *op0, ExprOp *op1, ExprInfo *ei) { op0->val *= op1->val; }
1280 static void mdoDiv (ExprOp *op0, ExprOp *op1, ExprInfo *ei) { if (op1->val == 0) EERROR(ERR_DIV0); op0->val /= op1->val; }
1281 static void mdoMod (ExprOp *op0, ExprOp *op1, ExprInfo *ei) { if (op1->val == 0) EERROR(ERR_DIV0); op0->val %= op1->val; }
1282 static void mdoAdd (ExprOp *op0, ExprOp *op1, ExprInfo *ei) { op0->val += op1->val; }
1283 static void mdoSub (ExprOp *op0, ExprOp *op1, ExprInfo *ei) { op0->val -= op1->val; }
1284 static void mdoLogLess (ExprOp *op0, ExprOp *op1, ExprInfo *ei) { op0->val = op0->val < op1->val; }
1285 static void mdoLogGreat (ExprOp *op0, ExprOp *op1, ExprInfo *ei) { op0->val = op0->val > op1->val; }
1286 static void mdoLogEqu (ExprOp *op0, ExprOp *op1, ExprInfo *ei) { op0->val = op0->val == op1->val; }
1287 static void mdoLogNEqu (ExprOp *op0, ExprOp *op1, ExprInfo *ei) { op0->val = op0->val != op1->val; }
1288 static void mdoLogLEqu (ExprOp *op0, ExprOp *op1, ExprInfo *ei) { op0->val = op0->val >= op1->val; }
1289 static void mdoLogGEqu (ExprOp *op0, ExprOp *op1, ExprInfo *ei) { op0->val = op0->val >= op1->val; }
1291 static void mdoLogAnd (ExprOp *op0, ExprOp *op1, ExprInfo *ei) {
1292 ei->logRes = op0->val = (op0->val && op1->val);
1293 if (!op0->val) ei->logDone = 1;
1296 static void mdoLogOr (ExprOp *op0, ExprOp *op1, ExprInfo *ei) {
1297 ei->logRes = op0->val = (op0->val || op1->val);
1298 if (op0->val) ei->logDone = 1;
1302 // priority level 1 -- opertiors line "." and "[]", function calls
1303 // priority level 2 -- unary opertiors like "!" and "~"
1304 // priority level 7 -- always right-associative! (PRIO_RIGHT)
1305 // short forms must be put before long
1306 // priorities must be sorted
1307 static const ExprOperator operators[] = {
1308 { '~', NULL, 2, mdoBitNot },
1309 { '!', NULL, 2, mdoLogNot },
1311 { 0, "<<", 3, mdoLShift },
1312 { 0, ">>", 3, mdoRShift },
1314 { '&', NULL, 4, mdoBitAnd },
1316 { '|', NULL, 5, mdoBitOr },
1317 { '^', NULL, 5, mdoBitXor },
1319 { '*', NULL, 6, mdoMul },
1320 { '/', NULL, 6, mdoDiv },
1321 { '%', NULL, 6, mdoMod },
1323 { '+', NULL, 7, mdoAdd },
1324 { '-', NULL, 7, mdoSub },
1326 { 0, "&&", 8, mdoLogAnd },
1328 { 0, "||", 9, mdoLogOr },
1330 { '<', NULL, 10, mdoLogLess },
1331 { '>', NULL, 10, mdoLogGreat },
1332 { '=', NULL, 10, mdoLogEqu },
1333 { 0, "==", 10, mdoLogEqu },
1334 { 0, "!=", 10, mdoLogNEqu },
1335 { 0, "<>", 10, mdoLogNEqu },
1336 { 0, "<=", 10, mdoLogLEqu },
1337 { 0, ">=", 10, mdoLogGEqu },
1338 { 0, NULL, -1, NULL },
1340 #define MAX_PRIO 10
1341 #define UNARY_PRIO 2
1344 ///////////////////////////////////////////////////////////////////////////////
1345 // expression parser engine
1346 static void expression (ExprOp *res, ExprInfo *ei);
1347 //int *res, const char *expr, uint16_t addr, int *defined, int *error);
1350 #define SKIP_BLANKS { ei->errpos = ei->expr = skipBlanks(ei->expr); }
1352 static const char *parseNumber (ExprOp *res, const char *expr, int *error) {
1353 int noH = 1, n = 0, base;
1354 const char *p;
1356 if (*error) return expr;
1357 if (!expr[0]) { *error = 1; return expr; }
1358 /* can it be hex? */
1359 for (p = expr; *p && isxdigit(*p); ++p) ;
1360 if (toupper(*p) == 'H') {
1361 base = 16;
1362 noH = 0;
1363 } else {
1364 switch (*expr) {
1365 case '0':
1366 if (toupper(expr[1]) == 'X') {
1367 base = 16;
1368 expr += 2;
1369 } else {
1370 base = 8;
1372 break;
1373 case '%': base = 2; ++expr; break;
1374 //case '@': base = 8; ++expr; break;
1375 case '#': case '$': base = 16; ++expr; break;
1376 case '1' ... '9': base = 10; break;
1377 default: *error = 1; return expr;
1380 if (dig2n(*expr, base) < 0) { *error = 1; return expr-(base!=10?1:0); }
1381 for (;;) {
1382 int d;
1384 if (*expr == '_') { ++expr; continue; }
1385 if ((d = dig2n(*expr++, base)) < 0) { res->val = n; return expr-noH; }
1386 n *= base;
1387 n += d;
1392 static void getAddr (const char *lbl, ExprOp *res, ExprInfo *ei) {
1393 int defined = 0, found = 0;
1394 int32_t val = 0;
1396 if (!urFindLabelByName) EERROR(ERR_LABEL);
1397 val = urFindLabelByName(lbl, ei->addr, &defined, &found);
1398 if (!found) EERROR(ERR_LABEL);
1399 if (!defined) ei->defined = 0;
1400 res->val = val;
1404 // !0: invalid label
1405 static int readLabelName (char *buf, ExprInfo *ei) {
1406 int pos = 0;
1407 for (;;) {
1408 if (pos >= 128) return -3;
1409 char ch = ei->expr[0];
1410 if (!ch) break;
1411 if (isalnum(ch) || ch == '$' || ch == '.' || ch == '_' || ch == '@') {
1412 buf[pos++] = ch; ++(ei->expr);
1413 } else {
1414 break;
1417 if (pos < 1) return -2;
1418 buf[pos] = '\0';
1419 if (!urIsValidLabelName(buf)) return -1;
1420 return 0;
1424 static void fnDefKn (ExprOp *res, ExprInfo *ei, int qtype) {
1425 char lbl[130];
1426 if (readLabelName(lbl, ei)) EERROR(ERR_LABEL);
1427 SKIP_BLANKS
1428 if (ei->expr[0] != ')') EERROR(ERR_FUNC);
1429 ++(ei->expr);
1430 if (ei->logDone) return;
1431 res->val = urIsLabelDefinedOrKnown ? (urIsLabelDefinedOrKnown(lbl, ei->addr, qtype) != 0) : 0;
1434 static void fnDefined (ExprOp *res, ExprInfo *ei) { fnDefKn(res, ei, UR_QTYPE_DEFINED); }
1435 static void fnKnown (ExprOp *res, ExprInfo *ei) { fnDefKn(res, ei, UR_QTYPE_KNOWN); }
1438 static void fnAligned256 (ExprOp *res, ExprInfo *ei) {
1439 ExprOp v;
1441 expression(&v, ei);
1442 if (ei->expr[0] != ')') EERROR(ERR_FUNC);
1443 ++(ei->expr);
1444 if (ei->logDone) return;
1445 res->val = v.val%256?0:1;
1449 static void fnSameSeg (ExprOp *res, ExprInfo *ei) {
1450 ExprOp v0, v1;
1452 expression(&v0, ei);
1453 if (ei->expr[0] != ',') EERROR(ERR_FUNC);
1454 ++(ei->expr);
1455 expression(&v1, ei);
1456 if (ei->expr[0] != ')') EERROR(ERR_FUNC);
1457 ++(ei->expr);
1458 if (ei->logDone) return;
1459 res->val = v0.val/256==v1.val/256;
1463 static void fnAlign (ExprOp *res, ExprInfo *ei) {
1464 ExprOp v0, v1;
1466 expression(&v0, ei);
1467 if (ei->expr[0] == ',') {
1468 ++(ei->expr);
1469 expression(&v1, ei);
1470 } else {
1471 v1.val = 256;
1473 if (ei->expr[0] != ')') EERROR(ERR_FUNC);
1474 if (v1.val < 1) EERROR(ERR_FUNC);
1475 ++(ei->expr);
1476 if (ei->logDone) return;
1477 res->val = (v0.val+v1.val-1)/v1.val*v1.val;
1481 static void term (ExprOp *res, ExprInfo *ei) {
1482 char ch, lbl[130];
1483 int tmp = 0, f, c, base;
1485 int xDigit (char ch, int base) {
1486 if (ch < '0') return -1;
1487 if (base <= 10) {
1488 if (ch >= '0'+base) return -1;
1489 return ch-'0';
1491 ch = toupper(ch);
1492 if (ch <= '9') return ch-'0';
1493 if (ch < 'A' || ch > 'A'+base-10) return -1;
1494 ch -= 'A'-10;
1495 return ch<base ? ch : -1;
1498 SKIP_BLANKS
1499 ch = (ei->errpos = ei->expr)[0];
1500 if (!ch) EERROR(ERR_EOS);
1501 switch (ch) {
1502 case '[': case '(':
1503 ++(ei->expr);
1504 ch = ch=='[' ? ']' : ')';
1505 expression(res, ei);
1506 if (ei->expr[0] != ch) EERROR(ERR_PARENS);
1507 ++(ei->expr);
1508 break;
1509 case '0' ... '9': case '#': case '%':
1510 donumber:
1511 ei->expr = parseNumber(res, ei->expr, &tmp);
1512 if (tmp) EERROR(ERR_NUMBER);
1513 break;
1514 case '$':
1515 if (dig2n(ei->expr[1], 16) >= 0) goto donumber;
1516 res->val = ei->addr;
1517 ++(ei->expr);
1518 break;
1519 case '"': // char or 2 chars
1520 case '\'': // char or 2 reversed chars
1521 ++(ei->expr);
1522 res->val = 0;
1523 // max 2 chars allowed here
1524 for (c = 0; c < 2; ++c) {
1525 char cc = *ei->expr;
1526 if (cc == ch) break; // done
1527 ++(ei->expr);
1528 if (cc == '\\') {
1529 switch (*(++ei->expr)) {
1530 case '\0': EERROR(ERR_EOS);
1531 case 'a': cc = '\a'; break;
1532 case 'b': cc = '\b'; break;
1533 case 'f': cc = '\f'; break;
1534 case 'n': cc = '\n'; break;
1535 case 'r': cc = '\r'; break;
1536 case 't': cc = '\t'; break;
1537 case 'v': cc = '\v'; break;
1538 case 'z': cc = '\0'; break;
1539 case 'x': case 'X': // hex
1540 base = 16; f = 2; ++ei->expr;
1541 donum: for (cc = 0; f > 0; --f) {
1542 char c1 = xDigit(*(ei->expr++), base);
1543 if (c1 < 0) { --(ei->expr); break; }
1544 cc *= base;
1545 cc += c1;
1547 if (cc > 255) EERROR(ERR_STRING);
1548 --(ei->expr); // return to the last digit, 'for' will skip it
1549 break;
1550 case '0': // octal
1551 base = 8; f = 4;
1552 goto donum;
1553 case '1' ... '9': // decimal
1554 base = 10; f = 3;
1555 goto donum;
1556 default: cc = *(ei->expr); break; // others
1559 if (c == 0) res->val = cc&0xFFU;
1560 else {
1561 if (ch == '"') res->val |= (cc&0xFFU)<<(8*c);
1562 else res->val = (res->val<<8)|(cc&0xFFU);
1565 if (*ei->expr != ch) EERROR(ERR_STRING);
1566 ++ei->expr;
1567 break;
1568 case ';':
1569 case ':':
1570 EERROR(ERR_TERM);
1571 case ')':
1572 case ']':
1573 return;
1574 default:
1575 if (readLabelName(lbl, ei)) EERROR(ERR_LABEL);
1576 SKIP_BLANKS
1577 if (ei->expr[0] == '(') {
1578 // function call
1579 ++(ei->expr);
1580 if (strcmp(lbl, "defined") == 0) fnDefined(res, ei);
1581 else if (strcmp(lbl, "known") == 0) fnKnown(res, ei);
1582 else if (strcmp(lbl, "aligned256") == 0) fnAligned256(res, ei);
1583 else if (strcmp(lbl, "sameseg") == 0) fnSameSeg(res, ei);
1584 else if (strcmp(lbl, "align") == 0) fnAlign(res, ei);
1585 else EERROR(ERR_FUNC);
1586 } else {
1587 // just a label
1588 if (!ei->logDone) getAddr(lbl, res, ei);
1590 break;
1595 static const ExprOperator *getOperator (int prio, ExprInfo *ei) {
1596 char opc = ei->expr[0];
1597 int oplen = 1;
1598 const ExprOperator *res = operators, *cur;
1600 //for (; res->prio > 0; ++res) if (res->prio == prio) break;
1601 //if (res->prio < 0) return NULL;
1602 //for (cur = res, res = NULL; cur->prio == prio; ++cur) {
1603 for (cur = res, res = NULL; cur->prio >= 0; ++cur) {
1604 if (cur->sn) {
1605 if (oplen > 1) continue;
1606 if (opc == cur->sn) res = cur;
1607 } else {
1608 int l = strlen(cur->ln);
1609 if (l < oplen) continue;
1610 if (!strncmp(ei->expr, cur->ln, l)) { res = cur; oplen = l; }
1613 if (res && res->prio != prio) res = NULL;
1614 //if (res) printf("res: '%c' \"%s\"\n", res->sn, res->ln);
1615 if (res) ei->expr += oplen; /* eat operator */
1616 return res;
1620 static void expressionDo (int prio, ExprOp *res, ExprInfo *ei) {
1621 const ExprOperator *op;
1622 ExprOp o1;
1624 SKIP_BLANKS
1625 if (ei->expr[0] == ')' || ei->expr[0] == ']') return;
1626 if (prio <= 0) { term(res, ei); return; }
1627 if (prio == UNARY_PRIO) {
1628 int wasIt = 0;
1629 for (;;) {
1630 SKIP_BLANKS
1631 ei->errpos = ei->expr;
1632 if (!(op = getOperator(prio, ei))) break;
1633 //expression(res, ei);
1634 expressionDo(prio, res, ei);
1635 if (!ei->logDone) op->doer(res, &o1, ei); else res->val = ei->logRes;
1636 wasIt = 1;
1638 if (!wasIt) expressionDo(prio-1, res, ei);
1639 return;
1641 expressionDo(prio-1, res, ei); // first operand
1642 for (;;) {
1643 SKIP_BLANKS
1644 ei->errpos = ei->expr;
1645 if (!ei->expr[0] || ei->expr[0] == ';' || ei->expr[0] == ':' || ei->expr[0] == ')' || ei->expr[0] == ']') break;
1646 if (!(op = getOperator(prio, ei))) break;
1647 if (!ei->logDone) {
1648 switch (prio) {
1649 case 7: //&&
1650 if (!res->val) { ei->logDone = 1; ei->logRes = 0; }
1651 break;
1652 case 8: //||
1653 if (res->val) { ei->logDone = 1; ei->logRes = res->val; }
1654 break;
1657 expressionDo(prio-1, &o1, ei); // second operand
1658 if (!ei->logDone) op->doer(res, &o1, ei); else res->val = ei->logRes;
1663 static void expression (ExprOp *res, ExprInfo *ei) {
1664 int neg = 0;
1665 SKIP_BLANKS
1666 ei->errpos = ei->expr;
1667 switch (ei->expr[0]) {
1668 case '\0': EERROR(ERR_EOS);
1669 case '-': neg = 1; ++(ei->expr); break;
1670 case '+': neg = 0; ++(ei->expr); break;
1671 default: ;
1673 expressionDo(MAX_PRIO, res, ei);
1674 if (neg) res->val = -(res->val);
1675 SKIP_BLANKS
1679 const char *urExpression (int32_t *res, const char *expr, uint16_t addr, int *defined, int *error) {
1680 ExprOp r;
1681 ExprInfo ei;
1682 int jr;
1684 if (error) *error = 0;
1685 if (defined) *defined = 1;
1686 if (!expr) { if (error) *error = ERR_EOS; return NULL; }
1687 r.val = 0;
1688 ei.expr = expr;
1689 ei.addr = addr;
1690 ei.defined = 1;
1691 ei.error = 0;
1692 ei.logDone = 0;
1693 ei.logRes = 0;
1694 jr = setjmp(ei.errJP);
1695 if (jr) {
1696 if (error) *error = ei.error;
1697 return ei.errpos;
1699 expression(&r, &ei);
1700 if (res) *res = r.val;
1701 if (defined) *defined = ei.defined;
1702 return ei.expr;
1706 ///////////////////////////////////////////////////////////////////////////////
1707 // operand parser
1709 const char *urNextOperand (URAOperand *op, const char *expr, uint16_t addr, int *error) {
1710 const char *oe;
1711 char opstr[256], inQ = 0;
1712 int f;
1714 *error = 0;
1715 memset(op, 0, sizeof(URAOperand));
1716 op->defined = 1;
1717 expr = skipBlanks(expr);
1718 if (!expr[0] || expr[0] == ';') return NULL;
1719 if (expr[0] == ':') return expr;
1720 op->parsed = 1;
1721 // get operand string
1722 for (oe = expr; *expr; ++expr) {
1723 char ch = *expr;
1724 if (inQ) {
1725 if (ch == inQ) inQ = 0;
1726 } else {
1727 if (ch == '"' || ch == '`') inQ = ch;
1728 else if (ch == '\'' && (oe == expr || !isalnum(expr[-1]))) inQ = ch;
1729 else if (ch == '\\' && expr[1]) ++expr;
1730 else if (!inQ && ch == ',') break;
1731 else if (ch == ';' || ch == ':') break;
1734 if (expr-oe > 255) { *error = 1; return oe; }
1735 memset(opstr, 0, sizeof(opstr));
1736 memcpy(opstr, oe, expr-oe);
1737 while (opstr[0] && isspace(opstr[strlen(opstr)-1])) opstr[strlen(opstr)-1] = '\0';
1738 if (!opstr[0]) { *error = 1; return oe; }
1739 // determine operand type
1740 if (isalpha(opstr[0]) && urIsValidLabelName(opstr)) {
1741 goto doexpression;
1744 if (opstr[0] == '(') {
1745 // memref
1746 op->mem = 1; op->special = 1;
1747 if (!opstr[1] || opstr[strlen(opstr)-1] != ')') { *error = 1; return oe; }
1748 // operand w/o "()"
1749 opstr[strlen(opstr)-1] = '\0';
1750 memmove(opstr, opstr+1, sizeof(opstr)-1);
1751 // trim spaces
1752 while (opstr[0] && isspace(opstr[0])) memmove(opstr, opstr+1, sizeof(opstr)-1);
1753 while (opstr[0] && isspace(opstr[strlen(opstr)-1])) opstr[strlen(opstr)-1] = '\0';
1754 // empty brackets?
1755 if (!opstr[0]) { *error = 1; return oe; }
1756 for (f = 0; opstr[f]; ++f) op->s[f] = toupper(opstr[f]);
1757 if (!strcmp(op->s, "C")) {
1758 op->special = 1; op->mem = 0; strcpy(op->s, "(C)");
1759 return expr;
1761 if (!strcmp(op->s, "HL")) return expr;
1762 if (!strcmp(op->s, "DE")) return expr;
1763 if (!strcmp(op->s, "BC")) return expr;
1764 if (!strcmp(op->s, "SP")) return expr;
1765 if (op->s[0] == 'I' && (op->s[1] == 'X' || op->s[1] == 'Y')) {
1766 // memref: IX or IY
1767 op->ixy = op->s[1]=='X' ? 0xDDU : 0xFDU;
1768 op->v = 0;
1769 memmove(opstr, opstr+1, sizeof(opstr)-1);
1770 opstr[0] = '0';
1771 while (opstr[1] && isspace(opstr[1])) memmove(opstr+1, opstr+2, sizeof(opstr)-2);
1772 if (!opstr[1]) return expr;
1773 if (opstr[1] != '+' && opstr[1] != '-') { *error = 1; return oe; }
1774 // opstr must be an expression
1775 const char *t = urExpression(&op->v, opstr, addr, &op->defined, error);
1776 if (*error) return oe;
1777 if (t[0]) { *error = 1; return oe; }
1778 if (op->defined && (op->v < -128 || op->v > 127)) { *error = 1; return oe; }
1779 return expr;
1781 op->special = 0;
1782 } else {
1783 if (!strcasecmp(opstr, "af'")) goto registerop;
1784 for (f = 0; isalpha(opstr[f]); ++f) ;
1785 if (!opstr[f]) {
1786 registerop:
1787 for (f = 0; opstr[f]; ++f) opstr[f] = toupper(opstr[f]);
1788 strcpy(op->s, opstr);
1789 op->special = 1;
1790 return skipBlanks(expr);
1793 // this must be an expression
1794 doexpression:
1795 strcpy(op->s, opstr);
1796 const char *t = urExpression(&op->v, opstr, addr, &op->defined, error);
1797 if (t[0]) { *error = 1; return oe; }
1798 return skipBlanks(expr);
1802 ///////////////////////////////////////////////////////////////////////////////
1803 // assembler
1805 // for regsters & conditions: op->v will be set to reg number
1806 int urIsValidOp (URAOperand *op, uint16_t addr, int opt) {
1807 int i;
1808 if (opt == UO_NONE) return op->s[0] == '\0';
1809 if (!op->s[0]) return 0;
1810 switch (opt) {
1811 case UO_IMM8:
1812 if (op->special || op->mem) return 0;
1813 if (op->defined && (op->v < -128 || op->v > 255)) return 0;
1814 return 1;
1815 case UO_IMM16:
1816 if (op->special || op->mem) return 0;
1817 if (op->defined && (op->v < -32768 || op->v > 65535)) return 0;
1818 return 1;
1819 case UO_ADDR16:
1820 if (op->special || op->mem) return 0;
1821 if (op->defined && (op->v < -32768 || op->v > 65535)) return 0;
1822 if (op->v < 0) op->v = 65536+op->v;
1823 return 1;
1824 case UO_ADDR8:
1825 if (op->special || op->mem) return 0;
1826 if (op->defined && (op->v < -32768 || op->v > 65535)) return 0;
1827 if (!op->defined) op->v = addr;
1828 if (op->v < 0) op->v = 65536+op->v;
1829 i = op->v-((int)addr+2);
1830 if (i < -128 || i > 127) return 0;
1831 op->v = i&0xff;
1832 return 1;
1833 case UO_MEM16:
1834 if (op->special || !op->mem) return 0;
1835 if (op->defined && (op->v < -32768 || op->v > 65535)) return 0;
1836 if (op->v < 0) op->v = 65536+op->v;
1837 return 1;
1838 case UO_R8: case UO_2R8:
1839 if (op->mem && !strcmp(op->s, "HL")) { /*strcpy(op->s, "M");*/ op->v = 6; return 1; }
1840 /* fallthru */
1841 case UO_R8_NOM: case UO_2R8_NOM:
1842 if (!op->special || op->mem || op->s[1]) return 0;
1843 switch (op->s[0]) {
1844 case 'B': op->v = 0; break;
1845 case 'C': op->v = 1; break;
1846 case 'D': op->v = 2; break;
1847 case 'E': op->v = 3; break;
1848 case 'H': op->v = 4; break;
1849 case 'L': op->v = 5; break;
1850 case 'A': op->v = 7; break;
1851 default: return 0;
1853 return 1;
1854 case UO_PORTC:
1855 if (!op->special || op->mem) return 0;
1856 return strcmp(op->s, "(C)")==0;
1857 case UO_PORTIMM: /* mem, 'cause (n) */
1858 if (op->special || !op->mem) return 0;
1859 op->mem = 0;
1860 if (op->defined && (op->v < 0 || op->v > 255)) return 0;
1861 return 1;
1862 case UO_R8_XH:
1863 if (!op->special || op->mem) return 0;
1864 if (!strcmp(op->s, "XH") || !strcmp(op->s, "HX") || !strcmp(op->s, "IXH")) return 1;
1865 return 0;
1866 case UO_R8_XL:
1867 if (!op->special || op->mem) return 0;
1868 if (!strcmp(op->s, "XL") || !strcmp(op->s, "LX") || !strcmp(op->s, "IXL")) return 1;
1869 return 0;
1870 case UO_R8_YH:
1871 if (!op->special || op->mem) return 0;
1872 if (!strcmp(op->s, "YH") || !strcmp(op->s, "HY") || !strcmp(op->s, "IYH")) return 1;
1873 return 0;
1874 case UO_R8_YL:
1875 if (!op->special || op->mem) return 0;
1876 if (!strcmp(op->s, "YL") || !strcmp(op->s, "LY") || !strcmp(op->s, "IYL")) return 1;
1877 return 0;
1878 case UO_R8_A:
1879 if (!op->special || op->mem) return 0;
1880 if (!strcmp(op->s, "A")) return 1;
1881 return 0;
1882 case UO_R8_R:
1883 if (!op->special || op->mem) return 0;
1884 if (!strcmp(op->s, "R")) return 1;
1885 return 0;
1886 case UO_R8_I:
1887 if (!op->special || op->mem) return 0;
1888 if (!strcmp(op->s, "I")) return 1;
1889 return 0;
1890 case UO_R16:
1891 if (!op->special || op->mem || !op->s[1] || op->s[2]) return 0;
1892 if (!strcmp(op->s, "BC")) { op->v = 0; return 1; }
1893 if (!strcmp(op->s, "DE")) { op->v = 1; return 1; }
1894 if (!strcmp(op->s, "HL")) { op->v = 2; return 1; }
1895 if (!strcmp(op->s, "SP")) { op->v = 3; return 1; }
1896 return 0;
1897 case UO_R16A:
1898 if (!op->special || op->mem || !op->s[1] || op->s[2]) return 0;
1899 if (!strcmp(op->s, "BC")) { op->v = 0; return 1; }
1900 if (!strcmp(op->s, "DE")) { op->v = 1; return 1; }
1901 if (!strcmp(op->s, "HL")) { op->v = 2; return 1; }
1902 if (!strcmp(op->s, "AF")) { op->v = 3; return 1; }
1903 return 0;
1904 case UO_R16AF:
1905 if (!op->special || op->mem || strcmp(op->s, "AF")) return 0;
1906 op->v = 3;
1907 return 1;
1908 case UO_R16AFX:
1909 if (!op->special || op->mem || (strcmp(op->s, "AF'") && strcmp(op->s, "AFX"))) return 0;
1910 op->v = 3;
1911 return 1;
1912 case UO_R16BC:
1913 if (!op->special || op->mem || strcmp(op->s, "BC")) return 0;
1914 op->v = 0;
1915 return 1;
1916 case UO_R16DE:
1917 if (!op->special || op->mem || strcmp(op->s, "DE")) return 0;
1918 op->v = 1;
1919 return 1;
1920 case UO_R16HL:
1921 if (!op->special || op->mem || strcmp(op->s, "HL")) return 0;
1922 op->v = 2;
1923 return 1;
1924 case UO_R16IX:
1925 if (!op->special || op->mem || strcmp(op->s, "IX")) return 0;
1926 op->v = 2;
1927 return 1;
1928 case UO_R16IY:
1929 if (!op->special || op->mem || strcmp(op->s, "IY")) return 0;
1930 op->v = 2;
1931 return 1;
1932 case UO_R16SP:
1933 if (!op->special || op->mem || strcmp(op->s, "SP")) return 0;
1934 op->v = 3;
1935 return 1;
1936 case UO_MSP:
1937 if (!op->special || !op->mem || strcmp(op->s, "SP")) return 0;
1938 op->v = 3;
1939 return 1;
1940 case UO_MBC:
1941 if (!op->special || !op->mem || strcmp(op->s, "BC")) return 0;
1942 op->v = 0;
1943 return 1;
1944 case UO_MDE:
1945 if (!op->special || !op->mem || strcmp(op->s, "DE")) return 0;
1946 op->v = 1;
1947 return 1;
1948 case UO_MHL:
1949 if (!op->special || !op->mem || strcmp(op->s, "HL")) return 0;
1950 op->v = 2;
1951 return 1;
1952 case UO_MIX:
1953 if (!op->special || !op->mem || op->ixy != 0xDDU) return 0;
1954 if (op->defined && (op->v < -128 || op->v > 127)) return 0;
1955 return 1;
1956 case UO_MIY:
1957 if (!op->special || !op->mem || op->ixy != 0xFDU) return 0;
1958 if (op->defined && (op->v < -128 || op->v > 127)) return 0;
1959 return 1;
1960 case UO_MIX0:
1961 if (!op->special || !op->mem || op->ixy != 0xDDU) return 0;
1962 if (op->defined && op->v != 0) return 0;
1963 return 1;
1964 case UO_MIY0:
1965 if (!op->special || !op->mem || op->ixy != 0xFDU) return 0;
1966 if (op->defined && op->v != 0) return 0;
1967 return 1;
1968 case UO_JRCOND:
1969 if (!op->special || op->mem || strlen(op->s) > 2) return 0;
1970 if (!strcmp(op->s, "NZ")) { op->v = 0; return 1; }
1971 if (!strcmp(op->s, "Z")) { op->v = 1; return 1; }
1972 if (!strcmp(op->s, "NC")) { op->v = 2; return 1; }
1973 if (!strcmp(op->s, "C")) { op->v = 3; return 1; }
1974 return 0;
1975 case UO_COND:
1976 if (!op->special || op->mem || strlen(op->s) > 2) return 0;
1977 if (!strcmp(op->s, "NZ")) { op->v = 0; return 1; }
1978 if (!strcmp(op->s, "Z")) { op->v = 1; return 1; }
1979 if (!strcmp(op->s, "NC")) { op->v = 2; return 1; }
1980 if (!strcmp(op->s, "C")) { op->v = 3; return 1; }
1981 if (!strcmp(op->s, "PO")) { op->v = 4; return 1; }
1982 if (!strcmp(op->s, "PE")) { op->v = 5; return 1; }
1983 if (!strcmp(op->s, "P")) { op->v = 6; return 1; }
1984 if (!strcmp(op->s, "M")) { op->v = 7; return 1; }
1985 return 0;
1986 case UO_BITN:
1987 if (op->special || op->mem) return 0;
1988 if (op->defined && (op->v < 0 || op->v > 7)) return 0;
1989 return 1;
1990 case UO_RSTDEST:
1991 if (op->special || op->mem) return 0;
1992 if (op->defined && (op->v < 0 || op->v > 0x38 || (op->v&7))) return 0;
1993 op->v >>= 3;
1994 return 1;
1995 case UO_IM0:
1996 if (op->special || op->mem) return 0;
1997 if (op->defined && op->v != 0) return 0;
1998 return 1;
1999 case UO_IM1:
2000 if (op->special || op->mem) return 0;
2001 if (op->defined && op->v != 1) return 0;
2002 return 1;
2003 case UO_IM2:
2004 if (op->special || op->mem) return 0;
2005 if (op->defined && op->v != 2) return 0;
2006 return 1;
2008 return 0;
2012 // mem size should be at least 7 bytes
2013 // returns size of the assembled code
2014 // result <0 on error
2015 // understands comments
2016 int urAssembleOne (const char *expr, uint16_t destaddr, uint16_t addr, const char **errpos) {
2017 uint8_t buf[8];
2018 int len = 0;
2019 const char *oe;
2020 char mnem[6];
2021 int tkn;
2022 URAOperand ops[3];
2023 const URAsmCmdInfo *cm;
2024 uint32_t code, mask;
2025 int opcPos; // opcode will be placed here
2027 void doOperand (int idx) {
2028 const URAOperand *op = ops+idx;
2030 switch (cm->ops[idx]) {
2031 case UO_IMM8:
2032 case UO_PORTIMM:
2033 case UO_ADDR8:
2034 buf[len++] = op->v&0xFFU;
2035 break;
2036 case UO_IMM16:
2037 case UO_ADDR16:
2038 case UO_MEM16:
2039 buf[len++] = op->v&0xFFU;
2040 buf[len++] = ((op->v&0xFFFFU)>>8)&0xFFU;
2041 break;
2042 case UO_R8:
2043 case UO_R8_NOM:
2044 code |= op->v&0xFFU;
2045 break;
2046 case UO_JRCOND:
2047 case UO_COND:
2048 case UO_BITN:
2049 case UO_RSTDEST:
2050 case UO_2R8:
2051 case UO_2R8_NOM:
2052 code |= (op->v&0xFFU)<<3;
2053 break;
2054 case UO_R16:
2055 case UO_R16A:
2056 code |= (op->v&0xFFU)<<4;
2057 break;
2058 case UO_MIX:
2059 case UO_MIY:
2060 buf[len++] = op->v;
2061 break;
2065 // <0: error; 0: ok; >0: last operand (ops[opix].parsed != 0: non-empty one)
2066 int parseOperand (int opidx) {
2067 int error = 0;
2068 const char *oe = expr;
2070 expr = urNextOperand(ops+opidx, expr, addr, &error);
2071 if (error) { if (errpos) *errpos = oe; return URA_BAD_OPERAND; }
2072 if (!expr || !expr[0] || expr[0] == ';' || expr[0] == ':') return 1;
2073 if (*expr != ',') { if (errpos) *errpos = oe; return URA_BAD_OPERAND; }
2074 ++expr;
2075 return 0;
2078 int genCode (void) {
2079 for (int pos = URASM_MAX_COMMAND; pos >= 0; --pos) {
2080 int f;
2082 if (tkn != URASM_COMMANDS[pos].mnemo) continue;
2083 for (f = 0; f < 3; ++f) {
2084 if (!urIsValidOp(&ops[f], addr, URASM_COMMANDS[pos].ops[f])) break;
2086 if (f < 3) continue;
2087 // command found, generate code
2088 len = 0; cm = URASM_COMMANDS+pos;
2089 code = cm->code; mask = cm->mask;
2090 if ((code&0xFFFFUL) == 0xCBDDUL || (code&0xFFFFUL) == 0xCBFDUL) {
2091 // special commands
2092 // emit unmasked code
2093 buf[0] = (code&0xFFU); buf[1] = 0xCBU;
2094 for (f = 0; f < 3; ++f) {
2095 if (cm->ops[f] == UO_MIX || cm->ops[f] == UO_MIY) {
2096 if (ops[f].defined && (ops[f].v < -128 || ops[f].v > 127)) f = -1;
2097 else if (ops[f].defined) buf[2] = ops[f].v;
2098 break;
2101 if (f < 0) continue; // not me
2102 len = 4;
2103 code >>= 24; mask >>= 24;
2104 if ((mask&0xFFUL) != 0xFFUL) {
2105 for (f = 0; f < 3; ++f) if (cm->ops[f] != UO_MIX && cm->ops[f] != UO_MIY) doOperand(f);
2107 buf[3] = code;
2108 // that's all
2109 for (f = 0; f < len; ++f) { urPutByte(destaddr++, buf[f]); ++addr; }
2110 return len;
2111 } else {
2112 // normal commands
2113 // emit unmasked code
2114 while ((mask&0xFFUL) == 0xFFUL) {
2115 buf[len++] = code&0xFFUL;
2116 code >>= 8; mask >>= 8;
2118 //ASSERT((code&0xFFFFFF00UL) == 0);
2119 if (mask == 0) {
2120 //ASSERT(len > 0);
2121 code = buf[--len];
2123 opcPos = len++;
2124 doOperand(0);
2125 doOperand(1);
2126 doOperand(2);
2127 buf[opcPos] = code;
2128 // that's all
2129 for (f = 0; f < len; ++f) { urPutByte(destaddr++, buf[f]); ++addr; }
2130 return len;
2133 if (errpos) *errpos = oe;
2134 return URA_BAD_INSTRUCTION;
2137 int doPushPop (void) {
2138 int f, len;
2140 for (f = len = 0; ; ++f) {
2141 int doQuit = 0;
2142 const char *oe = expr;
2143 int res = parseOperand(0);
2145 if (res < 0) return res;
2146 if (res > 0) {
2147 if (f == 0 && !ops[0].parsed) { *errpos = oe; return URA_BAD_INSTRUCTION; }
2148 doQuit = 1;
2151 code = (tkn==UT_POP ? 0xC1U : 0xC5U);
2152 if (urIsValidOp(ops, addr, UO_R16A)) {
2153 code |= (ops[0].v&0xFFU)<<4;
2154 urPutByte(destaddr++, code);
2155 ++addr;
2156 ++len;
2157 } else if (urIsValidOp(ops, addr, UO_R16IX)) {
2158 code |= (ops[0].v&0xFFU)<<4;
2159 urPutByte(destaddr++, 0xDDU);
2160 urPutByte(destaddr++, code);
2161 addr += 2;
2162 len += 2;
2163 } else if (urIsValidOp(ops, addr, UO_R16IY)) {
2164 code |= (ops[0].v&0xFFU)<<4;
2165 urPutByte(destaddr++, 0xFDU);
2166 urPutByte(destaddr++, code);
2167 addr += 2;
2168 len += 2;
2169 } else {
2170 if (errpos) *errpos = oe;
2171 return URA_BAD_OPERAND;
2173 if (doQuit) break;
2176 if (expr) {
2177 expr = skipBlanks(expr);
2178 if (expr[0] && expr[0] != ';') {
2179 if (errpos) *errpos = expr;
2180 if (expr[0] != ':') return URA_EXTRA_TEXT;
2183 return len;
2186 int dorep (int opcnt) {
2187 int f, len;
2189 memset(ops, 0, sizeof(ops));
2190 for (f = len = 0; ; ++f) {
2191 int doQuit = 0, res;
2192 const char *oe;
2194 for (int c = 0; c < opcnt; ++c) {
2195 oe = expr;
2196 res = parseOperand(c);
2197 if (res < 0) return res;
2198 if (res > 0) {
2199 if (c != opcnt-1 || !ops[c].parsed) { *errpos = oe; return URA_BAD_INSTRUCTION; }
2200 doQuit = 1;
2204 if ((res = genCode()) < 0) return res;
2205 len += res;
2207 if (doQuit) break;
2210 if (expr) {
2211 expr = skipBlanks(expr);
2212 if (expr[0] && expr[0] != ';') {
2213 if (errpos) *errpos = expr;
2214 if (expr[0] != ':') return URA_EXTRA_TEXT;
2217 return len;
2220 if (errpos) *errpos = NULL;
2221 if (!urPutByte || !expr) return URA_GENERIC;
2223 expr = skipBlanks(expr);
2224 if (!expr[0] || expr[0] == ';') return 0;
2225 if (expr[0] == ':') { if (errpos) *errpos = expr; return 0; }
2226 for (oe = expr; *expr && !isspace(*expr) && *expr != ':' && *expr != ';'; ++expr) ;
2227 if (expr-oe > 4) { if (errpos) *errpos = oe; return URA_BAD_MNEMO; } // bad mnemonics
2229 memset(mnem, 0, sizeof(mnem));
2230 memcpy(mnem, oe, expr-oe);
2231 for (int f = 0; mnem[f]; ++f) mnem[f] = toupper(mnem[f]);
2232 // find it
2233 for (tkn = 0; tkn < URASM_MAX_TOKEN; ++tkn) if (!strcmp(mnem, URASM_TOKENS[tkn])) break;
2234 if (tkn >= URASM_MAX_TOKEN) { if (errpos) *errpos = oe; return URA_BAD_MNEMO; } // unknown mnemonics
2236 expr = skipBlanks(expr);
2237 if (expr[0] == ',') { if (errpos) *errpos = oe; return URA_BAD_OPERAND; }
2238 /* special for PUSH and POP */
2239 if (tkn == UT_POP || tkn == UT_PUSH) return doPushPop();
2240 /* special for LD */
2241 if (tkn == UT_LD || tkn == UT_ADD || tkn == UT_ADC || tkn == UT_SBC) return dorep(2);
2242 /* special for RR/RL */
2243 if (tkn == UT_RL || tkn == UT_RR || tkn == UT_INC || tkn == UT_DEC) return dorep(1);
2245 memset(ops, 0, sizeof(ops));
2246 for (int f = 0; f < 3; ++f) {
2247 int res = parseOperand(f);
2249 if (res > 0) break;
2250 if (res < 0) return res;
2253 if (expr) {
2254 expr = skipBlanks(expr);
2255 if (expr[0] && expr[0] != ';') {
2256 if (errpos) *errpos = expr;
2257 if (expr[0] != ':') return URA_EXTRA_TEXT;
2261 return genCode();
2265 static const char *msgs[5] = {
2266 "generic error",
2267 "bad mnemonics",
2268 "bad operand",
2269 "extra text after instruction",
2270 "bad instruction",
2274 const char *urErrorMessage (int errcode) {
2275 if (errcode >= 0) return "";
2276 if (errcode < -5) return "unknown error";
2277 return msgs[(-errcode)-1];
2281 #ifdef __cplusplus
2283 #endif