Debugger can now read .sym files, and display them. (No expression support yet)

This commit is contained in:
Lior Halphon 2016-07-13 23:00:50 +03:00
parent e9b3a38171
commit d49404d248
8 changed files with 338 additions and 42 deletions

View File

@ -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;
}

View File

@ -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,13 +804,13 @@ 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_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_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) {
@ -1085,3 +1122,65 @@ 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;
}

View File

@ -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 */

View File

@ -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)

View File

@ -6,6 +6,7 @@
#include <time.h>
#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;

66
Core/symbol_hash.c Normal file
View File

@ -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);
}

23
Core/symbol_hash.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef symbol_hash_h
#define symbol_hash_h
#include <stdlib.h>
#include <string.h>
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 */

View File

@ -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;
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;
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);
}