1 /*
2 * libtilemdb - Utilities for debugging Z80 assembly programs
3 *
4 * Copyright (C) 2010 Benjamin Moody
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdarg.h>
29 #include "tilemdb.h"
30
31 typedef struct _TilemDisasmSymbol {
32 char* name;
33 dword value;
34 } TilemDisasmSymbol;
35
36 typedef struct _TilemDisasmSymTable {
37 int nsyms;
38 int nsyms_a;
39 TilemDisasmSymbol* syms;
40 } TilemDisasmSymTable;
41
42 struct _TilemDisasm {
43 TilemDisasmSymTable labels;
44 TilemDisasmSymTable romcalls;
45 TilemDisasmSymTable flags;
46 TilemDisasmSymTable macros;
47 };
48
tilem_disasm_new()49 TilemDisasm* tilem_disasm_new()
50 {
51 TilemDisasm* dasm = tilem_new0(TilemDisasm, 1);
52 dasm->labels.syms = NULL;
53 dasm->romcalls.syms = NULL;
54 dasm->flags.syms = NULL;
55 dasm->macros.syms = NULL;
56 return dasm;
57 }
58
tilem_disasm_sym_table_free(TilemDisasmSymTable * stab)59 static void tilem_disasm_sym_table_free(TilemDisasmSymTable* stab)
60 {
61 int i;
62
63 for (i = 0; i < stab->nsyms; i++)
64 tilem_free(stab->syms[i].name);
65 tilem_free(stab->syms);
66 }
67
tilem_disasm_free(TilemDisasm * dasm)68 void tilem_disasm_free(TilemDisasm* dasm)
69 {
70 if (!dasm)
71 return;
72
73 tilem_disasm_sym_table_free(&dasm->labels);
74 tilem_disasm_sym_table_free(&dasm->romcalls);
75 tilem_disasm_sym_table_free(&dasm->flags);
76 tilem_disasm_sym_table_free(&dasm->macros);
77 tilem_free(dasm);
78 }
79
80 /* Find symbol in the given table, if any */
find_symbol(const TilemDisasmSymTable * stab,dword value)81 static TilemDisasmSymbol* find_symbol(const TilemDisasmSymTable* stab,
82 dword value)
83 {
84 int start, end, i;
85
86 start = 0;
87 end = stab->nsyms;
88 while (start < end) {
89 i = (start + end) / 2;
90 if (stab->syms[i].value == value)
91 return &stab->syms[i];
92 else if (stab->syms[i].value <= value)
93 start = i + 1;
94 else
95 end = i;
96 }
97 return NULL;
98 }
99
100 /* Find previous symbol in the given table, if any */
find_prev_symbol(const TilemDisasmSymTable * stab,dword value)101 static TilemDisasmSymbol* find_prev_symbol(const TilemDisasmSymTable* stab,
102 dword value)
103 {
104 int start, end, i;
105
106 start = 0;
107 end = stab->nsyms;
108 while (start < end) {
109 i = (start + end) / 2;
110 if (stab->syms[i].value <= value)
111 start = i + 1;
112 else
113 end = i;
114 }
115 if (start > 0)
116 return &stab->syms[start - 1];
117 else
118 return NULL;
119 }
120
121 /* Find symbol with given name */
find_symbol_by_name(const TilemDisasmSymTable * stab,const char * name)122 static TilemDisasmSymbol* find_symbol_by_name(const TilemDisasmSymTable* stab,
123 const char* name)
124 {
125 int i;
126 for (i = 0; i < stab->nsyms; i++)
127 if (!strcmp(stab->syms[i].name, name))
128 return &stab->syms[i];
129 return NULL;
130 }
131
132 /* Find a given symbol in the table, or create a new one */
add_symbol(TilemDisasmSymTable * stab,dword value)133 static TilemDisasmSymbol* add_symbol(TilemDisasmSymTable* stab,
134 dword value)
135 {
136 int start, end, i;
137 TilemDisasmSymbol* syms;
138
139 start = 0;
140 end = stab->nsyms;
141
142 while (start < end) {
143 i = (start + end) / 2;
144 if (stab->syms[i].value == value)
145 return &stab->syms[i];
146 else if (stab->syms[i].value < value)
147 start = i + 1;
148 else
149 end = i;
150 }
151
152 /* insert new label into the array */
153 if (stab->nsyms < stab->nsyms_a) {
154 if (start < stab->nsyms)
155 memmove(&stab->syms[start + 1], &stab->syms[start],
156 ((stab->nsyms - start)
157 * sizeof(TilemDisasmSymbol)));
158 }
159 else {
160 stab->nsyms_a = (stab->nsyms + 1) * 2;
161 syms = tilem_new(TilemDisasmSymbol, stab->nsyms_a);
162 if (start > 0)
163 memcpy(syms, stab->syms,
164 start * sizeof(TilemDisasmSymbol));
165 if (start < stab->nsyms)
166 memcpy(syms + start + 1, stab->syms + start,
167 ((stab->nsyms - start)
168 * sizeof(TilemDisasmSymbol)));
169 tilem_free(stab->syms);
170 stab->syms = syms;
171 }
172
173 stab->nsyms++;
174
175 stab->syms[start].value = value;
176 stab->syms[start].name = NULL;
177 return &stab->syms[start];
178 }
179
180 /* Remove a symbol from the table */
del_symbol(TilemDisasmSymTable * stab,TilemDisasmSymbol * sym)181 static void del_symbol(TilemDisasmSymTable* stab,
182 TilemDisasmSymbol* sym)
183 {
184 int n = sym - stab->syms;
185
186 tilem_free(sym->name);
187
188 if (n < stab->nsyms - 1) {
189 memmove(sym, sym + 1,
190 (stab->nsyms - n - 1) * sizeof(TilemDisasmSymbol));
191 }
192
193 stab->nsyms--;
194 }
195
set_symbol(TilemDisasmSymTable * stab,const char * name,dword value)196 static void set_symbol(TilemDisasmSymTable* stab,
197 const char* name, dword value)
198 {
199 TilemDisasmSymbol* sym;
200
201 if ((sym = find_symbol_by_name(stab, name))) {
202 if (sym->value == value)
203 return;
204 else
205 del_symbol(stab, sym);
206 }
207
208 sym = add_symbol(stab, value);
209 tilem_free(sym->name);
210 sym->name = tilem_new_atomic(char, strlen(name) + 1);
211 strcpy(sym->name, name);
212 }
213
skipws(char * p)214 static char* skipws(char* p)
215 {
216 while (*p == ' ' || *p == '\t')
217 p++;
218 return p;
219 }
220
skipwc(char * p)221 static char* skipwc(char* p)
222 {
223 while ((unsigned char) *p > ' ')
224 p++;
225 return p;
226 }
227
parse_sym_value(const char * text,dword * value)228 static int parse_sym_value(const char* text, dword* value)
229 {
230 char* p;
231 dword x;
232
233 if (text[0] >= '0' && text[0] <= '7' && text[1] == ',') {
234 x = strtol(text + 2, &p, 16);
235 *value = 0x1000 + (x << 4) + (text[0] - '0');
236 }
237 else {
238 *value = strtol(text, &p, 16);
239 }
240
241 return (p != text && *p == 0);
242 }
243
parse_sym_line(TilemDisasmSymTable * stab,char * line)244 static int parse_sym_line(TilemDisasmSymTable* stab, char* line)
245 {
246 char *w1end, *w2start, *w2end, *name;
247 dword value;
248
249 if (line[0] == '#' || line[0] == ';')
250 return 1;
251
252 w1end = skipwc(line);
253 w2start = skipws(w1end);
254 w2end = skipwc(w2start);
255
256 if (w1end == line || w2start == w1end || w2end == w2start)
257 return 1;
258 if (*w2end)
259 return 1;
260
261 *w1end = *w2end = 0;
262
263 if (*line >= '0' && *line <= '9') {
264 name = w2start;
265 if (!parse_sym_value(line, &value))
266 return 1;
267 }
268 else {
269 name = line;
270 if (!parse_sym_value(w2start, &value))
271 return 1;
272 }
273
274 set_symbol(stab, name, value);
275 return 0;
276 }
277
tilem_disasm_read_symbol_file(TilemDisasm * dasm,FILE * symfile)278 int tilem_disasm_read_symbol_file(TilemDisasm* dasm, FILE* symfile)
279 {
280 char buf[1024];
281 char* p;
282 TilemDisasmSymTable* curtbl;
283 int status = 1;
284
285 curtbl = &dasm->labels;
286
287 while (fgets(buf, sizeof(buf), symfile)) {
288 p = buf + strlen(buf);
289 while (p != buf && (p[-1] == '\n' || p[-1] == '\r'))
290 p--;
291 *p = 0;
292
293 if (!strcmp(buf, "[labels]"))
294 curtbl = &dasm->labels;
295 else if (!strcmp(buf, "[romcalls]"))
296 curtbl = &dasm->romcalls;
297 else if (!strcmp(buf, "[flags]"))
298 curtbl = &dasm->flags;
299 else if (!strcmp(buf, "[macros]"))
300 curtbl = &dasm->macros;
301 else if (!parse_sym_line(curtbl, buf))
302 status = 0;
303 }
304
305 return status;
306 }
307
tilem_disasm_set_label(TilemDisasm * dasm,const char * name,dword value)308 void tilem_disasm_set_label(TilemDisasm* dasm, const char* name,
309 dword value)
310 {
311 set_symbol(&dasm->labels, name, value);
312 }
313
tilem_disasm_get_label(const TilemDisasm * dasm,const char * name,dword * value)314 int tilem_disasm_get_label(const TilemDisasm* dasm, const char* name,
315 dword* value)
316 {
317 TilemDisasmSymbol* sym = find_symbol_by_name(&dasm->labels, name);
318
319 if (!sym)
320 return 0;
321 else if (value)
322 *value = sym->value;
323 return 1;
324 }
325
tilem_disasm_get_label_at_address(const TilemDisasm * dasm,dword addr)326 const char* tilem_disasm_get_label_at_address(const TilemDisasm* dasm,
327 dword addr)
328 {
329 TilemDisasmSymbol* sym = find_symbol(&dasm->labels, addr);
330
331 if (sym)
332 return sym->name;
333 else
334 return NULL;
335 }
336
337 typedef struct _TilemDisasmInstruction {
338 int length;
339 const char* pattern;
340 } TilemDisasmInstruction;
341
342 static const TilemDisasmInstruction insts_main[256] = {
343 {1,"NOP"}, {3,"LD~BC,%w"}, {1,"LD~(BC),A"}, {1,"INC~BC"},
344 {1,"INC~B"}, {1,"DEC~B"}, {2,"LD~B,%b"}, {1,"RLCA"},
345 {1,"EX~AF,AF'"}, {1,"ADD~HL,BC"}, {1,"LD~A,(BC)"}, {1,"DEC~BC"},
346 {1,"INC~C"}, {1,"DEC~C"}, {2,"LD~C,%b"}, {1,"RRCA"},
347 {2,"DJNZ~%r"}, {3,"LD~DE,%w"}, {1,"LD~(DE),A"}, {1,"INC~DE"},
348 {1,"INC~D"}, {1,"DEC~D"}, {2,"LD~D,%b"}, {1,"RLA"},
349 {2,"JR~%r"}, {1,"ADD~HL,DE"}, {1,"LD~A,(DE)"}, {1,"DEC~DE"},
350 {1,"INC~E"}, {1,"DEC~E"}, {2,"LD~E,%b"}, {1,"RRA"},
351 {2,"JR~NZ,%r"}, {3,"LD~HL,%w"}, {3,"LD~(%a),HL"}, {1,"INC~HL"},
352 {1,"INC~H"}, {1,"DEC~H"}, {2,"LD~H,%b"}, {1,"DAA"},
353 {2,"JR~Z,%r"}, {1,"ADD~HL,HL"}, {3,"LD~HL,(%a)"}, {1,"DEC~HL"},
354 {1,"INC~L"}, {1,"DEC~L"}, {2,"LD~L,%b"}, {1,"CPL"},
355 {2,"JR~NC,%r"}, {3,"LD~SP,%w"}, {3,"LD~(%a),A"}, {1,"INC~SP"},
356 {1,"INC~(HL)"}, {1,"DEC~(HL)"}, {2,"LD~(HL),%b"}, {1,"SCF"},
357 {2,"JR~C,%r"}, {1,"ADD~HL,SP"}, {3,"LD~A,(%a)"}, {1,"DEC~SP"},
358 {1,"INC~A"}, {1,"DEC~A"}, {2,"LD~A,%b"}, {1,"CCF"},
359
360 {1,"LD~B,B"}, {1,"LD~B,C"}, {1,"LD~B,D"}, {1,"LD~B,E"},
361 {1,"LD~B,H"}, {1,"LD~B,L"}, {1,"LD~B,(HL)"}, {1,"LD~B,A"},
362 {1,"LD~C,B"}, {1,"LD~C,C"}, {1,"LD~C,D"}, {1,"LD~C,E"},
363 {1,"LD~C,H"}, {1,"LD~C,L"}, {1,"LD~C,(HL)"}, {1,"LD~C,A"},
364 {1,"LD~D,B"}, {1,"LD~D,C"}, {1,"LD~D,D"}, {1,"LD~D,E"},
365 {1,"LD~D,H"}, {1,"LD~D,L"}, {1,"LD~D,(HL)"}, {1,"LD~D,A"},
366 {1,"LD~E,B"}, {1,"LD~E,C"}, {1,"LD~E,D"}, {1,"LD~E,E"},
367 {1,"LD~E,H"}, {1,"LD~E,L"}, {1,"LD~E,(HL)"}, {1,"LD~E,A"},
368 {1,"LD~H,B"}, {1,"LD~H,C"}, {1,"LD~H,D"}, {1,"LD~H,E"},
369 {1,"LD~H,H"}, {1,"LD~H,L"}, {1,"LD~H,(HL)"}, {1,"LD~H,A"},
370 {1,"LD~L,B"}, {1,"LD~L,C"}, {1,"LD~L,D"}, {1,"LD~L,E"},
371 {1,"LD~L,H"}, {1,"LD~L,L"}, {1,"LD~L,(HL)"}, {1,"LD~L,A"},
372 {1,"LD~(HL),B"}, {1,"LD~(HL),C"}, {1,"LD~(HL),D"}, {1,"LD~(HL),E"},
373 {1,"LD~(HL),H"}, {1,"LD~(HL),L"}, {1,"HALT"}, {1,"LD~(HL),A"},
374 {1,"LD~A,B"}, {1,"LD~A,C"}, {1,"LD~A,D"}, {1,"LD~A,E"},
375 {1,"LD~A,H"}, {1,"LD~A,L"}, {1,"LD~A,(HL)"}, {1,"LD~A,A"},
376
377 {1,"ADD~A,B"}, {1,"ADD~A,C"}, {1,"ADD~A,D"}, {1,"ADD~A,E"},
378 {1,"ADD~A,H"}, {1,"ADD~A,L"}, {1,"ADD~A,(HL)"}, {1,"ADD~A,A"},
379 {1,"ADC~A,B"}, {1,"ADC~A,C"}, {1,"ADC~A,D"}, {1,"ADC~A,E"},
380 {1,"ADC~A,H"}, {1,"ADC~A,L"}, {1,"ADC~A,(HL)"}, {1,"ADC~A,A"},
381 {1,"SUB~B"}, {1,"SUB~C"}, {1,"SUB~D"}, {1,"SUB~E"},
382 {1,"SUB~H"}, {1,"SUB~L"}, {1,"SUB~(HL)"}, {1,"SUB~A"},
383 {1,"SBC~A,B"}, {1,"SBC~A,C"}, {1,"SBC~A,D"}, {1,"SBC~A,E"},
384 {1,"SBC~A,H"}, {1,"SBC~A,L"}, {1,"SBC~A,(HL)"}, {1,"SBC~A,A"},
385 {1,"AND~B"}, {1,"AND~C"}, {1,"AND~D"}, {1,"AND~E"},
386 {1,"AND~H"}, {1,"AND~L"}, {1,"AND~(HL)"}, {1,"AND~A"},
387 {1,"XOR~B"}, {1,"XOR~C"}, {1,"XOR~D"}, {1,"XOR~E"},
388 {1,"XOR~H"}, {1,"XOR~L"}, {1,"XOR~(HL)"}, {1,"XOR~A"},
389 {1,"OR~B"}, {1,"OR~C"}, {1,"OR~D"}, {1,"OR~E"},
390 {1,"OR~H"}, {1,"OR~L"}, {1,"OR~(HL)"}, {1,"OR~A"},
391 {1,"CP~B"}, {1,"CP~C"}, {1,"CP~D"}, {1,"CP~E"},
392 {1,"CP~H"}, {1,"CP~L"}, {1,"CP~(HL)"}, {1,"CP~A"},
393
394 {1,"RET~NZ"}, {1,"POP~BC"}, {3,"JP~NZ,%j"}, {3,"JP~%j"},
395 {3,"CALL~NZ,%j"}, {1,"PUSH~BC"}, {2,"ADD~A,%b"}, {1,"RST~%z"},
396 {1,"RET~Z"}, {1,"RET"}, {3,"JP~Z,%j"}, {1,0},
397 {3,"CALL~Z,%j"}, {3,"CALL~%j"}, {2,"ADC~A,%b"}, {1,"RST~%z"},
398 {1,"RET~NC"}, {1,"POP~DE"}, {3,"JP~NC,%j"}, {2,"OUT~(%b),A"},
399 {3,"CALL~NC,%j"}, {1,"PUSH~DE"}, {2,"SUB~%b"}, {1,"RST~%z"},
400 {1,"RET~C"}, {1,"EXX"}, {3,"JP~C,%j"}, {2,"IN~A,(%b)"},
401 {3,"CALL~C,%j"}, {1,0}, {2,"SBC~A,%b"}, {1,"RST~%z"},
402 {1,"RET~PO"}, {1,"POP~HL"}, {3,"JP~PO,%j"}, {1,"EX~(SP),HL"},
403 {3,"CALL~PO,%j"}, {1,"PUSH~HL"}, {2,"AND~%b"}, {1,"RST~%z"},
404 {1,"RET~PE"}, {1,"JP~(HL)"}, {3,"JP~PE,%j"}, {1,"EX~DE,HL"},
405 {3,"CALL~PE,%j"}, {1,0}, {2,"XOR~%b"}, {1,"RST~%z"},
406 {1,"RET~P"}, {1,"POP~AF"}, {3,"JP~P,%j"}, {1,"DI"},
407 {3,"CALL~P,%j"}, {1,"PUSH~AF"}, {2,"OR~%b"}, {1,"RST~%z"},
408 {1,"RET~M"}, {1,"LD~SP,HL"}, {3,"JP~M,%j"}, {1,"EI"},
409 {3,"CALL~M,%j"}, {1,0}, {2,"CP~%b"}, {1,"RST~%z"}};
410
411 static const TilemDisasmInstruction insts_ddfd[256] = {
412 {1,0}, {1,0}, {1,0}, {1,0},
413 {1,0}, {1,0}, {1,0}, {1,0},
414 {1,0}, {2,"ADD~%i,BC"}, {1,0}, {1,0},
415 {1,0}, {1,0}, {1,0}, {1,0},
416 {1,0}, {1,0}, {1,0}, {1,0},
417 {1,0}, {1,0}, {1,0}, {1,0},
418 {1,0}, {2,"ADD~%i,DE"}, {1,0}, {1,0},
419 {1,0}, {1,0}, {1,0}, {1,0},
420 {1,0}, {4,"LD~%i,%w"}, {4,"LD~(%a),%i"}, {2,"INC~%i"},
421 {2,"INC~%iH"}, {2,"DEC~%iH"}, {3,"LD~%iH,%b"}, {1,0},
422 {1,0}, {2,"ADD~%i,%i"}, {4,"LD~%i,(%a)"}, {2,"DEC~%i"},
423 {2,"INC~%iL"}, {2,"DEC~%iL"}, {3,"LD~%iL,%b"}, {1,0},
424 {1,0}, {1,0}, {1,0}, {1,0},
425 {3,"INC~(%i%s)"}, {3,"DEC~(%i%s)"}, {4,"LD~(%i%s),%b"}, {1,0},
426 {1,0}, {2,"ADD~%i,SP"}, {1,0}, {1,0},
427 {1,0}, {1,0}, {1,0}, {1,0},
428
429 {1,0}, {1,0}, {1,0}, {1,0},
430 {2,"LD~B,%iH"}, {2,"LD~B,%iL"}, {3,"LD~B,(%i%s)"}, {1,0},
431 {1,0}, {1,0}, {1,0}, {1,0},
432 {2,"LD~C,%iH"}, {2,"LD~C,%iL"}, {3,"LD~C,(%i%s)"}, {1,0},
433 {1,0}, {1,0}, {1,0}, {1,0},
434 {2,"LD~D,%iH"}, {2,"LD~D,%iL"}, {3,"LD~D,(%i%s)"}, {1,0},
435 {1,0}, {1,0}, {1,0}, {1,0},
436 {2,"LD~E,%iH"}, {2,"LD~E,%iL"}, {3,"LD~E,(%i%s)"}, {1,0},
437 {2,"LD~%iH,B"}, {2,"LD~%iH,C"}, {2,"LD~%iH,D"}, {2,"LD~%iH,E"},
438 {2,"LD~%iH,%iH"}, {2,"LD~%iH,%iL"}, {3,"LD~H,(%i%s)"}, {2,"LD~%iH,A"},
439 {2,"LD~%iL,B"}, {2,"LD~%iL,C"}, {2,"LD~%iL,D"}, {2,"LD~%iL,E"},
440 {2,"LD~%iL,%iH"}, {2,"LD~%iL,%iL"}, {3,"LD~L,(%i%s)"}, {2,"LD~%iL,A"},
441 {3,"LD~(%i%s),B"}, {3,"LD~(%i%s),C"}, {3,"LD~(%i%s),D"}, {3,"LD~(%i%s),E"},
442 {3,"LD~(%i%s),H"}, {3,"LD~(%i%s),L"}, {1,0}, {3,"LD~(%i%s),A"},
443 {1,0}, {1,0}, {1,0}, {1,0},
444 {2,"LD~A,%iH"}, {2,"LD~A,%iL"}, {3,"LD~A,(%i%s)"}, {1,0},
445
446 {1,0}, {1,0}, {1,0}, {1,0},
447 {2,"ADD~A,%iH"}, {2,"ADD~A,%iL"}, {3,"ADD~A,(%i%s)"}, {1,0},
448 {1,0}, {1,0}, {1,0}, {1,0},
449 {2,"ADC~A,%iH"}, {2,"ADC~A,%iL"}, {3,"ADC~A,(%i%s)"}, {1,0},
450 {1,0}, {1,0}, {1,0}, {1,0},
451 {2,"SUB~%iH"}, {2,"SUB~%iL"}, {3,"SUB~(%i%s)"}, {1,0},
452 {1,0}, {1,0}, {1,0}, {1,0},
453 {2,"SBC~A,%iH"}, {2,"SBC~A,%iL"}, {3,"SBC~A,(%i%s)"}, {1,0},
454 {1,0}, {1,0}, {1,0}, {1,0},
455 {2,"AND~%iH"}, {2,"AND~%iL"}, {3,"AND~(%i%s)"}, {1,0},
456 {1,0}, {1,0}, {1,0}, {1,0},
457 {2,"XOR~%iH"}, {2,"XOR~%iL"}, {3,"XOR~(%i%s)"}, {1,0},
458 {1,0}, {1,0}, {1,0}, {1,0},
459 {2,"OR~%iH"}, {2,"OR~%iL"}, {3,"OR~(%i%s)"}, {1,0},
460 {1,0}, {1,0}, {1,0}, {1,0},
461 {2,"CP~%iH"}, {2,"CP~%iL"}, {3,"CP~(%i%s)"}, {1,0},
462
463 {1,0}, {1,0}, {1,0}, {1,0},
464 {1,0}, {1,0}, {1,0}, {1,0},
465 {1,0}, {1,0}, {1,0}, {1,0},
466 {1,0}, {1,0}, {1,0}, {1,0},
467 {1,0}, {1,0}, {1,0}, {1,0},
468 {1,0}, {1,0}, {1,0}, {1,0},
469 {1,0}, {1,0}, {1,0}, {1,0},
470 {1,0}, {1,0}, {1,0}, {1,0},
471 {1,0}, {2,"POP~%i"}, {1,0}, {2,"EX~(SP),%i"},
472 {1,0}, {2,"PUSH~%i"}, {1,0}, {1,0},
473 {1,0}, {2,"JP~(%i)"}, {1,0}, {1,0},
474 {1,0}, {1,0}, {1,0}, {1,0},
475 {1,0}, {1,0}, {1,0}, {1,0},
476 {1,0}, {1,0}, {1,0}, {1,0},
477 {1,0}, {2,"LD~SP,%i"}, {1,0}, {1,0},
478 {1,0}, {1,0}, {1,0}, {1,0}};
479
480 static const TilemDisasmInstruction insts_cb[256] = {
481 {2,"RLC~B"}, {2,"RLC~C"}, {2,"RLC~D"}, {2,"RLC~E"},
482 {2,"RLC~H"}, {2,"RLC~L"}, {2,"RLC~(HL)"}, {2,"RLC~A"},
483 {2,"RRC~B"}, {2,"RRC~C"}, {2,"RRC~D"}, {2,"RRC~E"},
484 {2,"RRC~H"}, {2,"RRC~L"}, {2,"RRC~(HL)"}, {2,"RRC~A"},
485 {2,"RL~B"}, {2,"RL~C"}, {2,"RL~D"}, {2,"RL~E"},
486 {2,"RL~H"}, {2,"RL~L"}, {2,"RL~(HL)"}, {2,"RL~A"},
487 {2,"RR~B"}, {2,"RR~C"}, {2,"RR~D"}, {2,"RR~E"},
488 {2,"RR~H"}, {2,"RR~L"}, {2,"RR~(HL)"}, {2,"RR~A"},
489 {2,"SLA~B"}, {2,"SLA~C"}, {2,"SLA~D"}, {2,"SLA~E"},
490 {2,"SLA~H"}, {2,"SLA~L"}, {2,"SLA~(HL)"}, {2,"SLA~A"},
491 {2,"SRA~B"}, {2,"SRA~C"}, {2,"SRA~D"}, {2,"SRA~E"},
492 {2,"SRA~H"}, {2,"SRA~L"}, {2,"SRA~(HL)"}, {2,"SRA~A"},
493 {2,"SLIA~B"}, {2,"SLIA~C"}, {2,"SLIA~D"}, {2,"SLIA~E"},
494 {2,"SLIA~H"}, {2,"SLIA~L"}, {2,"SLIA~(HL)"}, {2,"SLIA~A"},
495 {2,"SRL~B"}, {2,"SRL~C"}, {2,"SRL~D"}, {2,"SRL~E"},
496 {2,"SRL~H"}, {2,"SRL~L"}, {2,"SRL~(HL)"}, {2,"SRL~A"},
497
498 {2,"BIT~0,B"}, {2,"BIT~0,C"}, {2,"BIT~0,D"}, {2,"BIT~0,E"},
499 {2,"BIT~0,H"}, {2,"BIT~0,L"}, {2,"BIT~0,(HL)"}, {2,"BIT~0,A"},
500 {2,"BIT~1,B"}, {2,"BIT~1,C"}, {2,"BIT~1,D"}, {2,"BIT~1,E"},
501 {2,"BIT~1,H"}, {2,"BIT~1,L"}, {2,"BIT~1,(HL)"}, {2,"BIT~1,A"},
502 {2,"BIT~2,B"}, {2,"BIT~2,C"}, {2,"BIT~2,D"}, {2,"BIT~2,E"},
503 {2,"BIT~2,H"}, {2,"BIT~2,L"}, {2,"BIT~2,(HL)"}, {2,"BIT~2,A"},
504 {2,"BIT~3,B"}, {2,"BIT~3,C"}, {2,"BIT~3,D"}, {2,"BIT~3,E"},
505 {2,"BIT~3,H"}, {2,"BIT~3,L"}, {2,"BIT~3,(HL)"}, {2,"BIT~3,A"},
506 {2,"BIT~4,B"}, {2,"BIT~4,C"}, {2,"BIT~4,D"}, {2,"BIT~4,E"},
507 {2,"BIT~4,H"}, {2,"BIT~4,L"}, {2,"BIT~4,(HL)"}, {2,"BIT~4,A"},
508 {2,"BIT~5,B"}, {2,"BIT~5,C"}, {2,"BIT~5,D"}, {2,"BIT~5,E"},
509 {2,"BIT~5,H"}, {2,"BIT~5,L"}, {2,"BIT~5,(HL)"}, {2,"BIT~5,A"},
510 {2,"BIT~6,B"}, {2,"BIT~6,C"}, {2,"BIT~6,D"}, {2,"BIT~6,E"},
511 {2,"BIT~6,H"}, {2,"BIT~6,L"}, {2,"BIT~6,(HL)"}, {2,"BIT~6,A"},
512 {2,"BIT~7,B"}, {2,"BIT~7,C"}, {2,"BIT~7,D"}, {2,"BIT~7,E"},
513 {2,"BIT~7,H"}, {2,"BIT~7,L"}, {2,"BIT~7,(HL)"}, {2,"BIT~7,A"},
514
515 {2,"RES~0,B"}, {2,"RES~0,C"}, {2,"RES~0,D"}, {2,"RES~0,E"},
516 {2,"RES~0,H"}, {2,"RES~0,L"}, {2,"RES~0,(HL)"}, {2,"RES~0,A"},
517 {2,"RES~1,B"}, {2,"RES~1,C"}, {2,"RES~1,D"}, {2,"RES~1,E"},
518 {2,"RES~1,H"}, {2,"RES~1,L"}, {2,"RES~1,(HL)"}, {2,"RES~1,A"},
519 {2,"RES~2,B"}, {2,"RES~2,C"}, {2,"RES~2,D"}, {2,"RES~2,E"},
520 {2,"RES~2,H"}, {2,"RES~2,L"}, {2,"RES~2,(HL)"}, {2,"RES~2,A"},
521 {2,"RES~3,B"}, {2,"RES~3,C"}, {2,"RES~3,D"}, {2,"RES~3,E"},
522 {2,"RES~3,H"}, {2,"RES~3,L"}, {2,"RES~3,(HL)"}, {2,"RES~3,A"},
523 {2,"RES~4,B"}, {2,"RES~4,C"}, {2,"RES~4,D"}, {2,"RES~4,E"},
524 {2,"RES~4,H"}, {2,"RES~4,L"}, {2,"RES~4,(HL)"}, {2,"RES~4,A"},
525 {2,"RES~5,B"}, {2,"RES~5,C"}, {2,"RES~5,D"}, {2,"RES~5,E"},
526 {2,"RES~5,H"}, {2,"RES~5,L"}, {2,"RES~5,(HL)"}, {2,"RES~5,A"},
527 {2,"RES~6,B"}, {2,"RES~6,C"}, {2,"RES~6,D"}, {2,"RES~6,E"},
528 {2,"RES~6,H"}, {2,"RES~6,L"}, {2,"RES~6,(HL)"}, {2,"RES~6,A"},
529 {2,"RES~7,B"}, {2,"RES~7,C"}, {2,"RES~7,D"}, {2,"RES~7,E"},
530 {2,"RES~7,H"}, {2,"RES~7,L"}, {2,"RES~7,(HL)"}, {2,"RES~7,A"},
531
532 {2,"SET~0,B"}, {2,"SET~0,C"}, {2,"SET~0,D"}, {2,"SET~0,E"},
533 {2,"SET~0,H"}, {2,"SET~0,L"}, {2,"SET~0,(HL)"}, {2,"SET~0,A"},
534 {2,"SET~1,B"}, {2,"SET~1,C"}, {2,"SET~1,D"}, {2,"SET~1,E"},
535 {2,"SET~1,H"}, {2,"SET~1,L"}, {2,"SET~1,(HL)"}, {2,"SET~1,A"},
536 {2,"SET~2,B"}, {2,"SET~2,C"}, {2,"SET~2,D"}, {2,"SET~2,E"},
537 {2,"SET~2,H"}, {2,"SET~2,L"}, {2,"SET~2,(HL)"}, {2,"SET~2,A"},
538 {2,"SET~3,B"}, {2,"SET~3,C"}, {2,"SET~3,D"}, {2,"SET~3,E"},
539 {2,"SET~3,H"}, {2,"SET~3,L"}, {2,"SET~3,(HL)"}, {2,"SET~3,A"},
540 {2,"SET~4,B"}, {2,"SET~4,C"}, {2,"SET~4,D"}, {2,"SET~4,E"},
541 {2,"SET~4,H"}, {2,"SET~4,L"}, {2,"SET~4,(HL)"}, {2,"SET~4,A"},
542 {2,"SET~5,B"}, {2,"SET~5,C"}, {2,"SET~5,D"}, {2,"SET~5,E"},
543 {2,"SET~5,H"}, {2,"SET~5,L"}, {2,"SET~5,(HL)"}, {2,"SET~5,A"},
544 {2,"SET~6,B"}, {2,"SET~6,C"}, {2,"SET~6,D"}, {2,"SET~6,E"},
545 {2,"SET~6,H"}, {2,"SET~6,L"}, {2,"SET~6,(HL)"}, {2,"SET~6,A"},
546 {2,"SET~7,B"}, {2,"SET~7,C"}, {2,"SET~7,D"}, {2,"SET~7,E"},
547 {2,"SET~7,H"}, {2,"SET~7,L"}, {2,"SET~7,(HL)"}, {2,"SET~7,A"}};
548
549 static const TilemDisasmInstruction insts_ddfdcb[256] = {
550 {4,"RLC~B,(%i%s)"}, {4,"RLC~C,(%i%s)"}, {4,"RLC~D,(%i%s)"}, {4,"RLC~E,(%i%s)"},
551 {4,"RLC~H,(%i%s)"}, {4,"RLC~L,(%i%s)"}, {4,"RLC~(%i%s)"}, {4,"RLC~A,(%i%s)"},
552 {4,"RRC~B,(%i%s)"}, {4,"RRC~C,(%i%s)"}, {4,"RRC~D,(%i%s)"}, {4,"RRC~E,(%i%s)"},
553 {4,"RRC~H,(%i%s)"}, {4,"RRC~L,(%i%s)"}, {4,"RRC~(%i%s)"}, {4,"RRC~A,(%i%s)"},
554 {4,"RL~B,(%i%s)"}, {4,"RL~C,(%i%s)"}, {4,"RL~D,(%i%s)"}, {4,"RL~E,(%i%s)"},
555 {4,"RL~H,(%i%s)"}, {4,"RL~L,(%i%s)"}, {4,"RL~(%i%s)"}, {4,"RL~A,(%i%s)"},
556 {4,"RR~B,(%i%s)"}, {4,"RR~C,(%i%s)"}, {4,"RR~D,(%i%s)"}, {4,"RR~E,(%i%s)"},
557 {4,"RR~H,(%i%s)"}, {4,"RR~L,(%i%s)"}, {4,"RR~(%i%s)"}, {4,"RR~A,(%i%s)"},
558 {4,"SLA~B,(%i%s)"}, {4,"SLA~C,(%i%s)"}, {4,"SLA~D,(%i%s)"}, {4,"SLA~E,(%i%s)"},
559 {4,"SLA~H,(%i%s)"}, {4,"SLA~L,(%i%s)"}, {4,"SLA~(%i%s)"}, {4,"SLA~A,(%i%s)"},
560 {4,"SRA~B,(%i%s)"}, {4,"SRA~C,(%i%s)"}, {4,"SRA~D,(%i%s)"}, {4,"SRA~E,(%i%s)"},
561 {4,"SRA~H,(%i%s)"}, {4,"SRA~L,(%i%s)"}, {4,"SRA~(%i%s)"}, {4,"SRA~A,(%i%s)"},
562 {4,"SLIA~B,(%i%s)"}, {4,"SLIA~C,(%i%s)"}, {4,"SLIA~D,(%i%s)"}, {4,"SLIA~E,(%i%s)"},
563 {4,"SLIA~H,(%i%s)"}, {4,"SLIA~L,(%i%s)"}, {4,"SLIA~(%i%s)"}, {4,"SLIA~A,(%i%s)"},
564 {4,"SRL~B,(%i%s)"}, {4,"SRL~C,(%i%s)"}, {4,"SRL~D,(%i%s)"}, {4,"SRL~E,(%i%s)"},
565 {4,"SRL~H,(%i%s)"}, {4,"SRL~L,(%i%s)"}, {4,"SRL~(%i%s)"}, {4,"SRL~A,(%i%s)"},
566
567 {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"},
568 {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"},
569 {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"},
570 {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"},
571 {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"},
572 {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"},
573 {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"},
574 {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"},
575 {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"},
576 {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"},
577 {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"},
578 {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"},
579 {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"},
580 {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"},
581 {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"},
582 {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"},
583
584 {4,"RES~0,B,(%i%s)"}, {4,"RES~0,C,(%i%s)"}, {4,"RES~0,D,(%i%s)"}, {4,"RES~0,E,(%i%s)"},
585 {4,"RES~0,H,(%i%s)"}, {4,"RES~0,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~0,A,(%i%s)"},
586 {4,"RES~1,B,(%i%s)"}, {4,"RES~1,C,(%i%s)"}, {4,"RES~1,D,(%i%s)"}, {4,"RES~1,E,(%i%s)"},
587 {4,"RES~1,H,(%i%s)"}, {4,"RES~1,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~1,A,(%i%s)"},
588 {4,"RES~2,B,(%i%s)"}, {4,"RES~2,C,(%i%s)"}, {4,"RES~2,D,(%i%s)"}, {4,"RES~2,E,(%i%s)"},
589 {4,"RES~2,H,(%i%s)"}, {4,"RES~2,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~2,A,(%i%s)"},
590 {4,"RES~3,B,(%i%s)"}, {4,"RES~3,C,(%i%s)"}, {4,"RES~3,D,(%i%s)"}, {4,"RES~3,E,(%i%s)"},
591 {4,"RES~3,H,(%i%s)"}, {4,"RES~3,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~3,A,(%i%s)"},
592 {4,"RES~4,B,(%i%s)"}, {4,"RES~4,C,(%i%s)"}, {4,"RES~4,D,(%i%s)"}, {4,"RES~4,E,(%i%s)"},
593 {4,"RES~4,H,(%i%s)"}, {4,"RES~4,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~4,A,(%i%s)"},
594 {4,"RES~5,B,(%i%s)"}, {4,"RES~5,C,(%i%s)"}, {4,"RES~5,D,(%i%s)"}, {4,"RES~5,E,(%i%s)"},
595 {4,"RES~5,H,(%i%s)"}, {4,"RES~5,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~5,A,(%i%s)"},
596 {4,"RES~6,B,(%i%s)"}, {4,"RES~6,C,(%i%s)"}, {4,"RES~6,D,(%i%s)"}, {4,"RES~6,E,(%i%s)"},
597 {4,"RES~6,H,(%i%s)"}, {4,"RES~6,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~6,A,(%i%s)"},
598 {4,"RES~7,B,(%i%s)"}, {4,"RES~7,C,(%i%s)"}, {4,"RES~7,D,(%i%s)"}, {4,"RES~7,E,(%i%s)"},
599 {4,"RES~7,H,(%i%s)"}, {4,"RES~7,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~7,A,(%i%s)"},
600
601 {4,"SET~0,B,(%i%s)"}, {4,"SET~0,C,(%i%s)"}, {4,"SET~0,D,(%i%s)"}, {4,"SET~0,E,(%i%s)"},
602 {4,"SET~0,H,(%i%s)"}, {4,"SET~0,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~0,A,(%i%s)"},
603 {4,"SET~1,B,(%i%s)"}, {4,"SET~1,C,(%i%s)"}, {4,"SET~1,D,(%i%s)"}, {4,"SET~1,E,(%i%s)"},
604 {4,"SET~1,H,(%i%s)"}, {4,"SET~1,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~1,A,(%i%s)"},
605 {4,"SET~2,B,(%i%s)"}, {4,"SET~2,C,(%i%s)"}, {4,"SET~2,D,(%i%s)"}, {4,"SET~2,E,(%i%s)"},
606 {4,"SET~2,H,(%i%s)"}, {4,"SET~2,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~2,A,(%i%s)"},
607 {4,"SET~3,B,(%i%s)"}, {4,"SET~3,C,(%i%s)"}, {4,"SET~3,D,(%i%s)"}, {4,"SET~3,E,(%i%s)"},
608 {4,"SET~3,H,(%i%s)"}, {4,"SET~3,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~3,A,(%i%s)"},
609 {4,"SET~4,B,(%i%s)"}, {4,"SET~4,C,(%i%s)"}, {4,"SET~4,D,(%i%s)"}, {4,"SET~4,E,(%i%s)"},
610 {4,"SET~4,H,(%i%s)"}, {4,"SET~4,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~4,A,(%i%s)"},
611 {4,"SET~5,B,(%i%s)"}, {4,"SET~5,C,(%i%s)"}, {4,"SET~5,D,(%i%s)"}, {4,"SET~5,E,(%i%s)"},
612 {4,"SET~5,H,(%i%s)"}, {4,"SET~5,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~5,A,(%i%s)"},
613 {4,"SET~6,B,(%i%s)"}, {4,"SET~6,C,(%i%s)"}, {4,"SET~6,D,(%i%s)"}, {4,"SET~6,E,(%i%s)"},
614 {4,"SET~6,H,(%i%s)"}, {4,"SET~6,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~6,A,(%i%s)"},
615 {4,"SET~7,B,(%i%s)"}, {4,"SET~7,C,(%i%s)"}, {4,"SET~7,D,(%i%s)"}, {4,"SET~7,E,(%i%s)"},
616 {4,"SET~7,H,(%i%s)"}, {4,"SET~7,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~7,A,(%i%s)"}};
617
618 static const TilemDisasmInstruction insts_ed[256] = {
619 {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0},
620 {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0},
621 {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0},
622 {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0},
623 {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0},
624 {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0},
625 {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0},
626 {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0},
627
628 {2,"IN~B,(C)"}, {2,"OUT~(C),B"}, {2,"SBC~HL,BC"}, {4,"LD~(%a),BC"},
629 {2,"NEG"}, {2,"RETN"}, {2,"IM~0"}, {2,"LD~I,A"},
630 {2,"IN~C,(C)"}, {2,"OUT~(C),C"}, {2,"ADC~HL,BC"}, {4,"LD~BC,(%a)"},
631 {2,"NEG*"}, {2,"RETI"}, {2,"IM~0*"}, {2,"LD~R,A"},
632 {2,"IN~D,(C)"}, {2,"OUT~(C),D"}, {2,"SBC~HL,DE"}, {4,"LD~(%a),DE"},
633 {2,"NEG*"}, {2,"RETN*"}, {2,"IM~1"}, {2,"LD~A,I"},
634 {2,"IN~E,(C)"}, {2,"OUT~(C),E"}, {2,"ADC~HL,DE"}, {4,"LD~DE,(%a)"},
635 {2,"NEG*"}, {2,"RETN*"}, {2,"IM~2"}, {2,"LD~A,R"},
636 {2,"IN~H,(C)"}, {2,"OUT~(C),H"}, {2,"SBC~HL,HL"}, {4,"LD~(%a),HL*"},
637 {2,"NEG*"}, {2,"RETN*"}, {2,"IM~0*"}, {2,"RRD"},
638 {2,"IN~L,(C)"}, {2,"OUT~(C),L"}, {2,"ADC~HL,HL"}, {4,"LD~HL,(%a)*"},
639 {2,"NEG*"}, {2,"RETN*"}, {2,"IM~0*"}, {2,"RLD"},
640 {2,"IN~(C)"}, {2,"OUT~(C),0"}, {2,"SBC~HL,SP"}, {4,"LD~(%a),SP"},
641 {2,"NEG*"}, {2,"RETN*"}, {2,"IM~1*"}, {2,0},
642 {2,"IN~A,(C)"}, {2,"OUT~(C),A"}, {2,"ADC~HL,SP"}, {4,"LD~SP,(%a)"},
643 {2,"NEG*"}, {2,"RETN*"}, {2,"IM~2*"}, {2,0},
644
645 {2,0}, {2,0}, {2,0}, {2,0},
646 {2,0}, {2,0}, {2,0}, {2,0},
647 {2,0}, {2,0}, {2,0}, {2,0},
648 {2,0}, {2,0}, {2,0}, {2,0},
649 {2,0}, {2,0}, {2,0}, {2,0},
650 {2,0}, {2,0}, {2,0}, {2,0},
651 {2,0}, {2,0}, {2,0}, {2,0},
652 {2,0}, {2,0}, {2,0}, {2,0},
653 {2,"LDI"}, {2,"CPI"}, {2,"INI"}, {2,"OUTI"},
654 {2,0}, {2,0}, {2,0}, {2,0},
655 {2,"LDD"}, {2,"CPD"}, {2,"IND"}, {2,"OUTD"},
656 {2,0}, {2,0}, {2,0}, {2,0},
657 {2,"LDIR"}, {2,"CPIR"}, {2,"INIR"}, {2,"OTIR"},
658 {2,0}, {2,0}, {2,0}, {2,0},
659 {2,"LDDR"}, {2,"CPDR"}, {2,"INDR"}, {2,"OTDR"},
660 {2,0}, {2,0}, {2,0}, {2,0},
661
662 {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0},
663 {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0},
664 {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0},
665 {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0},
666 {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0},
667 {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0},
668 {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0},
669 {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}};
670
671 /* Count number of bytes of arguments for a given instruction/macro
672 pattern */
pattern_arg_size(const char * pattern)673 static int pattern_arg_size(const char* pattern)
674 {
675 char* p;
676 int count = 0, offs;
677
678 while (*pattern) {
679 if (*pattern != '%')
680 pattern++;
681 else {
682 pattern++;
683
684 if (*pattern >= '0' && *pattern <= '9') {
685 offs = strtol(pattern, &p, 10);
686 pattern = p;
687 }
688 else {
689 offs = count;
690 }
691
692 switch (*pattern) {
693 case 0:
694 pattern--;
695 break;
696
697 case 'b':
698 case 'C':
699 case 'r':
700 case 's':
701 offs++;
702 break;
703
704 case 'a':
705 case 'c':
706 case 'f':
707 case 'j':
708 case 'w':
709 offs += 2;
710 break;
711 }
712
713 pattern++;
714 if (offs > count)
715 count = offs;
716 }
717 }
718
719 return count;
720 }
721
get_instruction_info(const TilemDisasm * dasm,const byte * instr,int * length,int * argbase,const char ** pattern)722 static void get_instruction_info(const TilemDisasm* dasm,
723 const byte* instr,
724 int* length, int* argbase,
725 const char** pattern)
726 {
727 const TilemDisasmSymbol* sym;
728 const TilemDisasmInstruction* ii;
729 dword mvalue;
730 int i;
731
732 mvalue = 0;
733 for (i = 0; i < 4; i++) {
734 mvalue = (mvalue << 8) | instr[i];
735 if ((sym = find_symbol(&dasm->macros, mvalue))) {
736 *pattern = sym->name;
737 *length = i + 1 + pattern_arg_size(sym->name);
738 *argbase = i + 1;
739 return;
740 }
741 }
742
743 if (instr[0] == 0xed) {
744 ii = &insts_ed[instr[1]];
745 *argbase = 2;
746 }
747 else if (instr[0] == 0xdd || instr[0] == 0xfd) {
748 if (instr[1] == 0xcb) {
749 ii = &insts_ddfdcb[instr[3]];
750 }
751 else {
752 ii = &insts_ddfd[instr[1]];
753 }
754 *argbase = 2;
755 }
756 else if (instr[0] == 0xcb) {
757 ii = &insts_cb[instr[1]];
758 *argbase = 2;
759 }
760 else {
761 ii = &insts_main[instr[0]];
762 *argbase = 1;
763 }
764
765 *length = ii->length;
766
767 if (ii->pattern) {
768 *pattern = ii->pattern;
769 }
770 else {
771 *argbase = 0;
772 if (ii->length == 1)
773 *pattern = "DB~%b";
774 else
775 *pattern = "DB~%b,%b";
776 }
777 }
778
779 static void TILEM_ATTR_PRINTF(3, 4)
printv(char ** buf,int * bsize,const char * fmt,...)780 printv(char** buf, int* bsize, const char* fmt, ...)
781 {
782 va_list ap;
783 int n;
784
785 if (*bsize == 0)
786 return;
787
788 va_start(ap, fmt);
789 n = vsnprintf(*buf, *bsize, fmt, ap);
790 va_end(ap);
791
792 if (n >= *bsize) {
793 *buf += *bsize - 1;
794 **buf = 0;
795 *bsize = 0;
796 }
797 else {
798 *buf += n;
799 **buf = 0;
800 *bsize -= n;
801 }
802 }
803
print_byte(char ** buf,int * bsize,unsigned int b)804 static void print_byte(char** buf, int* bsize, unsigned int b)
805 {
806 printv(buf, bsize, "$%02X", b);
807 }
808
print_word(const TilemDisasm * dasm,char ** buf,int * bsize,dword w,int autonum,int autodiff)809 static void print_word(const TilemDisasm* dasm, char** buf, int* bsize,
810 dword w, int autonum, int autodiff)
811 {
812 TilemDisasmSymbol* sym;
813
814 if (autonum && w < 0x100) {
815 printv(buf, bsize, "$%04X", w);
816 return;
817 }
818
819 sym = find_prev_symbol(&dasm->labels, w);
820
821 if (sym && !strcmp(sym->name, "flags")) {
822 w -= sym->value;
823 sym = find_symbol(&dasm->flags, w);
824 if (sym) {
825 printv(buf, bsize, "flags + %s", sym->name);
826 }
827 else {
828 printv(buf, bsize, "flags + $%02X", w);
829 }
830 }
831 else if (sym && w == sym->value) {
832 printv(buf, bsize, "%s", sym->name);
833 }
834 else if (sym && autodiff && w > 0x8000 && w - sym->value < 64) {
835 printv(buf, bsize, "%s + %d", sym->name, w - sym->value);
836 }
837 else {
838 printv(buf, bsize, "$%04X", w);
839 }
840 }
841
print_romcall(const TilemDisasm * dasm,char ** buf,int * bsize,dword w)842 static void print_romcall(const TilemDisasm* dasm, char** buf, int* bsize,
843 dword w)
844 {
845 TilemDisasmSymbol* sym;
846
847 sym = find_symbol(&dasm->romcalls, w);
848 if (sym) {
849 printv(buf, bsize, "%s", sym->name);
850 }
851 else {
852 printv(buf, bsize, "$%04X", w);
853 }
854 }
855
print_flag(const TilemDisasm * dasm,char ** buf,int * bsize,unsigned int bit,unsigned int offset,unsigned int prefix)856 static void print_flag(const TilemDisasm* dasm, char** buf, int* bsize,
857 unsigned int bit, unsigned int offset,
858 unsigned int prefix)
859 {
860 TilemDisasmSymbol* sym;
861 int i;
862
863 if (prefix == 0xfd) {
864 sym = find_symbol(&dasm->flags, 0x1000 + (offset << 4) + bit);
865 if (sym) {
866 for (i = 0; sym->name[i]; i++) {
867 printv(buf, bsize, "%c", sym->name[i]);
868 if (sym->name[i] == ',')
869 printv(buf, bsize, " (IY + ");
870 }
871 printv(buf, bsize, ")");
872 return;
873 }
874
875 sym = find_symbol(&dasm->flags, offset);
876 if (sym) {
877 printv(buf, bsize, "%d, (IY + %s)", bit, sym->name);
878 return;
879 }
880 }
881
882 printv(buf, bsize, "%d, (%s", bit, (prefix == 0xfd ? "IY" : "IX"));
883
884 if (offset & 0x80) {
885 printv(buf, bsize, " - $%02X", 0x100 - offset);
886 }
887 else if (offset) {
888 printv(buf, bsize, " + $%02X", offset);
889 }
890
891 printv(buf, bsize, ")");
892 }
893
disassemble_pattern(const TilemDisasm * dasm,const char * pattern,const byte * ibuf,dword pc,int argbase,char ** buf,int * bsize)894 static void disassemble_pattern(const TilemDisasm* dasm, const char* pattern,
895 const byte* ibuf, dword pc, int argbase,
896 char** buf, int* bsize)
897 {
898 int argidx, offs;
899 char* p;
900 dword w;
901 TilemDisasmSymbol* sym;
902
903 argidx = argbase;
904
905 while (*bsize && *pattern) {
906 if (*pattern == '~')
907 printv(buf, bsize, "\t");
908 else if (*pattern == ',') {
909 printv(buf, bsize, ", ");
910 }
911 else if (*pattern != '%') {
912 printv(buf, bsize, "%c", *pattern);
913 }
914 else {
915 pattern++;
916 if (*pattern >= '0' && *pattern <= '9') {
917 offs = argbase + strtol(pattern, &p, 10);
918 pattern = p;
919 }
920 else {
921 offs = argidx;
922 }
923
924 switch (*pattern) {
925 case 0:
926 pattern--;
927 break;
928
929 case '%':
930 printv(buf, bsize, "%%");
931 break;
932
933 case 'a':
934 /* %a: word value, always an address */
935 w = ibuf[offs] | (ibuf[offs + 1] << 8);
936 print_word(dasm, buf, bsize, w, 0, 1);
937 offs += 2;
938 break;
939
940 case 'b':
941 /* %b: byte value */
942 print_byte(buf, bsize, ibuf[offs]);
943 offs++;
944 break;
945
946 case 'c':
947 /* %c: word value, always a ROM call number */
948 w = ibuf[offs] | (ibuf[offs + 1] << 8);
949 print_romcall(dasm, buf, bsize, w);
950 offs += 2;
951 break;
952
953 case 'C':
954 /* %C: byte value, always a ROM call number */
955 print_romcall(dasm, buf, bsize, ibuf[offs]);
956 offs++;
957 break;
958
959 case 'f':
960 /* %f: flag value */
961 print_flag(dasm, buf, bsize,
962 (ibuf[offs + 1] >> 3) & 7,
963 ibuf[offs], ibuf[0]);
964 offs += 2;
965 break;
966
967 case 'i':
968 /* %i: IX or IY by instruction prefix */
969 if (ibuf[0] == 0xdd)
970 printv(buf, bsize, "IX");
971 else
972 printv(buf, bsize, "IY");
973 break;
974
975 case 'j':
976 /* %j: word value, always a jump address */
977 w = ibuf[offs] | (ibuf[offs + 1] << 8);
978 print_word(dasm, buf, bsize, w, 0, 0);
979 offs += 2;
980 break;
981
982 case 'r':
983 /* %r: one-byte PC-relative value */
984 if (ibuf[offs] & 0x80)
985 w = pc + offs - 0xff + ibuf[offs];
986 else
987 w = pc + offs + 1 + ibuf[offs];
988 print_word(dasm, buf, bsize, w, 0, 0);
989 offs++;
990 break;
991
992 case 's':
993 /* %s: one-byte signed displacement */
994 if (ibuf[0] == 0xfd
995 && (sym = find_symbol(&dasm->flags,
996 ibuf[offs]))) {
997 printv(buf, bsize, " + %s", sym->name);
998 }
999 else if (ibuf[offs] & 0x80) {
1000 printv(buf, bsize, " - ");
1001 print_byte(buf, bsize,
1002 0x100 - ibuf[offs]);
1003 }
1004 else if (ibuf[offs]) {
1005 printv(buf, bsize, " + ");
1006 print_byte(buf, bsize, ibuf[offs]);
1007 }
1008 offs++;
1009 break;
1010
1011 case 'w':
1012 /* %w: word value */
1013 w = ibuf[offs] | (ibuf[offs + 1] << 8);
1014 print_word(dasm, buf, bsize, w, 1, 1);
1015 offs += 2;
1016 break;
1017
1018 case 'z':
1019 /* %z: RST target address */
1020 print_word(dasm, buf, bsize, ibuf[0] & 0x38,
1021 0, 0);
1022 break;
1023 }
1024 if (offs > argidx)
1025 argidx = offs;
1026 }
1027
1028 pattern++;
1029 }
1030 }
1031
tilem_disasm_disassemble(const TilemDisasm * dasm,TilemCalc * calc,int phys,dword addr,dword * nextaddr,char * buffer,int bufsize)1032 void tilem_disasm_disassemble(const TilemDisasm* dasm, TilemCalc* calc,
1033 int phys, dword addr, dword* nextaddr,
1034 char* buffer, int bufsize)
1035 {
1036 byte ibuf[64];
1037 dword a, addr_l, max;
1038 int length, argbase, i;
1039 const char* pattern;
1040
1041 if (phys) {
1042 max = calc->hw.romsize + calc->hw.ramsize;
1043 for (i = 0; i < 4; i++) {
1044 a = (addr + i) % max;
1045 ibuf[i] = calc->mem[a];
1046 }
1047
1048 addr_l = (*calc->hw.mem_ptol)(calc, addr);
1049 if (addr_l == 0xffffffff)
1050 addr_l = (addr & 0x3fff) | 0x4000;
1051 }
1052 else {
1053 max = 0x10000;
1054 for (i = 0; i < 4; i++) {
1055 a = (addr + i) & 0xffff;
1056 ibuf[i] = calc->mem[(*calc->hw.mem_ltop)(calc, a)];
1057 }
1058
1059 addr_l = addr;
1060 }
1061
1062 get_instruction_info(dasm, ibuf, &length, &argbase, &pattern);
1063
1064 if (phys) {
1065 for (i = 0; i < length; i++) {
1066 ibuf[i] = calc->mem[addr];
1067 addr = (addr + 1) % max;
1068 }
1069 }
1070 else {
1071 for (i = 0; i < length; i++) {
1072 ibuf[i] = calc->mem[(*calc->hw.mem_ltop)(calc, addr)];
1073 addr = (addr + 1) & 0xffff;
1074 }
1075 }
1076
1077 if (nextaddr)
1078 *nextaddr = addr;
1079
1080 if (buffer) {
1081 disassemble_pattern(dasm, pattern, ibuf, addr_l, argbase,
1082 &buffer, &bufsize);
1083 }
1084 }
1085