diff --git a/Cocoa/Document.m b/Cocoa/Document.m index 0c40776..d8fb71f 100644 --- a/Cocoa/Document.m +++ b/Cocoa/Document.m @@ -74,8 +74,15 @@ enum model { topMargin:(unsigned) topMargin bottomMargin: (unsigned) bottomMargin exposure:(unsigned) exposure; - (void) gotNewSample:(GB_sample_t *)sample; +- (void) loadBootROM:(GB_boot_rom_t)type; @end +static void boot_rom_load(GB_gameboy_t *gb, GB_boot_rom_t type) +{ + Document *self = (__bridge Document *)GB_get_user_data(gb); + [self loadBootROM: type]; +} + static void vblank(GB_gameboy_t *gb) { Document *self = (__bridge Document *)GB_get_user_data(gb); @@ -209,6 +216,7 @@ static void audioCallback(GB_gameboy_t *gb, GB_sample_t *sample) { GB_init(&gb, [self internalModel]); GB_set_user_data(&gb, (__bridge void *)(self)); + GB_set_boot_rom_load_callback(&gb, (GB_boot_rom_load_callback_t)boot_rom_load); GB_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank); GB_set_log_callback(&gb, (GB_log_callback_t) consoleLog); GB_set_input_callback(&gb, (GB_input_callback_t) consoleInput); @@ -340,15 +348,19 @@ static void audioCallback(GB_gameboy_t *gb, GB_sample_t *sample) GB_debugger_set_disabled(&gb, false); } -- (void) loadBootROM +- (void) loadBootROM: (GB_boot_rom_t)type { - static NSString * const boot_names[] = {@"dmg_boot", @"cgb_boot", @"agb_boot", @"sgb_boot"}; - if ([self internalModel] == GB_MODEL_SGB2) { - GB_load_boot_rom(&gb, [[self bootROMPathForName:@"sgb2_boot"] UTF8String]); - } - else { - GB_load_boot_rom(&gb, [[self bootROMPathForName:boot_names[current_model - 1]] UTF8String]); - } + static NSString *const names[] = { + [GB_BOOT_ROM_DMG0] = @"dmg0_boot", + [GB_BOOT_ROM_DMG] = @"dmg_boot", + [GB_BOOT_ROM_MGB] = @"mgb_boot", + [GB_BOOT_ROM_SGB] = @"sgb_boot", + [GB_BOOT_ROM_SGB2] = @"sgb2_boot", + [GB_BOOT_ROM_CGB0] = @"cgb0_boot", + [GB_BOOT_ROM_CGB] = @"cgb_boot", + [GB_BOOT_ROM_AGB] = @"agb_boot", + }; + GB_load_boot_rom(&gb, [[self bootROMPathForName:names[type]] UTF8String]); } - (IBAction)reset:(id)sender @@ -360,8 +372,6 @@ static void audioCallback(GB_gameboy_t *gb, GB_sample_t *sample) current_model = (enum model)[sender tag]; } - [self loadBootROM]; - if (!modelsChanging && [sender tag] == MODEL_NONE) { GB_reset(&gb); } diff --git a/Core/gb.c b/Core/gb.c index d019fc4..4a9525c 100644 --- a/Core/gb.c +++ b/Core/gb.c @@ -878,6 +878,36 @@ static void reset_ram(GB_gameboy_t *gb) } } +static void request_boot_rom(GB_gameboy_t *gb) +{ + if (gb->boot_rom_load_callback) { + GB_boot_rom_t type = 0; + switch (gb->model) { + case GB_MODEL_DMG_B: + type = GB_BOOT_ROM_DMG; + break; + case GB_MODEL_SGB_NTSC: + case GB_MODEL_SGB_PAL: + case GB_MODEL_SGB_NTSC_NO_SFC: + case GB_MODEL_SGB_PAL_NO_SFC: + type = GB_BOOT_ROM_SGB; + break; + case GB_MODEL_SGB2: + case GB_MODEL_SGB2_NO_SFC: + type = GB_BOOT_ROM_SGB2; + break; + case GB_MODEL_CGB_C: + case GB_MODEL_CGB_E: + type = GB_BOOT_ROM_CGB; + break; + case GB_MODEL_AGB: + type = GB_BOOT_ROM_AGB; + break; + } + gb->boot_rom_load_callback(gb, type); + } +} + void GB_reset(GB_gameboy_t *gb) { uint32_t mbc_ram_size = gb->mbc_ram_size; @@ -948,6 +978,7 @@ void GB_reset(GB_gameboy_t *gb) } gb->magic = state_magic(); + request_boot_rom(gb); } void GB_switch_model_and_reset(GB_gameboy_t *gb, GB_model_t model) @@ -1093,3 +1124,9 @@ void GB_set_icd_vreset_callback(GB_gameboy_t *gb, GB_icd_vreset_callback_t callb { gb->icd_vreset_callback = callback; } + +void GB_set_boot_rom_load_callback(GB_gameboy_t *gb, GB_boot_rom_load_callback_t callback) +{ + gb->boot_rom_load_callback = callback; + request_boot_rom(gb); +} diff --git a/Core/gb.h b/Core/gb.h index 7831cb7..487269f 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -229,6 +229,17 @@ typedef enum { GB_LOG_UNDERLINE_MASK = GB_LOG_DASHED_UNDERLINE | GB_LOG_UNDERLINE } GB_log_attributes; +typedef enum { + GB_BOOT_ROM_DMG0, + GB_BOOT_ROM_DMG, + GB_BOOT_ROM_MGB, + GB_BOOT_ROM_SGB, + GB_BOOT_ROM_SGB2, + GB_BOOT_ROM_CGB0, + GB_BOOT_ROM_CGB, + GB_BOOT_ROM_AGB, +} GB_boot_rom_t; + #ifdef GB_INTERNAL #define LCDC_PERIOD 70224 #define CPU_FREQUENCY 0x400000 @@ -259,6 +270,7 @@ typedef void (*GB_joyp_write_callback_t)(GB_gameboy_t *gb, uint8_t value); typedef void (*GB_icd_pixel_callback_t)(GB_gameboy_t *gb, uint8_t row); typedef void (*GB_icd_hreset_callback_t)(GB_gameboy_t *gb); typedef void (*GB_icd_vreset_callback_t)(GB_gameboy_t *gb); +typedef void (*GB_boot_rom_load_callback_t)(GB_gameboy_t *gb, GB_boot_rom_t type); typedef struct { bool state; @@ -553,6 +565,7 @@ struct GB_gameboy_internal_s { GB_icd_vreset_callback_t icd_hreset_callback; GB_icd_vreset_callback_t icd_vreset_callback; GB_read_memory_callback_t read_memory_callback; + GB_boot_rom_load_callback_t boot_rom_load_callback; /* IR */ long cycles_since_ir_change; // In 8MHz units @@ -706,7 +719,9 @@ void GB_set_rgb_encode_callback(GB_gameboy_t *gb, GB_rgb_encode_callback_t callb 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); void GB_set_update_input_hint_callback(GB_gameboy_t *gb, GB_update_input_hint_callback_t callback); - +/* Called when a new boot ROM is needed. The callback should call GB_load_boot_rom or GB_load_boot_rom_from_buffer */ +void GB_set_boot_rom_load_callback(GB_gameboy_t *gb, GB_boot_rom_load_callback_t callback); + void GB_set_palette(GB_gameboy_t *gb, const GB_palette_t *palette); /* These APIs are used when using internal clock */ diff --git a/SDL/main.c b/SDL/main.c index e83bfd8..cb9d00f 100644 --- a/SDL/main.c +++ b/SDL/main.c @@ -445,6 +445,24 @@ static bool handle_pending_command(void) return false; } +static void load_boot_rom(GB_gameboy_t *gb, GB_boot_rom_t type) +{ + bool error = false; + start_capturing_logs(); + static const char *const names[] = { + [GB_BOOT_ROM_DMG0] = "dmg0_boot.bin", + [GB_BOOT_ROM_DMG] = "dmg_boot.bin", + [GB_BOOT_ROM_MGB] = "mgb_boot.bin", + [GB_BOOT_ROM_SGB] = "sgb_boot.bin", + [GB_BOOT_ROM_SGB2] = "sgb2_boot.bin", + [GB_BOOT_ROM_CGB0] = "cgb0_boot.bin", + [GB_BOOT_ROM_CGB] = "cgb_boot.bin", + [GB_BOOT_ROM_AGB] = "agb_boot.bin", + }; + GB_load_boot_rom(gb, resource_path(names[type])); + end_capturing_logs(true, error); +} + static void run(void) { SDL_ShowCursor(SDL_DISABLE); @@ -470,6 +488,7 @@ restart: else { GB_init(&gb, model); + GB_set_boot_rom_load_callback(&gb, load_boot_rom); GB_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank); GB_set_pixels_output(&gb, active_pixel_buffer); GB_set_rgb_encode_callback(&gb, rgb_encode); @@ -490,15 +509,6 @@ restart: bool error = false; - start_capturing_logs(); - const char * const boot_roms[] = {"dmg_boot.bin", "cgb_boot.bin", "agb_boot.bin", "sgb_boot.bin"}; - const char *boot_rom = boot_roms[configuration.model]; - if (configuration.model == MODEL_SGB && configuration.sgb_revision == SGB_2) { - boot_rom = "sgb2_boot.bin"; - } - error = GB_load_boot_rom(&gb, resource_path(boot_rom)); - end_capturing_logs(true, error); - start_capturing_logs(); error = GB_load_rom(&gb, filename); end_capturing_logs(true, error);