Skip to content

Commit

Permalink
Add a debugger reset command, with a frontend-handled reload option. C…
Browse files Browse the repository at this point in the history
…loses LIJI32#537
  • Loading branch information
LIJI32 committed Apr 11, 2023
1 parent 9a5aa6b commit 5b37d3c
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 4 deletions.
12 changes: 12 additions & 0 deletions Cocoa/Document.m
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,17 @@ static void infraredStateChanged(GB_gameboy_t *gb, bool on)
[self infraredStateChanged:on];
}

static void debuggerReloadCallback(GB_gameboy_t *gb)
{
Document *self = (__bridge Document *)GB_get_user_data(gb);
dispatch_sync(dispatch_get_main_queue(), ^{
bool wasRunning = self->running;
self->running = false; // Hack for output capture
[self loadROM];
self->running = wasRunning;
GB_reset(gb);
});
}

- (instancetype)init
{
Expand Down Expand Up @@ -320,6 +331,7 @@ - (void) initCommon
GB_apu_set_sample_callback(&gb, audioCallback);
GB_set_rumble_callback(&gb, rumbleCallback);
GB_set_infrared_callback(&gb, infraredStateChanged);
GB_set_debugger_reload_callback(&gb, debuggerReloadCallback);
[self updateRumbleMode];
}

Expand Down
67 changes: 63 additions & 4 deletions Core/debugger.c
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,61 @@ static bool interrupt(GB_gameboy_t *gb, char *arguments, char *modifiers, const
return true;
}

static char *reset_completer(GB_gameboy_t *gb, const char *string, uintptr_t *context)
{
size_t length = strlen(string);
const char *suggestions[] = {"quick", "reload"};
while (*context < sizeof(suggestions) / sizeof(suggestions[0])) {
if (memcmp(string, suggestions[*context], length) == 0) {
return strdup(suggestions[(*context)++] + length);
}
(*context)++;
}
return NULL;
}

static bool reset(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command)
{
NO_MODIFIERS

const char *stripped_argument = lstrip(arguments);

if (stripped_argument[0] == 0) {
GB_reset(gb);
if (gb->debug_stopped) {
GB_cpu_disassemble(gb, gb->pc, 5);
}
return true;
}

if (strcmp(stripped_argument, "quick") == 0) {
GB_quick_reset(gb);
if (gb->debug_stopped) {
GB_cpu_disassemble(gb, gb->pc, 5);
}
return true;
}

if (strcmp(stripped_argument, "reload") == 0) {
if (gb->debugger_reload_callback) {
gb->debugger_reload_callback(gb);
if (gb->undo_state) {
free(gb->undo_state);
gb->undo_state = NULL;
}
if (gb->debug_stopped) {
GB_cpu_disassemble(gb, gb->pc, 5);
}
return true;
}
GB_log(gb, "ROM reloading via the debugger is not supported in this frontend.\n");
return true;
}

print_usage(gb, command);
return true;
}

static bool next(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command)
{
NO_MODIFIERS
Expand Down Expand Up @@ -2022,22 +2077,26 @@ static bool help(GB_gameboy_t *gb, char *arguments, char *modifiers, const debug
static const debugger_command_t commands[] = {
{"continue", 1, cont, "Continue running until next stop"},
{"interrupt", 1, interrupt, "Interrupt the program execution"},
{"reset", 3, reset, "Reset the program execution. "
"Add 'quick' as an argument to perform a quick reset that does not reset RAM. "
"Add 'reload' as an argument to reload the ROM and symbols before resetting.",
"[quick|reload]", .argument_completer = reset_completer},
{"next", 1, next, "Run the next instruction, skipping over function calls"},
{"step", 1, step, "Run the next instruction, stepping into function calls"},
{"finish", 1, finish, "Run until the current function returns"},
{"undo", 1, undo, "Revert the last command"},
{"registers", 1, registers, "Print values of processor registers and other important registers"},
{"backtrace", 2, backtrace, "Display the current call stack"},
{"bt", 2, }, /* Alias */
{"print", 1, print, "Evaluate and print an expression "
{"print", 1, print, "Evaluate and print an expression. "
"Use modifier to format as an address (a, default) or as a number in "
"decimal (d), hexadecimal (x), octal (o) or binary (b).",
"<expression>", "format", .argument_completer = symbol_completer, .modifiers_completer = format_completer},
{"eval", 2, }, /* Alias */
{"examine", 2, examine, "Examine values at address", "<expression>", "count", .argument_completer = symbol_completer},
{"x", 1, }, /* Alias */
{"disassemble", 1, disassemble, "Disassemble instructions at address", "<expression>", "count", .argument_completer = symbol_completer},
{"breakpoint", 1, breakpoint, "Add a new breakpoint at the specified address/expression "
{"breakpoint", 1, breakpoint, "Add a new breakpoint at the specified address/expression. "
"Can also modify the condition of existing breakpoints. "
"If the j modifier is used, the breakpoint will occur just before "
"jumping to the target.",
Expand All @@ -2058,8 +2117,8 @@ static const debugger_command_t commands[] = {
"the count.", "(keep)", .argument_completer = keep_completer},
{"cartridge", 2, mbc, "Display information about the MBC and cartridge"},
{"mbc", 3, }, /* Alias */
{"apu", 3, apu, "Display information about the current state of the audio processing "
"unit", "[channel (1-4, 5 for NR5x)]"},
{"apu", 3, apu, "Display information about the current state of the audio processing unit",
"[channel (1-4, 5 for NR5x)]"},
{"wave", 3, wave, "Print a visual representation of the wave RAM. "
"Modifiers can be used for a (f)ull print (the default), "
"a more (c)ompact one, or a one-(l)iner", "", "(f|c|l)", .modifiers_completer = wave_completer},
Expand Down
5 changes: 5 additions & 0 deletions Core/gb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1253,6 +1253,11 @@ void GB_set_async_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback)
#endif
}

void GB_set_debugger_reload_callback(GB_gameboy_t *gb, GB_debugger_reload_callback_t callback)
{
gb->debugger_reload_callback = callback;
}

void GB_set_execution_callback(GB_gameboy_t *gb, GB_execution_callback_t callback)
{
gb->execution_callback = callback;
Expand Down
4 changes: 4 additions & 0 deletions Core/gb.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ typedef enum {
typedef void (*GB_vblank_callback_t)(GB_gameboy_t *gb, GB_vblank_type_t type);
typedef void (*GB_log_callback_t)(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes);
typedef char *(*GB_input_callback_t)(GB_gameboy_t *gb);
typedef void (*GB_debugger_reload_callback_t)(GB_gameboy_t *gb);
typedef uint32_t (*GB_rgb_encode_callback_t)(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b);
typedef void (*GB_infrared_callback_t)(GB_gameboy_t *gb, bool on);
typedef void (*GB_rumble_callback_t)(GB_gameboy_t *gb, double rumble_amplitude);
Expand Down Expand Up @@ -730,6 +731,8 @@ struct GB_gameboy_internal_s {
GB_execution_callback_t execution_callback;
GB_lcd_line_callback_t lcd_line_callback;
GB_lcd_status_callback_t lcd_status_callback;
GB_debugger_reload_callback_t debugger_reload_callback;

/*** Debugger ***/
volatile bool debug_stopped, debug_disable;
bool debug_fin_command, debug_next_command;
Expand Down Expand Up @@ -930,6 +933,7 @@ void GB_set_vblank_callback(GB_gameboy_t *gb, GB_vblank_callback_t callback);
void GB_set_log_callback(GB_gameboy_t *gb, GB_log_callback_t callback);
void GB_set_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback);
void GB_set_async_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback);
void GB_set_debugger_reload_callback(GB_gameboy_t *gb, GB_debugger_reload_callback_t callback);
void GB_set_rgb_encode_callback(GB_gameboy_t *gb, GB_rgb_encode_callback_t callback);
void GB_set_infrared_callback(GB_gameboy_t *gb, GB_infrared_callback_t callback);
void GB_set_rumble_callback(GB_gameboy_t *gb, GB_rumble_callback_t callback);
Expand Down
32 changes: 32 additions & 0 deletions SDL/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,36 @@ static bool is_path_writeable(const char *path)
return true;
}

static void debugger_reload_callback(GB_gameboy_t *gb)
{
size_t path_length = strlen(filename);
char extension[4] = {0,};
if (path_length > 4) {
if (filename[path_length - 4] == '.') {
extension[0] = tolower((unsigned char)filename[path_length - 3]);
extension[1] = tolower((unsigned char)filename[path_length - 2]);
extension[2] = tolower((unsigned char)filename[path_length - 1]);
}
}
if (strcmp(extension, "isx") == 0) {
GB_load_isx(gb, filename);
}
else {
GB_load_rom(gb, filename);
}

GB_load_battery(gb, battery_save_path_ptr);

GB_debugger_clear_symbols(gb);
GB_debugger_load_symbol_file(gb, resource_path("registers.sym"));

char symbols_path[path_length + 5];
replace_extension(filename, path_length, symbols_path, ".sym");
GB_debugger_load_symbol_file(gb, symbols_path);

GB_reset(gb);
}

static void run(void)
{
SDL_ShowCursor(SDL_DISABLE);
Expand Down Expand Up @@ -740,6 +770,8 @@ static void run(void)
GB_set_input_callback(&gb, input_callback);
GB_set_async_input_callback(&gb, asyc_input_callback);
}

GB_set_debugger_reload_callback(&gb, debugger_reload_callback);
}
if (stop_on_start) {
stop_on_start = false;
Expand Down

0 comments on commit 5b37d3c

Please sign in to comment.