/* * libtilemdb - Utilities for debugging Z80 assembly programs * * Copyright (C) 2010 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include "tilemdb.h" typedef struct _TilemDisasmSymbol { char* name; dword value; } TilemDisasmSymbol; typedef struct _TilemDisasmSymTable { int nsyms; int nsyms_a; TilemDisasmSymbol* syms; } TilemDisasmSymTable; struct _TilemDisasm { TilemDisasmSymTable labels; TilemDisasmSymTable romcalls; TilemDisasmSymTable flags; TilemDisasmSymTable macros; }; TilemDisasm* tilem_disasm_new() { TilemDisasm* dasm = tilem_new0(TilemDisasm, 1); dasm->labels.syms = NULL; dasm->romcalls.syms = NULL; dasm->flags.syms = NULL; dasm->macros.syms = NULL; return dasm; } static void tilem_disasm_sym_table_free(TilemDisasmSymTable* stab) { int i; for (i = 0; i < stab->nsyms; i++) tilem_free(stab->syms[i].name); tilem_free(stab->syms); } void tilem_disasm_free(TilemDisasm* dasm) { if (!dasm) return; tilem_disasm_sym_table_free(&dasm->labels); tilem_disasm_sym_table_free(&dasm->romcalls); tilem_disasm_sym_table_free(&dasm->flags); tilem_disasm_sym_table_free(&dasm->macros); tilem_free(dasm); } /* Find symbol in the given table, if any */ static TilemDisasmSymbol* find_symbol(const TilemDisasmSymTable* stab, dword value) { int start, end, i; start = 0; end = stab->nsyms; while (start < end) { i = (start + end) / 2; if (stab->syms[i].value == value) return &stab->syms[i]; else if (stab->syms[i].value <= value) start = i + 1; else end = i; } return NULL; } /* Find previous symbol in the given table, if any */ static TilemDisasmSymbol* find_prev_symbol(const TilemDisasmSymTable* stab, dword value) { int start, end, i; start = 0; end = stab->nsyms; while (start < end) { i = (start + end) / 2; if (stab->syms[i].value <= value) start = i + 1; else end = i; } if (start > 0) return &stab->syms[start - 1]; else return NULL; } /* Find symbol with given name */ static TilemDisasmSymbol* find_symbol_by_name(const TilemDisasmSymTable* stab, const char* name) { int i; for (i = 0; i < stab->nsyms; i++) if (!strcmp(stab->syms[i].name, name)) return &stab->syms[i]; return NULL; } /* Find a given symbol in the table, or create a new one */ static TilemDisasmSymbol* add_symbol(TilemDisasmSymTable* stab, dword value) { int start, end, i; TilemDisasmSymbol* syms; start = 0; end = stab->nsyms; while (start < end) { i = (start + end) / 2; if (stab->syms[i].value == value) return &stab->syms[i]; else if (stab->syms[i].value < value) start = i + 1; else end = i; } /* insert new label into the array */ if (stab->nsyms < stab->nsyms_a) { if (start < stab->nsyms) memmove(&stab->syms[start + 1], &stab->syms[start], ((stab->nsyms - start) * sizeof(TilemDisasmSymbol))); } else { stab->nsyms_a = (stab->nsyms + 1) * 2; syms = tilem_new(TilemDisasmSymbol, stab->nsyms_a); if (start > 0) memcpy(syms, stab->syms, start * sizeof(TilemDisasmSymbol)); if (start < stab->nsyms) memcpy(syms + start + 1, stab->syms + start, ((stab->nsyms - start) * sizeof(TilemDisasmSymbol))); tilem_free(stab->syms); stab->syms = syms; } stab->nsyms++; stab->syms[start].value = value; stab->syms[start].name = NULL; return &stab->syms[start]; } /* Remove a symbol from the table */ static void del_symbol(TilemDisasmSymTable* stab, TilemDisasmSymbol* sym) { int n = sym - stab->syms; tilem_free(sym->name); if (n < stab->nsyms - 1) { memmove(sym, sym + 1, (stab->nsyms - n - 1) * sizeof(TilemDisasmSymbol)); } stab->nsyms--; } static void set_symbol(TilemDisasmSymTable* stab, const char* name, dword value) { TilemDisasmSymbol* sym; if ((sym = find_symbol_by_name(stab, name))) { if (sym->value == value) return; else del_symbol(stab, sym); } sym = add_symbol(stab, value); tilem_free(sym->name); sym->name = tilem_new_atomic(char, strlen(name) + 1); strcpy(sym->name, name); } static char* skipws(char* p) { while (*p == ' ' || *p == '\t') p++; return p; } static char* skipwc(char* p) { while ((unsigned char) *p > ' ') p++; return p; } static int parse_sym_value(const char* text, dword* value) { char* p; dword x; if (text[0] >= '0' && text[0] <= '7' && text[1] == ',') { x = strtol(text + 2, &p, 16); *value = 0x1000 + (x << 4) + (text[0] - '0'); } else { *value = strtol(text, &p, 16); } return (p != text && *p == 0); } static int parse_sym_line(TilemDisasmSymTable* stab, char* line) { char *w1end, *w2start, *w2end, *name; dword value; if (line[0] == '#' || line[0] == ';') return 1; w1end = skipwc(line); w2start = skipws(w1end); w2end = skipwc(w2start); if (w1end == line || w2start == w1end || w2end == w2start) return 1; if (*w2end) return 1; *w1end = *w2end = 0; if (*line >= '0' && *line <= '9') { name = w2start; if (!parse_sym_value(line, &value)) return 1; } else { name = line; if (!parse_sym_value(w2start, &value)) return 1; } set_symbol(stab, name, value); return 0; } int tilem_disasm_read_symbol_file(TilemDisasm* dasm, FILE* symfile) { char buf[1024]; char* p; TilemDisasmSymTable* curtbl; int status = 1; curtbl = &dasm->labels; while (fgets(buf, sizeof(buf), symfile)) { p = buf + strlen(buf); while (p != buf && (p[-1] == '\n' || p[-1] == '\r')) p--; *p = 0; if (!strcmp(buf, "[labels]")) curtbl = &dasm->labels; else if (!strcmp(buf, "[romcalls]")) curtbl = &dasm->romcalls; else if (!strcmp(buf, "[flags]")) curtbl = &dasm->flags; else if (!strcmp(buf, "[macros]")) curtbl = &dasm->macros; else if (!parse_sym_line(curtbl, buf)) status = 0; } return status; } void tilem_disasm_set_label(TilemDisasm* dasm, const char* name, dword value) { set_symbol(&dasm->labels, name, value); } int tilem_disasm_get_label(const TilemDisasm* dasm, const char* name, dword* value) { TilemDisasmSymbol* sym = find_symbol_by_name(&dasm->labels, name); if (!sym) return 0; else if (value) *value = sym->value; return 1; } const char* tilem_disasm_get_label_at_address(const TilemDisasm* dasm, dword addr) { TilemDisasmSymbol* sym = find_symbol(&dasm->labels, addr); if (sym) return sym->name; else return NULL; } typedef struct _TilemDisasmInstruction { int length; const char* pattern; } TilemDisasmInstruction; static const TilemDisasmInstruction insts_main[256] = { {1,"NOP"}, {3,"LD~BC,%w"}, {1,"LD~(BC),A"}, {1,"INC~BC"}, {1,"INC~B"}, {1,"DEC~B"}, {2,"LD~B,%b"}, {1,"RLCA"}, {1,"EX~AF,AF'"}, {1,"ADD~HL,BC"}, {1,"LD~A,(BC)"}, {1,"DEC~BC"}, {1,"INC~C"}, {1,"DEC~C"}, {2,"LD~C,%b"}, {1,"RRCA"}, {2,"DJNZ~%r"}, {3,"LD~DE,%w"}, {1,"LD~(DE),A"}, {1,"INC~DE"}, {1,"INC~D"}, {1,"DEC~D"}, {2,"LD~D,%b"}, {1,"RLA"}, {2,"JR~%r"}, {1,"ADD~HL,DE"}, {1,"LD~A,(DE)"}, {1,"DEC~DE"}, {1,"INC~E"}, {1,"DEC~E"}, {2,"LD~E,%b"}, {1,"RRA"}, {2,"JR~NZ,%r"}, {3,"LD~HL,%w"}, {3,"LD~(%a),HL"}, {1,"INC~HL"}, {1,"INC~H"}, {1,"DEC~H"}, {2,"LD~H,%b"}, {1,"DAA"}, {2,"JR~Z,%r"}, {1,"ADD~HL,HL"}, {3,"LD~HL,(%a)"}, {1,"DEC~HL"}, {1,"INC~L"}, {1,"DEC~L"}, {2,"LD~L,%b"}, {1,"CPL"}, {2,"JR~NC,%r"}, {3,"LD~SP,%w"}, {3,"LD~(%a),A"}, {1,"INC~SP"}, {1,"INC~(HL)"}, {1,"DEC~(HL)"}, {2,"LD~(HL),%b"}, {1,"SCF"}, {2,"JR~C,%r"}, {1,"ADD~HL,SP"}, {3,"LD~A,(%a)"}, {1,"DEC~SP"}, {1,"INC~A"}, {1,"DEC~A"}, {2,"LD~A,%b"}, {1,"CCF"}, {1,"LD~B,B"}, {1,"LD~B,C"}, {1,"LD~B,D"}, {1,"LD~B,E"}, {1,"LD~B,H"}, {1,"LD~B,L"}, {1,"LD~B,(HL)"}, {1,"LD~B,A"}, {1,"LD~C,B"}, {1,"LD~C,C"}, {1,"LD~C,D"}, {1,"LD~C,E"}, {1,"LD~C,H"}, {1,"LD~C,L"}, {1,"LD~C,(HL)"}, {1,"LD~C,A"}, {1,"LD~D,B"}, {1,"LD~D,C"}, {1,"LD~D,D"}, {1,"LD~D,E"}, {1,"LD~D,H"}, {1,"LD~D,L"}, {1,"LD~D,(HL)"}, {1,"LD~D,A"}, {1,"LD~E,B"}, {1,"LD~E,C"}, {1,"LD~E,D"}, {1,"LD~E,E"}, {1,"LD~E,H"}, {1,"LD~E,L"}, {1,"LD~E,(HL)"}, {1,"LD~E,A"}, {1,"LD~H,B"}, {1,"LD~H,C"}, {1,"LD~H,D"}, {1,"LD~H,E"}, {1,"LD~H,H"}, {1,"LD~H,L"}, {1,"LD~H,(HL)"}, {1,"LD~H,A"}, {1,"LD~L,B"}, {1,"LD~L,C"}, {1,"LD~L,D"}, {1,"LD~L,E"}, {1,"LD~L,H"}, {1,"LD~L,L"}, {1,"LD~L,(HL)"}, {1,"LD~L,A"}, {1,"LD~(HL),B"}, {1,"LD~(HL),C"}, {1,"LD~(HL),D"}, {1,"LD~(HL),E"}, {1,"LD~(HL),H"}, {1,"LD~(HL),L"}, {1,"HALT"}, {1,"LD~(HL),A"}, {1,"LD~A,B"}, {1,"LD~A,C"}, {1,"LD~A,D"}, {1,"LD~A,E"}, {1,"LD~A,H"}, {1,"LD~A,L"}, {1,"LD~A,(HL)"}, {1,"LD~A,A"}, {1,"ADD~A,B"}, {1,"ADD~A,C"}, {1,"ADD~A,D"}, {1,"ADD~A,E"}, {1,"ADD~A,H"}, {1,"ADD~A,L"}, {1,"ADD~A,(HL)"}, {1,"ADD~A,A"}, {1,"ADC~A,B"}, {1,"ADC~A,C"}, {1,"ADC~A,D"}, {1,"ADC~A,E"}, {1,"ADC~A,H"}, {1,"ADC~A,L"}, {1,"ADC~A,(HL)"}, {1,"ADC~A,A"}, {1,"SUB~B"}, {1,"SUB~C"}, {1,"SUB~D"}, {1,"SUB~E"}, {1,"SUB~H"}, {1,"SUB~L"}, {1,"SUB~(HL)"}, {1,"SUB~A"}, {1,"SBC~A,B"}, {1,"SBC~A,C"}, {1,"SBC~A,D"}, {1,"SBC~A,E"}, {1,"SBC~A,H"}, {1,"SBC~A,L"}, {1,"SBC~A,(HL)"}, {1,"SBC~A,A"}, {1,"AND~B"}, {1,"AND~C"}, {1,"AND~D"}, {1,"AND~E"}, {1,"AND~H"}, {1,"AND~L"}, {1,"AND~(HL)"}, {1,"AND~A"}, {1,"XOR~B"}, {1,"XOR~C"}, {1,"XOR~D"}, {1,"XOR~E"}, {1,"XOR~H"}, {1,"XOR~L"}, {1,"XOR~(HL)"}, {1,"XOR~A"}, {1,"OR~B"}, {1,"OR~C"}, {1,"OR~D"}, {1,"OR~E"}, {1,"OR~H"}, {1,"OR~L"}, {1,"OR~(HL)"}, {1,"OR~A"}, {1,"CP~B"}, {1,"CP~C"}, {1,"CP~D"}, {1,"CP~E"}, {1,"CP~H"}, {1,"CP~L"}, {1,"CP~(HL)"}, {1,"CP~A"}, {1,"RET~NZ"}, {1,"POP~BC"}, {3,"JP~NZ,%j"}, {3,"JP~%j"}, {3,"CALL~NZ,%j"}, {1,"PUSH~BC"}, {2,"ADD~A,%b"}, {1,"RST~%z"}, {1,"RET~Z"}, {1,"RET"}, {3,"JP~Z,%j"}, {1,0}, {3,"CALL~Z,%j"}, {3,"CALL~%j"}, {2,"ADC~A,%b"}, {1,"RST~%z"}, {1,"RET~NC"}, {1,"POP~DE"}, {3,"JP~NC,%j"}, {2,"OUT~(%b),A"}, {3,"CALL~NC,%j"}, {1,"PUSH~DE"}, {2,"SUB~%b"}, {1,"RST~%z"}, {1,"RET~C"}, {1,"EXX"}, {3,"JP~C,%j"}, {2,"IN~A,(%b)"}, {3,"CALL~C,%j"}, {1,0}, {2,"SBC~A,%b"}, {1,"RST~%z"}, {1,"RET~PO"}, {1,"POP~HL"}, {3,"JP~PO,%j"}, {1,"EX~(SP),HL"}, {3,"CALL~PO,%j"}, {1,"PUSH~HL"}, {2,"AND~%b"}, {1,"RST~%z"}, {1,"RET~PE"}, {1,"JP~(HL)"}, {3,"JP~PE,%j"}, {1,"EX~DE,HL"}, {3,"CALL~PE,%j"}, {1,0}, {2,"XOR~%b"}, {1,"RST~%z"}, {1,"RET~P"}, {1,"POP~AF"}, {3,"JP~P,%j"}, {1,"DI"}, {3,"CALL~P,%j"}, {1,"PUSH~AF"}, {2,"OR~%b"}, {1,"RST~%z"}, {1,"RET~M"}, {1,"LD~SP,HL"}, {3,"JP~M,%j"}, {1,"EI"}, {3,"CALL~M,%j"}, {1,0}, {2,"CP~%b"}, {1,"RST~%z"}}; static const TilemDisasmInstruction insts_ddfd[256] = { {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"ADD~%i,BC"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"ADD~%i,DE"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {4,"LD~%i,%w"}, {4,"LD~(%a),%i"}, {2,"INC~%i"}, {2,"INC~%iH"}, {2,"DEC~%iH"}, {3,"LD~%iH,%b"}, {1,0}, {1,0}, {2,"ADD~%i,%i"}, {4,"LD~%i,(%a)"}, {2,"DEC~%i"}, {2,"INC~%iL"}, {2,"DEC~%iL"}, {3,"LD~%iL,%b"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {3,"INC~(%i%s)"}, {3,"DEC~(%i%s)"}, {4,"LD~(%i%s),%b"}, {1,0}, {1,0}, {2,"ADD~%i,SP"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"LD~B,%iH"}, {2,"LD~B,%iL"}, {3,"LD~B,(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"LD~C,%iH"}, {2,"LD~C,%iL"}, {3,"LD~C,(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"LD~D,%iH"}, {2,"LD~D,%iL"}, {3,"LD~D,(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"LD~E,%iH"}, {2,"LD~E,%iL"}, {3,"LD~E,(%i%s)"}, {1,0}, {2,"LD~%iH,B"}, {2,"LD~%iH,C"}, {2,"LD~%iH,D"}, {2,"LD~%iH,E"}, {2,"LD~%iH,%iH"}, {2,"LD~%iH,%iL"}, {3,"LD~H,(%i%s)"}, {2,"LD~%iH,A"}, {2,"LD~%iL,B"}, {2,"LD~%iL,C"}, {2,"LD~%iL,D"}, {2,"LD~%iL,E"}, {2,"LD~%iL,%iH"}, {2,"LD~%iL,%iL"}, {3,"LD~L,(%i%s)"}, {2,"LD~%iL,A"}, {3,"LD~(%i%s),B"}, {3,"LD~(%i%s),C"}, {3,"LD~(%i%s),D"}, {3,"LD~(%i%s),E"}, {3,"LD~(%i%s),H"}, {3,"LD~(%i%s),L"}, {1,0}, {3,"LD~(%i%s),A"}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"LD~A,%iH"}, {2,"LD~A,%iL"}, {3,"LD~A,(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"ADD~A,%iH"}, {2,"ADD~A,%iL"}, {3,"ADD~A,(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"ADC~A,%iH"}, {2,"ADC~A,%iL"}, {3,"ADC~A,(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"SUB~%iH"}, {2,"SUB~%iL"}, {3,"SUB~(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"SBC~A,%iH"}, {2,"SBC~A,%iL"}, {3,"SBC~A,(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"AND~%iH"}, {2,"AND~%iL"}, {3,"AND~(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"XOR~%iH"}, {2,"XOR~%iL"}, {3,"XOR~(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"OR~%iH"}, {2,"OR~%iL"}, {3,"OR~(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"CP~%iH"}, {2,"CP~%iL"}, {3,"CP~(%i%s)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"POP~%i"}, {1,0}, {2,"EX~(SP),%i"}, {1,0}, {2,"PUSH~%i"}, {1,0}, {1,0}, {1,0}, {2,"JP~(%i)"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {2,"LD~SP,%i"}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}, {1,0}}; static const TilemDisasmInstruction insts_cb[256] = { {2,"RLC~B"}, {2,"RLC~C"}, {2,"RLC~D"}, {2,"RLC~E"}, {2,"RLC~H"}, {2,"RLC~L"}, {2,"RLC~(HL)"}, {2,"RLC~A"}, {2,"RRC~B"}, {2,"RRC~C"}, {2,"RRC~D"}, {2,"RRC~E"}, {2,"RRC~H"}, {2,"RRC~L"}, {2,"RRC~(HL)"}, {2,"RRC~A"}, {2,"RL~B"}, {2,"RL~C"}, {2,"RL~D"}, {2,"RL~E"}, {2,"RL~H"}, {2,"RL~L"}, {2,"RL~(HL)"}, {2,"RL~A"}, {2,"RR~B"}, {2,"RR~C"}, {2,"RR~D"}, {2,"RR~E"}, {2,"RR~H"}, {2,"RR~L"}, {2,"RR~(HL)"}, {2,"RR~A"}, {2,"SLA~B"}, {2,"SLA~C"}, {2,"SLA~D"}, {2,"SLA~E"}, {2,"SLA~H"}, {2,"SLA~L"}, {2,"SLA~(HL)"}, {2,"SLA~A"}, {2,"SRA~B"}, {2,"SRA~C"}, {2,"SRA~D"}, {2,"SRA~E"}, {2,"SRA~H"}, {2,"SRA~L"}, {2,"SRA~(HL)"}, {2,"SRA~A"}, {2,"SLIA~B"}, {2,"SLIA~C"}, {2,"SLIA~D"}, {2,"SLIA~E"}, {2,"SLIA~H"}, {2,"SLIA~L"}, {2,"SLIA~(HL)"}, {2,"SLIA~A"}, {2,"SRL~B"}, {2,"SRL~C"}, {2,"SRL~D"}, {2,"SRL~E"}, {2,"SRL~H"}, {2,"SRL~L"}, {2,"SRL~(HL)"}, {2,"SRL~A"}, {2,"BIT~0,B"}, {2,"BIT~0,C"}, {2,"BIT~0,D"}, {2,"BIT~0,E"}, {2,"BIT~0,H"}, {2,"BIT~0,L"}, {2,"BIT~0,(HL)"}, {2,"BIT~0,A"}, {2,"BIT~1,B"}, {2,"BIT~1,C"}, {2,"BIT~1,D"}, {2,"BIT~1,E"}, {2,"BIT~1,H"}, {2,"BIT~1,L"}, {2,"BIT~1,(HL)"}, {2,"BIT~1,A"}, {2,"BIT~2,B"}, {2,"BIT~2,C"}, {2,"BIT~2,D"}, {2,"BIT~2,E"}, {2,"BIT~2,H"}, {2,"BIT~2,L"}, {2,"BIT~2,(HL)"}, {2,"BIT~2,A"}, {2,"BIT~3,B"}, {2,"BIT~3,C"}, {2,"BIT~3,D"}, {2,"BIT~3,E"}, {2,"BIT~3,H"}, {2,"BIT~3,L"}, {2,"BIT~3,(HL)"}, {2,"BIT~3,A"}, {2,"BIT~4,B"}, {2,"BIT~4,C"}, {2,"BIT~4,D"}, {2,"BIT~4,E"}, {2,"BIT~4,H"}, {2,"BIT~4,L"}, {2,"BIT~4,(HL)"}, {2,"BIT~4,A"}, {2,"BIT~5,B"}, {2,"BIT~5,C"}, {2,"BIT~5,D"}, {2,"BIT~5,E"}, {2,"BIT~5,H"}, {2,"BIT~5,L"}, {2,"BIT~5,(HL)"}, {2,"BIT~5,A"}, {2,"BIT~6,B"}, {2,"BIT~6,C"}, {2,"BIT~6,D"}, {2,"BIT~6,E"}, {2,"BIT~6,H"}, {2,"BIT~6,L"}, {2,"BIT~6,(HL)"}, {2,"BIT~6,A"}, {2,"BIT~7,B"}, {2,"BIT~7,C"}, {2,"BIT~7,D"}, {2,"BIT~7,E"}, {2,"BIT~7,H"}, {2,"BIT~7,L"}, {2,"BIT~7,(HL)"}, {2,"BIT~7,A"}, {2,"RES~0,B"}, {2,"RES~0,C"}, {2,"RES~0,D"}, {2,"RES~0,E"}, {2,"RES~0,H"}, {2,"RES~0,L"}, {2,"RES~0,(HL)"}, {2,"RES~0,A"}, {2,"RES~1,B"}, {2,"RES~1,C"}, {2,"RES~1,D"}, {2,"RES~1,E"}, {2,"RES~1,H"}, {2,"RES~1,L"}, {2,"RES~1,(HL)"}, {2,"RES~1,A"}, {2,"RES~2,B"}, {2,"RES~2,C"}, {2,"RES~2,D"}, {2,"RES~2,E"}, {2,"RES~2,H"}, {2,"RES~2,L"}, {2,"RES~2,(HL)"}, {2,"RES~2,A"}, {2,"RES~3,B"}, {2,"RES~3,C"}, {2,"RES~3,D"}, {2,"RES~3,E"}, {2,"RES~3,H"}, {2,"RES~3,L"}, {2,"RES~3,(HL)"}, {2,"RES~3,A"}, {2,"RES~4,B"}, {2,"RES~4,C"}, {2,"RES~4,D"}, {2,"RES~4,E"}, {2,"RES~4,H"}, {2,"RES~4,L"}, {2,"RES~4,(HL)"}, {2,"RES~4,A"}, {2,"RES~5,B"}, {2,"RES~5,C"}, {2,"RES~5,D"}, {2,"RES~5,E"}, {2,"RES~5,H"}, {2,"RES~5,L"}, {2,"RES~5,(HL)"}, {2,"RES~5,A"}, {2,"RES~6,B"}, {2,"RES~6,C"}, {2,"RES~6,D"}, {2,"RES~6,E"}, {2,"RES~6,H"}, {2,"RES~6,L"}, {2,"RES~6,(HL)"}, {2,"RES~6,A"}, {2,"RES~7,B"}, {2,"RES~7,C"}, {2,"RES~7,D"}, {2,"RES~7,E"}, {2,"RES~7,H"}, {2,"RES~7,L"}, {2,"RES~7,(HL)"}, {2,"RES~7,A"}, {2,"SET~0,B"}, {2,"SET~0,C"}, {2,"SET~0,D"}, {2,"SET~0,E"}, {2,"SET~0,H"}, {2,"SET~0,L"}, {2,"SET~0,(HL)"}, {2,"SET~0,A"}, {2,"SET~1,B"}, {2,"SET~1,C"}, {2,"SET~1,D"}, {2,"SET~1,E"}, {2,"SET~1,H"}, {2,"SET~1,L"}, {2,"SET~1,(HL)"}, {2,"SET~1,A"}, {2,"SET~2,B"}, {2,"SET~2,C"}, {2,"SET~2,D"}, {2,"SET~2,E"}, {2,"SET~2,H"}, {2,"SET~2,L"}, {2,"SET~2,(HL)"}, {2,"SET~2,A"}, {2,"SET~3,B"}, {2,"SET~3,C"}, {2,"SET~3,D"}, {2,"SET~3,E"}, {2,"SET~3,H"}, {2,"SET~3,L"}, {2,"SET~3,(HL)"}, {2,"SET~3,A"}, {2,"SET~4,B"}, {2,"SET~4,C"}, {2,"SET~4,D"}, {2,"SET~4,E"}, {2,"SET~4,H"}, {2,"SET~4,L"}, {2,"SET~4,(HL)"}, {2,"SET~4,A"}, {2,"SET~5,B"}, {2,"SET~5,C"}, {2,"SET~5,D"}, {2,"SET~5,E"}, {2,"SET~5,H"}, {2,"SET~5,L"}, {2,"SET~5,(HL)"}, {2,"SET~5,A"}, {2,"SET~6,B"}, {2,"SET~6,C"}, {2,"SET~6,D"}, {2,"SET~6,E"}, {2,"SET~6,H"}, {2,"SET~6,L"}, {2,"SET~6,(HL)"}, {2,"SET~6,A"}, {2,"SET~7,B"}, {2,"SET~7,C"}, {2,"SET~7,D"}, {2,"SET~7,E"}, {2,"SET~7,H"}, {2,"SET~7,L"}, {2,"SET~7,(HL)"}, {2,"SET~7,A"}}; static const TilemDisasmInstruction insts_ddfdcb[256] = { {4,"RLC~B,(%i%s)"}, {4,"RLC~C,(%i%s)"}, {4,"RLC~D,(%i%s)"}, {4,"RLC~E,(%i%s)"}, {4,"RLC~H,(%i%s)"}, {4,"RLC~L,(%i%s)"}, {4,"RLC~(%i%s)"}, {4,"RLC~A,(%i%s)"}, {4,"RRC~B,(%i%s)"}, {4,"RRC~C,(%i%s)"}, {4,"RRC~D,(%i%s)"}, {4,"RRC~E,(%i%s)"}, {4,"RRC~H,(%i%s)"}, {4,"RRC~L,(%i%s)"}, {4,"RRC~(%i%s)"}, {4,"RRC~A,(%i%s)"}, {4,"RL~B,(%i%s)"}, {4,"RL~C,(%i%s)"}, {4,"RL~D,(%i%s)"}, {4,"RL~E,(%i%s)"}, {4,"RL~H,(%i%s)"}, {4,"RL~L,(%i%s)"}, {4,"RL~(%i%s)"}, {4,"RL~A,(%i%s)"}, {4,"RR~B,(%i%s)"}, {4,"RR~C,(%i%s)"}, {4,"RR~D,(%i%s)"}, {4,"RR~E,(%i%s)"}, {4,"RR~H,(%i%s)"}, {4,"RR~L,(%i%s)"}, {4,"RR~(%i%s)"}, {4,"RR~A,(%i%s)"}, {4,"SLA~B,(%i%s)"}, {4,"SLA~C,(%i%s)"}, {4,"SLA~D,(%i%s)"}, {4,"SLA~E,(%i%s)"}, {4,"SLA~H,(%i%s)"}, {4,"SLA~L,(%i%s)"}, {4,"SLA~(%i%s)"}, {4,"SLA~A,(%i%s)"}, {4,"SRA~B,(%i%s)"}, {4,"SRA~C,(%i%s)"}, {4,"SRA~D,(%i%s)"}, {4,"SRA~E,(%i%s)"}, {4,"SRA~H,(%i%s)"}, {4,"SRA~L,(%i%s)"}, {4,"SRA~(%i%s)"}, {4,"SRA~A,(%i%s)"}, {4,"SLIA~B,(%i%s)"}, {4,"SLIA~C,(%i%s)"}, {4,"SLIA~D,(%i%s)"}, {4,"SLIA~E,(%i%s)"}, {4,"SLIA~H,(%i%s)"}, {4,"SLIA~L,(%i%s)"}, {4,"SLIA~(%i%s)"}, {4,"SLIA~A,(%i%s)"}, {4,"SRL~B,(%i%s)"}, {4,"SRL~C,(%i%s)"}, {4,"SRL~D,(%i%s)"}, {4,"SRL~E,(%i%s)"}, {4,"SRL~H,(%i%s)"}, {4,"SRL~L,(%i%s)"}, {4,"SRL~(%i%s)"}, {4,"SRL~A,(%i%s)"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f*"}, {4,"BIT~%f"}, {4,"BIT~%f*"}, {4,"RES~0,B,(%i%s)"}, {4,"RES~0,C,(%i%s)"}, {4,"RES~0,D,(%i%s)"}, {4,"RES~0,E,(%i%s)"}, {4,"RES~0,H,(%i%s)"}, {4,"RES~0,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~0,A,(%i%s)"}, {4,"RES~1,B,(%i%s)"}, {4,"RES~1,C,(%i%s)"}, {4,"RES~1,D,(%i%s)"}, {4,"RES~1,E,(%i%s)"}, {4,"RES~1,H,(%i%s)"}, {4,"RES~1,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~1,A,(%i%s)"}, {4,"RES~2,B,(%i%s)"}, {4,"RES~2,C,(%i%s)"}, {4,"RES~2,D,(%i%s)"}, {4,"RES~2,E,(%i%s)"}, {4,"RES~2,H,(%i%s)"}, {4,"RES~2,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~2,A,(%i%s)"}, {4,"RES~3,B,(%i%s)"}, {4,"RES~3,C,(%i%s)"}, {4,"RES~3,D,(%i%s)"}, {4,"RES~3,E,(%i%s)"}, {4,"RES~3,H,(%i%s)"}, {4,"RES~3,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~3,A,(%i%s)"}, {4,"RES~4,B,(%i%s)"}, {4,"RES~4,C,(%i%s)"}, {4,"RES~4,D,(%i%s)"}, {4,"RES~4,E,(%i%s)"}, {4,"RES~4,H,(%i%s)"}, {4,"RES~4,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~4,A,(%i%s)"}, {4,"RES~5,B,(%i%s)"}, {4,"RES~5,C,(%i%s)"}, {4,"RES~5,D,(%i%s)"}, {4,"RES~5,E,(%i%s)"}, {4,"RES~5,H,(%i%s)"}, {4,"RES~5,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~5,A,(%i%s)"}, {4,"RES~6,B,(%i%s)"}, {4,"RES~6,C,(%i%s)"}, {4,"RES~6,D,(%i%s)"}, {4,"RES~6,E,(%i%s)"}, {4,"RES~6,H,(%i%s)"}, {4,"RES~6,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~6,A,(%i%s)"}, {4,"RES~7,B,(%i%s)"}, {4,"RES~7,C,(%i%s)"}, {4,"RES~7,D,(%i%s)"}, {4,"RES~7,E,(%i%s)"}, {4,"RES~7,H,(%i%s)"}, {4,"RES~7,L,(%i%s)"}, {4,"RES~%f"}, {4,"RES~7,A,(%i%s)"}, {4,"SET~0,B,(%i%s)"}, {4,"SET~0,C,(%i%s)"}, {4,"SET~0,D,(%i%s)"}, {4,"SET~0,E,(%i%s)"}, {4,"SET~0,H,(%i%s)"}, {4,"SET~0,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~0,A,(%i%s)"}, {4,"SET~1,B,(%i%s)"}, {4,"SET~1,C,(%i%s)"}, {4,"SET~1,D,(%i%s)"}, {4,"SET~1,E,(%i%s)"}, {4,"SET~1,H,(%i%s)"}, {4,"SET~1,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~1,A,(%i%s)"}, {4,"SET~2,B,(%i%s)"}, {4,"SET~2,C,(%i%s)"}, {4,"SET~2,D,(%i%s)"}, {4,"SET~2,E,(%i%s)"}, {4,"SET~2,H,(%i%s)"}, {4,"SET~2,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~2,A,(%i%s)"}, {4,"SET~3,B,(%i%s)"}, {4,"SET~3,C,(%i%s)"}, {4,"SET~3,D,(%i%s)"}, {4,"SET~3,E,(%i%s)"}, {4,"SET~3,H,(%i%s)"}, {4,"SET~3,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~3,A,(%i%s)"}, {4,"SET~4,B,(%i%s)"}, {4,"SET~4,C,(%i%s)"}, {4,"SET~4,D,(%i%s)"}, {4,"SET~4,E,(%i%s)"}, {4,"SET~4,H,(%i%s)"}, {4,"SET~4,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~4,A,(%i%s)"}, {4,"SET~5,B,(%i%s)"}, {4,"SET~5,C,(%i%s)"}, {4,"SET~5,D,(%i%s)"}, {4,"SET~5,E,(%i%s)"}, {4,"SET~5,H,(%i%s)"}, {4,"SET~5,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~5,A,(%i%s)"}, {4,"SET~6,B,(%i%s)"}, {4,"SET~6,C,(%i%s)"}, {4,"SET~6,D,(%i%s)"}, {4,"SET~6,E,(%i%s)"}, {4,"SET~6,H,(%i%s)"}, {4,"SET~6,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~6,A,(%i%s)"}, {4,"SET~7,B,(%i%s)"}, {4,"SET~7,C,(%i%s)"}, {4,"SET~7,D,(%i%s)"}, {4,"SET~7,E,(%i%s)"}, {4,"SET~7,H,(%i%s)"}, {4,"SET~7,L,(%i%s)"}, {4,"SET~%f"}, {4,"SET~7,A,(%i%s)"}}; static const TilemDisasmInstruction insts_ed[256] = { {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,"IN~B,(C)"}, {2,"OUT~(C),B"}, {2,"SBC~HL,BC"}, {4,"LD~(%a),BC"}, {2,"NEG"}, {2,"RETN"}, {2,"IM~0"}, {2,"LD~I,A"}, {2,"IN~C,(C)"}, {2,"OUT~(C),C"}, {2,"ADC~HL,BC"}, {4,"LD~BC,(%a)"}, {2,"NEG*"}, {2,"RETI"}, {2,"IM~0*"}, {2,"LD~R,A"}, {2,"IN~D,(C)"}, {2,"OUT~(C),D"}, {2,"SBC~HL,DE"}, {4,"LD~(%a),DE"}, {2,"NEG*"}, {2,"RETN*"}, {2,"IM~1"}, {2,"LD~A,I"}, {2,"IN~E,(C)"}, {2,"OUT~(C),E"}, {2,"ADC~HL,DE"}, {4,"LD~DE,(%a)"}, {2,"NEG*"}, {2,"RETN*"}, {2,"IM~2"}, {2,"LD~A,R"}, {2,"IN~H,(C)"}, {2,"OUT~(C),H"}, {2,"SBC~HL,HL"}, {4,"LD~(%a),HL*"}, {2,"NEG*"}, {2,"RETN*"}, {2,"IM~0*"}, {2,"RRD"}, {2,"IN~L,(C)"}, {2,"OUT~(C),L"}, {2,"ADC~HL,HL"}, {4,"LD~HL,(%a)*"}, {2,"NEG*"}, {2,"RETN*"}, {2,"IM~0*"}, {2,"RLD"}, {2,"IN~(C)"}, {2,"OUT~(C),0"}, {2,"SBC~HL,SP"}, {4,"LD~(%a),SP"}, {2,"NEG*"}, {2,"RETN*"}, {2,"IM~1*"}, {2,0}, {2,"IN~A,(C)"}, {2,"OUT~(C),A"}, {2,"ADC~HL,SP"}, {4,"LD~SP,(%a)"}, {2,"NEG*"}, {2,"RETN*"}, {2,"IM~2*"}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,"LDI"}, {2,"CPI"}, {2,"INI"}, {2,"OUTI"}, {2,0}, {2,0}, {2,0}, {2,0}, {2,"LDD"}, {2,"CPD"}, {2,"IND"}, {2,"OUTD"}, {2,0}, {2,0}, {2,0}, {2,0}, {2,"LDIR"}, {2,"CPIR"}, {2,"INIR"}, {2,"OTIR"}, {2,0}, {2,0}, {2,0}, {2,0}, {2,"LDDR"}, {2,"CPDR"}, {2,"INDR"}, {2,"OTDR"}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}, {2,0}}; /* Count number of bytes of arguments for a given instruction/macro pattern */ static int pattern_arg_size(const char* pattern) { char* p; int count = 0, offs; while (*pattern) { if (*pattern != '%') pattern++; else { pattern++; if (*pattern >= '0' && *pattern <= '9') { offs = strtol(pattern, &p, 10); pattern = p; } else { offs = count; } switch (*pattern) { case 0: pattern--; break; case 'b': case 'C': case 'r': case 's': offs++; break; case 'a': case 'c': case 'f': case 'j': case 'w': offs += 2; break; } pattern++; if (offs > count) count = offs; } } return count; } static void get_instruction_info(const TilemDisasm* dasm, const byte* instr, int* length, int* argbase, const char** pattern) { const TilemDisasmSymbol* sym; const TilemDisasmInstruction* ii; dword mvalue; int i; mvalue = 0; for (i = 0; i < 4; i++) { mvalue = (mvalue << 8) | instr[i]; if ((sym = find_symbol(&dasm->macros, mvalue))) { *pattern = sym->name; *length = i + 1 + pattern_arg_size(sym->name); *argbase = i + 1; return; } } if (instr[0] == 0xed) { ii = &insts_ed[instr[1]]; *argbase = 2; } else if (instr[0] == 0xdd || instr[0] == 0xfd) { if (instr[1] == 0xcb) { ii = &insts_ddfdcb[instr[3]]; } else { ii = &insts_ddfd[instr[1]]; } *argbase = 2; } else if (instr[0] == 0xcb) { ii = &insts_cb[instr[1]]; *argbase = 2; } else { ii = &insts_main[instr[0]]; *argbase = 1; } *length = ii->length; if (ii->pattern) { *pattern = ii->pattern; } else { *argbase = 0; if (ii->length == 1) *pattern = "DB~%b"; else *pattern = "DB~%b,%b"; } } static void TILEM_ATTR_PRINTF(3, 4) printv(char** buf, int* bsize, const char* fmt, ...) { va_list ap; int n; if (*bsize == 0) return; va_start(ap, fmt); n = vsnprintf(*buf, *bsize, fmt, ap); va_end(ap); if (n >= *bsize) { *buf += *bsize - 1; **buf = 0; *bsize = 0; } else { *buf += n; **buf = 0; *bsize -= n; } } static void print_byte(char** buf, int* bsize, unsigned int b) { printv(buf, bsize, "$%02X", b); } static void print_word(const TilemDisasm* dasm, char** buf, int* bsize, dword w, int autonum, int autodiff) { TilemDisasmSymbol* sym; if (autonum && w < 0x100) { printv(buf, bsize, "$%04X", w); return; } sym = find_prev_symbol(&dasm->labels, w); if (sym && !strcmp(sym->name, "flags")) { w -= sym->value; sym = find_symbol(&dasm->flags, w); if (sym) { printv(buf, bsize, "flags + %s", sym->name); } else { printv(buf, bsize, "flags + $%02X", w); } } else if (sym && w == sym->value) { printv(buf, bsize, "%s", sym->name); } else if (sym && autodiff && w > 0x8000 && w - sym->value < 64) { printv(buf, bsize, "%s + %d", sym->name, w - sym->value); } else { printv(buf, bsize, "$%04X", w); } } static void print_romcall(const TilemDisasm* dasm, char** buf, int* bsize, dword w) { TilemDisasmSymbol* sym; sym = find_symbol(&dasm->romcalls, w); if (sym) { printv(buf, bsize, "%s", sym->name); } else { printv(buf, bsize, "$%04X", w); } } static void print_flag(const TilemDisasm* dasm, char** buf, int* bsize, unsigned int bit, unsigned int offset, unsigned int prefix) { TilemDisasmSymbol* sym; int i; if (prefix == 0xfd) { sym = find_symbol(&dasm->flags, 0x1000 + (offset << 4) + bit); if (sym) { for (i = 0; sym->name[i]; i++) { printv(buf, bsize, "%c", sym->name[i]); if (sym->name[i] == ',') printv(buf, bsize, " (IY + "); } printv(buf, bsize, ")"); return; } sym = find_symbol(&dasm->flags, offset); if (sym) { printv(buf, bsize, "%d, (IY + %s)", bit, sym->name); return; } } printv(buf, bsize, "%d, (%s", bit, (prefix == 0xfd ? "IY" : "IX")); if (offset & 0x80) { printv(buf, bsize, " - $%02X", 0x100 - offset); } else if (offset) { printv(buf, bsize, " + $%02X", offset); } printv(buf, bsize, ")"); } static void disassemble_pattern(const TilemDisasm* dasm, const char* pattern, const byte* ibuf, dword pc, int argbase, char** buf, int* bsize) { int argidx, offs; char* p; dword w; TilemDisasmSymbol* sym; argidx = argbase; while (*bsize && *pattern) { if (*pattern == '~') printv(buf, bsize, "\t"); else if (*pattern == ',') { printv(buf, bsize, ", "); } else if (*pattern != '%') { printv(buf, bsize, "%c", *pattern); } else { pattern++; if (*pattern >= '0' && *pattern <= '9') { offs = argbase + strtol(pattern, &p, 10); pattern = p; } else { offs = argidx; } switch (*pattern) { case 0: pattern--; break; case '%': printv(buf, bsize, "%%"); break; case 'a': /* %a: word value, always an address */ w = ibuf[offs] | (ibuf[offs + 1] << 8); print_word(dasm, buf, bsize, w, 0, 1); offs += 2; break; case 'b': /* %b: byte value */ print_byte(buf, bsize, ibuf[offs]); offs++; break; case 'c': /* %c: word value, always a ROM call number */ w = ibuf[offs] | (ibuf[offs + 1] << 8); print_romcall(dasm, buf, bsize, w); offs += 2; break; case 'C': /* %C: byte value, always a ROM call number */ print_romcall(dasm, buf, bsize, ibuf[offs]); offs++; break; case 'f': /* %f: flag value */ print_flag(dasm, buf, bsize, (ibuf[offs + 1] >> 3) & 7, ibuf[offs], ibuf[0]); offs += 2; break; case 'i': /* %i: IX or IY by instruction prefix */ if (ibuf[0] == 0xdd) printv(buf, bsize, "IX"); else printv(buf, bsize, "IY"); break; case 'j': /* %j: word value, always a jump address */ w = ibuf[offs] | (ibuf[offs + 1] << 8); print_word(dasm, buf, bsize, w, 0, 0); offs += 2; break; case 'r': /* %r: one-byte PC-relative value */ if (ibuf[offs] & 0x80) w = pc + offs - 0xff + ibuf[offs]; else w = pc + offs + 1 + ibuf[offs]; print_word(dasm, buf, bsize, w, 0, 0); offs++; break; case 's': /* %s: one-byte signed displacement */ if (ibuf[0] == 0xfd && (sym = find_symbol(&dasm->flags, ibuf[offs]))) { printv(buf, bsize, " + %s", sym->name); } else if (ibuf[offs] & 0x80) { printv(buf, bsize, " - "); print_byte(buf, bsize, 0x100 - ibuf[offs]); } else if (ibuf[offs]) { printv(buf, bsize, " + "); print_byte(buf, bsize, ibuf[offs]); } offs++; break; case 'w': /* %w: word value */ w = ibuf[offs] | (ibuf[offs + 1] << 8); print_word(dasm, buf, bsize, w, 1, 1); offs += 2; break; case 'z': /* %z: RST target address */ print_word(dasm, buf, bsize, ibuf[0] & 0x38, 0, 0); break; } if (offs > argidx) argidx = offs; } pattern++; } } void tilem_disasm_disassemble(const TilemDisasm* dasm, TilemCalc* calc, int phys, dword addr, dword* nextaddr, char* buffer, int bufsize) { byte ibuf[64]; dword a, addr_l, max; int length, argbase, i; const char* pattern; if (phys) { max = calc->hw.romsize + calc->hw.ramsize; for (i = 0; i < 4; i++) { a = (addr + i) % max; ibuf[i] = calc->mem[a]; } addr_l = (*calc->hw.mem_ptol)(calc, addr); if (addr_l == 0xffffffff) addr_l = (addr & 0x3fff) | 0x4000; } else { max = 0x10000; for (i = 0; i < 4; i++) { a = (addr + i) & 0xffff; ibuf[i] = calc->mem[(*calc->hw.mem_ltop)(calc, a)]; } addr_l = addr; } get_instruction_info(dasm, ibuf, &length, &argbase, &pattern); if (phys) { for (i = 0; i < length; i++) { ibuf[i] = calc->mem[addr]; addr = (addr + 1) % max; } } else { for (i = 0; i < length; i++) { ibuf[i] = calc->mem[(*calc->hw.mem_ltop)(calc, addr)]; addr = (addr + 1) & 0xffff; } } if (nextaddr) *nextaddr = addr; if (buffer) { disassemble_pattern(dasm, pattern, ibuf, addr_l, argbase, &buffer, &bufsize); } }