From d49404d2480148601896871e4f04228245558a90 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Wed, 13 Jul 2016 23:00:50 +0300 Subject: [PATCH] Debugger can now read .sym files, and display them. (No expression support yet) --- Cocoa/Document.m | 3 + Core/debugger.c | 159 ++++++++++++++++++++++++++++++++-------- Core/debugger.h | 4 +- Core/gb.c | 5 ++ Core/gb.h | 3 + Core/symbol_hash.c | 66 +++++++++++++++++ Core/symbol_hash.h | 23 ++++++ Core/z80_disassembler.c | 117 ++++++++++++++++++++++++++--- 8 files changed, 338 insertions(+), 42 deletions(-) create mode 100644 Core/symbol_hash.c create mode 100644 Core/symbol_hash.h diff --git a/Cocoa/Document.m b/Cocoa/Document.m index bc276cf..b278630 100644 --- a/Cocoa/Document.m +++ b/Cocoa/Document.m @@ -3,6 +3,7 @@ #include "Document.h" #include "AppDelegate.h" #include "gb.h" +#include "debugger.h" @interface Document () { @@ -204,6 +205,8 @@ static uint32_t rgbEncode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b) } GB_load_rom(&gb, [fileName UTF8String]); GB_load_battery(&gb, [[[fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"sav"] UTF8String]); + GB_debugger_load_symbol_file(&gb, [[[fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"sym"] UTF8String]); + return YES; } diff --git a/Core/debugger.c b/Core/debugger.c index 5b28dec..04d7e97 100644 --- a/Core/debugger.c +++ b/Core/debugger.c @@ -34,6 +34,40 @@ struct GB_watchpoint_s { uint8_t flags; }; + +static const char *value_to_string(GB_gameboy_t *gb, uint16_t value, bool prefer_name) +{ + static __thread char output[256]; + const GB_bank_symbol_t *symbol = GB_debugger_find_symbol(gb, value); + + if (symbol && (value - symbol->addr > 0x1000 || symbol->addr == 0) ) { + symbol = NULL; + } + + if (!symbol) { + sprintf(output, "$%04x", value); + } + + else if (symbol->addr == value) { + if (prefer_name) { + sprintf(output, "%s ($%04x)", symbol->name, value); + } + else { + sprintf(output, "$%04x (%s)", value, symbol->name); + } + } + + else { + if (prefer_name) { + sprintf(output, "%s+$%03x ($%04x)", symbol->name, value - symbol->addr, value); + } + else { + sprintf(output, "$%04x (%s+$%03x)", value, symbol->name, value - symbol->addr); + } + } + return output; +} + static uint16_t read_lvalue(GB_gameboy_t *gb, lvalue_t lvalue) { /* Not used until we add support for operators like += */ @@ -459,12 +493,13 @@ static bool registers(GB_gameboy_t *gb, char *arguments) return true; } - GB_log(gb, "AF = $%04x\n", gb->registers[GB_REGISTER_AF]); - GB_log(gb, "BC = $%04x\n", gb->registers[GB_REGISTER_BC]); - GB_log(gb, "DE = $%04x\n", gb->registers[GB_REGISTER_DE]); - GB_log(gb, "HL = $%04x\n", gb->registers[GB_REGISTER_HL]); - GB_log(gb, "SP = $%04x\n", gb->registers[GB_REGISTER_SP]); - GB_log(gb, "PC = $%04x\n", gb->pc); + GB_log(gb, "AF = $%04x\n", gb->registers[GB_REGISTER_AF]); /* AF can't really be an address */ + GB_log(gb, "BC = %s\n", value_to_string(gb, gb->registers[GB_REGISTER_BC], false)); + GB_log(gb, "DE = %s\n", value_to_string(gb, gb->registers[GB_REGISTER_DE], false)); + GB_log(gb, "HL = %s\n", value_to_string(gb, gb->registers[GB_REGISTER_HL], false)); + GB_log(gb, "SP = %s\n", value_to_string(gb, gb->registers[GB_REGISTER_SP], false)); + GB_log(gb, "PC = %s\n", value_to_string(gb, gb->pc, false)); + GB_log(gb, "TIMA = %d/%u\n", gb->io_registers[GB_IO_TIMA], gb->tima_cycles); GB_log(gb, "Display Controller: LY = %d/%u\n", gb->io_registers[GB_IO_LY], gb->display_cycles % 456); return true; @@ -516,7 +551,7 @@ static bool breakpoint(GB_gameboy_t *gb, char *arguments) uint16_t index = find_breakpoint(gb, result); if (index < gb->n_breakpoints && gb->breakpoints[index].addr == result) { - GB_log(gb, "Breakpoint already set at $%04x\n", result); + GB_log(gb, "Breakpoint already set at %s\n", value_to_string(gb, result, true)); if (!gb->breakpoints[index].condition && condition) { GB_log(gb, "Added condition to breakpoint\n"); gb->breakpoints[index].condition = strdup(condition); @@ -545,7 +580,7 @@ static bool breakpoint(GB_gameboy_t *gb, char *arguments) } gb->n_breakpoints++; - GB_log(gb, "Breakpoint set at $%04x\n", result); + GB_log(gb, "Breakpoint set at %s\n", value_to_string(gb, result, true)); return true; } @@ -574,7 +609,7 @@ static bool delete(GB_gameboy_t *gb, char *arguments) uint16_t index = find_breakpoint(gb, result); if (index >= gb->n_breakpoints || gb->breakpoints[index].addr != result) { - GB_log(gb, "No breakpoint set at $%04x\n", result); + GB_log(gb, "No breakpoint set at %s\n", value_to_string(gb, result, true)); return true; } @@ -586,7 +621,7 @@ static bool delete(GB_gameboy_t *gb, char *arguments) gb->n_breakpoints--; gb->breakpoints = realloc(gb->breakpoints, gb->n_breakpoints * sizeof(gb->breakpoints[0])); - GB_log(gb, "Breakpoint removed from $%04x\n", result); + GB_log(gb, "Breakpoint removed from %s\n", value_to_string(gb, result, true)); return true; } @@ -659,7 +694,7 @@ print_usage: uint16_t index = find_watchpoint(gb, result); if (index < gb->n_watchpoints && gb->watchpoints[index].addr == result) { - GB_log(gb, "Watchpoint already set at $%04x\n", result); + GB_log(gb, "Watchpoint already set at %s\n", value_to_string(gb, result, true)); if (!gb->watchpoints[index].flags != flags) { GB_log(gb, "Modified watchpoint type\n"); gb->watchpoints[index].flags = flags; @@ -693,7 +728,7 @@ print_usage: } gb->n_watchpoints++; - GB_log(gb, "Watchpoint set at $%04x\n", result); + GB_log(gb, "Watchpoint set at %s\n", value_to_string(gb, result, true)); return true; } @@ -722,7 +757,7 @@ static bool unwatch(GB_gameboy_t *gb, char *arguments) uint16_t index = find_watchpoint(gb, result); if (index >= gb->n_watchpoints || gb->watchpoints[index].addr != result) { - GB_log(gb, "No watchpoint set at $%04x\n", result); + GB_log(gb, "No watchpoint set at %s\n", value_to_string(gb, result, true)); return true; } @@ -734,7 +769,7 @@ static bool unwatch(GB_gameboy_t *gb, char *arguments) gb->n_watchpoints--; gb->watchpoints = realloc(gb->watchpoints, gb->n_watchpoints* sizeof(gb->watchpoints[0])); - GB_log(gb, "Watchpoint removed from $%04x\n", result); + GB_log(gb, "Watchpoint removed from %s\n", value_to_string(gb, result, true)); return true; } @@ -752,10 +787,12 @@ static bool list(GB_gameboy_t *gb, char *arguments) GB_log(gb, "%d breakpoint(s) set:\n", gb->n_breakpoints); for (uint16_t i = 0; i < gb->n_breakpoints; i++) { if (gb->breakpoints[i].condition) { - GB_log(gb, " %d. $%04x (Condition: %s)\n", i + 1, gb->breakpoints[i].addr, gb->breakpoints[i].condition); + GB_log(gb, " %d. %s (Condition: %s)\n", i + 1, + value_to_string(gb, gb->breakpoints[i].addr, true), + gb->breakpoints[i].condition); } else { - GB_log(gb, " %d. $%04x\n", i + 1, gb->breakpoints[i].addr); + GB_log(gb, " %d. %s\n", i + 1, value_to_string(gb, gb->breakpoints[i].addr, true)); } } } @@ -767,15 +804,15 @@ static bool list(GB_gameboy_t *gb, char *arguments) GB_log(gb, "%d watchpoint(s) set:\n", gb->n_watchpoints); for (uint16_t i = 0; i < gb->n_watchpoints; i++) { if (gb->watchpoints[i].condition) { - GB_log(gb, " %d. $%04x (%c%c, Condition: %s)\n", i + 1, gb->watchpoints[i].addr, - (gb->watchpoints[i].flags & GB_WATCHPOINT_R)? 'r' : '-', - (gb->watchpoints[i].flags & GB_WATCHPOINT_W)? 'w' : '-', - gb->watchpoints[i].condition); + GB_log(gb, " %d. %s (%c%c, Condition: %s)\n", i + 1, value_to_string(gb, gb->watchpoints[i].addr, true), + (gb->watchpoints[i].flags & GB_WATCHPOINT_R)? 'r' : '-', + (gb->watchpoints[i].flags & GB_WATCHPOINT_W)? 'w' : '-', + gb->watchpoints[i].condition); } else { - GB_log(gb, " %d. $%04x (%c%c)\n", i + 1, gb->watchpoints[i].addr, - (gb->watchpoints[i].flags & GB_WATCHPOINT_R)? 'r' : '-', - (gb->watchpoints[i].flags & GB_WATCHPOINT_W)? 'w' : '-'); + GB_log(gb, " %d. %s (%c%c)\n", i + 1, value_to_string(gb, gb->watchpoints[i].addr, true), + (gb->watchpoints[i].flags & GB_WATCHPOINT_R)? 'r' : '-', + (gb->watchpoints[i].flags & GB_WATCHPOINT_W)? 'w' : '-'); } } } @@ -813,7 +850,7 @@ static bool print(GB_gameboy_t *gb, char *arguments) bool error; uint16_t result = debugger_evaluate(gb, arguments, (unsigned int)strlen(arguments), &error, NULL, NULL); if (!error) { - GB_log(gb, "=$%04x\n", result); + GB_log(gb, "=%s\n", value_to_string(gb, result, false)); } return true; } @@ -965,7 +1002,7 @@ void GB_debugger_ret_hook(GB_gameboy_t *gb) } else { if (gb->registers[GB_REGISTER_SP] != gb->sp_for_call_depth[gb->debug_call_depth]) { - GB_log(gb, "Stack leak detected for function $%04x!\n", gb->addr_for_call_depth[gb->debug_call_depth]); + GB_log(gb, "Stack leak detected for function %s!\n", value_to_string(gb, gb->addr_for_call_depth[gb->debug_call_depth], true)); GB_log(gb, "SP is $%04x, should be $%04x.\n", gb->registers[GB_REGISTER_SP], gb->sp_for_call_depth[gb->debug_call_depth]); gb->debug_stopped = true; @@ -983,7 +1020,7 @@ void GB_debugger_test_write_watchpoint(GB_gameboy_t *gb, uint16_t addr, uint8_t } if (!gb->watchpoints[index].condition) { gb->debug_stopped = true; - GB_log(gb, "Watchpoint: [$%04x] = $%02x\n", addr, value); + GB_log(gb, "Watchpoint: [%s] = $%02x\n", value_to_string(gb, addr, true), value); return; } bool error; @@ -996,7 +1033,7 @@ void GB_debugger_test_write_watchpoint(GB_gameboy_t *gb, uint16_t addr, uint8_t } if (condition) { gb->debug_stopped = true; - GB_log(gb, "Watchpoint: [$%04x] = $%02x\n", addr, value); + GB_log(gb, "Watchpoint: [%s] = $%02x\n", value_to_string(gb, addr, true), value); } } } @@ -1010,7 +1047,7 @@ void GB_debugger_test_read_watchpoint(GB_gameboy_t *gb, uint16_t addr) } if (!gb->watchpoints[index].condition) { gb->debug_stopped = true; - GB_log(gb, "Watchpoint: [$%04x]\n", addr); + GB_log(gb, "Watchpoint: [%s]\n", value_to_string(gb, addr, true)); return; } bool error; @@ -1023,7 +1060,7 @@ void GB_debugger_test_read_watchpoint(GB_gameboy_t *gb, uint16_t addr) } if (condition) { gb->debug_stopped = true; - GB_log(gb, "Watchpoint: [$%04x]\n", addr); + GB_log(gb, "Watchpoint: [%s]\n", value_to_string(gb, addr, true)); } } } @@ -1046,7 +1083,7 @@ next_command: } if (!gb->debug_stopped && should_break(gb, gb->pc)) { gb->debug_stopped = true; - GB_log(gb, "Breakpoint: PC = $%04x\n", gb->pc); + GB_log(gb, "Breakpoint: PC = %s\n", value_to_string(gb, gb->pc, true)); GB_cpu_disassemble(gb, gb->pc, 5); } if (gb->debug_stopped) { @@ -1084,4 +1121,66 @@ next_command: free(input); } +} + +void GB_debugger_load_symbol_file(GB_gameboy_t *gb, const char *path) +{ + FILE *f = fopen(path, "r"); + if (!f) return; + + char *line = NULL; + size_t size = 0; + size_t length = 0; + while ((length = getline(&line, &size, f)) != -1) { + for (unsigned i = 0; i < length; i++) { + if (line[i] == ';' || line[i] == '\n' || line[i] == '\r') { + line[i] = 0; + length = i; + break; + } + } + if (length == 0) continue; + + unsigned int bank, address; + char symbol[length]; + + if (sscanf(line, "%02x:%04x %s", &bank, &address, symbol) == 3) { + if (!gb->bank_symbols[bank]) { + gb->bank_symbols[bank] = GB_map_alloc(); + } + GB_map_add_symbol(gb->bank_symbols[bank], address, symbol); + } + } + free(line); + fclose(f); +} + +const GB_bank_symbol_t *GB_debugger_find_symbol(GB_gameboy_t *gb, uint16_t addr) +{ + unsigned char bank = 0; + if (addr < 0x4000) { + bank = gb->mbc_rom0_bank; + } + else if (addr < 0x8000) { + bank = gb->mbc_rom_bank; + } + + else if (addr < 0xD000) { + bank = 0; + } + else if (addr < 0xE000) { + bank = gb->cgb_ram_bank; + } + + const GB_bank_symbol_t *symbol = GB_map_find_symbol(gb->bank_symbols[bank], addr); + if (symbol) return symbol; + if (bank != 0) GB_map_find_symbol(gb->bank_symbols[0], addr); /* Maybe the symbol incorrectly uses bank 0? */ + return NULL; +} + +const char *GB_debugger_name_for_address(GB_gameboy_t *gb, uint16_t addr) +{ + const GB_bank_symbol_t *symbol = GB_debugger_find_symbol(gb, addr); + if (symbol && symbol->addr == addr) return symbol->name; + return NULL; } \ No newline at end of file diff --git a/Core/debugger.h b/Core/debugger.h index 9f0f922..78f60ce 100644 --- a/Core/debugger.h +++ b/Core/debugger.h @@ -7,5 +7,7 @@ void GB_debugger_call_hook(GB_gameboy_t *gb); void GB_debugger_ret_hook(GB_gameboy_t *gb); void GB_debugger_test_write_watchpoint(GB_gameboy_t *gb, uint16_t addr, uint8_t value); void GB_debugger_test_read_watchpoint(GB_gameboy_t *gb, uint16_t addr); - +void GB_debugger_load_symbol_file(GB_gameboy_t *gb, const char *path); +const GB_bank_symbol_t *GB_debugger_find_symbol(GB_gameboy_t *gb, uint16_t addr); +const char *GB_debugger_name_for_address(GB_gameboy_t *gb, uint16_t addr); #endif /* debugger_h */ diff --git a/Core/gb.c b/Core/gb.c index 85279af..4d75a2e 100644 --- a/Core/gb.c +++ b/Core/gb.c @@ -137,6 +137,11 @@ void GB_free(GB_gameboy_t *gb) if (gb->breakpoints) { free(gb->breakpoints); } + for (unsigned char i = 0; i--;) { + if (gb->bank_symbols[i]) { + GB_map_free(gb->bank_symbols[i]); + } + } } int GB_load_boot_rom(GB_gameboy_t *gb, const char *path) diff --git a/Core/gb.h b/Core/gb.h index d92f496..8ec1a2f 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -6,6 +6,7 @@ #include #include "apu.h" #include "save_struct.h" +#include "symbol_hash.h" #define GB_STRUCT_VERSION 9 @@ -359,6 +360,8 @@ typedef struct GB_gameboy_s { uint16_t n_watchpoints; struct GB_watchpoint_s *watchpoints; + /* Symbol table */ + GB_symbol_map_t *bank_symbols[0x100]; /* Misc */ bool turbo; diff --git a/Core/symbol_hash.c b/Core/symbol_hash.c new file mode 100644 index 0000000..7c4532a --- /dev/null +++ b/Core/symbol_hash.c @@ -0,0 +1,66 @@ +#include "gb.h" + +static size_t GB_map_find_symbol_index(GB_symbol_map_t *map, uint16_t addr) +{ + if (!map->symbols) { + return 0; + } + ssize_t min = 0; + ssize_t max = map->n_symbols; + while (min < max) { + size_t pivot = (min + max) / 2; + if (map->symbols[pivot].addr == addr) return pivot; + if (map->symbols[pivot].addr > addr) { + max = pivot; + } + else { + min = pivot + 1; + } + } + return (size_t) min; +} + +void GB_map_add_symbol(GB_symbol_map_t *map, uint16_t addr, const char *name) +{ + size_t index = GB_map_find_symbol_index(map, addr); + + if (index < map->n_symbols && map->symbols[index].addr == addr) return; + + map->symbols = realloc(map->symbols, (map->n_symbols + 1) * sizeof(map->symbols[0])); + memmove(&map->symbols[index + 1], &map->symbols[index], (map->n_symbols - index) * sizeof(map->symbols[0])); + map->symbols[index].addr = addr; + map->symbols[index].name = strdup(name); + map->n_symbols++; +} + +const GB_bank_symbol_t *GB_map_find_symbol(GB_symbol_map_t *map, uint16_t addr) +{ + size_t index = GB_map_find_symbol_index(map, addr); + if (index < map->n_symbols && map->symbols[index].addr != addr) { + index--; + } + if (index < map->n_symbols) { + return &map->symbols[index]; + } + return NULL; +} + +GB_symbol_map_t *GB_map_alloc(void) +{ + GB_symbol_map_t *map = malloc(sizeof(*map)); + memset(map, 0, sizeof(*map)); + return map; +} + +void GB_map_free(GB_symbol_map_t *map) +{ + for (unsigned char i = 0; i < map->n_symbols; i++) { + free(map->symbols[i].name); + } + + if (map->symbols) { + free(map->symbols); + } + + free(map); +} \ No newline at end of file diff --git a/Core/symbol_hash.h b/Core/symbol_hash.h new file mode 100644 index 0000000..8044e3f --- /dev/null +++ b/Core/symbol_hash.h @@ -0,0 +1,23 @@ +#ifndef symbol_hash_h +#define symbol_hash_h + +#include +#include + +typedef struct { + uint16_t addr; + char *name; +} GB_bank_symbol_t; + + +typedef struct { + GB_bank_symbol_t *symbols; + size_t n_symbols; +} GB_symbol_map_t; + +void GB_map_add_symbol(GB_symbol_map_t *map, uint16_t addr, const char *name); +const GB_bank_symbol_t *GB_map_find_symbol(GB_symbol_map_t *map, uint16_t addr); +GB_symbol_map_t *GB_map_alloc(void); +void GB_map_free(GB_symbol_map_t *map); + +#endif /* symbol_hash_h */ diff --git a/Core/z80_disassembler.c b/Core/z80_disassembler.c index c312a90..8bfada2 100644 --- a/Core/z80_disassembler.c +++ b/Core/z80_disassembler.c @@ -3,6 +3,7 @@ #include "z80_cpu.h" #include "memory.h" #include "gb.h" +#include "debugger.h" typedef void GB_opcode_t(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc); @@ -34,7 +35,13 @@ static void ld_rr_d16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) register_id = (GB_read_memory(gb, (*pc)++) >> 4) + 1; value = GB_read_memory(gb, (*pc)++); value |= GB_read_memory(gb, (*pc)++) << 8; - GB_log(gb, "LD %s, $%04x\n", register_names[register_id], value); + const char *symbol = GB_debugger_name_for_address(gb, value); + if (symbol) { + GB_log(gb, "LD %s, %s ; =$%04x\n", register_names[register_id], symbol, value); + } + else { + GB_log(gb, "LD %s, $%04x\n", register_names[register_id], value); + } } static void ld_drr_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) @@ -92,7 +99,13 @@ static void ld_da16_sp(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc){ (*pc)++; addr = GB_read_memory(gb, (*pc)++); addr |= GB_read_memory(gb, (*pc)++) << 8; - GB_log(gb, "LD [$%04x], sp\n", addr); + const char *symbol = GB_debugger_name_for_address(gb, addr); + if (symbol) { + GB_log(gb, "LD [%s], sp ; =$%04x\n", symbol, addr); + } + else { + GB_log(gb, "LD [$%04x], sp\n", addr); + } } static void add_hl_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) @@ -155,7 +168,14 @@ static void rra(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) static void jr_r8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) { (*pc)++; - GB_attributed_log(gb, GB_LOG_UNDERLINE, "JR $%04x\n", *pc + (int8_t) GB_read_memory(gb, (*pc)) + 1); + uint16_t addr = *pc + (int8_t) GB_read_memory(gb, (*pc)) + 1; + const char *symbol = GB_debugger_name_for_address(gb, addr); + if (symbol) { + GB_attributed_log(gb, GB_LOG_UNDERLINE, "JR %s ; =$%04x\n", symbol, addr); + } + else { + GB_attributed_log(gb, GB_LOG_UNDERLINE, "JR $%04x\n", addr); + } (*pc)++; } @@ -178,7 +198,14 @@ static const char *condition_code(uint8_t opcode) static void jr_cc_r8(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) { (*pc)++; - GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JR %s, $%04x\n", condition_code(opcode), *pc + (int8_t)GB_read_memory(gb, (*pc)) + 1); + uint16_t addr = *pc + (int8_t) GB_read_memory(gb, (*pc)) + 1; + const char *symbol = GB_debugger_name_for_address(gb, addr); + if (symbol) { + GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JR %s, %s ; =$%04x\n", condition_code(opcode), symbol, addr); + } + else { + GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JR %s, $%04x\n", condition_code(opcode), addr); + } (*pc)++; } @@ -356,21 +383,42 @@ static void pop_rr(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) static void jp_cc_a16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) { (*pc)++; - GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JP %s, $%04x\n", condition_code(opcode), GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8)); + uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8); + const char *symbol = GB_debugger_name_for_address(gb, addr); + if (symbol) { + GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JP %s, %s ; =$%04x\n", condition_code(opcode), symbol, addr); + } + else { + GB_attributed_log(gb, GB_LOG_DASHED_UNDERLINE, "JP %s, $%04x\n", condition_code(opcode), addr); + } (*pc) += 2; } static void jp_a16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) { (*pc)++; - GB_log(gb, "JP $%04x\n", GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8)); + uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8); + const char *symbol = GB_debugger_name_for_address(gb, addr); + if (symbol) { + GB_log(gb, "JP %s ; =$%04x\n", symbol, addr); + } + else { + GB_log(gb, "JP $%04x\n", addr); + } (*pc) += 2; } static void call_cc_a16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) { (*pc)++; - GB_log(gb, "CALL %s, $%04x\n", condition_code(opcode), GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8)); + uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8); + const char *symbol = GB_debugger_name_for_address(gb, addr); + if (symbol) { + GB_log(gb, "CALL %s, %s ; =$%04x\n", condition_code(opcode), symbol, addr); + } + else { + GB_log(gb, "CALL %s, $%04x\n", condition_code(opcode), addr); + } (*pc) += 2; } @@ -451,7 +499,14 @@ static void reti(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) static void call_a16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) { (*pc)++; - GB_log(gb, "CALL $%04x\n", GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8)); + uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8); + const char *symbol = GB_debugger_name_for_address(gb, addr); + if (symbol) { + GB_log(gb, "CALL %s ; =$%04x\n", symbol, addr); + } + else { + GB_log(gb, "CALL $%04x\n", addr); + } (*pc) += 2; } @@ -497,14 +552,28 @@ static void jp_hl(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) static void ld_da16_a(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) { (*pc)++; - GB_log(gb, "LD [$%04x], a\n", GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8)); + uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8); + const char *symbol = GB_debugger_name_for_address(gb, addr); + if (symbol) { + GB_log(gb, "LD [%s], a ; =$%04x\n", symbol, addr); + } + else { + GB_log(gb, "LD [$%04x], a\n", addr); + } (*pc) += 2; } static void ld_a_da16(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc) { (*pc)++; - GB_log(gb, "LD a, [$%04x]\n", GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8)); + uint16_t addr = GB_read_memory(gb, *pc) | (GB_read_memory(gb, *pc + 1) << 8); + const char *symbol = GB_debugger_name_for_address(gb, addr); + if (symbol) { + GB_log(gb, "LD a, [%s] ; =$%04x\n", symbol, addr); + } + else { + GB_log(gb, "LD a, [$%04x]\n", addr); + } (*pc) += 2; } @@ -668,10 +737,36 @@ static GB_opcode_t *opcodes[256] = { ld_hl_sp_r8,ld_sp_hl, ld_a_da16, ei, ill, ill, cp_a_d8, rst, }; + + void GB_cpu_disassemble(GB_gameboy_t *gb, uint16_t pc, uint16_t count) { + const GB_bank_symbol_t *function_symbol = GB_debugger_find_symbol(gb, pc); + + if (function_symbol && pc - function_symbol->addr > 0x1000) { + function_symbol = NULL; + } + + if (function_symbol && pc != function_symbol->addr) { + GB_log(gb, "%s:\n", function_symbol->name); + } + + uint16_t current_function = function_symbol? function_symbol->addr : 0; + while (count--) { - GB_log(gb, "%s%04x: ", pc == gb->pc? "-> ": " ", pc); + function_symbol = GB_debugger_find_symbol(gb, pc); + if (function_symbol && function_symbol->addr == pc) { + if (current_function != function_symbol->addr) { + GB_log(gb, "\n"); + } + GB_log(gb, "%s:\n", function_symbol->name); + } + if (function_symbol) { + GB_log(gb, "%s%04x <+%03x>: ", pc == gb->pc? " ->": " ", pc, pc - function_symbol->addr); + } + else { + GB_log(gb, "%s%04x: ", pc == gb->pc? " ->": " ", pc); + } uint8_t opcode = GB_read_memory(gb, pc); opcodes[opcode](gb, opcode, &pc); }