added "iv.dynstring"
[iv.d.git] / zymosis / urasm.d
blobe15e83c5480cc78eb7f7fed9249ea076044dcc09
1 /* Invisible Vector Library
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * URASM: Z80 assembler/disassembler engine v0.0.2b
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, version 3 of the License ONLY.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 module iv.zymosis.urasm /*is aliced*/;
20 import iv.alice;
22 //version = urasm_test;
25 // ////////////////////////////////////////////////////////////////////////// //
26 enum URMnemo {
27 ADC, ADD, AND, BIT,
28 CALL, CCF, CP, CPD,
29 CPDR, CPI, CPIR, CPL,
30 DAA, DEC, DI, DJNZ,
31 EI, EX, EXX, HALT,
32 IM, IN, INC, IND,
33 INDR, INI, INIR, JP,
34 JR, LD, LDD, LDDR,
35 LDI, LDIR, NEG, NOP,
36 OR, OTDR, OTIR, OUT,
37 OUTD, OUTI, POP, PUSH,
38 RES, RET, RETI, RETN,
39 RL, RLA, RLC, RLCA,
40 RLD, RR, RRA, RRC,
41 RRCA, RRD, RST, SBC,
42 SCF, SET, SLA, SLI,
43 SLL, SRA, SRL, SUB,
44 XOR, XSLT, NOPX, NOPY,
47 // all possible operands
48 // there are so many for proper assembling
49 // (i wanted to do a simple table lookup w/o special cases, so all special cases were encoded as various operand types)
50 enum UROpType {
51 NONE,
52 IMM8, // immediate constant
53 IMM16, // immediate constant
54 ADDR16, // immediate address (JP/CALL)
55 ADDR8, // immediate address (JR/DJNZ)
56 MEM16, // immediate memory (nnnn)
57 // 8 bit registers (bits 0-2 of opcode)
58 R8, // B,C,D,E,H,L,(HL),A
59 R8NOM, // B,C,D,E,H,L,A (no (HL) )
60 // 8 bit registers (bits 3-5 of opcode)
61 R83, // B,C,D,E,H,L,(HL),A
62 R83NOM,// B,C,D,E,H,L,A (no (HL) )
63 // for port i/o
64 PORTC, // (C)
65 PORTIMM,// (nn)
66 // special 8 bit registers
67 R8XH, // XH
68 R8XL, // XL
69 R8YH, // YH
70 R8YL, // YL
71 R8A, // A
72 R8R, // R
73 R8I, // I
74 // 16 bit registers (bits 4-5 of opcode)
75 R16, // BC,DE,HL,SP
76 // 16 bit registers (bits 4-5 of opcode)
77 R16A, // BC,DE,HL,AF
78 // AF & AF' for EX AF,AF'
79 R16AF, // AF
80 R16AFX, // AF'
81 R16BC, // BC
82 R16DE, // DE
83 R16HL, // HL
84 R16IX, // IX
85 R16IY, // IY
86 R16SP, // SP
87 MSP, // (SP)
88 MBC, // (BC)
89 MDE, // (DE)
90 MHL, // (HL)
91 MIX, // (IX+disp)
92 MIY, // (IY+disp)
93 MIX0, // (IX)
94 MIY0, // (IY)
95 // JR condition (bits 3-4 of opcode)
96 JRCOND,
97 // conditions (bits 3-5 of opcode)
98 COND,
99 // CB opcodes -- bit numbers (bits 3-5 of opcode)
100 BITN, // 0..7
101 // RST address (bits 3-5 of opcode <-- (address shr 3))
102 RSTDEST,
103 // IM operands
104 IM0, // not necessary for IM, denotes any 0
105 IM1, // not necessary for IM, denotes any 1
106 IM2 // not necessary for IM, denotes any 2
107 //IM01 // undocumented IM 0/1
110 // ////////////////////////////////////////////////////////////////////////// //
111 alias URFindLabelByAddrCB = const(char)[] delegate (ushort addr);
112 alias URGetByteCB = ubyte delegate (ushort addr);
116 struct URDisState {
117 public:
118 bool decimal; /// use decimal numbers in output?
120 private:
121 char[128] buf;
122 uint bufpos;
123 const(char)[] mnem;
124 const(char)[][3] ops; // operands
125 int iidx = -1;
127 public:
128 void clear () pure nothrow @trusted @nogc { bufpos = 0; mnem = null; ops[] = null; iidx = 0; }
130 @property bool valid () const pure nothrow @trusted @nogc { pragma(inline, true); return (bufpos > 0); }
132 /// get disassembled text; mnemonic delimited by '\t'
133 const(char)[] getbuf () const pure nothrow @trusted @nogc { pragma(inline, true); return buf[0..bufpos]; }
135 /// get mnemonic text
136 const(char)[] getmnemo () const pure nothrow @trusted @nogc { pragma(inline, true); return mnem; }
138 /// get operand text
139 const(char)[] getop (int idx) const pure nothrow @trusted @nogc { pragma(inline, true); return (idx >= 0 && idx < 3 ? ops.ptr[idx] : null); }
141 /// get instruction index into `URInstructionsTable`
142 int itableidx () const pure nothrow @trusted @nogc { pragma(inline, true); return iidx; }
144 private:
145 void resetbuf () nothrow @trusted @nogc { bufpos = 0; }
147 void put (const(char)[] s...) nothrow @trusted @nogc {
148 if (s.length > buf.length) s = s[0..buf.length];
149 if (bufpos+cast(uint)s.length > buf.length) s = s[0..buf.length-bufpos];
150 if (s.length == 0) return;
151 buf[bufpos..bufpos+s.length] = s[];
152 bufpos += cast(uint)s.length;
155 void putnum(T) (string fmt, T n) nothrow @trusted @nogc {
156 import core.stdc.stdio : snprintf;
157 if (fmt.length > 32) assert(0, "wtf?!");
158 char[33] fmtbuf = 0;
159 char[33] destbuf = 0;
160 fmtbuf[0..fmt.length] = fmt[];
161 static if (T.sizeof <= 4) {
162 static if (__traits(isUnsigned, T)) {
163 auto len = snprintf(destbuf.ptr, destbuf.length, fmtbuf.ptr, cast(uint)n);
164 } else {
165 auto len = snprintf(destbuf.ptr, destbuf.length, fmtbuf.ptr, cast(int)n);
167 } else {
168 static assert(0, "wtf?!");
170 if (len < 0) assert(0, "wtf?!");
171 put(destbuf[0..len]);
174 void putxnum(T) (string fmth, string fmtd, T n) nothrow @trusted @nogc {
175 putnum!T((decimal ? fmtd : fmth), n);
180 static immutable string[URMnemo.max+1] URMnemonics = [
181 "ADC", "ADD", "AND", "BIT", "CALL","CCF", "CP", "CPD",
182 "CPDR","CPI", "CPIR","CPL", "DAA", "DEC", "DI", "DJNZ",
183 "EI", "EX", "EXX", "HALT","IM", "IN", "INC", "IND",
184 "INDR","INI", "INIR","JP", "JR", "LD", "LDD", "LDDR",
185 "LDI", "LDIR","NEG", "NOP", "OR", "OTDR","OTIR","OUT",
186 "OUTD","OUTI","POP", "PUSH","RES", "RET", "RETI","RETN",
187 "RL", "RLA", "RLC", "RLCA","RLD", "RR", "RRA", "RRC",
188 "RRCA","RRD", "RST", "SBC", "SCF", "SET", "SLA", "SLI",
189 "SLL", "SRA", "SRL", "SUB", "XOR", "XSLT","NOPX","NOPY",
192 // various things...
193 static immutable string[8] URRegs8 = ["B","C","D","E","H","L","(HL)","A"];
194 static immutable string[4] URRegs16 = ["BC","DE","HL","SP"];
195 static immutable string[4] URRegs16a = ["BC","DE","HL","AF"];
196 static immutable string[8] URCond = ["NZ","Z","NC","C","PO","PE","P","M"];
199 struct URAsmCmdInfo {
200 URMnemo mnemo; ///
201 uint code; /// Z80 machine code
202 uint mask; /// mask (for disassembler)
203 UROpType[3] ops; ///
206 // the longest matches must come first (for disassembler)
207 // solid-masked must come first (for disassembler)
208 // assembler searches the table from the last command
209 // disassembler searches the table from the first command
210 // heh, i spent a whole night creating this shit! %-)
211 static immutable URAsmCmdInfo[358] URInstructionsTable = [
212 URAsmCmdInfo(URMnemo.NOPX, 0x000000DDU, 0x00000000U, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
213 URAsmCmdInfo(URMnemo.NOPY, 0x000000FDU, 0x00000000U, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
214 // DD/CB opcodes (special)
215 // RLC (IX+d)
216 URAsmCmdInfo(URMnemo.RLC, 0x0600CBDDU, 0xFF00FFFFU, [UROpType.MIX, UROpType.NONE, UROpType.NONE]),
217 // RRC (IX+d)
218 URAsmCmdInfo(URMnemo.RRC, 0x0E00CBDDU, 0xFF00FFFFU, [UROpType.MIX, UROpType.NONE, UROpType.NONE]),
219 // RL (IX+d)
220 URAsmCmdInfo(URMnemo.RL, 0x1600CBDDU, 0xFF00FFFFU, [UROpType.MIX, UROpType.NONE, UROpType.NONE]),
221 // RR (IX+d)
222 URAsmCmdInfo(URMnemo.RR, 0x1E00CBDDU, 0xFF00FFFFU, [UROpType.MIX, UROpType.NONE, UROpType.NONE]),
223 // SLA (IX+d)
224 URAsmCmdInfo(URMnemo.SLA, 0x2600CBDDU, 0xFF00FFFFU, [UROpType.MIX, UROpType.NONE, UROpType.NONE]),
225 // SRA (IX+d)
226 URAsmCmdInfo(URMnemo.SRA, 0x2E00CBDDU, 0xFF00FFFFU, [UROpType.MIX, UROpType.NONE, UROpType.NONE]),
227 // SLL (IX+d)
228 URAsmCmdInfo(URMnemo.SLL, 0x3600CBDDU, 0xFF00FFFFU, [UROpType.MIX, UROpType.NONE, UROpType.NONE]),
229 // SLI (IX+d)
230 URAsmCmdInfo(URMnemo.SLI, 0x3600CBDDU, 0xFF00FFFFU, [UROpType.MIX, UROpType.NONE, UROpType.NONE]),
231 // SRL (IX+d)
232 URAsmCmdInfo(URMnemo.SRL, 0x3E00CBDDU, 0xFF00FFFFU, [UROpType.MIX, UROpType.NONE, UROpType.NONE]),
233 // RES n,(IX+d)
234 URAsmCmdInfo(URMnemo.RES, 0x8600CBDDU, 0xC700FFFFU, [UROpType.BITN, UROpType.MIX, UROpType.NONE]),
235 // SET n,(IX+d)
236 URAsmCmdInfo(URMnemo.SET, 0xC600CBDDU, 0xC700FFFFU, [UROpType.BITN, UROpType.MIX, UROpType.NONE]),
237 // FD/CB opcodes (special)
238 // RLC (IY+d)
239 URAsmCmdInfo(URMnemo.RLC, 0x0600CBFDU, 0xFF00FFFFU, [UROpType.MIY, UROpType.NONE, UROpType.NONE]),
240 // RRC (IY+d)
241 URAsmCmdInfo(URMnemo.RRC, 0x0E00CBFDU, 0xFF00FFFFU, [UROpType.MIY, UROpType.NONE, UROpType.NONE]),
242 // RL (IY+d)
243 URAsmCmdInfo(URMnemo.RL, 0x1600CBFDU, 0xFF00FFFFU, [UROpType.MIY, UROpType.NONE, UROpType.NONE]),
244 // RR (IY+d)
245 URAsmCmdInfo(URMnemo.RR, 0x1E00CBFDU, 0xFF00FFFFU, [UROpType.MIY, UROpType.NONE, UROpType.NONE]),
246 // SLA (IY+d)
247 URAsmCmdInfo(URMnemo.SLA, 0x2600CBFDU, 0xFF00FFFFU, [UROpType.MIY, UROpType.NONE, UROpType.NONE]),
248 // SRA (IY+d)
249 URAsmCmdInfo(URMnemo.SRA, 0x2E00CBFDU, 0xFF00FFFFU, [UROpType.MIY, UROpType.NONE, UROpType.NONE]),
250 // SLL (IY+d)
251 URAsmCmdInfo(URMnemo.SLL, 0x3600CBFDU, 0xFF00FFFFU, [UROpType.MIY, UROpType.NONE, UROpType.NONE]),
252 // SLI (IY+d)
253 URAsmCmdInfo(URMnemo.SLI, 0x3600CBFDU, 0xFF00FFFFU, [UROpType.MIY, UROpType.NONE, UROpType.NONE]),
254 // SRL (IY+d)
255 URAsmCmdInfo(URMnemo.SRL, 0x3E00CBFDU, 0xFF00FFFFU, [UROpType.MIY, UROpType.NONE, UROpType.NONE]),
256 // RES n,(IY+d)
257 URAsmCmdInfo(URMnemo.RES, 0x8600CBFDU, 0xC700FFFFU, [UROpType.BITN, UROpType.MIY, UROpType.NONE]),
258 // SET n,(IY+d)
259 URAsmCmdInfo(URMnemo.SET, 0xC600CBFDU, 0xC700FFFFU, [UROpType.BITN, UROpType.MIY, UROpType.NONE]),
261 // DD/CB opcodes
262 // RLC (IX+d),r8
263 URAsmCmdInfo(URMnemo.RLC, 0x0000CBDDU, 0xF800FFFFU, [UROpType.MIX, UROpType.R8NOM, UROpType.NONE]),
264 // RRC (IX+d),r8
265 URAsmCmdInfo(URMnemo.RRC, 0x0800CBDDU, 0xF800FFFFU, [UROpType.MIX, UROpType.R8NOM, UROpType.NONE]),
266 // RL (IX+d),r8
267 URAsmCmdInfo(URMnemo.RL, 0x1000CBDDU, 0xF800FFFFU, [UROpType.MIX, UROpType.R8NOM, UROpType.NONE]),
268 // RR (IX+d),r8
269 URAsmCmdInfo(URMnemo.RR, 0x1800CBDDU, 0xF800FFFFU, [UROpType.MIX, UROpType.R8NOM, UROpType.NONE]),
270 // SLA (IX+d),r8
271 URAsmCmdInfo(URMnemo.SLA, 0x2000CBDDU, 0xF800FFFFU, [UROpType.MIX, UROpType.R8NOM, UROpType.NONE]),
272 // SRA (IX+d),r8
273 URAsmCmdInfo(URMnemo.SRA, 0x2800CBDDU, 0xF800FFFFU, [UROpType.MIX, UROpType.R8NOM, UROpType.NONE]),
274 // SLL (IX+d),r8
275 URAsmCmdInfo(URMnemo.SLL, 0x3000CBDDU, 0xF800FFFFU, [UROpType.MIX, UROpType.R8NOM, UROpType.NONE]),
276 // SLI (IX+d),r8
277 URAsmCmdInfo(URMnemo.SLI, 0x3000CBDDU, 0xF800FFFFU, [UROpType.MIX, UROpType.R8NOM, UROpType.NONE]),
278 // SRL (IX+d),r8
279 URAsmCmdInfo(URMnemo.SRL, 0x3800CBDDU, 0xF800FFFFU, [UROpType.MIX, UROpType.R8NOM, UROpType.NONE]),
280 // BIT n,(IX+d)
281 URAsmCmdInfo(URMnemo.BIT, 0x4600CBDDU, 0xC700FFFFU, [UROpType.BITN, UROpType.MIX, UROpType.NONE]),
282 // BIT n,(IX+d),r8
283 URAsmCmdInfo(URMnemo.BIT, 0x4000CBDDU, 0xC000FFFFU, [UROpType.BITN, UROpType.MIX, UROpType.R8NOM]),
284 // RES n,(IX+d),r8
285 URAsmCmdInfo(URMnemo.RES, 0x8000CBDDU, 0xC000FFFFU, [UROpType.BITN, UROpType.MIX, UROpType.R8NOM]),
286 // SET n,(IX+d),r8
287 URAsmCmdInfo(URMnemo.SET, 0xC000CBDDU, 0xC000FFFFU, [UROpType.BITN, UROpType.MIX, UROpType.R8NOM]),
288 // FD/CB opcodes
289 // RLC (IY+d),r8
290 URAsmCmdInfo(URMnemo.RLC, 0x0000CBFDU, 0xF800FFFFU, [UROpType.MIY, UROpType.R8NOM, UROpType.NONE]),
291 // RRC (IY+d),r8
292 URAsmCmdInfo(URMnemo.RRC, 0x0800CBFDU, 0xF800FFFFU, [UROpType.MIY, UROpType.R8NOM, UROpType.NONE]),
293 // RL (IY+d),r8
294 URAsmCmdInfo(URMnemo.RL, 0x1000CBFDU, 0xF800FFFFU, [UROpType.MIY, UROpType.R8NOM, UROpType.NONE]),
295 // RR (IY+d),r8
296 URAsmCmdInfo(URMnemo.RR, 0x1800CBFDU, 0xF800FFFFU, [UROpType.MIY, UROpType.R8NOM, UROpType.NONE]),
297 // SLA (IY+d),r8
298 URAsmCmdInfo(URMnemo.SLA, 0x2000CBFDU, 0xF800FFFFU, [UROpType.MIY, UROpType.R8NOM, UROpType.NONE]),
299 // SRA (IY+d),r8
300 URAsmCmdInfo(URMnemo.SRA, 0x2800CBFDU, 0xF800FFFFU, [UROpType.MIY, UROpType.R8NOM, UROpType.NONE]),
301 // SLL (IY+d),r8
302 URAsmCmdInfo(URMnemo.SLL, 0x3000CBFDU, 0xF800FFFFU, [UROpType.MIY, UROpType.R8NOM, UROpType.NONE]),
303 // SLI (IY+d),r8
304 URAsmCmdInfo(URMnemo.SLI, 0x3000CBFDU, 0xF800FFFFU, [UROpType.MIY, UROpType.R8NOM, UROpType.NONE]),
305 // SRL (IY+d),r8
306 URAsmCmdInfo(URMnemo.SRL, 0x3800CBFDU, 0xF800FFFFU, [UROpType.MIY, UROpType.R8NOM, UROpType.NONE]),
307 // BIT n,(IY+d)
308 URAsmCmdInfo(URMnemo.BIT, 0x4600CBFDU, 0xC700FFFFU, [UROpType.BITN, UROpType.MIY, UROpType.NONE]),
309 // BIT n,(IY+d),r8
310 URAsmCmdInfo(URMnemo.BIT, 0x4000CBFDU, 0xC000FFFFU, [UROpType.BITN, UROpType.MIY, UROpType.R8NOM]),
311 // RES n,(IY+d),r8
312 URAsmCmdInfo(URMnemo.RES, 0x8000CBFDU, 0xC000FFFFU, [UROpType.BITN, UROpType.MIY, UROpType.R8NOM]),
313 // SET n,(IY+d),r8
314 URAsmCmdInfo(URMnemo.SET, 0xC000CBFDU, 0xC000FFFFU, [UROpType.BITN, UROpType.MIY, UROpType.R8NOM]),
315 // standard CB opcodes
316 // RLC r8
317 URAsmCmdInfo(URMnemo.RLC, 0x00CBU, 0xF8FFU, [UROpType.R8, UROpType.NONE, UROpType.NONE]),
318 // RRC r8
319 URAsmCmdInfo(URMnemo.RRC, 0x08CBU, 0xF8FFU, [UROpType.R8, UROpType.NONE, UROpType.NONE]),
320 // RL r8
321 URAsmCmdInfo(URMnemo.RL, 0x10CBU, 0xF8FFU, [UROpType.R8, UROpType.NONE, UROpType.NONE]),
322 // RR r8
323 URAsmCmdInfo(URMnemo.RR, 0x18CBU, 0xF8FFU, [UROpType.R8, UROpType.NONE, UROpType.NONE]),
324 // SLA r8
325 URAsmCmdInfo(URMnemo.SLA, 0x20CBU, 0xF8FFU, [UROpType.R8, UROpType.NONE, UROpType.NONE]),
326 // SRA r8
327 URAsmCmdInfo(URMnemo.SRA, 0x28CBU, 0xF8FFU, [UROpType.R8, UROpType.NONE, UROpType.NONE]),
328 // SLL r8
329 URAsmCmdInfo(URMnemo.SLL, 0x30CBU, 0xF8FFU, [UROpType.R8, UROpType.NONE, UROpType.NONE]),
330 // SLI r8
331 URAsmCmdInfo(URMnemo.SLI, 0x30CBU, 0xF8FFU, [UROpType.R8, UROpType.NONE, UROpType.NONE]),
332 // SRL r8
333 URAsmCmdInfo(URMnemo.SRL, 0x38CBU, 0xF8FFU, [UROpType.R8, UROpType.NONE, UROpType.NONE]),
334 // BIT n,r8
335 URAsmCmdInfo(URMnemo.BIT, 0x40CBU, 0xC0FFU, [UROpType.BITN, UROpType.R8, UROpType.NONE]),
336 // RES n,r8
337 URAsmCmdInfo(URMnemo.RES, 0x80CBU, 0xC0FFU, [UROpType.BITN, UROpType.R8, UROpType.NONE]),
338 // SET n,r8
339 URAsmCmdInfo(URMnemo.SET, 0xC0CBU, 0xC0FFU, [UROpType.BITN, UROpType.R8, UROpType.NONE]),
341 // some ED opcodes
342 // traps
343 URAsmCmdInfo(URMnemo.XSLT, 0xFBEDU, 0xFFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
344 // ED string instructions
345 URAsmCmdInfo(URMnemo.LDI, 0xA0EDU, 0xFFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
346 URAsmCmdInfo(URMnemo.LDIR, 0xB0EDU, 0xFFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
347 URAsmCmdInfo(URMnemo.CPI, 0xA1EDU, 0xFFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
348 URAsmCmdInfo(URMnemo.CPIR, 0xB1EDU, 0xFFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
349 URAsmCmdInfo(URMnemo.INI, 0xA2EDU, 0xFFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
350 URAsmCmdInfo(URMnemo.INIR, 0xB2EDU, 0xFFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
351 URAsmCmdInfo(URMnemo.OUTI, 0xA3EDU, 0xFFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
352 URAsmCmdInfo(URMnemo.OTIR, 0xB3EDU, 0xFFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
353 URAsmCmdInfo(URMnemo.LDD, 0xA8EDU, 0xFFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
354 URAsmCmdInfo(URMnemo.LDDR, 0xB8EDU, 0xFFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
355 URAsmCmdInfo(URMnemo.CPD, 0xA9EDU, 0xFFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
356 URAsmCmdInfo(URMnemo.CPDR, 0xB9EDU, 0xFFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
357 URAsmCmdInfo(URMnemo.IND, 0xAAEDU, 0xFFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
358 URAsmCmdInfo(URMnemo.INDR, 0xBAEDU, 0xFFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
359 URAsmCmdInfo(URMnemo.OUTD, 0xABEDU, 0xFFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
360 URAsmCmdInfo(URMnemo.OTDR, 0xBBEDU, 0xFFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
362 // ED w/o operands
363 URAsmCmdInfo(URMnemo.RRD, 0x67EDU, 0xFFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
364 URAsmCmdInfo(URMnemo.RLD, 0x6FEDU, 0xFFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
366 // IN (C)
367 URAsmCmdInfo(URMnemo.IN, 0x70EDU, 0xFFFFU, [UROpType.PORTC, UROpType.NONE, UROpType.NONE]),
368 // OUT (C),0
369 URAsmCmdInfo(URMnemo.OUT, 0x71EDU, 0xFFFFU, [UROpType.PORTC, UROpType.IM0, UROpType.NONE]),
371 // LD I,A
372 URAsmCmdInfo(URMnemo.LD, 0x47EDU, 0xFFFFU, [UROpType.R8I, UROpType.R8A, UROpType.NONE]),
373 // LD A,I
374 URAsmCmdInfo(URMnemo.LD, 0x57EDU, 0xFFFFU, [UROpType.R8A, UROpType.R8I, UROpType.NONE]),
375 // LD R,A
376 URAsmCmdInfo(URMnemo.LD, 0x4FEDU, 0xFFFFU, [UROpType.R8R, UROpType.R8A, UROpType.NONE]),
377 // LD A,R
378 URAsmCmdInfo(URMnemo.LD, 0x5FEDU, 0xFFFFU, [UROpType.R8A, UROpType.R8R, UROpType.NONE]),
379 // IM 0/1
380 //(.mnemo=UT_IM, .code=0x4EEDU, .mask=0xFFFFU, .ops={UO_IM01, UO_NONE, UO_NONE}},
382 // ED w/o operands
383 URAsmCmdInfo(URMnemo.RETN, 0x45EDU, 0xCFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
384 URAsmCmdInfo(URMnemo.RETI, 0x4DEDU, 0xCFFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
386 // SBC HL,r16
387 URAsmCmdInfo(URMnemo.SBC, 0x42EDU, 0xCFFFU, [UROpType.R16HL, UROpType.R16, UROpType.NONE]),
388 // ADC HL,r16
389 URAsmCmdInfo(URMnemo.ADC, 0x4AEDU, 0xCFFFU, [UROpType.R16HL, UROpType.R16, UROpType.NONE]),
390 // LD (nnnn),r16
391 URAsmCmdInfo(URMnemo.LD, 0x43EDU, 0xCFFFU, [UROpType.MEM16, UROpType.R16, UROpType.NONE]),
392 // LD r16,(nnnn)
393 URAsmCmdInfo(URMnemo.LD, 0x4BEDU, 0xCFFFU, [UROpType.R16, UROpType.MEM16, UROpType.NONE]),
395 // ED w/o operands
396 URAsmCmdInfo(URMnemo.NEG, 0x44EDU, 0xC7FFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
398 // IN r8,(C)
399 URAsmCmdInfo(URMnemo.IN, 0x40EDU, 0xC7FFU, [UROpType.R83NOM, UROpType.PORTC, UROpType.NONE]),
400 // OUT (C),r8
401 URAsmCmdInfo(URMnemo.OUT, 0x41EDU, 0xC7FFU, [UROpType.PORTC, UROpType.R83NOM, UROpType.NONE]),
403 // IM 2
404 URAsmCmdInfo(URMnemo.IM, 0x5EEDU, 0xDFFFU, [UROpType.IM2, UROpType.NONE, UROpType.NONE]),
405 // IM 1
406 URAsmCmdInfo(URMnemo.IM, 0x56EDU, 0xDFFFU, [UROpType.IM1, UROpType.NONE, UROpType.NONE]),
407 // IM 0
408 URAsmCmdInfo(URMnemo.IM, 0x46EDU, 0xD7FFU, [UROpType.IM0, UROpType.NONE, UROpType.NONE]),
410 // LD SP,IX
411 URAsmCmdInfo(URMnemo.LD, 0xF9DDU, 0xFFFFU, [UROpType.R16SP, UROpType.R16IX, UROpType.NONE]),
412 // LD SP,IY
413 URAsmCmdInfo(URMnemo.LD, 0xF9FDU, 0xFFFFU, [UROpType.R16SP, UROpType.R16IY, UROpType.NONE]),
415 // EX (SP),IX
416 URAsmCmdInfo(URMnemo.EX, 0xE3DDU, 0xFFFFU, [UROpType.MSP, UROpType.R16IX, UROpType.NONE]),
417 // EX IX,(SP) (ditto)
418 URAsmCmdInfo(URMnemo.EX, 0xE3DDU, 0xFFFFU, [UROpType.R16IX, UROpType.MSP, UROpType.NONE]),
419 // EX (SP),IY
420 URAsmCmdInfo(URMnemo.EX, 0xE3FDU, 0xFFFFU, [UROpType.MSP, UROpType.R16IY, UROpType.NONE]),
421 // EX IY,(SP) (ditto)
422 URAsmCmdInfo(URMnemo.EX, 0xE3FDU, 0xFFFFU, [UROpType.R16IY, UROpType.MSP, UROpType.NONE]),
424 // JP (IX)
425 URAsmCmdInfo(URMnemo.JP, 0xE9DDU, 0xFFFFU, [UROpType.MIX0, UROpType.NONE, UROpType.NONE]),
426 // JP (IY)
427 URAsmCmdInfo(URMnemo.JP, 0xE9FDU, 0xFFFFU, [UROpType.MIY0, UROpType.NONE, UROpType.NONE]),
428 // JP IX
429 URAsmCmdInfo(URMnemo.JP, 0xE9DDU, 0xFFFFU, [UROpType.R16IX, UROpType.NONE, UROpType.NONE]),
430 // JP IY
431 URAsmCmdInfo(URMnemo.JP, 0xE9FDU, 0xFFFFU, [UROpType.R16IY, UROpType.NONE, UROpType.NONE]),
433 // POP IX
434 URAsmCmdInfo(URMnemo.POP, 0xE1DDU, 0xFFFFU, [UROpType.R16IX, UROpType.NONE, UROpType.NONE]),
435 // PUSH IX
436 URAsmCmdInfo(URMnemo.PUSH, 0xE5DDU, 0xFFFFU, [UROpType.R16IX, UROpType.NONE, UROpType.NONE]),
437 // POP IY
438 URAsmCmdInfo(URMnemo.POP, 0xE1FDU, 0xFFFFU, [UROpType.R16IY, UROpType.NONE, UROpType.NONE]),
439 // PUSH IY
440 URAsmCmdInfo(URMnemo.PUSH, 0xE5FDU, 0xFFFFU, [UROpType.R16IY, UROpType.NONE, UROpType.NONE]),
442 // ADD A,(IX+d)
443 URAsmCmdInfo(URMnemo.ADD, 0x86DDU, 0xFFFFU, [UROpType.R8A, UROpType.MIX, UROpType.NONE]),
444 // ADD (IX+d)
445 URAsmCmdInfo(URMnemo.ADD, 0x86DDU, 0xFFFFU, [UROpType.MIX, UROpType.NONE, UROpType.NONE]),
446 // ADC A,(IX+d)
447 URAsmCmdInfo(URMnemo.ADC, 0x8EDDU, 0xFFFFU, [UROpType.R8A, UROpType.MIX, UROpType.NONE]),
448 // ADC (IX+d)
449 URAsmCmdInfo(URMnemo.ADC, 0x8EDDU, 0xFFFFU, [UROpType.MIX, UROpType.NONE, UROpType.NONE]),
450 // SUB (IX+d)
451 URAsmCmdInfo(URMnemo.SUB, 0x96DDU, 0xFFFFU, [UROpType.MIX, UROpType.NONE, UROpType.NONE]),
452 // SUB A,(IX+d)
453 URAsmCmdInfo(URMnemo.SUB, 0x96DDU, 0xFFFFU, [UROpType.R8A, UROpType.MIX, UROpType.NONE]),
454 // SBC A,(IX+d)
455 URAsmCmdInfo(URMnemo.SBC, 0x9EDDU, 0xFFFFU, [UROpType.R8A, UROpType.MIX, UROpType.NONE]),
456 // SBC (IX+d)
457 URAsmCmdInfo(URMnemo.SBC, 0x9EDDU, 0xFFFFU, [UROpType.MIX, UROpType.NONE, UROpType.NONE]),
458 // AND (IX+d)
459 URAsmCmdInfo(URMnemo.AND, 0xA6DDU, 0xFFFFU, [UROpType.MIX, UROpType.NONE, UROpType.NONE]),
460 // AND A,(IX+d)
461 URAsmCmdInfo(URMnemo.AND, 0xA6DDU, 0xFFFFU, [UROpType.R8A, UROpType.MIX, UROpType.NONE]),
462 // XOR (IX+d)
463 URAsmCmdInfo(URMnemo.XOR, 0xAEDDU, 0xFFFFU, [UROpType.MIX, UROpType.NONE, UROpType.NONE]),
464 // XOR A,(IX+d)
465 URAsmCmdInfo(URMnemo.XOR, 0xAEDDU, 0xFFFFU, [UROpType.R8A, UROpType.MIX, UROpType.NONE]),
466 // OR (IX+d)
467 URAsmCmdInfo(URMnemo.OR, 0xB6DDU, 0xFFFFU, [UROpType.MIX, UROpType.NONE, UROpType.NONE]),
468 // OR A,(IX+d)
469 URAsmCmdInfo(URMnemo.OR, 0xB6DDU, 0xFFFFU, [UROpType.R8A, UROpType.MIX, UROpType.NONE]),
470 // CP (IX+d)
471 URAsmCmdInfo(URMnemo.CP, 0xBEDDU, 0xFFFFU, [UROpType.MIX, UROpType.NONE, UROpType.NONE]),
472 // CP A,(IX+d)
473 URAsmCmdInfo(URMnemo.CP, 0xBEDDU, 0xFFFFU, [UROpType.R8A, UROpType.MIX, UROpType.NONE]),
474 // ADD A,(IY+d)
475 URAsmCmdInfo(URMnemo.ADD, 0x86FDU, 0xFFFFU, [UROpType.R8A, UROpType.MIY, UROpType.NONE]),
476 // ADD (IY+d)
477 URAsmCmdInfo(URMnemo.ADD, 0x86FDU, 0xFFFFU, [UROpType.MIY, UROpType.NONE, UROpType.NONE]),
478 // ADC A,(IY+d)
479 URAsmCmdInfo(URMnemo.ADC, 0x8EFDU, 0xFFFFU, [UROpType.R8A, UROpType.MIY, UROpType.NONE]),
480 // ADC (IY+d)
481 URAsmCmdInfo(URMnemo.ADC, 0x8EFDU, 0xFFFFU, [UROpType.MIY, UROpType.NONE, UROpType.NONE]),
482 // SUB (IY+d)
483 URAsmCmdInfo(URMnemo.SUB, 0x96FDU, 0xFFFFU, [UROpType.MIY, UROpType.NONE, UROpType.NONE]),
484 // SUB A,(IY+d)
485 URAsmCmdInfo(URMnemo.SUB, 0x96FDU, 0xFFFFU, [UROpType.R8A, UROpType.MIY, UROpType.NONE]),
486 // SBC A,(IY+d)
487 URAsmCmdInfo(URMnemo.SBC, 0x9EFDU, 0xFFFFU, [UROpType.R8A, UROpType.MIY, UROpType.NONE]),
488 // SBC (IY+d)
489 URAsmCmdInfo(URMnemo.SBC, 0x9EFDU, 0xFFFFU, [UROpType.MIY, UROpType.NONE, UROpType.NONE]),
490 // AND (IY+d)
491 URAsmCmdInfo(URMnemo.AND, 0xA6FDU, 0xFFFFU, [UROpType.MIY, UROpType.NONE, UROpType.NONE]),
492 // AND A,(IY+d)
493 URAsmCmdInfo(URMnemo.AND, 0xA6FDU, 0xFFFFU, [UROpType.R8A, UROpType.MIY, UROpType.NONE]),
494 // XOR (IY+d)
495 URAsmCmdInfo(URMnemo.XOR, 0xAEFDU, 0xFFFFU, [UROpType.MIY, UROpType.NONE, UROpType.NONE]),
496 // XOR A,(IY+d)
497 URAsmCmdInfo(URMnemo.XOR, 0xAEFDU, 0xFFFFU, [UROpType.R8A, UROpType.MIY, UROpType.NONE]),
498 // OR (IY+d)
499 URAsmCmdInfo(URMnemo.OR, 0xB6FDU, 0xFFFFU, [UROpType.MIY, UROpType.NONE, UROpType.NONE]),
500 // OR A,(IY+d)
501 URAsmCmdInfo(URMnemo.OR, 0xB6FDU, 0xFFFFU, [UROpType.R8A, UROpType.MIY, UROpType.NONE]),
502 // CP (IY+d)
503 URAsmCmdInfo(URMnemo.CP, 0xBEFDU, 0xFFFFU, [UROpType.MIY, UROpType.NONE, UROpType.NONE]),
504 // CP A,(IY+d)
505 URAsmCmdInfo(URMnemo.CP, 0xBEFDU, 0xFFFFU, [UROpType.R8A, UROpType.MIY, UROpType.NONE]),
506 // ADD A,XH
507 URAsmCmdInfo(URMnemo.ADD, 0x84DDU, 0xFFFFU, [UROpType.R8A, UROpType.R8XH, UROpType.NONE]),
508 // ADD XH
509 URAsmCmdInfo(URMnemo.ADD, 0x84DDU, 0xFFFFU, [UROpType.R8XH, UROpType.NONE, UROpType.NONE]),
510 // ADC A,XH
511 URAsmCmdInfo(URMnemo.ADC, 0x8CDDU, 0xFFFFU, [UROpType.R8A, UROpType.R8XH, UROpType.NONE]),
512 // ADC XH
513 URAsmCmdInfo(URMnemo.ADC, 0x8CDDU, 0xFFFFU, [UROpType.R8XH, UROpType.NONE, UROpType.NONE]),
514 // SUB XH
515 URAsmCmdInfo(URMnemo.SUB, 0x94DDU, 0xFFFFU, [UROpType.R8XH, UROpType.NONE, UROpType.NONE]),
516 // SUB A,XH
517 URAsmCmdInfo(URMnemo.SUB, 0x94DDU, 0xFFFFU, [UROpType.R8A, UROpType.R8XH, UROpType.NONE]),
518 // SBC A,XH
519 URAsmCmdInfo(URMnemo.SBC, 0x9CDDU, 0xFFFFU, [UROpType.R8A, UROpType.R8XH, UROpType.NONE]),
520 // SBC XH
521 URAsmCmdInfo(URMnemo.SBC, 0x9CDDU, 0xFFFFU, [UROpType.R8XH, UROpType.NONE, UROpType.NONE]),
522 // AND XH
523 URAsmCmdInfo(URMnemo.AND, 0xA4DDU, 0xFFFFU, [UROpType.R8XH, UROpType.NONE, UROpType.NONE]),
524 // AND A,XH
525 URAsmCmdInfo(URMnemo.AND, 0xA4DDU, 0xFFFFU, [UROpType.R8A, UROpType.R8XH, UROpType.NONE]),
526 // XOR XH
527 URAsmCmdInfo(URMnemo.XOR, 0xACDDU, 0xFFFFU, [UROpType.R8XH, UROpType.NONE, UROpType.NONE]),
528 // XOR A,XH
529 URAsmCmdInfo(URMnemo.XOR, 0xACDDU, 0xFFFFU, [UROpType.R8A, UROpType.R8XH, UROpType.NONE]),
530 // OR XH
531 URAsmCmdInfo(URMnemo.OR, 0xB4DDU, 0xFFFFU, [UROpType.R8XH, UROpType.NONE, UROpType.NONE]),
532 // OR A,XH
533 URAsmCmdInfo(URMnemo.OR, 0xB4DDU, 0xFFFFU, [UROpType.R8A, UROpType.R8XH, UROpType.NONE]),
534 // CP XH
535 URAsmCmdInfo(URMnemo.CP, 0xBCDDU, 0xFFFFU, [UROpType.R8XH, UROpType.NONE, UROpType.NONE]),
536 // CP A,XH
537 URAsmCmdInfo(URMnemo.CP, 0xBCDDU, 0xFFFFU, [UROpType.R8A, UROpType.R8XH, UROpType.NONE]),
538 // ADD A,XL
539 URAsmCmdInfo(URMnemo.ADD, 0x85DDU, 0xFFFFU, [UROpType.R8A, UROpType.R8XL, UROpType.NONE]),
540 // ADD XL
541 URAsmCmdInfo(URMnemo.ADD, 0x85DDU, 0xFFFFU, [UROpType.R8XL, UROpType.NONE, UROpType.NONE]),
542 // ADC A,XL
543 URAsmCmdInfo(URMnemo.ADC, 0x8DDDU, 0xFFFFU, [UROpType.R8A, UROpType.R8XL, UROpType.NONE]),
544 // ADC XL
545 URAsmCmdInfo(URMnemo.ADC, 0x8DDDU, 0xFFFFU, [UROpType.R8XL, UROpType.NONE, UROpType.NONE]),
546 // SUB XL
547 URAsmCmdInfo(URMnemo.SUB, 0x95DDU, 0xFFFFU, [UROpType.R8XL, UROpType.NONE, UROpType.NONE]),
548 // SUB A,XL
549 URAsmCmdInfo(URMnemo.SUB, 0x95DDU, 0xFFFFU, [UROpType.R8A, UROpType.R8XL, UROpType.NONE]),
550 // SBC A,XL
551 URAsmCmdInfo(URMnemo.SBC, 0x9DDDU, 0xFFFFU, [UROpType.R8A, UROpType.R8XL, UROpType.NONE]),
552 // SBC XL
553 URAsmCmdInfo(URMnemo.SBC, 0x9DDDU, 0xFFFFU, [UROpType.R8XL, UROpType.NONE, UROpType.NONE]),
554 // AND XL
555 URAsmCmdInfo(URMnemo.AND, 0xA5DDU, 0xFFFFU, [UROpType.R8XL, UROpType.NONE, UROpType.NONE]),
556 // AND A,XL
557 URAsmCmdInfo(URMnemo.AND, 0xA5DDU, 0xFFFFU, [UROpType.R8A, UROpType.R8XL, UROpType.NONE]),
558 // XOR XL
559 URAsmCmdInfo(URMnemo.XOR, 0xADDDU, 0xFFFFU, [UROpType.R8XL, UROpType.NONE, UROpType.NONE]),
560 // XOR A,XL
561 URAsmCmdInfo(URMnemo.XOR, 0xADDDU, 0xFFFFU, [UROpType.R8A, UROpType.R8XL, UROpType.NONE]),
562 // OR XL
563 URAsmCmdInfo(URMnemo.OR, 0xB5DDU, 0xFFFFU, [UROpType.R8XL, UROpType.NONE, UROpType.NONE]),
564 // OR A,XL
565 URAsmCmdInfo(URMnemo.OR, 0xB5DDU, 0xFFFFU, [UROpType.R8A, UROpType.R8XL, UROpType.NONE]),
566 // CP XL
567 URAsmCmdInfo(URMnemo.CP, 0xBDDDU, 0xFFFFU, [UROpType.R8XL, UROpType.NONE, UROpType.NONE]),
568 // CP A,XL
569 URAsmCmdInfo(URMnemo.CP, 0xBDDDU, 0xFFFFU, [UROpType.R8A, UROpType.R8XL, UROpType.NONE]),
570 // ADD A,YH
571 URAsmCmdInfo(URMnemo.ADD, 0x84FDU, 0xFFFFU, [UROpType.R8A, UROpType.R8YH, UROpType.NONE]),
572 // ADD YH
573 URAsmCmdInfo(URMnemo.ADD, 0x84FDU, 0xFFFFU, [UROpType.R8YH, UROpType.NONE, UROpType.NONE]),
574 // ADC A,YH
575 URAsmCmdInfo(URMnemo.ADC, 0x8CFDU, 0xFFFFU, [UROpType.R8A, UROpType.R8YH, UROpType.NONE]),
576 // ADC YH
577 URAsmCmdInfo(URMnemo.ADC, 0x8CFDU, 0xFFFFU, [UROpType.R8YH, UROpType.NONE, UROpType.NONE]),
578 // SUB YH
579 URAsmCmdInfo(URMnemo.SUB, 0x94FDU, 0xFFFFU, [UROpType.R8YH, UROpType.NONE, UROpType.NONE]),
580 // SUB A,YH
581 URAsmCmdInfo(URMnemo.SUB, 0x94FDU, 0xFFFFU, [UROpType.R8A, UROpType.R8YH, UROpType.NONE]),
582 // SBC A,YH
583 URAsmCmdInfo(URMnemo.SBC, 0x9CFDU, 0xFFFFU, [UROpType.R8A, UROpType.R8YH, UROpType.NONE]),
584 // SBC YH
585 URAsmCmdInfo(URMnemo.SBC, 0x9CFDU, 0xFFFFU, [UROpType.R8YH, UROpType.NONE, UROpType.NONE]),
586 // AND YH
587 URAsmCmdInfo(URMnemo.AND, 0xA4FDU, 0xFFFFU, [UROpType.R8YH, UROpType.NONE, UROpType.NONE]),
588 // AND A,YH
589 URAsmCmdInfo(URMnemo.AND, 0xA4FDU, 0xFFFFU, [UROpType.R8A, UROpType.R8YH, UROpType.NONE]),
590 // XOR YH
591 URAsmCmdInfo(URMnemo.XOR, 0xACFDU, 0xFFFFU, [UROpType.R8YH, UROpType.NONE, UROpType.NONE]),
592 // XOR A,YH
593 URAsmCmdInfo(URMnemo.XOR, 0xACFDU, 0xFFFFU, [UROpType.R8A, UROpType.R8YH, UROpType.NONE]),
594 // OR YH
595 URAsmCmdInfo(URMnemo.OR, 0xB4FDU, 0xFFFFU, [UROpType.R8YH, UROpType.NONE, UROpType.NONE]),
596 // OR A,YH
597 URAsmCmdInfo(URMnemo.OR, 0xB4FDU, 0xFFFFU, [UROpType.R8A, UROpType.R8YH, UROpType.NONE]),
598 // CP YH
599 URAsmCmdInfo(URMnemo.CP, 0xBCFDU, 0xFFFFU, [UROpType.R8YH, UROpType.NONE, UROpType.NONE]),
600 // CP A,YH
601 URAsmCmdInfo(URMnemo.CP, 0xBCFDU, 0xFFFFU, [UROpType.R8A, UROpType.R8YH, UROpType.NONE]),
602 // ADD A,YL
603 URAsmCmdInfo(URMnemo.ADD, 0x85FDU, 0xFFFFU, [UROpType.R8A, UROpType.R8YL, UROpType.NONE]),
604 // ADD YL
605 URAsmCmdInfo(URMnemo.ADD, 0x85FDU, 0xFFFFU, [UROpType.R8YL, UROpType.NONE, UROpType.NONE]),
606 // ADC A,YL
607 URAsmCmdInfo(URMnemo.ADC, 0x8DFDU, 0xFFFFU, [UROpType.R8A, UROpType.R8YL, UROpType.NONE]),
608 // ADC YL
609 URAsmCmdInfo(URMnemo.ADC, 0x8DFDU, 0xFFFFU, [UROpType.R8YL, UROpType.NONE, UROpType.NONE]),
610 // SUB YL
611 URAsmCmdInfo(URMnemo.SUB, 0x95FDU, 0xFFFFU, [UROpType.R8YL, UROpType.NONE, UROpType.NONE]),
612 // SUB A,YL
613 URAsmCmdInfo(URMnemo.SUB, 0x95FDU, 0xFFFFU, [UROpType.R8A, UROpType.R8YL, UROpType.NONE]),
614 // SBC A,YL
615 URAsmCmdInfo(URMnemo.SBC, 0x9DFDU, 0xFFFFU, [UROpType.R8A, UROpType.R8YL, UROpType.NONE]),
616 // SBC YL
617 URAsmCmdInfo(URMnemo.SBC, 0x9DFDU, 0xFFFFU, [UROpType.R8YL, UROpType.NONE, UROpType.NONE]),
618 // AND YL
619 URAsmCmdInfo(URMnemo.AND, 0xA5FDU, 0xFFFFU, [UROpType.R8YL, UROpType.NONE, UROpType.NONE]),
620 // AND A,YL
621 URAsmCmdInfo(URMnemo.AND, 0xA5FDU, 0xFFFFU, [UROpType.R8A, UROpType.R8YL, UROpType.NONE]),
622 // XOR YL
623 URAsmCmdInfo(URMnemo.XOR, 0xADFDU, 0xFFFFU, [UROpType.R8YL, UROpType.NONE, UROpType.NONE]),
624 // XOR A,YL
625 URAsmCmdInfo(URMnemo.XOR, 0xADFDU, 0xFFFFU, [UROpType.R8A, UROpType.R8YL, UROpType.NONE]),
626 // OR YL
627 URAsmCmdInfo(URMnemo.OR, 0xB5FDU, 0xFFFFU, [UROpType.R8YL, UROpType.NONE, UROpType.NONE]),
628 // OR A,YL
629 URAsmCmdInfo(URMnemo.OR, 0xB5FDU, 0xFFFFU, [UROpType.R8A, UROpType.R8YL, UROpType.NONE]),
630 // CP YL
631 URAsmCmdInfo(URMnemo.CP, 0xBDFDU, 0xFFFFU, [UROpType.R8YL, UROpType.NONE, UROpType.NONE]),
632 // CP A,YL
633 URAsmCmdInfo(URMnemo.CP, 0xBDFDU, 0xFFFFU, [UROpType.R8A, UROpType.R8YL, UROpType.NONE]),
635 // LD XH,XH
636 URAsmCmdInfo(URMnemo.LD, 0x64DDU, 0xFFFFU, [UROpType.R8XH, UROpType.R8XH, UROpType.NONE]),
637 // LD XH,XL
638 URAsmCmdInfo(URMnemo.LD, 0x65DDU, 0xFFFFU, [UROpType.R8XH, UROpType.R8XL, UROpType.NONE]),
639 // LD XL,XH
640 URAsmCmdInfo(URMnemo.LD, 0x6CDDU, 0xFFFFU, [UROpType.R8XL, UROpType.R8XH, UROpType.NONE]),
641 // LD XL,XL
642 URAsmCmdInfo(URMnemo.LD, 0x6DDDU, 0xFFFFU, [UROpType.R8XL, UROpType.R8XL, UROpType.NONE]),
643 // LD YH,YH
644 URAsmCmdInfo(URMnemo.LD, 0x64FDU, 0xFFFFU, [UROpType.R8YH, UROpType.R8YH, UROpType.NONE]),
645 // LD YH,YL
646 URAsmCmdInfo(URMnemo.LD, 0x65FDU, 0xFFFFU, [UROpType.R8YH, UROpType.R8YL, UROpType.NONE]),
647 // LD YL,YH
648 URAsmCmdInfo(URMnemo.LD, 0x6CFDU, 0xFFFFU, [UROpType.R8YL, UROpType.R8YH, UROpType.NONE]),
649 // LD YL,YL
650 URAsmCmdInfo(URMnemo.LD, 0x6DFDU, 0xFFFFU, [UROpType.R8YL, UROpType.R8YL, UROpType.NONE]),
652 // LD (nnnn),IX
653 URAsmCmdInfo(URMnemo.LD, 0x22DDU, 0xFFFFU, [UROpType.MEM16, UROpType.R16IX, UROpType.NONE]),
654 // LD IX,(nnnn)
655 URAsmCmdInfo(URMnemo.LD, 0x2ADDU, 0xFFFFU, [UROpType.R16IX, UROpType.MEM16, UROpType.NONE]),
656 // LD (nnnn),IY
657 URAsmCmdInfo(URMnemo.LD, 0x22FDU, 0xFFFFU, [UROpType.MEM16, UROpType.R16IY, UROpType.NONE]),
658 // LD IY,(nnnn)
659 URAsmCmdInfo(URMnemo.LD, 0x2AFDU, 0xFFFFU, [UROpType.R16IY, UROpType.MEM16, UROpType.NONE]),
661 // LD IX,nnnn
662 URAsmCmdInfo(URMnemo.LD, 0x21DDU, 0xFFFFU, [UROpType.R16IX, UROpType.IMM16, UROpType.NONE]),
663 // LD IY,nnnn
664 URAsmCmdInfo(URMnemo.LD, 0x21FDU, 0xFFFFU, [UROpType.R16IY, UROpType.IMM16, UROpType.NONE]),
666 // INC IX
667 URAsmCmdInfo(URMnemo.INC, 0x23DDU, 0xFFFFU, [UROpType.R16IX, UROpType.NONE, UROpType.NONE]),
668 // DEC IX
669 URAsmCmdInfo(URMnemo.DEC, 0x2BDDU, 0xFFFFU, [UROpType.R16IX, UROpType.NONE, UROpType.NONE]),
670 // INC IY
671 URAsmCmdInfo(URMnemo.INC, 0x23FDU, 0xFFFFU, [UROpType.R16IY, UROpType.NONE, UROpType.NONE]),
672 // DEC IY
673 URAsmCmdInfo(URMnemo.DEC, 0x2BFDU, 0xFFFFU, [UROpType.R16IY, UROpType.NONE, UROpType.NONE]),
675 // INC (IX+d)
676 URAsmCmdInfo(URMnemo.INC, 0x34DDU, 0xFFFFU, [UROpType.MIX, UROpType.NONE, UROpType.NONE]),
677 // DEC (IX+d)
678 URAsmCmdInfo(URMnemo.DEC, 0x35DDU, 0xFFFFU, [UROpType.MIX, UROpType.NONE, UROpType.NONE]),
679 // LD (IX+d),nn
680 URAsmCmdInfo(URMnemo.LD, 0x36DDU, 0xFFFFU, [UROpType.MIX, UROpType.IMM8, UROpType.NONE]),
681 // INC (IY+d)
682 URAsmCmdInfo(URMnemo.INC, 0x34FDU, 0xFFFFU, [UROpType.MIY, UROpType.NONE, UROpType.NONE]),
683 // DEC (IY+d)
684 URAsmCmdInfo(URMnemo.DEC, 0x35FDU, 0xFFFFU, [UROpType.MIY, UROpType.NONE, UROpType.NONE]),
685 // LD (IY+d),nn
686 URAsmCmdInfo(URMnemo.LD, 0x36FDU, 0xFFFFU, [UROpType.MIY, UROpType.IMM8, UROpType.NONE]),
688 // INC XH
689 URAsmCmdInfo(URMnemo.INC, 0x24DDU, 0xFFFFU, [UROpType.R8XH, UROpType.NONE, UROpType.NONE]),
690 // DEC XH
691 URAsmCmdInfo(URMnemo.DEC, 0x25DDU, 0xFFFFU, [UROpType.R8XH, UROpType.NONE, UROpType.NONE]),
692 // INC XL
693 URAsmCmdInfo(URMnemo.INC, 0x2CDDU, 0xFFFFU, [UROpType.R8XL, UROpType.NONE, UROpType.NONE]),
694 // DEC XL
695 URAsmCmdInfo(URMnemo.DEC, 0x2DDDU, 0xFFFFU, [UROpType.R8XL, UROpType.NONE, UROpType.NONE]),
696 // INC YH
697 URAsmCmdInfo(URMnemo.INC, 0x24FDU, 0xFFFFU, [UROpType.R8YH, UROpType.NONE, UROpType.NONE]),
698 // DEC YH
699 URAsmCmdInfo(URMnemo.DEC, 0x25FDU, 0xFFFFU, [UROpType.R8YH, UROpType.NONE, UROpType.NONE]),
700 // INC YL
701 URAsmCmdInfo(URMnemo.INC, 0x2CFDU, 0xFFFFU, [UROpType.R8YL, UROpType.NONE, UROpType.NONE]),
702 // DEC YL
703 URAsmCmdInfo(URMnemo.DEC, 0x2DFDU, 0xFFFFU, [UROpType.R8YL, UROpType.NONE, UROpType.NONE]),
705 // LD XH,nn
706 URAsmCmdInfo(URMnemo.LD, 0x26DDU, 0xFFFFU, [UROpType.R8XH, UROpType.IMM8, UROpType.NONE]),
707 // LD XL,nn
708 URAsmCmdInfo(URMnemo.LD, 0x2EDDU, 0xFFFFU, [UROpType.R8XL, UROpType.IMM8, UROpType.NONE]),
709 // LD YH,nn
710 URAsmCmdInfo(URMnemo.LD, 0x26FDU, 0xFFFFU, [UROpType.R8YH, UROpType.IMM8, UROpType.NONE]),
711 // LD YL,nn
712 URAsmCmdInfo(URMnemo.LD, 0x2EFDU, 0xFFFFU, [UROpType.R8YL, UROpType.IMM8, UROpType.NONE]),
714 // ADD IX,BC
715 URAsmCmdInfo(URMnemo.ADD, 0x09DDU, 0xFFFFU, [UROpType.R16IX, UROpType.R16BC, UROpType.NONE]),
716 // ADD IX,DE
717 URAsmCmdInfo(URMnemo.ADD, 0x19DDU, 0xFFFFU, [UROpType.R16IX, UROpType.R16DE, UROpType.NONE]),
718 // ADD IX,IX
719 URAsmCmdInfo(URMnemo.ADD, 0x29DDU, 0xFFFFU, [UROpType.R16IX, UROpType.R16IX, UROpType.NONE]),
720 // ADD IX,SP
721 URAsmCmdInfo(URMnemo.ADD, 0x39DDU, 0xFFFFU, [UROpType.R16IX, UROpType.R16SP, UROpType.NONE]),
722 // ADD IY,BC
723 URAsmCmdInfo(URMnemo.ADD, 0x09FDU, 0xFFFFU, [UROpType.R16IY, UROpType.R16BC, UROpType.NONE]),
724 // ADD IY,DE
725 URAsmCmdInfo(URMnemo.ADD, 0x19FDU, 0xFFFFU, [UROpType.R16IY, UROpType.R16DE, UROpType.NONE]),
726 // ADD IY,IY
727 URAsmCmdInfo(URMnemo.ADD, 0x29FDU, 0xFFFFU, [UROpType.R16IY, UROpType.R16IY, UROpType.NONE]),
728 // ADD IY,SP
729 URAsmCmdInfo(URMnemo.ADD, 0x39FDU, 0xFFFFU, [UROpType.R16IY, UROpType.R16SP, UROpType.NONE]),
731 // LD XH,r8
732 URAsmCmdInfo(URMnemo.LD, 0x60DDU, 0xF8FFU, [UROpType.R8XH, UROpType.R8NOM, UROpType.NONE]),
733 // LD XL,r8
734 URAsmCmdInfo(URMnemo.LD, 0x68DDU, 0xF8FFU, [UROpType.R8XL, UROpType.R8NOM, UROpType.NONE]),
735 // LD (IX+d),r8
736 URAsmCmdInfo(URMnemo.LD, 0x70DDU, 0xF8FFU, [UROpType.MIX, UROpType.R8NOM, UROpType.NONE]),
737 // LD YH,r8
738 URAsmCmdInfo(URMnemo.LD, 0x60FDU, 0xF8FFU, [UROpType.R8YH, UROpType.R8NOM, UROpType.NONE]),
739 // LD YL,r8
740 URAsmCmdInfo(URMnemo.LD, 0x68FDU, 0xF8FFU, [UROpType.R8YL, UROpType.R8NOM, UROpType.NONE]),
741 // LD (IY+d),r8
742 URAsmCmdInfo(URMnemo.LD, 0x70FDU, 0xF8FFU, [UROpType.MIY, UROpType.R8NOM, UROpType.NONE]),
744 // LD r8,XH
745 URAsmCmdInfo(URMnemo.LD, 0x44DDU, 0xC7FFU, [UROpType.R83NOM, UROpType.R8XH, UROpType.NONE]),
746 // LD r8,XL
747 URAsmCmdInfo(URMnemo.LD, 0x45DDU, 0xC7FFU, [UROpType.R83NOM, UROpType.R8XL, UROpType.NONE]),
748 // LD r8,(IX+d)
749 URAsmCmdInfo(URMnemo.LD, 0x46DDU, 0xC7FFU, [UROpType.R83NOM, UROpType.MIX, UROpType.NONE]),
751 // LD r8,YH
752 URAsmCmdInfo(URMnemo.LD, 0x44FDU, 0xC7FFU, [UROpType.R83NOM, UROpType.R8YH, UROpType.NONE]),
753 // LD r8,YL
754 URAsmCmdInfo(URMnemo.LD, 0x45FDU, 0xC7FFU, [UROpType.R83NOM, UROpType.R8YL, UROpType.NONE]),
755 // LD r8,(IY+d)
756 URAsmCmdInfo(URMnemo.LD, 0x46FDU, 0xC7FFU, [UROpType.R83NOM, UROpType.MIY, UROpType.NONE]),
758 // instructions w/o operands or with unchangeable operands
759 URAsmCmdInfo(URMnemo.NOP, 0x00U, 0xFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
760 URAsmCmdInfo(URMnemo.RLCA, 0x07U, 0xFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
761 URAsmCmdInfo(URMnemo.RRCA, 0x0FU, 0xFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
762 URAsmCmdInfo(URMnemo.RLA, 0x17U, 0xFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
763 URAsmCmdInfo(URMnemo.RRA, 0x1FU, 0xFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
764 URAsmCmdInfo(URMnemo.DAA, 0x27U, 0xFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
765 URAsmCmdInfo(URMnemo.CPL, 0x2FU, 0xFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
766 URAsmCmdInfo(URMnemo.SCF, 0x37U, 0xFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
767 URAsmCmdInfo(URMnemo.CCF, 0x3FU, 0xFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
768 URAsmCmdInfo(URMnemo.HALT, 0x76U, 0xFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
769 URAsmCmdInfo(URMnemo.RET, 0xC9U, 0xFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
770 URAsmCmdInfo(URMnemo.EXX, 0xD9U, 0xFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
771 URAsmCmdInfo(URMnemo.DI, 0xF3U, 0xFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
772 URAsmCmdInfo(URMnemo.EI, 0xFBU, 0xFFU, [UROpType.NONE, UROpType.NONE, UROpType.NONE]),
773 // LD SP,HL
774 URAsmCmdInfo(URMnemo.LD, 0xF9U, 0xFFU, [UROpType.R16SP, UROpType.R16HL, UROpType.NONE]),
775 // EX AF,AF'
776 URAsmCmdInfo(URMnemo.EX, 0x08U, 0xFFU, [UROpType.R16AF, UROpType.R16AFX, UROpType.NONE]),
777 // EX AF',AF (ditto)
778 URAsmCmdInfo(URMnemo.EX, 0x08U, 0xFFU, [UROpType.R16AFX, UROpType.R16AF, UROpType.NONE]),
779 // EX (SP),HL
780 URAsmCmdInfo(URMnemo.EX, 0xE3U, 0xFFU, [UROpType.MSP, UROpType.R16HL, UROpType.NONE]),
781 // EX HL,(SP) (ditto)
782 URAsmCmdInfo(URMnemo.EX, 0xE3U, 0xFFU, [UROpType.R16HL, UROpType.MSP, UROpType.NONE]),
783 // EX DE,HL
784 URAsmCmdInfo(URMnemo.EX, 0xEBU, 0xFFU, [UROpType.R16DE, UROpType.R16HL, UROpType.NONE]),
785 // EX HL,DE (ditto)
786 URAsmCmdInfo(URMnemo.EX, 0xEBU, 0xFFU, [UROpType.R16HL, UROpType.R16DE, UROpType.NONE]),
787 // JP (HL)
788 URAsmCmdInfo(URMnemo.JP, 0xE9U, 0xFFU, [UROpType.MHL, UROpType.NONE, UROpType.NONE]),
789 // JP HL
790 URAsmCmdInfo(URMnemo.JP, 0xE9U, 0xFFU, [UROpType.R16HL, UROpType.NONE, UROpType.NONE]),
791 // JP nnnn
792 URAsmCmdInfo(URMnemo.JP, 0xC3U, 0xFFU, [UROpType.ADDR16, UROpType.NONE, UROpType.NONE]),
793 // CALL nnnn
794 URAsmCmdInfo(URMnemo.CALL, 0xCDU, 0xFFU, [UROpType.ADDR16, UROpType.NONE, UROpType.NONE]),
795 // OUT (n),A
796 URAsmCmdInfo(URMnemo.OUT, 0xD3U, 0xFFU, [UROpType.PORTIMM, UROpType.R8A, UROpType.NONE]),
797 // IN A,(n)
798 URAsmCmdInfo(URMnemo.IN, 0xDBU, 0xFFU, [UROpType.R8A, UROpType.PORTIMM, UROpType.NONE]),
800 // ADD A,nn
801 URAsmCmdInfo(URMnemo.ADD, 0xC6U, 0xFFU, [UROpType.R8A, UROpType.IMM8, UROpType.NONE]),
802 // ADD nn (ditto)
803 URAsmCmdInfo(URMnemo.ADD, 0xC6U, 0xFFU, [UROpType.IMM8, UROpType.NONE, UROpType.NONE]),
804 // ADC A,nn
805 URAsmCmdInfo(URMnemo.ADC, 0xCEU, 0xFFU, [UROpType.R8A, UROpType.IMM8, UROpType.NONE]),
806 // ADC nn (ditto)
807 URAsmCmdInfo(URMnemo.ADC, 0xCEU, 0xFFU, [UROpType.IMM8, UROpType.NONE, UROpType.NONE]),
808 // SUB nn
809 URAsmCmdInfo(URMnemo.SUB, 0xD6U, 0xFFU, [UROpType.IMM8, UROpType.NONE, UROpType.NONE]),
810 // SUB A,nn (ditto)
811 URAsmCmdInfo(URMnemo.SUB, 0xD6U, 0xFFU, [UROpType.R8A, UROpType.IMM8, UROpType.NONE]),
812 // SBC A,nn
813 URAsmCmdInfo(URMnemo.SBC, 0xDEU, 0xFFU, [UROpType.R8A, UROpType.IMM8, UROpType.NONE]),
814 // SBC nn (ditto)
815 URAsmCmdInfo(URMnemo.SBC, 0xDEU, 0xFFU, [UROpType.IMM8, UROpType.NONE, UROpType.NONE]),
816 // AND nn
817 URAsmCmdInfo(URMnemo.AND, 0xE6U, 0xFFU, [UROpType.IMM8, UROpType.NONE, UROpType.NONE]),
818 // AND A,nn (ditto)
819 URAsmCmdInfo(URMnemo.AND, 0xE6U, 0xFFU, [UROpType.R8A, UROpType.IMM8, UROpType.NONE]),
820 // XOR nn
821 URAsmCmdInfo(URMnemo.XOR, 0xEEU, 0xFFU, [UROpType.IMM8, UROpType.NONE, UROpType.NONE]),
822 // XOR A,nn (ditto)
823 URAsmCmdInfo(URMnemo.XOR, 0xEEU, 0xFFU, [UROpType.R8A, UROpType.IMM8, UROpType.NONE]),
824 // OR nn
825 URAsmCmdInfo(URMnemo.OR, 0xF6U, 0xFFU, [UROpType.IMM8, UROpType.NONE, UROpType.NONE]),
826 // OR A,nn (ditto)
827 URAsmCmdInfo(URMnemo.OR, 0xF6U, 0xFFU, [UROpType.R8A, UROpType.IMM8, UROpType.NONE]),
828 // CP nn
829 URAsmCmdInfo(URMnemo.CP, 0xFEU, 0xFFU, [UROpType.IMM8, UROpType.NONE, UROpType.NONE]),
830 // CP A,nn (ditto)
831 URAsmCmdInfo(URMnemo.CP, 0xFEU, 0xFFU, [UROpType.R8A, UROpType.IMM8, UROpType.NONE]),
832 // LD (BC),A
833 URAsmCmdInfo(URMnemo.LD, 0x02U, 0xFFU, [UROpType.MBC, UROpType.R8A, UROpType.NONE]),
834 // LD (DE),A
835 URAsmCmdInfo(URMnemo.LD, 0x12U, 0xFFU, [UROpType.MDE, UROpType.R8A, UROpType.NONE]),
836 // LD A,(BC)
837 URAsmCmdInfo(URMnemo.LD, 0x0AU, 0xFFU, [UROpType.R8A, UROpType.MBC, UROpType.NONE]),
838 // LD A,(DE)
839 URAsmCmdInfo(URMnemo.LD, 0x1AU, 0xFFU, [UROpType.R8A, UROpType.MDE, UROpType.NONE]),
840 // LD (nnnn),HL
841 URAsmCmdInfo(URMnemo.LD, 0x22U, 0xFFU, [UROpType.MEM16, UROpType.R16HL, UROpType.NONE]),
842 // LD HL,(nnnn)
843 URAsmCmdInfo(URMnemo.LD, 0x2AU, 0xFFU, [UROpType.R16HL, UROpType.MEM16, UROpType.NONE]),
844 // LD (nnnn),A
845 URAsmCmdInfo(URMnemo.LD, 0x32U, 0xFFU, [UROpType.MEM16, UROpType.R8A, UROpType.NONE]),
846 // LD A,(nnnn)
847 URAsmCmdInfo(URMnemo.LD, 0x3AU, 0xFFU, [UROpType.R8A, UROpType.MEM16, UROpType.NONE]),
848 // DJNZ d
849 URAsmCmdInfo(URMnemo.DJNZ, 0x10U, 0xFFU, [UROpType.ADDR8, UROpType.NONE, UROpType.NONE]),
850 // JR d
851 URAsmCmdInfo(URMnemo.JR, 0x18U, 0xFFU, [UROpType.ADDR8, UROpType.NONE, UROpType.NONE]),
853 // ADD HL,r16
854 URAsmCmdInfo(URMnemo.ADD, 0x09U, 0xCFU, [UROpType.R16HL, UROpType.R16, UROpType.NONE]),
856 // ADD A,r8
857 URAsmCmdInfo(URMnemo.ADD, 0x80U, 0xF8U, [UROpType.R8A, UROpType.R8, UROpType.NONE]),
858 // ADD r8
859 URAsmCmdInfo(URMnemo.ADD, 0x80U, 0xF8U, [UROpType.R8, UROpType.NONE, UROpType.NONE]),
860 // ADC A,r8
861 URAsmCmdInfo(URMnemo.ADC, 0x88U, 0xF8U, [UROpType.R8A, UROpType.R8, UROpType.NONE]),
862 // ADC r8
863 URAsmCmdInfo(URMnemo.ADC, 0x88U, 0xF8U, [UROpType.R8, UROpType.NONE, UROpType.NONE]),
864 // SUB r8
865 URAsmCmdInfo(URMnemo.SUB, 0x90U, 0xF8U, [UROpType.R8, UROpType.NONE, UROpType.NONE]),
866 // SUB A,r8
867 URAsmCmdInfo(URMnemo.SUB, 0x90U, 0xF8U, [UROpType.R8A, UROpType.R8, UROpType.NONE]),
868 // SBC A,r8
869 URAsmCmdInfo(URMnemo.SBC, 0x98U, 0xF8U, [UROpType.R8A, UROpType.R8, UROpType.NONE]),
870 // SBC r8
871 URAsmCmdInfo(URMnemo.SBC, 0x98U, 0xF8U, [UROpType.R8, UROpType.NONE, UROpType.NONE]),
872 // AND r8
873 URAsmCmdInfo(URMnemo.AND, 0xA0U, 0xF8U, [UROpType.R8, UROpType.NONE, UROpType.NONE]),
874 // AND A,r8
875 URAsmCmdInfo(URMnemo.AND, 0xA0U, 0xF8U, [UROpType.R8A, UROpType.R8, UROpType.NONE]),
876 // XOR r8
877 URAsmCmdInfo(URMnemo.XOR, 0xA8U, 0xF8U, [UROpType.R8, UROpType.NONE, UROpType.NONE]),
878 // XOR A,r8
879 URAsmCmdInfo(URMnemo.XOR, 0xA8U, 0xF8U, [UROpType.R8A, UROpType.R8, UROpType.NONE]),
880 // OR r8
881 URAsmCmdInfo(URMnemo.OR, 0xB0U, 0xF8U, [UROpType.R8, UROpType.NONE, UROpType.NONE]),
882 // OR A,r8
883 URAsmCmdInfo(URMnemo.OR, 0xB0U, 0xF8U, [UROpType.R8A, UROpType.R8, UROpType.NONE]),
884 // CP r8
885 URAsmCmdInfo(URMnemo.CP, 0xB8U, 0xF8U, [UROpType.R8, UROpType.NONE, UROpType.NONE]),
886 // CP A,r8
887 URAsmCmdInfo(URMnemo.CP, 0xB8U, 0xF8U, [UROpType.R8A, UROpType.R8, UROpType.NONE]),
889 // JR cc,d
890 URAsmCmdInfo(URMnemo.JR, 0x20U, 0xE7U, [UROpType.JRCOND, UROpType.ADDR8, UROpType.NONE]),
892 // POP r16
893 URAsmCmdInfo(URMnemo.POP, 0xC1U, 0xCFU, [UROpType.R16A, UROpType.NONE, UROpType.NONE]),
894 // PUSH r16
895 URAsmCmdInfo(URMnemo.PUSH, 0xC5U, 0xCFU, [UROpType.R16A, UROpType.NONE, UROpType.NONE]),
896 // RET cc
897 URAsmCmdInfo(URMnemo.RET, 0xC0U, 0xC7U, [UROpType.COND, UROpType.NONE, UROpType.NONE]),
898 // JP cc,nnnn
899 URAsmCmdInfo(URMnemo.JP, 0xC2U, 0xC7U, [UROpType.COND, UROpType.ADDR16, UROpType.NONE]),
900 // CALL cc,nnnn
901 URAsmCmdInfo(URMnemo.CALL, 0xC4U, 0xC7U, [UROpType.COND, UROpType.ADDR16, UROpType.NONE]),
902 // RST n
903 URAsmCmdInfo(URMnemo.RST, 0xC7U, 0xC7U, [UROpType.RSTDEST, UROpType.NONE, UROpType.NONE]),
905 // INC r8
906 URAsmCmdInfo(URMnemo.INC, 0x04U, 0xC7U, [UROpType.R83, UROpType.NONE, UROpType.NONE]),
907 // DEC r8
908 URAsmCmdInfo(URMnemo.DEC, 0x05U, 0xC7U, [UROpType.R83, UROpType.NONE, UROpType.NONE]),
909 // LD r8,nn
910 URAsmCmdInfo(URMnemo.LD, 0x06U, 0xC7U, [UROpType.R83, UROpType.IMM8, UROpType.NONE]),
912 // LD r16,nnnn
913 URAsmCmdInfo(URMnemo.LD, 0x01U, 0xCFU, [UROpType.R16, UROpType.IMM16, UROpType.NONE]),
914 // INC r16
915 URAsmCmdInfo(URMnemo.INC, 0x03U, 0xCFU, [UROpType.R16, UROpType.NONE, UROpType.NONE]),
916 // DEC r16
917 URAsmCmdInfo(URMnemo.DEC, 0x0BU, 0xCFU, [UROpType.R16, UROpType.NONE, UROpType.NONE]),
919 // LD r8,r8
920 URAsmCmdInfo(URMnemo.LD, 0x40U, 0xC0U, [UROpType.R83, UROpType.R8, UROpType.NONE]),
922 // syntetics
923 // LD BC,BC
924 URAsmCmdInfo(URMnemo.LD, 0x4940U, 0xFFFFU, [UROpType.R16BC, UROpType.R16BC, UROpType.NONE]),
925 // LD BC,DE
926 URAsmCmdInfo(URMnemo.LD, 0x4B42U, 0xFFFFU, [UROpType.R16BC, UROpType.R16DE, UROpType.NONE]),
927 // LD BC,HL
928 URAsmCmdInfo(URMnemo.LD, 0x4D44U, 0xFFFFU, [UROpType.R16BC, UROpType.R16HL, UROpType.NONE]),
929 // LD DE,BC
930 URAsmCmdInfo(URMnemo.LD, 0x5950U, 0xFFFFU, [UROpType.R16DE, UROpType.R16BC, UROpType.NONE]),
931 // LD DE,DE
932 URAsmCmdInfo(URMnemo.LD, 0x5B52U, 0xFFFFU, [UROpType.R16DE, UROpType.R16DE, UROpType.NONE]),
933 // LD DE,HL
934 URAsmCmdInfo(URMnemo.LD, 0x5D54U, 0xFFFFU, [UROpType.R16DE, UROpType.R16HL, UROpType.NONE]),
935 // LD HL,BC
936 URAsmCmdInfo(URMnemo.LD, 0x6960U, 0xFFFFU, [UROpType.R16HL, UROpType.R16BC, UROpType.NONE]),
937 // LD HL,DE
938 URAsmCmdInfo(URMnemo.LD, 0x6B62U, 0xFFFFU, [UROpType.R16HL, UROpType.R16DE, UROpType.NONE]),
939 // LD HL,HL
940 URAsmCmdInfo(URMnemo.LD, 0x6D64U, 0xFFFFU, [UROpType.R16HL, UROpType.R16HL, UROpType.NONE]),
944 // instructions unaffected by DD/FF prefixes
945 // this table used by disassembler (we don't want to eat prefixes)
946 static immutable ubyte[256] URIgnoreDDFDTable = [
947 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
948 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
949 1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,
950 1,1,1,1,0,0,0,1,1,0,1,1,1,1,1,1,
951 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
952 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
953 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
954 0,0,0,0,0,0,1,0,1,1,1,1,0,0,0,1,
955 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
956 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
957 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
958 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,1,
959 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,
960 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
961 1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,
962 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
966 private:
967 // ////////////////////////////////////////////////////////////////////////// //
968 // disassembler
970 private bool isDDSensitive (uint c) pure nothrow @trusted @nogc { pragma(inline, true); return (URIgnoreDDFDTable.ptr[c&0xff] != 0); }
972 // opc: opcode
973 // nextW: next 2 bytes (after opcode)
974 // idx: I? displacement
975 void urdisOp2Str (ref URDisState ctx, int op, ushort addr, ubyte opc, ushort nextW, int idx, scope URFindLabelByAddrCB findLabel) {
976 import core.stdc.stdio : sprintf;
977 //int add, ismem = 0;
978 bool ismem = false;
979 switch (op) {
980 case UROpType.NONE: break;
981 case UROpType.IMM8: ctx.putxnum("#%02X", "%u", nextW&0xFF); break;
982 case UROpType.IMM16: ctx.putxnum("#%04X", "%u", nextW); break;
983 case UROpType.ADDR8:
984 addr += 2;
985 nextW &= 0xFFU;
986 int add = (nextW < 128 ? nextW : (cast(int)nextW)-256);
987 addr += add;
988 nextW = addr;
989 goto case;
990 case UROpType.ADDR16:
991 if (findLabel !is null) {
992 auto lbl = findLabel(nextW);
993 if (lbl.length) { ctx.put(lbl); break; }
994 lbl = findLabel(cast(ushort)(nextW-1));
995 if (lbl.length) { ctx.put(lbl); ctx.put("-1"); break; }
996 lbl = findLabel(cast(ushort)(nextW-2));
997 if (lbl.length) { ctx.put(lbl); ctx.put("-2"); break; }
998 lbl = findLabel(cast(ushort)(nextW+1));
999 if (lbl.length) { ctx.put(lbl); ctx.put("+1"); break; }
1000 lbl = findLabel(cast(ushort)(nextW+2));
1001 if (lbl.length) { ctx.put(lbl); ctx.put("+2"); break; }
1003 ctx.putxnum("#%04X", "%u", nextW);
1004 break;
1005 case UROpType.MEM16:
1006 ismem = true;
1007 ctx.put("(");
1008 goto case UROpType.ADDR16;
1009 case UROpType.R8:
1010 case UROpType.R8NOM:
1011 ctx.put(URRegs8.ptr[opc&0x07UL]);
1012 break;
1013 case UROpType.R83:
1014 case UROpType.R83NOM:
1015 ctx.put(URRegs8.ptr[(opc>>3)&0x07UL]);
1016 break;
1017 case UROpType.PORTC: ctx.put("(C)"); break;
1018 case UROpType.PORTIMM: ctx.putxnum("(#%02X)", "(%u)", nextW&0xFF); break;
1019 case UROpType.R8XH: ctx.put("XH"); break;
1020 case UROpType.R8XL: ctx.put("XL"); break;
1021 case UROpType.R8YH: ctx.put("YH"); break;
1022 case UROpType.R8YL: ctx.put("YL"); break;
1023 case UROpType.R8A: ctx.put("A"); break;
1024 case UROpType.R8R: ctx.put("R"); break;
1025 case UROpType.R8I: ctx.put("I"); break;
1026 case UROpType.R16: ctx.put(URRegs16.ptr[(opc>>4)&0x03UL]); break;
1027 case UROpType.R16A: ctx.put(URRegs16a.ptr[(opc>>4)&0x03UL]); break;
1028 case UROpType.R16AF: ctx.put("AF"); break;
1029 case UROpType.R16AFX: ctx.put("AF'"); break;
1030 case UROpType.R16BC: ctx.put("BC"); break;
1031 case UROpType.R16DE: ctx.put("DE"); break;
1032 case UROpType.R16HL: ctx.put("HL"); break;
1033 case UROpType.R16IX: ctx.put("IX"); break;
1034 case UROpType.R16IY: ctx.put("IY"); break;
1035 case UROpType.R16SP: ctx.put("SP"); break;
1036 case UROpType.MSP: ctx.put("(SP)"); break;
1037 case UROpType.MBC: ctx.put("(BC)"); break;
1038 case UROpType.MDE: ctx.put("(DE)"); break;
1039 case UROpType.MHL: ctx.put("(HL)"); break;
1040 case UROpType.MIX0: ctx.put("(IX)"); break;
1041 case UROpType.MIY0: ctx.put("(IY)"); break;
1042 case UROpType.MIX:
1043 ctx.put("(IX");
1044 if (idx > 0) ctx.put("+");
1045 ctx.putnum("%d", idx);
1046 ctx.put(")");
1047 break;
1048 case UROpType.MIY:
1049 ctx.put("(IY");
1050 if (idx > 0) ctx.put("+");
1051 ctx.putnum("%d", idx);
1052 ctx.put(")");
1053 break;
1054 case UROpType.JRCOND: ctx.put(URCond.ptr[(opc>>3)&0x03U]); break;
1055 case UROpType.COND: ctx.put(URCond.ptr[(opc>>3)&0x07U]); break;
1056 case UROpType.BITN: ctx.putnum("%u", (opc>>3)&0x07U); break;
1057 case UROpType.RSTDEST: ctx.putxnum("#%02X", "%u", opc&0x38U); break;
1058 case UROpType.IM0: ctx.put("0"); break;
1059 case UROpType.IM1: ctx.put("1"); break;
1060 case UROpType.IM2: ctx.put("2"); break;
1061 default: assert(0); // we should never come here
1063 if (ismem) ctx.put(")");
1067 /// find the corresponding record in URInstructionsTable
1068 public int urDisassembleFind (ref URDisState ctx, ushort addr, scope URGetByteCB getByte) {
1069 ubyte[8] buf;
1070 if (getByte is null) return -1;
1071 foreach (immutable n, ref ubyte b; buf[]) b = getByte(cast(ushort)(addr+n));
1072 if (buf.ptr[0] == 0xDDU || buf.ptr[0] == 0xFDU) {
1073 // dummy prefix
1074 if (isDDSensitive(buf.ptr[1])) return (buf.ptr[0] == 0xDDU ? 0 : 1);
1076 uint ci = buf.ptr[0]|(buf.ptr[1]<<8)|(buf.ptr[2]<<16)|(buf.ptr[3]<<24);
1077 for (int opn = 0; opn < URInstructionsTable.length; ++opn) {
1078 // find command
1079 while (opn < URInstructionsTable.length && (ci&URInstructionsTable.ptr[opn].mask) != URInstructionsTable.ptr[opn].code) ++opn;
1080 if (opn >= URInstructionsTable.length) return (buf.ptr[0] == 0xEDU ? -2 : -1);
1081 // skip prefixes, determine command length
1082 uint f = URInstructionsTable.ptr[opn].mask;
1083 uint c = URInstructionsTable.ptr[opn].code;
1084 int bpos = 0;
1085 for (;; ++bpos) {
1086 if ((f&0xFFUL) != 0xFFUL) break;
1087 ubyte b = c&0xFFUL;
1088 if (b != 0xFDU && b != 0xDDU && b != 0xEDU && b != 0xCBU) break;
1089 f >>= 8;
1090 c >>= 8;
1092 // are there any operands?
1093 if (URInstructionsTable.ptr[opn].ops.ptr[0] == UROpType.NONE) return opn;
1094 // is this CB-prefixed?
1095 if ((URInstructionsTable.ptr[opn].code&0xFFFFUL) == 0xCBDDUL ||
1096 (URInstructionsTable.ptr[opn].code&0xFFFFUL) == 0xCBFDUL) ++bpos; // skip displacement
1097 ubyte opc = buf.ptr[bpos];
1098 // do operands
1099 foreach (immutable n; 0..4) {
1100 if (n == 4) return cast(int)opn;
1101 auto op = URInstructionsTable.ptr[opn].ops.ptr[n];
1102 if (op == UROpType.NONE) return cast(int)opn;
1103 // check for valid operand
1104 if (op == UROpType.R8NOM) {
1105 if ((opc&0x07U) == 6) break; // bad (HL)
1107 if (op == UROpType.R83NOM) {
1108 if (((opc>>3)&0x07U) == 6) break; // bad (HL)
1112 return -1;
1116 /// length of the instruction with the given record (returned from `urDisassembleFind()`)
1117 public int urDisassembleLength (int idx) {
1118 if (idx == -2) return 2;
1119 if (idx < 0 || idx >= URInstructionsTable.length) return 1;
1120 if (idx < 2) return 1;
1121 int res = 0;
1122 uint m = URInstructionsTable.ptr[idx].mask;
1123 uint c = URInstructionsTable.ptr[idx].code;
1124 // I?/CB?
1125 //if ((m&0xFFFFUL) == 0xFFFFUL && (c&0xFF00UL) == 0xCBUL && ((c&0xFFUL) == 0xDDUL || (c&0xFFUL) == 0xFDUL)) return 4;
1126 // skip prefixes, determine command length
1127 for (;;) {
1128 ubyte b;
1129 if ((m&0xFFUL) != 0xFFUL) break;
1130 b = c&0xFFUL;
1131 if (b != 0xFDU && b != 0xDDU && b != 0xEDU && b != 0xCBU) break;
1132 m >>= 8;
1133 c >>= 8; ++res;
1135 // is this CB-prefixed?
1136 if ((URInstructionsTable.ptr[idx].code&0xFFFFUL) == 0xCBDDUL ||
1137 (URInstructionsTable.ptr[idx].code&0xFFFFUL) == 0xCBFDUL) m >>= 8;
1138 // count opcodes
1139 while (m != 0) { m >>= 8; ++res; }
1140 // process operands
1141 oploop: foreach (immutable n; 0..3) {
1142 auto op = URInstructionsTable.ptr[idx].ops.ptr[n];
1143 switch (op) {
1144 case UROpType.NONE: break oploop;
1145 // command with displacement
1146 case UROpType.MIX: case UROpType.MIY: ++res; break;
1147 // command has immediate operand
1148 case UROpType.IMM8: case UROpType.ADDR8: case UROpType.PORTIMM: ++res; break;
1149 case UROpType.IMM16: case UROpType.ADDR16: case UROpType.MEM16: res += 2; break;
1150 default: break;
1153 return res;
1157 /// disassemble one command, return command length or <0 on error
1158 public int urDisassembleOne (ref URDisState ctx, ushort addr, scope URGetByteCB getByte, scope URFindLabelByAddrCB findLabel=null) {
1159 ubyte[8] buf;
1160 int res, idx = 0;
1161 uint ci, f, c;
1162 ubyte opc;
1163 int bpos, opn, op;
1164 ushort nextW;
1166 ctx.clear();
1167 ctx.resetbuf();
1168 scope(failure) ctx.clear();
1170 if (getByte is null) return -1;
1171 foreach (immutable n, ref ubyte b; buf[]) b = getByte(cast(ushort)(addr+n));
1173 if (buf.ptr[0] == 0xDDU || buf.ptr[0] == 0xFDU) {
1174 // dummy prefix
1175 if (isDDSensitive(buf.ptr[1])) {
1176 ctx.iidx = (buf.ptr[0] == 0xDDU ? 0 : 1);
1177 ctx.put(URMnemonics.ptr[buf.ptr[0] == 0xDDU ? URMnemo.NOPX : URMnemo.NOPY]);
1178 ctx.mnem = ctx.buf[0..ctx.bufpos];
1179 return 1;
1181 // take possible I? displacement
1182 idx = cast(byte)buf.ptr[2];
1184 ci = buf.ptr[0]|(buf.ptr[1]<<8)|(buf.ptr[2]<<16)|(buf.ptr[3]<<24);
1185 for (opn = 0; opn < URInstructionsTable.length; ++opn) {
1186 res = 0;
1187 ctx.resetbuf();
1188 // find command
1189 for (; opn < URInstructionsTable.length && (ci&URInstructionsTable.ptr[opn].mask) != URInstructionsTable.ptr[opn].code; ++opn) {}
1190 if (opn >= URInstructionsTable.length) {
1191 ctx.iidx = -1;
1192 ctx.put("DB\t");
1193 ctx.mnem = ctx.buf[0..ctx.bufpos-1];
1194 auto opstp = ctx.bufpos;
1195 if (buf.ptr[0] == 0xEDU) {
1196 ctx.putxnum("#%02X,", "%u,", buf.ptr[0]);
1197 ctx.ops[0] = ctx.buf[opstp..ctx.bufpos-1];
1198 opstp = ctx.bufpos;
1199 ctx.putxnum("#%02X", "%u", buf.ptr[1]);
1200 ctx.ops[1] = ctx.buf[opstp..ctx.bufpos];
1201 return 2;
1202 } else {
1203 ctx.putxnum("#%02X", "%u", buf.ptr[0]);
1204 ctx.ops[0] = ctx.buf[opstp..ctx.bufpos];
1205 return 1;
1208 // skip prefixes, determine command length
1209 f = URInstructionsTable.ptr[opn].mask;
1210 c = URInstructionsTable.ptr[opn].code;
1211 for (bpos = 0; ; ++bpos) {
1212 if ((f&0xFFUL) != 0xFFUL) break;
1213 ubyte b = c&0xFFUL;
1214 if (b != 0xFDU && b != 0xDDU && b != 0xEDU && b != 0xCBU) break;
1215 f >>= 8;
1216 c >>= 8;
1217 ++res;
1219 // is this CB-prefixed?
1220 if ((URInstructionsTable.ptr[opn].code&0xFFFFUL) == 0xCBDDUL ||
1221 (URInstructionsTable.ptr[opn].code&0xFFFFUL) == 0xCBFDUL) f >>= 8;
1222 while (f != 0) { f >>= 8; ++res; }
1223 // copy mnemonics
1224 ctx.iidx = opn;
1225 ctx.put(URMnemonics.ptr[URInstructionsTable.ptr[opn].mnemo]);
1226 ctx.mnem = ctx.buf[0..ctx.bufpos];
1227 // are there any operands?
1228 if (URInstructionsTable.ptr[opn].ops.ptr[0] == UROpType.NONE) return res;
1229 // is this CB-prefixed?
1230 if (((URInstructionsTable.ptr[opn].code&0xFFFFUL) == 0xCBDDUL) ||
1231 ((URInstructionsTable.ptr[opn].code&0xFFFFUL) == 0xCBFDUL)) {
1232 ++bpos; // skip displacement
1233 } else {
1234 if ((URInstructionsTable.ptr[opn].ops.ptr[0] == UROpType.MIX || URInstructionsTable.ptr[opn].ops.ptr[0] == UROpType.MIY) &&
1235 URInstructionsTable.ptr[opn].ops.ptr[1] == UROpType.IMM8 &&
1236 URInstructionsTable.ptr[opn].ops.ptr[2] == UROpType.NONE) ++bpos; // skip displacement
1238 opc = buf.ptr[bpos++];
1239 nextW = cast(ushort)(buf.ptr[bpos]|(buf.ptr[bpos+1]<<8));
1240 // do operands
1241 foreach (immutable n; 0..4) {
1242 if (n == 3) return res;
1243 op = URInstructionsTable.ptr[opn].ops.ptr[n];
1244 if (op == UROpType.NONE) return res;
1245 // check for valid operand
1246 if (op == UROpType.R8NOM) {
1247 if ((opc&0x07U) == 6) break; // bad (HL)
1249 if (op == UROpType.R83NOM) {
1250 if (((opc>>3)&0x07U) == 6) break; // bad (HL)
1252 // command with displacement?
1253 if (op == UROpType.MIX || op == UROpType.MIY) ++res;
1254 // command has immediate operand?
1255 if (op == UROpType.IMM8 || op == UROpType.ADDR8 || op == UROpType.PORTIMM) ++res;
1256 if (op == UROpType.IMM16 || op == UROpType.ADDR16 || op == UROpType.MEM16) res += 2;
1257 // add delimiter
1258 ctx.put(n ? "," : "\t");
1259 // decode operand
1260 auto opstp = ctx.bufpos;
1261 urdisOp2Str(ctx, op, addr, opc, nextW, idx, findLabel);
1262 ctx.ops[n] = ctx.buf[opstp..ctx.bufpos];
1265 return -1;
1269 // ////////////////////////////////////////////////////////////////////////// //
1271 public struct URAsmParser {
1272 private:
1273 const(char)[] text;
1274 uint textpos;
1276 pure nothrow @trusted @nogc:
1277 this (const(char)[] atext) { text = atext; }
1278 void setup (const(char)[] atext) { text = atext; }
1279 URAsmParser opSlice (uint lo, uint hi) pure const {
1280 if (hi <= lo || lo >= text.length) return URAsmParser.init;
1281 if (hi > text.length) hi = cast(uint)text.length;
1282 return URAsmParser(text[lo..hi]);
1284 @property uint tell () pure const { pragma(inline, true); return textpos; }
1285 void seek (uint pos) pure { pragma(inline, true); if (pos > text.length) pos = cast(uint)text.length; textpos = pos; }
1286 URAsmParser slice (uint len) pure const {
1287 if (len > text.length) len = cast(uint)text.length;
1288 if (textpos >= text.length) return URAsmParser.init;
1289 if (text.length-textpos < len) len = cast(uint)text.length-textpos;
1290 return URAsmParser(text[textpos..textpos+len]);
1292 @property bool empty () const { pragma(inline, true); return (textpos >= text.length); }
1293 @property bool eol () const { pragma(inline, true); return (textpos >= text.length || text.ptr[textpos] == ':' || text.ptr[textpos] == ';'); }
1294 @property char front () const { pragma(inline, true); return (textpos < text.length ? text.ptr[textpos] : '\x00'); }
1295 @property char ahead () const { pragma(inline, true); return (textpos+1 < text.length ? text.ptr[textpos+1] : '\x00'); }
1296 @property char peek (uint ofs) const { pragma(inline, true); return (ofs < text.length && textpos+ofs < text.length ? text.ptr[textpos+ofs] : '\x00'); }
1297 void popFront () { if (textpos < text.length) ++textpos; }
1298 void skipBlanks () { while (textpos < text.length && text.ptr[textpos] <= ' ') ++textpos; }
1300 static:
1301 char tolower (char ch) { pragma(inline, true); return (ch >= 'A' && ch <= 'Z' ? cast(char)(ch+32) : ch); }
1302 char toupper (char ch) { pragma(inline, true); return (ch >= 'a' && ch <= 'z' ? cast(char)(ch-32) : ch); }
1303 bool isdigit (char ch) { pragma(inline, true); return (ch >= '0' && ch <= '9'); }
1304 bool isalpha (char ch) { pragma(inline, true); return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); }
1305 bool isalnum (char ch) { pragma(inline, true); return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9'); }
1307 int digitInBase (char ch, int base=10) {
1308 pragma(inline, true);
1309 return
1310 ch >= '0' && ch <= '9' && ch-'0' < base ? ch-'0' :
1311 base > 10 && ch >= 'A' && ch < 'Z' && ch-'A'+10 < base ? ch-'A'+10 :
1312 base > 10 && ch >= 'a' && ch < 'z' && ch-'a'+10 < base ? ch-'a'+10 :
1316 bool strEquCI (const(char)[] s0, const(char)[] s1) {
1317 if (s0.length != s1.length) return false;
1318 foreach (immutable idx, char c0; s0) {
1319 if (c0 >= 'a' && c0 <= 'z') c0 -= 32;
1320 char c1 = s1.ptr[idx];
1321 if (c1 >= 'a' && c1 <= 'z') c1 -= 32;
1322 if (c0 != c1) return false;
1324 return true;
1329 // ////////////////////////////////////////////////////////////////////////// //
1331 public bool delegate (const(char)[] lbl) nothrow @trusted @nogc urIsValidLabelName;
1333 static this () { import std.functional : toDelegate; urIsValidLabelName = toDelegate(&urIsValidLabelNameDef); }
1336 public bool urIsValidLabelNameDef (const(char)[] lbl) nothrow @trusted @nogc {
1337 if (lbl.length == 0) return false;
1338 if (URAsmParser.isalpha(lbl.ptr[0])) {
1339 foreach (char ch; lbl[1..$]) {
1340 if (ch < 128 && !URAsmParser.isalnum(ch) && ch != '$' && ch != '.' && ch != '_' && ch != '@') return false;
1342 foreach (string s; URMnemonics) if (URAsmParser.strEquCI(s, lbl)) return false;
1343 foreach (string s; URRegs8) if (URAsmParser.strEquCI(s, lbl)) return false;
1344 foreach (string s; URRegs16) if (URAsmParser.strEquCI(s, lbl)) return false;
1345 foreach (string s; URRegs16a) if (URAsmParser.strEquCI(s, lbl)) return false;
1346 foreach (string s; URCond) if (URAsmParser.strEquCI(s, lbl)) return false;
1347 if (URAsmParser.strEquCI("DB", lbl)) return false;
1348 if (URAsmParser.strEquCI("DW", lbl)) return false;
1349 if (URAsmParser.strEquCI("DS", lbl)) return false;
1350 if (URAsmParser.strEquCI("DZ", lbl)) return false;
1351 if (URAsmParser.strEquCI("DEFB", lbl)) return false;
1352 if (URAsmParser.strEquCI("DEFW", lbl)) return false;
1353 if (URAsmParser.strEquCI("DEFS", lbl)) return false;
1354 if (URAsmParser.strEquCI("DEFZ", lbl)) return false;
1355 if (URAsmParser.strEquCI("DEFM", lbl)) return false;
1356 if (URAsmParser.strEquCI("ORG", lbl)) return false;
1357 if (URAsmParser.strEquCI("ENT", lbl)) return false;
1358 } else {
1359 if (lbl.ptr[0] != '$' && lbl.ptr[0] != '.' && lbl.ptr[0] != '_' && lbl.ptr[0] != '@') return false;
1360 foreach (char ch; lbl[1..$]) {
1361 if (ch < 128 && !URAsmParser.isalnum(ch) && ch != '$' && ch != '.' && ch != '_' && ch != '@') return false;
1364 return true;
1368 // ////////////////////////////////////////////////////////////////////////// //
1369 /// fixup types
1370 public enum URAsmFixup {
1371 None, ///
1372 Word, ///
1373 LoByte, ///
1374 HiByte, ///
1378 public int delegate (const(char)[] lbl, ushort addr, out bool defined, out URAsmFixup fixtype) urFindLabelByNameFn; ///
1380 /// pr is right after '(', spaces skipped; should parse all args and stop on closing ')'
1381 public void delegate (const(char)[] lbl, ref URAsmParser pr, out URExprValue res, ushort addr) urCallFunctionFn;
1383 /// get "special value" started with '*' or '=', pr is right after valtype, spaces skipped; should parse whole name
1384 public void delegate (char valtype, ref URAsmParser pr, out URExprValue res, ushort addr) urGetValueFn;
1387 enum URAsmExprError {
1388 None,
1389 Eos,
1390 Div0,
1391 Parens,
1392 Number,
1393 String,
1394 Label,
1395 Term,
1396 Func,
1397 Type,
1398 Marg,
1399 Fixup,
1400 Mem,
1401 Oper,
1404 static immutable string[URAsmExprError.max+1] URAsmExprErrorMsg = [
1405 "no error",
1406 "unexpected end of text",
1407 "division by zero",
1408 "unbalanced parentheses",
1409 "invalid number",
1410 "invalid string",
1411 "invalid label",
1412 "term expected",
1413 "function expected",
1414 "invalid type",
1415 "invalid special argument",
1416 "invalid fixup",
1417 "invalid memory access",
1418 "invalid operand",
1421 void EERROR (URAsmExprError code) { throw new Exception("urasm expression error: "~URAsmExprErrorMsg[code]); }
1424 // ////////////////////////////////////////////////////////////////////////// //
1425 /// expression parser
1426 public struct URExprValue {
1427 int val; ///
1428 char[] str; /// null: non-string value; val is set for strings too
1429 URAsmFixup fixuptype; /// can be changed only by low() and high()
1430 bool defined = true;
1432 @property bool isString () const pure nothrow @trusted @nogc { pragma(inline, true); return (str !is null); } ///
1434 void clear () pure nothrow @trusted @nogc { val = 0; str = null; fixuptype = URAsmFixup.None; defined = true; } ///
1437 struct URAOperand {
1438 UROpType type; // deduced type
1439 char[] s; // string value, if any
1440 int v; // expression value or index
1441 bool defined; // expression defined?
1442 URAsmFixup fixuptype;
1444 string toString () const {
1445 import std.format : format;
1446 return "<%s>: v=%d; defined=%s".format(type, v, defined);
1451 struct ExprInfo {
1452 ushort addr; // current address
1453 bool defined; // true: all used labels are defined
1454 bool logDone;
1455 bool logRes;
1459 // do math; op0 is the result
1460 alias ExprDoItFn = void function (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei);
1462 struct ExprOperator {
1463 char sn; // short name or 0
1464 string ln; // long name or null if `sn`!=0
1465 int prio; // priority
1466 ExprDoItFn doer;
1470 void propagateFixup (ref URExprValue op0, ref URExprValue op1) {
1471 if (op0.fixuptype == URAsmFixup.None) {
1472 op0.fixuptype = op1.fixuptype;
1473 } else if (op0.fixuptype == URAsmFixup.Word) {
1474 if (op1.fixuptype != URAsmFixup.None) op0.fixuptype = op1.fixuptype;
1475 } else if (op1.fixuptype != URAsmFixup.None && op0.fixuptype != op1.fixuptype) {
1476 op1.clear;
1477 op0.clear;
1478 EERROR(URAsmExprError.Fixup);
1483 void mdoBitNot (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei) {
1484 op0.val = ~op0.val;
1485 op0.fixuptype = URAsmFixup.None;
1487 void mdoLogNot (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei) {
1488 op0.val = !op0.val;
1489 op0.fixuptype = URAsmFixup.None;
1491 void mdoBitAnd (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei) {
1492 op0.val &= op1.val;
1493 if (op1.val == 0) op0.fixuptype = URAsmFixup.None;
1494 else if (op0.fixuptype != URAsmFixup.None) {
1495 switch (op1.val) {
1496 case 0x00ff: op0.fixuptype = (op0.fixuptype == URAsmFixup.Word ? URAsmFixup.LoByte : URAsmFixup.None); break;
1497 case 0xff00: op0.fixuptype = (op0.fixuptype == URAsmFixup.Word ? URAsmFixup.HiByte : URAsmFixup.None); break;
1498 default: break;
1500 } else {
1501 propagateFixup(op0, op1);
1504 void mdoBitOr (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei) { op0.val |= op1.val; op0.fixuptype = URAsmFixup.None; }
1505 void mdoBitXor (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei) { op0.val ^= op1.val; op0.fixuptype = URAsmFixup.None; }
1506 void mdoLShift (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei) { op0.val <<= op1.val; op0.fixuptype = URAsmFixup.None; }
1507 void mdoRShift (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei) { op0.val >>= op1.val; }
1508 void mdoMul (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei) { op0.val *= op1.val; op0.fixuptype = URAsmFixup.None; }
1509 void mdoDiv (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei) { if (op1.val == 0) EERROR(URAsmExprError.Div0); op0.val /= op1.val; op0.fixuptype = URAsmFixup.None; }
1510 void mdoMod (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei) { if (op1.val == 0) EERROR(URAsmExprError.Div0); op0.val %= op1.val; op0.fixuptype = URAsmFixup.None; }
1511 void mdoAdd (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei) { op0.val += op1.val; propagateFixup(op0, op1); }
1512 void mdoSub (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei) { op0.val -= op1.val; propagateFixup(op0, op1); }
1513 void mdoLogLess (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei) { op0.val = op0.val < op1.val; op0.fixuptype = URAsmFixup.None; }
1514 void mdoLogGreat (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei) { op0.val = op0.val > op1.val; op0.fixuptype = URAsmFixup.None; }
1515 void mdoLogEqu (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei) { op0.val = op0.val == op1.val; op0.fixuptype = URAsmFixup.None; }
1516 void mdoLogNEqu (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei) { op0.val = op0.val != op1.val; op0.fixuptype = URAsmFixup.None; }
1517 void mdoLogLEqu (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei) { op0.val = op0.val >= op1.val; op0.fixuptype = URAsmFixup.None; }
1518 void mdoLogGEqu (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei) { op0.val = op0.val >= op1.val; op0.fixuptype = URAsmFixup.None; }
1519 void mdoLogAnd (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei) { ei.logRes = op0.val = (op0.val && op1.val); if (!op0.val) ei.logDone = 1; op0.fixuptype = URAsmFixup.None; }
1520 void mdoLogOr (ref URExprValue op0, ref URExprValue op1, ref ExprInfo ei) { ei.logRes = op0.val = (op0.val || op1.val); if (op0.val) ei.logDone = 1; op0.fixuptype = URAsmFixup.None; }
1523 // priority level 1 -- opertiors like "." and "[]", function calls
1524 // priority level 2 -- unary opertiors like "!" and "~"
1525 // short forms must be put before long
1526 // priorities must be sorted
1527 static immutable ExprOperator[23] operators = [
1528 ExprOperator('~', null, 2, &mdoBitNot),
1529 ExprOperator('!', null, 2, &mdoLogNot),
1531 ExprOperator(0, "<<", 3, &mdoLShift),
1532 ExprOperator(0, ">>", 3, &mdoRShift),
1534 ExprOperator('&', null, 4, &mdoBitAnd),
1536 ExprOperator('|', null, 5, &mdoBitOr),
1537 ExprOperator('^', null, 5, &mdoBitXor),
1539 ExprOperator('*', null, 6, &mdoMul),
1540 ExprOperator('/', null, 6, &mdoDiv),
1541 ExprOperator('%', null, 6, &mdoMod),
1543 ExprOperator('+', null, 7, &mdoAdd),
1544 ExprOperator('-', null, 7, &mdoSub),
1546 ExprOperator(0, "&&", 8, &mdoLogAnd),
1548 ExprOperator(0, "||", 9, &mdoLogOr),
1550 ExprOperator('<', null, 10, &mdoLogLess),
1551 ExprOperator('>', null, 10, &mdoLogGreat),
1552 ExprOperator('=', null, 10, &mdoLogEqu),
1553 ExprOperator(0, "==", 10, &mdoLogEqu),
1554 ExprOperator(0, "!=", 10, &mdoLogNEqu),
1555 ExprOperator(0, "<>", 10, &mdoLogNEqu),
1556 ExprOperator(0, "<=", 10, &mdoLogLEqu),
1557 ExprOperator(0, ">=", 10, &mdoLogGEqu),
1558 ExprOperator(0, null, -1, null),
1560 enum UnaryPriority = 2;
1561 enum MaxPriority = operators[$-2].prio;
1562 // WARNING! keep this in sync with operator table!
1563 enum LogAndPriority = 8;
1564 enum LogOrPriority = 9;
1567 ///////////////////////////////////////////////////////////////////////////////
1568 // expression parser engine
1570 // quote is not skipped
1571 void parseStr (ref URAsmParser pr, ref URExprValue res) {
1572 int base, f, n;
1573 char[] rstr;
1574 if (pr.empty) EERROR(URAsmExprError.Eos);
1575 char qch = pr.front;
1576 pr.popFront();
1577 for (;;) {
1578 if (pr.empty) EERROR(URAsmExprError.Eos);
1579 char ch = pr.front;
1580 pr.popFront();
1581 if (ch == '\\') {
1582 if (pr.empty) EERROR(URAsmExprError.Eos);
1583 ch = pr.front;
1584 pr.popFront();
1585 switch (ch) {
1586 case 'a': rstr ~= '\a'; break;
1587 case 'b': rstr ~= '\b'; break;
1588 case 'e': rstr ~= '\x1b'; break;
1589 case 'f': rstr ~= '\f'; break;
1590 case 'n': rstr ~= '\n'; break;
1591 case 'r': rstr ~= '\r'; break;
1592 case 't': rstr ~= '\t'; break;
1593 case 'v': rstr ~= '\v'; break;
1594 case 'z': rstr ~= '\0'; break;
1595 case 'x': case 'X': // hex
1596 base = 16;
1597 f = 2;
1598 donum:
1599 if (pr.empty) EERROR(URAsmExprError.Eos);
1600 for (n = 0; f > 0; --f) {
1601 if (pr.empty) break;
1602 int d = URAsmParser.digitInBase(pr.front, base);
1603 if (d < 0) break;
1604 n *= base;
1605 n += d;
1607 rstr ~= cast(char)n;
1608 break;
1609 case '0': // octal
1610 base = 8;
1611 f = 4;
1612 goto donum;
1613 case '1': .. case '9': // decimal
1614 base = 10;
1615 f = 3;
1616 goto donum;
1617 default: rstr ~= ch; break; // others
1619 } else {
1620 if (ch == qch) break;
1621 rstr ~= ch;
1624 if (rstr.length == 0) { rstr.length = 1; rstr.length = 0; } // so it won't be null
1625 res.str = rstr;
1629 void parseNumber (ref URAsmParser pr, ref URExprValue res) {
1630 int n = 0, base = 0, nhex = 0;
1631 bool wantTrailingH = false;
1632 if (pr.empty) EERROR(URAsmExprError.Eos);
1633 res.val = 0;
1634 char ch = pr.front;
1635 switch (ch) {
1636 case '0':
1637 // this can be 0x prefix
1638 switch (pr.ahead) {
1639 case '0': .. case '9': EERROR(URAsmExprError.Number); assert(0); // no octals
1640 case 'B': case 'b': base = 2; pr.popFront(); pr.popFront(); break;
1641 case 'O': case 'o': base = 8; pr.popFront(); pr.popFront(); break;
1642 case 'D': case 'd': base = 10; pr.popFront(); pr.popFront(); break;
1643 case 'X': case 'x': base = 16; pr.popFront(); pr.popFront(); break;
1644 default: break;
1646 break;
1647 case '%': base = 2; pr.popFront(); break;
1648 case '#': case '$': base = 16; pr.popFront(); break;
1649 case '&':
1650 switch (pr.ahead) {
1651 case 'B': case 'b': base = 2; pr.popFront(); pr.popFront(); break;
1652 case 'O': case 'o': base = 8; pr.popFront(); pr.popFront(); break;
1653 case 'D': case 'd': base = 10; pr.popFront(); pr.popFront(); break;
1654 case 'X': case 'x': base = 16; pr.popFront(); pr.popFront(); break;
1655 case 'H': case 'h': base = 16; pr.popFront(); pr.popFront(); break;
1656 default: EERROR(URAsmExprError.Number); // no octals
1658 break;
1659 default: break;
1661 // if base != 0, parse in dec and in hex, and check last char
1662 if (pr.empty) EERROR(URAsmExprError.Eos);
1663 if (URAsmParser.digitInBase(pr.front, (base ? base : 16)) < 0) EERROR(URAsmExprError.Number);
1664 while (!pr.empty) {
1665 int d;
1666 ch = pr.front;
1667 if (ch == '_') { pr.popFront(); continue; }
1668 if (base) {
1669 d = URAsmParser.digitInBase(ch, base);
1670 if (d < 0) break;
1671 n = n*base+d;
1672 } else {
1673 if (wantTrailingH) {
1674 d = URAsmParser.digitInBase(ch, 16);
1675 if (d < 0) break;
1676 nhex = nhex*16+d;
1677 } else {
1678 d = URAsmParser.digitInBase(ch, 10);
1679 if (d < 0) {
1680 d = URAsmParser.digitInBase(ch, 16);
1681 if (d < 0) break;
1682 wantTrailingH = true;
1683 nhex = nhex*16+d;
1684 } else {
1685 n = n*10+d;
1686 nhex = nhex*16+d;
1690 pr.popFront();
1692 if (base == 0) {
1693 if (wantTrailingH) {
1694 if (pr.empty || (pr.front != 'H' && pr.front != 'h')) EERROR(URAsmExprError.Number);
1695 n = nhex;
1696 } else {
1697 if (!pr.empty && (pr.front == 'H' || pr.front == 'h')) { n = nhex; pr.popFront(); }
1700 res.val = n;
1704 void getAddr (const(char)[] lbl, ref URExprValue res, ref ExprInfo ei) {
1705 if (urFindLabelByNameFn is null) EERROR(URAsmExprError.Label);
1706 res.fixuptype = URAsmFixup.None;
1707 res.val = urFindLabelByNameFn(lbl, ei.addr, res.defined, res.fixuptype);
1708 if (!res.defined) ei.defined = false;
1712 // throw on invalid label, or return slice of `dbuf`
1713 char[] readLabelName (char[] dbuf, ref URAsmParser pr) {
1714 uint dbpos = 0;
1715 while (!pr.empty) {
1716 char ch = pr.front;
1717 if (URAsmParser.isalnum(ch) || ch == '$' || ch == '.' || ch == '_' || ch == '@' || ch >= 128) {
1718 if (dbpos >= dbuf.length) EERROR(URAsmExprError.Label);
1719 dbuf[dbpos++] = ch;
1720 pr.popFront();
1721 } else {
1722 break;
1725 if (dbpos < 1 || !urIsValidLabelName(dbuf[0..dbpos])) EERROR(URAsmExprError.Label);
1726 return dbuf[0..dbpos];
1730 void term (ref URAsmParser pr, ref URExprValue res, ref ExprInfo ei) {
1731 res.str = null;
1732 pr.skipBlanks();
1733 if (pr.empty) EERROR(URAsmExprError.Eos);
1734 char ch = pr.front;
1735 switch (ch) {
1736 case '[': case '(':
1737 pr.popFront();
1738 ch = (ch == '[' ? ']' : ')');
1739 expression(pr, res, ei);
1740 if (pr.empty) EERROR(URAsmExprError.Eos);
1741 if (pr.front != ch) EERROR(URAsmExprError.Parens);
1742 pr.popFront();
1743 break;
1744 case '0': .. case '9': case '#': case '%':
1745 parseNumber(pr, res);
1746 break;
1747 case '$':
1748 if (URAsmParser.digitInBase(pr.ahead, 16) >= 0) {
1749 parseNumber(pr, res);
1750 } else {
1751 res.val = ei.addr;
1752 res.fixuptype = URAsmFixup.Word;
1753 pr.popFront();
1755 break;
1756 case '&':
1757 switch (pr.ahead) {
1758 case 'H': case 'h':
1759 case 'O': case 'o':
1760 case 'B': case 'b':
1761 case 'D': case 'd':
1762 parseNumber(pr, res);
1763 return;
1764 default: break;
1766 goto default;
1767 case '"': // char or 2 chars
1768 case '\'': // char or 2 reversed chars
1769 res.val = 0;
1770 parseStr(pr, res);
1771 if (res.str.length == 1) {
1772 res.val = cast(ubyte)res.str[0];
1773 } else if (res.str.length >= 2) {
1774 res.val = (cast(ubyte)res.str[0])<<(ch == '"' ? 0 : 8);
1775 res.val |= (cast(ubyte)res.str[1])<<(ch == '"' ? 8 : 0);
1777 break;
1778 case ';':
1779 case ':':
1780 EERROR(URAsmExprError.Term);
1781 assert(0);
1782 case ')':
1783 case ']':
1784 return;
1785 case '=':
1786 case '*':
1787 pr.popFront();
1788 if (pr.empty || pr.front <= ' ' || pr.eol) EERROR(URAsmExprError.Marg);
1789 if (urGetValueFn !is null) {
1790 urGetValueFn(ch, pr, res, ei.addr);
1791 } else {
1792 EERROR(URAsmExprError.Marg);
1794 break;
1795 default:
1796 char[64] lblbuf;
1797 auto lbl = readLabelName(lblbuf[], pr);
1798 if (lbl is null) EERROR(URAsmExprError.Label);
1799 pr.skipBlanks();
1800 if (!pr.empty && pr.front == '(') {
1801 // function call
1802 pr.popFront();
1803 pr.skipBlanks();
1804 if (urCallFunctionFn !is null) {
1805 urCallFunctionFn(lbl, pr, res, ei.addr);
1806 pr.skipBlanks();
1807 if (!pr.empty && pr.front == ')') { pr.popFront(); break; }
1809 EERROR(URAsmExprError.Func);
1810 } else {
1811 // just a label
1812 if (!ei.logDone) getAddr(lbl, res, ei);
1814 break;
1819 const(ExprOperator)* getOperator (int prio, ref URAsmParser pr, ref ExprInfo ei) {
1820 if (pr.empty) return null;
1821 char opc = pr.front;
1822 int oplen = 1;
1823 const(ExprOperator)* res = operators.ptr, cur;
1824 for (cur = res, res = null; cur.prio >= 0; ++cur) {
1825 if (cur.sn) {
1826 if (oplen > 1) continue;
1827 if (opc == cur.sn) res = cur;
1828 } else {
1829 int l = cast(int)cur.ln.length;
1830 if (l < oplen) continue;
1831 bool ok = true;
1832 foreach (immutable idx; 0..l) if (pr.peek(idx) != cur.ln[idx]) { ok = false; break; }
1833 if (ok) { res = cur; oplen = l; }
1836 if (res !is null && res.prio != prio) res = null;
1837 if (res) foreach (immutable _; 0..oplen) pr.popFront(); // eat operator
1838 return res;
1842 void checkNotStr (ref URExprValue res, ref URExprValue o1) {
1843 if ((res.str !is null && res.str.length > 2) || (o1.str !is null && o1.str.length > 2)) {
1844 o1.clear();
1845 res.clear();
1846 EERROR(URAsmExprError.Type);
1851 void expressionDo (int prio, ref URAsmParser pr, ref URExprValue res, ref ExprInfo ei) {
1852 const(ExprOperator)* op;
1853 URExprValue o1;
1854 pr.skipBlanks();
1855 if (pr.empty) EERROR(URAsmExprError.Eos);
1856 if (pr.front == ')' || pr.front == ']') return;
1857 if (prio <= 0) { term(pr, res, ei); return; }
1858 o1.clear();
1859 if (prio == UnaryPriority) {
1860 bool wasIt = false;
1861 for (;;) {
1862 pr.skipBlanks();
1863 if ((op = getOperator(prio, pr, ei)) is null) break;
1864 expressionDo(prio, pr, res, ei);
1865 if (!ei.logDone) {
1866 checkNotStr(res, o1);
1867 op.doer(res, o1, ei);
1868 } else {
1869 res.fixuptype = URAsmFixup.None;
1870 res.val = ei.logRes;
1872 wasIt = true;
1874 if (!wasIt) expressionDo(prio-1, pr, res, ei);
1875 return;
1877 // first operand
1878 expressionDo(prio-1, pr, res, ei);
1879 // go on
1880 bool old = ei.logDone;
1881 for (;;) {
1882 pr.skipBlanks();
1883 if (pr.empty || pr.front == ';' || pr.front == ':' || pr.front == ')' || pr.front == ']') break;
1884 if ((op = getOperator(prio, pr, ei)) is null) break;
1885 if (!ei.logDone) {
1886 switch (prio) {
1887 case LogAndPriority: // &&
1888 if (!res.val) { ei.logDone = true; ei.logRes = 0; }
1889 break;
1890 case LogOrPriority: // ||
1891 if (res.val) { ei.logDone = true; ei.logRes = (res.val != 0); }
1892 break;
1893 default: break;
1896 expressionDo(prio-1, pr, o1, ei); // second operand
1897 if (!ei.logDone) {
1898 checkNotStr(res, o1);
1899 op.doer(res, o1, ei);
1900 o1.clear();
1901 } else {
1902 res.fixuptype = URAsmFixup.None;
1903 res.val = ei.logRes;
1906 ei.logDone = old;
1910 void expression (ref URAsmParser pr, ref URExprValue res, ref ExprInfo ei) {
1911 bool neg = false;
1912 pr.skipBlanks();
1913 if (pr.empty) EERROR(URAsmExprError.Eos);
1914 switch (pr.front) {
1915 case '-': neg = true; pr.popFront(); break;
1916 case '+': neg = false; pr.popFront(); break;
1917 default: break;
1919 if (pr.empty) EERROR(URAsmExprError.Eos);
1920 expressionDo(MaxPriority, pr, res, ei);
1921 if (neg) res.val = -(res.val);
1922 pr.skipBlanks(); // for convenience
1926 public void urExpressionEx (ref URAsmParser pr, ref URExprValue res, ushort addr) {
1927 ExprInfo ei;
1928 res.clear();
1929 if (pr.empty) EERROR(URAsmExprError.Eos);
1930 ei.addr = addr;
1931 ei.defined = true;
1932 ei.logDone = false;
1933 ei.logRes = 0;
1934 expression(pr, res, ei);
1935 res.defined = ei.defined;
1939 public int urExpression (ref URAsmParser pr, ushort addr, out bool defined, out URAsmFixup fixuptype) {
1940 URExprValue res;
1941 defined = true;
1942 fixuptype = URAsmFixup.None;
1943 urExpressionEx(pr, res, addr);
1944 fixuptype = res.fixuptype;
1945 defined = res.defined;
1946 if (res.str !is null && res.str.length > 2) EERROR(URAsmExprError.Type);
1947 return res.val;
1951 // ////////////////////////////////////////////////////////////////////////// //
1952 // operand parser
1954 // possible types:
1955 // UROpType.MHL
1956 // UROpType.MDE
1957 // UROpType.MBC
1958 // UROpType.MSP
1959 // UROpType.MIX
1960 // UROpType.MIY
1961 // UROpType.MIX0 ; no displacement
1962 // UROpType.MIY0 ; no displacement
1963 // UROpType.MEM16
1964 // UROpType.R8I
1965 // UROpType.R8R
1966 // UROpType.R8: v is 8-bit register index; warning: v==1 may be UROpType.COND(3)
1967 // UROpType.COND: v is condition index (warning: v==3 may be UROpType.R8(1))
1968 // UROpType.R16HL
1969 // UROpType.R16DE
1970 // UROpType.R16BC
1971 // UROpType.R16AF
1972 // UROpType.R16SP
1973 // UROpType.R16IX
1974 // UROpType.R16IY
1975 // UROpType.R16AFX
1976 // UROpType.R8XH
1977 // UROpType.R8YH
1978 // UROpType.R8XL
1979 // UROpType.R8YL
1980 // UROpType.IMM16
1981 // trailing blanks skipped
1982 void urNextOperand (ref URAsmParser pr, out URAOperand op, ushort addr) {
1983 op.defined = true;
1984 pr.skipBlanks();
1985 if (pr.eol) return;
1986 op.fixuptype = URAsmFixup.None;
1988 UROpType ot = UROpType.NONE;
1989 // memory access?
1990 if (pr.front == '(') {
1991 pr.popFront();
1992 pr.skipBlanks();
1993 if (pr.empty) EERROR(URAsmExprError.Mem);
1994 // (C) is special
1995 if ((pr.front == 'C' || pr.front == 'c') && (pr.ahead <= ' ' || pr.ahead == ')')) {
1996 op.type = UROpType.PORTC;
1997 pr.popFront();
1998 pr.skipBlanks();
1999 if (pr.empty || pr.front != ')') EERROR(URAsmExprError.Mem);
2000 pr.popFront();
2001 return;
2003 // check registers
2004 bool doPop = true;
2005 if ((pr.front == 'H' || pr.front == 'h') && (pr.ahead == 'L' || pr.ahead == 'l')) ot = UROpType.MHL;
2006 else if ((pr.front == 'D' || pr.front == 'd') && (pr.ahead == 'E' || pr.ahead == 'e')) ot = UROpType.MDE;
2007 else if ((pr.front == 'B' || pr.front == 'b') && (pr.ahead == 'C' || pr.ahead == 'c')) ot = UROpType.MBC;
2008 else if ((pr.front == 'S' || pr.front == 's') && (pr.ahead == 'P' || pr.ahead == 'p')) ot = UROpType.MSP;
2009 else if ((pr.front == 'I' || pr.front == 'i') && (pr.ahead == 'X' || pr.ahead == 'x'|| pr.ahead == 'Y' || pr.ahead == 'y')) {
2010 doPop = false;
2011 ot = (pr.ahead == 'X' || pr.ahead == 'x' ? UROpType.MIX : UROpType.MIY);
2012 pr.popFront();
2013 pr.popFront();
2014 pr.skipBlanks();
2015 if (pr.empty) EERROR(URAsmExprError.Mem);
2016 if (pr.front == '+' || pr.front == '-') {
2017 // expression
2018 op.v = urExpression(pr, addr, op.defined, op.fixuptype);
2019 if (op.defined) {
2020 if (op.v < byte.min || op.v > byte.max) EERROR(URAsmExprError.Mem);
2021 } else {
2022 op.v = 1;
2024 } else {
2025 ot = (ot == UROpType.MIX ? UROpType.MIX0 : UROpType.MIY0);
2027 } else {
2028 // expression
2029 doPop = false;
2030 op.v = urExpression(pr, addr, op.defined, op.fixuptype);
2031 ot = UROpType.MEM16;
2033 if (ot == UROpType.NONE) EERROR(URAsmExprError.Mem);
2034 if (doPop) { pr.popFront(); pr.popFront(); }
2035 pr.skipBlanks();
2036 //conwriteln("empty=", pr.empty);
2037 //conwriteln("front=", pr.front);
2038 if (pr.empty || pr.front != ')') EERROR(URAsmExprError.Mem);
2039 pr.popFront();
2040 op.type = ot;
2041 pr.skipBlanks();
2042 return;
2045 // registers?
2046 uint tklen = 0;
2048 void doCheck (string tk, UROpType type, int vv=0) {
2049 foreach (immutable idx, char ch; tk[]) {
2050 char pc = pr.peek(cast(uint)idx);
2051 if (pc >= 'a' && pc <= 'z') pc -= 32;
2052 if (pc != ch) return;
2054 ot = type;
2055 tklen = cast(uint)tk.length;
2056 op.v = vv;
2059 doCheck("I", UROpType.R8I);
2060 doCheck("R", UROpType.R8R);
2062 doCheck("B", UROpType.R8, 0);
2063 doCheck("C", UROpType.R8, 1); //WARNING! this may be condition as well
2064 doCheck("D", UROpType.R8, 2);
2065 doCheck("E", UROpType.R8, 3);
2066 doCheck("H", UROpType.R8, 4);
2067 doCheck("L", UROpType.R8, 5);
2068 doCheck("A", UROpType.R8, 7);
2070 doCheck("Z", UROpType.COND, 1);
2071 //doCheck("C", UROpType.COND, 3);
2072 doCheck("P", UROpType.COND, 6);
2073 doCheck("M", UROpType.COND, 7);
2075 doCheck("NZ", UROpType.COND, 0);
2076 doCheck("NC", UROpType.COND, 2);
2077 doCheck("PO", UROpType.COND, 4);
2078 doCheck("PE", UROpType.COND, 5);
2080 doCheck("HL", UROpType.R16HL);
2081 doCheck("DE", UROpType.R16DE);
2082 doCheck("BC", UROpType.R16BC);
2083 doCheck("AF", UROpType.R16AF);
2084 doCheck("SP", UROpType.R16SP);
2085 doCheck("IX", UROpType.R16IX);
2086 doCheck("IY", UROpType.R16IY);
2087 doCheck("XH", UROpType.R8XH);
2088 doCheck("YH", UROpType.R8YH);
2089 doCheck("XL", UROpType.R8XL);
2090 doCheck("YL", UROpType.R8YL);
2092 doCheck("AF'", UROpType.R16AFX);
2093 doCheck("AFX", UROpType.R16AFX);
2094 doCheck("IXH", UROpType.R8XH);
2095 doCheck("IYH", UROpType.R8YH);
2096 doCheck("IXL", UROpType.R8XL);
2097 doCheck("IYL", UROpType.R8YL);
2099 if (ot != UROpType.NONE) {
2100 // got register or another reserved thing?
2101 char ch = pr.peek(tklen);
2102 if (ch == ';' || ch == ':' || ch == ',' || ch <= ' ') {
2103 op.type = ot;
2104 foreach (immutable _; 0..tklen) pr.popFront();
2105 pr.skipBlanks();
2106 return;
2110 // expression
2111 op.v = urExpression(pr, addr, op.defined, op.fixuptype);
2112 op.type = UROpType.IMM16;
2113 pr.skipBlanks();
2117 // ////////////////////////////////////////////////////////////////////////// //
2118 // assembler
2119 bool urIsValidOp (ref URAOperand op, ushort addr, int opt) {
2120 if (opt == UROpType.NONE) return (op.type == UROpType.NONE);
2121 if (op.type == UROpType.NONE) return false;
2122 final switch (opt) {
2123 case UROpType.IMM8:
2124 if (op.type != UROpType.IMM16) return false;
2125 if (op.v < byte.min || op.v > ubyte.max) return false;
2126 return true;
2127 case UROpType.IMM16:
2128 if (op.type != UROpType.IMM16) return false;
2129 if (op.v < short.min || op.v > ushort.max) return false;
2130 return true;
2131 case UROpType.ADDR16:
2132 if (op.type != UROpType.IMM16) return false;
2133 if (op.v < short.min || op.v > ushort.max) return false;
2134 return true;
2135 case UROpType.ADDR8:
2136 if (op.type != UROpType.IMM16) return false;
2137 if (op.v < short.min || op.v > ushort.max) return false;
2138 if (op.defined) {
2139 int dist = op.v-(addr+2);
2140 if (dist < byte.min || dist > byte.max) return false;
2142 return true;
2143 case UROpType.MEM16:
2144 if (op.type != UROpType.MEM16) return false;
2145 return true;
2146 case UROpType.R8:
2147 case UROpType.R83:
2148 if (op.type == UROpType.MHL) { op.v = 6; return true; } // (HL) is ok here
2149 goto case;
2150 case UROpType.R8NOM:
2151 case UROpType.R83NOM:
2152 // fix "C" condition
2153 if (op.type == UROpType.COND && op.v == 3) { op.type = UROpType.R8; op.v = 1; }
2154 if (op.type != UROpType.R8) return false;
2155 return true;
2156 case UROpType.PORTC:
2157 return (op.type == UROpType.PORTC);
2158 case UROpType.PORTIMM:
2159 if (op.type != UROpType.MEM16) return false; // mem, 'cause (n)
2160 if (op.defined && (op.v < ubyte.min || op.v > ubyte.max)) return false;
2161 return true;
2162 case UROpType.R8XH:
2163 case UROpType.R8XL:
2164 case UROpType.R8YH:
2165 case UROpType.R8YL:
2166 case UROpType.R8R:
2167 case UROpType.R8I:
2168 case UROpType.R16AF:
2169 case UROpType.R16AFX:
2170 case UROpType.R16BC:
2171 case UROpType.R16DE:
2172 case UROpType.R16HL:
2173 case UROpType.R16IX:
2174 case UROpType.R16IY:
2175 case UROpType.R16SP:
2176 case UROpType.MSP:
2177 case UROpType.MBC:
2178 case UROpType.MDE:
2179 case UROpType.MHL:
2180 case UROpType.MIX0:
2181 case UROpType.MIY0:
2182 return (op.type == opt);
2183 case UROpType.R8A:
2184 return (op.type == UROpType.R8 && op.v == 7);
2185 case UROpType.R16:
2186 if (op.type == UROpType.R16BC) { op.v = 0; return true; }
2187 if (op.type == UROpType.R16DE) { op.v = 1; return true; }
2188 if (op.type == UROpType.R16HL) { op.v = 2; return true; }
2189 if (op.type == UROpType.R16SP) { op.v = 3; return true; }
2190 return false;
2191 case UROpType.R16A:
2192 if (op.type == UROpType.R16BC) { op.v = 0; return true; }
2193 if (op.type == UROpType.R16DE) { op.v = 1; return true; }
2194 if (op.type == UROpType.R16HL) { op.v = 2; return true; }
2195 if (op.type == UROpType.R16AF) { op.v = 3; return true; }
2196 return false;
2197 case UROpType.MIX:
2198 if (op.type != UROpType.MIX && op.type != UROpType.MIX0) return false;
2199 if (op.defined && (op.v < byte.min || op.v > byte.max)) return false;
2200 return true;
2201 case UROpType.MIY:
2202 if (op.type != UROpType.MIY && op.type != UROpType.MIY0) return false;
2203 if (op.defined && (op.v < byte.min || op.v > byte.max)) return false;
2204 return true;
2205 case UROpType.JRCOND:
2206 // fix "C" condition
2207 if (op.type == UROpType.R8 && op.v == 1) { op.type = UROpType.COND; op.v = 3; }
2208 if (op.type != UROpType.COND) return false;
2209 return (op.v >= 0 && op.v <= 3);
2210 case UROpType.COND:
2211 // fix "C" condition
2212 if (op.type == UROpType.R8 && op.v == 1) { op.type = UROpType.COND; op.v = 3; }
2213 return (op.type == UROpType.COND);
2214 case UROpType.BITN:
2215 if (op.type != UROpType.IMM16) return false;
2216 if (op.v < 0 || op.v > 7) return false;
2217 return true;
2218 case UROpType.RSTDEST:
2219 if (op.type != UROpType.IMM16) return false;
2220 if (op.v < 0 || op.v > 0x38 || (op.v&0x07) != 0) return false;
2221 return true;
2222 case UROpType.IM0:
2223 if (op.type != UROpType.IMM16) return false;
2224 if (op.v != 0) return false;
2225 return true;
2226 case UROpType.IM1:
2227 if (op.type != UROpType.IMM16) return false;
2228 if (op.v != 1) return false;
2229 return true;
2230 case UROpType.IM2:
2231 if (op.type != UROpType.IMM16) return false;
2232 if (op.v != 2) return false;
2233 return true;
2235 return false;
2239 /// buffer to keep assembled code
2240 public struct URAsmBuf {
2241 ubyte[] dest; /// can be of any length, will grow
2242 URAsmFixup[] dfixs; /// fixups
2243 uint destused;
2244 ubyte[] code; /// result of `urAssembleOne()` call, always slice of `dest`
2245 URAsmFixup[] fixup; /// result of `urAssembleOne()` call, always slice of `dfixs`
2247 void reset () pure nothrow @safe @nogc { destused = 0; code = null; fixup = null; }
2249 void putByte (ubyte v, URAsmFixup fix=URAsmFixup.None) pure nothrow @safe {
2250 if (destused >= dest.length) dest.length += 64; // way too much! ;-)
2251 if (destused >= dfixs.length) dfixs.length += 64; // way too much! ;-)
2252 dest[destused] = v;
2253 dfixs[destused] = fix;
2254 ++destused;
2255 code = dest[0..destused];
2256 fixup = dfixs[0..destused];
2259 void putWord (ushort v, URAsmFixup fix=URAsmFixup.None) pure nothrow @safe {
2260 putByte(v&0xff, fix);
2261 putByte((v>>8)&0xff, URAsmFixup.None);
2266 /// understands comments
2267 void urAssembleOne (ref URAsmBuf dbuf, ref URAsmParser pr, ushort addr) {
2268 char[6] mnem;
2269 int tkn;
2270 URAOperand[3] ops;
2271 const(URAsmCmdInfo)* cm;
2273 dbuf.reset();
2275 void doOperand (int idx, ref uint code) {
2276 const(URAOperand)* op = ops.ptr+idx;
2277 switch (cm.ops[idx]) {
2278 case UROpType.IMM8:
2279 case UROpType.PORTIMM:
2280 if (op.fixuptype != URAsmFixup.None) {
2281 if (op.fixuptype == URAsmFixup.Word) throw new Exception("invalid fixup");
2283 dbuf.putByte(op.v&0xFFU, op.fixuptype);
2284 break;
2285 case UROpType.ADDR8:
2286 if (op.defined) {
2287 int dist = op.v-(addr+2);
2288 if (dist < byte.min || dist > byte.max) throw new Exception("invalid jr destination");
2289 dbuf.putByte(dist&0xff);
2290 } else {
2291 dbuf.putByte(0);
2293 break;
2294 case UROpType.IMM16:
2295 case UROpType.ADDR16:
2296 case UROpType.MEM16:
2297 dbuf.putWord(op.v&0xFFFFU, op.fixuptype);
2298 break;
2299 case UROpType.R8:
2300 case UROpType.R8NOM:
2301 code |= op.v&0xFFU;
2302 break;
2303 case UROpType.RSTDEST:
2304 code |= op.v&0b111000;
2305 break;
2306 case UROpType.JRCOND:
2307 case UROpType.COND:
2308 case UROpType.BITN:
2309 case UROpType.R83:
2310 case UROpType.R83NOM:
2311 code |= (op.v&0xFFU)<<3;
2312 break;
2313 case UROpType.R16:
2314 case UROpType.R16A:
2315 code |= (op.v&0xFFU)<<4;
2316 break;
2317 case UROpType.MIX:
2318 case UROpType.MIY:
2319 dbuf.putByte(cast(ubyte)op.v);
2320 break;
2321 default: break;
2325 void genCode (void) {
2326 cmdloop: for (int pos = cast(int)URInstructionsTable.length-1; pos >= 0; --pos) {
2327 if (tkn != URInstructionsTable.ptr[pos].mnemo) continue;
2328 foreach (immutable oprn, ref op; ops[]) {
2329 if (!urIsValidOp(op, addr, URInstructionsTable.ptr[pos].ops.ptr[oprn])) continue cmdloop;
2331 // command found, generate code
2332 cm = URInstructionsTable.ptr+pos;
2333 uint code = cm.code;
2334 uint mask = cm.mask;
2335 if ((code&0xFFFFU) == 0xCBDDU || (code&0xFFFFU) == 0xCBFDU) {
2336 // special commands
2337 // emit unmasked code
2338 dbuf.putByte(code&0xFFU);
2339 dbuf.putByte(0xCB);
2340 dbuf.putByte(0);
2341 dbuf.putByte(0);
2342 foreach (immutable oprn; 0..3) {
2343 if (cm.ops[oprn] == UROpType.MIX || cm.ops[oprn] == UROpType.MIY) {
2344 if (ops[oprn].defined && (ops[oprn].v < byte.min || ops[oprn].v > byte.max)) throw new Exception("invalid displacement");
2345 if (ops[oprn].defined) dbuf.dest[dbuf.destused-2] = cast(ubyte)ops[oprn].v;
2346 break;
2349 auto ccpos = dbuf.destused-1;
2350 //len = 4;
2351 code >>= 24;
2352 mask >>= 24;
2353 if ((mask&0xFFU) != 0xFFU) {
2354 foreach (immutable oprn; 0..3) if (cm.ops[oprn] != UROpType.MIX && cm.ops[oprn] != UROpType.MIY) doOperand(oprn, code);
2356 dbuf.dest[ccpos] = cast(ubyte)code;
2357 // that's all
2358 return;
2359 } else {
2360 // normal commands
2361 // emit unmasked code
2362 while ((mask&0xFFU) == 0xFFU) {
2363 dbuf.putByte(code&0xFFU);
2364 code >>= 8;
2365 mask >>= 8;
2367 //ASSERT((code&0xFFFFFF00UL) == 0);
2368 if (mask == 0) {
2369 //ASSERT(len > 0);
2370 code = dbuf.dest[--dbuf.destused];
2372 uint ccpos = dbuf.destused;
2373 dbuf.putByte(0);
2374 doOperand(0, code);
2375 doOperand(1, code);
2376 doOperand(2, code);
2377 dbuf.dest[ccpos] = cast(ubyte)code;
2378 // that's all
2379 return;
2382 throw new Exception("invalid instruction");
2385 void doPushPop () {
2386 bool first = true;
2387 for (;;) {
2388 pr.skipBlanks();
2389 if (pr.eol) {
2390 if (first) throw new Exception("invalid operand");
2391 break;
2392 } else if (!first) {
2393 if (pr.empty || pr.front != ',') throw new Exception("invalid operand");
2394 pr.popFront();
2395 pr.skipBlanks();
2396 if (pr.eol) throw new Exception("invalid operand");
2398 ops[] = URAOperand.init;
2399 urNextOperand(pr, ops[0], addr);
2400 genCode();
2401 first = false;
2405 void dorep (int opcnt) {
2406 bool first = true;
2407 for (;;) {
2408 pr.skipBlanks();
2409 if (pr.eol) {
2410 if (first) throw new Exception("invalid operand");
2411 break;
2412 } else if (!first) {
2413 if (pr.empty || pr.front != ',') throw new Exception("invalid operand");
2414 pr.popFront();
2415 pr.skipBlanks();
2416 if (pr.eol) throw new Exception("invalid operand");
2418 ops[] = URAOperand.init;
2419 foreach (immutable c; 0..opcnt) {
2420 if (c != 0) {
2421 pr.skipBlanks();
2422 if (pr.empty || pr.front != ',') throw new Exception("invalid operand");
2423 pr.popFront();
2424 pr.skipBlanks();
2425 if (pr.eol) throw new Exception("invalid operand");
2427 urNextOperand(pr, ops[c], addr);
2429 // shifts has special (I?+n),r8 forms
2430 if (opcnt == 1 && tkn != URMnemo.INC && tkn != URMnemo.DEC) {
2431 if (ops[0].type == UROpType.MIX || ops[0].type == UROpType.MIY || ops[0].type == UROpType.MIX0 || ops[0].type == UROpType.MIY0) {
2432 if (!first) throw new Exception("invalid operand mix");
2433 pr.skipBlanks();
2434 if (!pr.empty && pr.front == ',') urNextOperand(pr, ops[1], addr);
2435 pr.skipBlanks();
2436 if (!pr.eol) throw new Exception("invalid operand");
2437 genCode();
2438 return;
2441 genCode();
2442 first = false;
2446 for (;;) {
2447 pr.skipBlanks();
2448 if (pr.empty || pr.front == ';') return;
2449 if (URAsmParser.isalpha(pr.front)) break;
2450 if (pr.front == ':') { pr.popFront(); continue; }
2451 throw new Exception("invalid instruction");
2454 //if (expr[0] == ':') { if (errpos) *errpos = expr; return 0; }
2455 // get mnemonics
2456 int mmlen = 0;
2457 while (!pr.empty) {
2458 char ch = pr.front;
2459 if (ch >= 'a' && ch <= 'z') ch -= 32;
2460 if (ch >= 'A' && ch <= 'Z') {
2461 if (mmlen > mnem.length) throw new Exception("invalid instruction");
2462 mnem[mmlen++] = ch;
2463 pr.popFront();
2464 } else {
2465 break;
2468 if (mmlen == 0) throw new Exception("invalid instruction");
2469 if (!pr.empty && pr.front > ' ' && pr.front != ';' && pr.front != ':') throw new Exception("invalid instruction");
2471 // find it
2472 for (tkn = 0; tkn <= URMnemo.max; ++tkn) if (mnem[0..mmlen] == URMnemonics.ptr[tkn]) break;
2473 if (tkn > URMnemo.max) throw new Exception("invalid instruction");
2475 switch (tkn) {
2476 // special for PUSH and POP
2477 case URMnemo.POP:
2478 case URMnemo.PUSH:
2479 return doPushPop();
2480 // special for LD
2481 case URMnemo.LD:
2482 return dorep(2);
2483 // special for RR/RL
2484 case URMnemo.INC:
2485 case URMnemo.DEC:
2486 case URMnemo.RL:
2487 case URMnemo.RR:
2488 case URMnemo.SRL:
2489 case URMnemo.SRA:
2490 case URMnemo.SLA:
2491 case URMnemo.SLI:
2492 case URMnemo.SLL:
2493 return dorep(1);
2494 default:
2497 pr.skipBlanks();
2499 foreach (immutable ci, ref URAOperand op; ops[]) {
2500 pr.skipBlanks();
2501 if (pr.eol) break;
2502 if (ci != 0) {
2503 if (pr.empty || pr.front != ',') throw new Exception("invalid operand");
2504 pr.popFront();
2505 pr.skipBlanks();
2506 if (pr.eol) throw new Exception("invalid operand");
2508 urNextOperand(pr, op, addr);
2509 //conwriteln("op #", ci, ": ", op.toString, " <", pr.text[pr.textpos..$], ">");
2512 pr.skipBlanks();
2513 if (!pr.eol) throw new Exception("invalid operand");
2515 genCode();
2519 // ////////////////////////////////////////////////////////////////////////// //
2520 version(urasm_test) {
2521 import iv.cmdcon;
2522 import iv.vfs.io;
2525 void testOne (string xname) {
2526 conwriteln("=== ", xname, " ===");
2527 ubyte[] eta;
2529 auto fi = VFile("_urtests/"~xname~"_0000.bin");
2530 eta.length = cast(uint)fi.size;
2531 fi.rawReadExact(eta[]);
2533 ushort addr = 0;
2534 //ubyte[] res;
2535 foreach (string s; VFile("_urtests/"~xname~".asm").byLineCopy) {
2536 //conwritefln!"%04X: %s: %s"(addr, addr, s);
2537 URAsmBuf abuf;
2538 auto pr = URAsmParser(s);
2539 urAssembleOne(abuf, pr, addr);
2540 pr.skipBlanks();
2541 if (!pr.empty && pr.front != ';') assert(0, "extra text");
2542 foreach (immutable idx, ubyte b; abuf.code) {
2543 if (b != eta[addr+idx]) {
2544 conwritefln!"%04X: %02X %02X"(addr+idx, eta[addr+idx], b);
2545 assert(0, "fucked");
2548 //res ~= db;
2549 addr += abuf.code.length;
2551 //auto fo = VFile("zres.bin", "w");
2552 //fo.rawWriteExact(res);
2556 void main () {
2557 version(none) {
2558 ubyte[16] buf;
2559 auto db = urAssembleOne(buf[], "ex af,afx", 0);
2560 conwriteln("len=", db.length);
2562 URDisState dis;
2563 ushort addr = 0;
2564 while (addr < db.length) {
2565 auto len = urDisassembleOne(dis, addr, (ushort addr) => buf[addr&0x0f]);
2566 conwriteln("dlen=", len);
2567 conwriteln(" ", dis.getbuf);
2568 addr += len;
2570 } else {
2571 testOne("allb_smp");
2572 testOne("undoc");