mirror of https://github.com/LIJI32/SameBoy.git
Add a debugger reset command, with a frontend-handled reload option. Closes #537
This commit is contained in:
parent
9a5aa6b5c8
commit
5b37d3c402
|
@ -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
|
||||
{
|
||||
|
@ -320,6 +331,7 @@ static void infraredStateChanged(GB_gameboy_t *gb, bool on)
|
|||
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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -2022,6 +2077,10 @@ 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"},
|
||||
|
@ -2029,7 +2088,7 @@ static const debugger_command_t commands[] = {
|
|||
{"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},
|
||||
|
@ -2037,7 +2096,7 @@ static const debugger_command_t commands[] = {
|
|||
{"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.",
|
||||
|
@ -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},
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
|
32
SDL/main.c
32
SDL/main.c
|
@ -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);
|
||||
|
@ -740,6 +770,8 @@ restart:
|
|||
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;
|
||||
|
|
Loading…
Reference in New Issue