diff --git a/Cocoa/Document.m b/Cocoa/Document.m index 40b6847..78dfd77 100644 --- a/Cocoa/Document.m +++ b/Cocoa/Document.m @@ -18,6 +18,13 @@ enum model { MODEL_AGB, }; +static const GB_model_t cocoa_to_internal_model[] = +{ + [MODEL_DMG] = GB_MODEL_DMG_B, + [MODEL_CGB] = GB_MODEL_CGB_E, + [MODEL_AGB] = GB_MODEL_AGB +}; + @interface Document () { /* NSTextViews freeze the entire app if they're modified too often and too quickly. @@ -137,21 +144,22 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height, - (void) initDMG { current_model = MODEL_DMG; - GB_init(&gb); + GB_init(&gb, cocoa_to_internal_model[current_model]); [self initCommon]; GB_load_boot_rom(&gb, [[[NSBundle mainBundle] pathForResource:@"dmg_boot" ofType:@"bin"] UTF8String]); } - (void) initCGB { - GB_init_cgb(&gb); [self initCommon]; if ([[NSUserDefaults standardUserDefaults] boolForKey:@"EmulateAGB"]) { current_model = MODEL_AGB; + GB_init(&gb, cocoa_to_internal_model[current_model]); GB_load_boot_rom(&gb, [[[NSBundle mainBundle] pathForResource:@"agb_boot" ofType:@"bin"] UTF8String]); } else { current_model = MODEL_CGB; + GB_init(&gb, cocoa_to_internal_model[current_model]); GB_load_boot_rom(&gb, [[[NSBundle mainBundle] pathForResource:@"cgb_boot" ofType:@"bin"] UTF8String]); } } @@ -250,7 +258,7 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height, } else { current_model = (enum model)[sender tag]; - GB_switch_model_and_reset(&gb, current_model != MODEL_DMG); + GB_switch_model_and_reset(&gb, cocoa_to_internal_model[current_model]); static NSString * const boot_names[] = {@"dmg_boot", @"cgb_boot", @"agb_boot"}; GB_load_boot_rom(&gb, [[[NSBundle mainBundle] pathForResource:boot_names[current_model - 1] ofType:@"bin"] UTF8String]); } diff --git a/Cocoa/GBMemoryByteArray.m b/Cocoa/GBMemoryByteArray.m index 2655579..32526ad 100644 --- a/Cocoa/GBMemoryByteArray.m +++ b/Cocoa/GBMemoryByteArray.m @@ -54,7 +54,7 @@ break; case GBMemoryVRAM: bank_backup = gb->cgb_vram_bank; - if (gb->is_cgb) { + if (GB_is_cgb(gb)) { gb->cgb_vram_bank = self.selectedBank; } addr += 0x8000; @@ -66,7 +66,7 @@ break; case GBMemoryRAM: bank_backup = gb->cgb_ram_bank; - if (gb->is_cgb) { + if (GB_is_cgb(gb)) { gb->cgb_ram_bank = self.selectedBank; } addr += 0xC000; @@ -127,7 +127,7 @@ break; case GBMemoryVRAM: bank_backup = gb->cgb_vram_bank; - if (gb->is_cgb) { + if (GB_is_cgb(gb)) { gb->cgb_vram_bank = self.selectedBank; } addr += 0x8000; @@ -139,7 +139,7 @@ break; case GBMemoryRAM: bank_backup = gb->cgb_ram_bank; - if (gb->is_cgb) { + if (GB_is_cgb(gb)) { gb->cgb_ram_bank = self.selectedBank; } addr += 0xC000; diff --git a/Core/apu.c b/Core/apu.c index 4f8f5c6..b5574c9 100644 --- a/Core/apu.c +++ b/Core/apu.c @@ -468,7 +468,7 @@ uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg) }; if (reg >= GB_IO_WAV_START && reg <= GB_IO_WAV_END && gb->apu.is_active[GB_WAVE]) { - if (!gb->is_cgb && !gb->apu.wave_channel.wave_form_just_read) { + if (!GB_is_cgb(gb) && !gb->apu.wave_channel.wave_form_just_read) { return 0xFF; } reg = GB_IO_WAV_START + gb->apu.wave_channel.current_sample_index / 2; @@ -479,7 +479,7 @@ uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg) void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) { - if (!gb->apu.global_enable && reg != GB_IO_NR52 && (gb->is_cgb || + if (!gb->apu.global_enable && reg != GB_IO_NR52 && (GB_is_cgb(gb) || ( reg != GB_IO_NR11 && reg != GB_IO_NR21 && @@ -491,7 +491,7 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) } if (reg >= GB_IO_WAV_START && reg <= GB_IO_WAV_END && gb->apu.is_active[GB_WAVE]) { - if (!gb->is_cgb && !gb->apu.wave_channel.wave_form_just_read) { + if (!GB_is_cgb(gb) && !gb->apu.wave_channel.wave_form_just_read) { return; } reg = GB_IO_WAV_START + gb->apu.wave_channel.current_sample_index / 2; @@ -533,7 +533,7 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) gb->apu.global_enable = false; } - if (!gb->is_cgb && (value & 0x80)) { + if (!GB_is_cgb(gb) && (value & 0x80)) { GB_apu_write(gb, GB_IO_NR11, old_nrx1[0]); GB_apu_write(gb, GB_IO_NR21, old_nrx1[1]); GB_apu_write(gb, GB_IO_NR31, old_nrx1[2]); @@ -694,7 +694,7 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) if ((value & 0x80)) { /* DMG bug: wave RAM gets corrupted if the channel is retriggerred 1 cycle before the APU reads from it. */ - if (!gb->is_cgb && + if (!GB_is_cgb(gb) && gb->apu.is_active[GB_WAVE] && gb->apu.wave_channel.sample_countdown == 0 && gb->apu.wave_channel.enable) { diff --git a/Core/debugger.c b/Core/debugger.c index a843f9b..3382ef3 100644 --- a/Core/debugger.c +++ b/Core/debugger.c @@ -112,7 +112,7 @@ static inline void switch_banking_state(GB_gameboy_t *gb, uint16_t bank) gb->mbc_rom_bank = bank; gb->mbc_ram_bank = bank; gb->mbc_ram_enable = true; - if (gb->is_cgb) { + if (GB_is_cgb(gb)) { gb->cgb_ram_bank = bank & 7; gb->cgb_vram_bank = bank & 1; if (gb->cgb_ram_bank == 0) { @@ -1462,7 +1462,7 @@ static bool palettes(GB_gameboy_t *gb, char *arguments, char *modifiers, const d return true; } - if (!gb->is_cgb) { + if (!GB_is_cgb(gb)) { GB_log(gb, "Not available on a DMG.\n"); return true; } @@ -1495,7 +1495,7 @@ static bool lcd(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugg } GB_log(gb, "LCDC:\n"); GB_log(gb, " LCD enabled: %s\n",(gb->io_registers[GB_IO_LCDC] & 128)? "Enabled" : "Disabled"); - GB_log(gb, " %s: %s\n", gb->is_cgb? (gb->cgb_mode? "Sprite priority flags" : "Background and Window") : "Background", + GB_log(gb, " %s: %s\n", GB_is_cgb(gb)? (gb->cgb_mode? "Sprite priority flags" : "Background and Window") : "Background", (gb->io_registers[GB_IO_LCDC] & 1)? "Enabled" : "Disabled"); GB_log(gb, " Objects: %s\n", (gb->io_registers[GB_IO_LCDC] & 2)? "Enabled" : "Disabled"); GB_log(gb, " Object size: %s\n", (gb->io_registers[GB_IO_LCDC] & 4)? "8x16" : "8x8"); diff --git a/Core/display.c b/Core/display.c index 20580de..0fa6e7b 100644 --- a/Core/display.c +++ b/Core/display.c @@ -113,7 +113,7 @@ typedef struct __attribute__((packed)) { static bool window_enabled(GB_gameboy_t *gb) { if ((gb->io_registers[GB_IO_LCDC] & 0x1) == 0) { - if (!gb->cgb_mode && gb->is_cgb) { + if (!gb->cgb_mode && GB_is_cgb(gb)) { return false; } } @@ -203,7 +203,7 @@ uint32_t GB_convert_rgb15(GB_gameboy_t *gb, uint16_t color) void GB_palette_changed(GB_gameboy_t *gb, bool background_palette, uint8_t index) { - if (!gb->rgb_encode_callback || !gb->is_cgb) return; + if (!gb->rgb_encode_callback || !GB_is_cgb(gb)) return; uint8_t *palette_data = background_palette? gb->background_palettes_data : gb->sprite_palettes_data; uint16_t color = palette_data[index & ~1] | (palette_data[index | 1] << 8); @@ -213,7 +213,7 @@ void GB_palette_changed(GB_gameboy_t *gb, bool background_palette, uint8_t index void GB_set_color_correction_mode(GB_gameboy_t *gb, GB_color_correction_mode_t mode) { gb->color_correction_mode = mode; - if (gb->is_cgb) { + if (GB_is_cgb(gb)) { for (unsigned i = 0; i < 32; i++) { GB_palette_changed(gb, false, i * 2); GB_palette_changed(gb, true, i * 2); @@ -236,7 +236,7 @@ void GB_STAT_update(GB_gameboy_t *gb) bool previous_interrupt_line = gb->stat_interrupt_line; /* Set LY=LYC bit */ - if (gb->ly_for_comparison != (uint16_t)-1 || !gb->is_cgb) { + if (gb->ly_for_comparison != (uint16_t)-1 || !GB_is_cgb(gb)) { if (gb->ly_for_comparison == gb->io_registers[GB_IO_LYC]) { gb->lyc_interrupt_line = true; gb->io_registers[GB_IO_STAT] |= 4; @@ -362,7 +362,7 @@ static void render_pixel_if_possible(GB_gameboy_t *gb) bg_enabled = false; } } - if (!gb->is_cgb && gb->in_window) { + if (!GB_is_cgb(gb) && gb->in_window) { bg_enabled = true; } @@ -434,7 +434,7 @@ static void advance_fetcher_state_machine(GB_gameboy_t *gb) /* Todo: Verified for DMG (Tested: SGB2), CGB timing is wrong. */ uint8_t y = fetcher_y(gb); - if (gb->is_cgb) { + if (GB_is_cgb(gb)) { /* This value is cached on the CGB, so it cannot be used to mix tiles together */ /* Todo: This is NOT true on CGB-B! This is likely the case for all CGBs prior to D. Currently, SameBoy is emulating CGB-E, but if other revisions are added in the future @@ -442,7 +442,7 @@ static void advance_fetcher_state_machine(GB_gameboy_t *gb) gb->fetcher_y = y; } gb->current_tile = gb->vram[map + gb->fetcher_x + y / 8 * 32]; - if (gb->is_cgb) { + if (GB_is_cgb(gb)) { /* The CGB actually accesses both the tile index AND the attributes in the same T-cycle. This probably means the CGB has a 16-bit data bus for the VRAM. */ gb->current_tile_attributes = gb->vram[map + gb->fetcher_x + y / 8 * 32 + 0x2000]; @@ -456,7 +456,7 @@ static void advance_fetcher_state_machine(GB_gameboy_t *gb) case GB_FETCHER_GET_TILE_DATA_LOWER: { uint8_t y_flip = 0; uint16_t tile_address = 0; - uint8_t y = gb->is_cgb? gb->fetcher_y : fetcher_y(gb); + uint8_t y = GB_is_cgb(gb)? gb->fetcher_y : fetcher_y(gb); /* Todo: Verified for DMG (Tested: SGB2), CGB timing is wrong. */ if (gb->io_registers[GB_IO_LCDC] & 0x10) { @@ -483,7 +483,7 @@ static void advance_fetcher_state_machine(GB_gameboy_t *gb) bit mid-fetching causes a glitched mixing of the two, in comparison to the more logical DMG version. */ uint16_t tile_address = 0; - uint8_t y = gb->is_cgb? gb->fetcher_y : fetcher_y(gb); + uint8_t y = GB_is_cgb(gb)? gb->fetcher_y : fetcher_y(gb); if (gb->io_registers[GB_IO_LCDC] & 0x10) { tile_address = gb->current_tile * 0x10; @@ -571,7 +571,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) return; } - if (!gb->is_cgb) { + if (!GB_is_cgb(gb)) { GB_SLEEP(gb, display, 23, 1); } @@ -593,9 +593,9 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) gb->io_registers[GB_IO_STAT] |= 3; gb->mode_for_interrupt = 3; gb->oam_read_blocked = true; - gb->vram_read_blocked = !gb->is_cgb; + gb->vram_read_blocked = !GB_is_cgb(gb); gb->oam_write_blocked = true; - gb->vram_write_blocked = !gb->is_cgb; + gb->vram_write_blocked = !GB_is_cgb(gb); GB_STAT_update(gb); gb->cycles_for_line += 2; @@ -634,7 +634,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) while (true) { /* Lines 0 - 143 */ for (; gb->current_line < LINES; gb->current_line++) { - gb->oam_write_blocked = gb->is_cgb; + gb->oam_write_blocked = GB_is_cgb(gb); gb->accessed_oam_row = 0; GB_SLEEP(gb, display, 6, 3); gb->io_registers[GB_IO_LY] = gb->current_line; @@ -647,7 +647,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) gb->mode_for_interrupt = 2; gb->io_registers[GB_IO_STAT] &= ~3; } - else if (!gb->is_cgb) { + else if (!GB_is_cgb(gb)) { gb->io_registers[GB_IO_STAT] &= ~3; } GB_STAT_update(gb); @@ -665,19 +665,19 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) gb->n_visible_objs = 0; for (gb->oam_search_index = 0; gb->oam_search_index < 40; gb->oam_search_index++) { - if (gb->is_cgb) { + if (GB_is_cgb(gb)) { add_object_from_index(gb, gb->oam_search_index); /* The CGB does not care about the accessed OAM row as there's no OAM bug*/ } GB_SLEEP(gb, display, 8, 2); - if (!gb->is_cgb) { + if (!GB_is_cgb(gb)) { add_object_from_index(gb, gb->oam_search_index); gb->accessed_oam_row = (gb->oam_search_index & ~1) * 4 + 8; } if (gb->oam_search_index == 37) { - gb->vram_read_blocked = !gb->is_cgb; + gb->vram_read_blocked = !GB_is_cgb(gb); gb->vram_write_blocked = false; - gb->oam_write_blocked = gb->is_cgb; + gb->oam_write_blocked = GB_is_cgb(gb); GB_STAT_update(gb); } } @@ -719,7 +719,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) gb->n_visible_objs--; } while (gb->n_visible_objs != 0 && - (gb->io_registers[GB_IO_LCDC] & 2 || gb->is_cgb) && + (gb->io_registers[GB_IO_LCDC] & 2 || GB_is_cgb(gb)) && gb->obj_comperators[gb->n_visible_objs - 1] == (uint8_t)(gb->position_in_line + 8)) { while (gb->fetcher_state < 5) { @@ -864,17 +864,17 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) gb->io_registers[GB_IO_LY] = 153; gb->ly_for_comparison = -1; GB_STAT_update(gb); - GB_SLEEP(gb, display, 14, gb->is_cgb? 4: 6); + GB_SLEEP(gb, display, 14, GB_is_cgb(gb)? 4: 6); - if (!gb->is_cgb) { + if (!GB_is_cgb(gb)) { gb->io_registers[GB_IO_LY] = 0; } gb->ly_for_comparison = 153; GB_STAT_update(gb); - GB_SLEEP(gb, display, 15, gb->is_cgb? 4: 2); + GB_SLEEP(gb, display, 15, GB_is_cgb(gb)? 4: 2); gb->io_registers[GB_IO_LY] = 0; - gb->ly_for_comparison = gb->is_cgb? 153 : -1; + gb->ly_for_comparison = GB_is_cgb(gb)? 153 : -1; GB_STAT_update(gb); GB_SLEEP(gb, display, 16, 4); @@ -896,7 +896,7 @@ void GB_draw_tileset(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette uint32_t none_palette[4]; uint32_t *palette = NULL; - switch (gb->is_cgb? palette_type : GB_PALETTE_NONE) { + switch (GB_is_cgb(gb)? palette_type : GB_PALETTE_NONE) { default: case GB_PALETTE_NONE: none_palette[0] = gb->rgb_encode_callback(gb, 0xFF, 0xFF, 0xFF); @@ -915,7 +915,7 @@ void GB_draw_tileset(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette for (unsigned y = 0; y < 192; y++) { for (unsigned x = 0; x < 256; x++) { - if (x >= 128 && !gb->is_cgb) { + if (x >= 128 && !GB_is_cgb(gb)) { *(dest++) = gb->background_palettes_rgb[0]; continue; } @@ -947,7 +947,7 @@ void GB_draw_tilemap(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette uint32_t *palette = NULL; uint16_t map = 0x1800; - switch (gb->is_cgb? palette_type : GB_PALETTE_NONE) { + switch (GB_is_cgb(gb)? palette_type : GB_PALETTE_NONE) { case GB_PALETTE_NONE: none_palette[0] = gb->rgb_encode_callback(gb, 0xFF, 0xFF, 0xFF); none_palette[1] = gb->rgb_encode_callback(gb, 0xAA, 0xAA, 0xAA); @@ -1048,7 +1048,7 @@ uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest, uint8_t *sprite_h uint16_t vram_address = dest[i].tile * 0x10; uint8_t flags = dest[i].flags; uint8_t palette = gb->cgb_mode? (flags & 7) : ((flags & 0x10)? 1 : 0); - if (gb->is_cgb && (flags & 0x8)) { + if (GB_is_cgb(gb) && (flags & 0x8)) { vram_address += 0x2000; } diff --git a/Core/gb.c b/Core/gb.c index da1e941..1f02a3f 100644 --- a/Core/gb.c +++ b/Core/gb.c @@ -90,11 +90,18 @@ static char *default_async_input_callback(GB_gameboy_t *gb) } #endif -void GB_init(GB_gameboy_t *gb) +void GB_init(GB_gameboy_t *gb, GB_model_t model) { memset(gb, 0, sizeof(*gb)); - gb->ram = malloc(gb->ram_size = 0x2000); - gb->vram = malloc(gb->vram_size = 0x2000); + gb->model = model; + if (GB_is_cgb(gb)) { + gb->ram = malloc(gb->ram_size = 0x2000 * 8); + gb->vram = malloc(gb->vram_size = 0x2000 * 2); + } + else { + gb->ram = malloc(gb->ram_size = 0x2000); + gb->vram = malloc(gb->vram_size = 0x2000); + } #ifndef DISABLE_DEBUGGER gb->input_callback = default_input_callback; @@ -106,21 +113,9 @@ void GB_init(GB_gameboy_t *gb) GB_reset(gb); } -void GB_init_cgb(GB_gameboy_t *gb) +GB_model_t GB_get_model(GB_gameboy_t *gb) { - memset(gb, 0, sizeof(*gb)); - gb->ram = malloc(gb->ram_size = 0x2000 * 8); - gb->vram = malloc(gb->vram_size = 0x2000 * 2); - gb->is_cgb = true; - -#ifndef DISABLE_DEBUGGER - gb->input_callback = default_input_callback; - gb->async_input_callback = default_async_input_callback; -#endif - gb->cartridge_type = &GB_cart_defs[0]; // Default cartridge type - gb->clock_multiplier = 1.0; - - GB_reset(gb); + return gb->model; } void GB_free(GB_gameboy_t *gb) @@ -339,7 +334,7 @@ void GB_set_async_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback) void GB_set_rgb_encode_callback(GB_gameboy_t *gb, GB_rgb_encode_callback_t callback) { - if (!gb->rgb_encode_callback && !gb->is_cgb) { + if (!gb->rgb_encode_callback && !GB_is_cgb(gb)) { gb->sprite_palettes_rgb[4] = gb->sprite_palettes_rgb[0] = gb->background_palettes_rgb[0] = callback(gb, 0xFF, 0xFF, 0xFF); gb->sprite_palettes_rgb[5] = gb->sprite_palettes_rgb[1] = gb->background_palettes_rgb[1] = @@ -424,7 +419,7 @@ bool GB_is_inited(GB_gameboy_t *gb) bool GB_is_cgb(GB_gameboy_t *gb) { - return gb->is_cgb; + return ((gb->model) & GB_MODEL_FAMILY_MASK) == GB_MODEL_CGB_FAMILY; } void GB_set_turbo_mode(GB_gameboy_t *gb, bool on, bool no_frame_skip) @@ -451,7 +446,7 @@ void GB_set_user_data(GB_gameboy_t *gb, void *data) void GB_reset(GB_gameboy_t *gb) { uint32_t mbc_ram_size = gb->mbc_ram_size; - bool cgb = gb->is_cgb; + bool cgb = GB_is_cgb(gb); memset(gb, 0, (size_t)GB_GET_SECTION((GB_gameboy_t *) 0, unsaved)); gb->version = GB_STRUCT_VERSION; @@ -466,7 +461,7 @@ void GB_reset(GB_gameboy_t *gb) gb->vram_size = 0x2000 * 2; memset(gb->vram, 0, gb->vram_size); - gb->is_cgb = true; + gb->model = GB_MODEL_CGB_E; gb->cgb_mode = true; } else { @@ -491,16 +486,17 @@ void GB_reset(GB_gameboy_t *gb) gb->io_registers[GB_IO_SC] = 0x7E; /* These are not deterministic, but 00 (CGB) and FF (DMG) are the most common initial values by far */ - gb->io_registers[GB_IO_DMA] = gb->io_registers[GB_IO_OBP0] = gb->io_registers[GB_IO_OBP1] = gb->is_cgb? 0x00 : 0xFF; + gb->io_registers[GB_IO_DMA] = gb->io_registers[GB_IO_OBP0] = gb->io_registers[GB_IO_OBP1] = GB_is_cgb(gb)? 0x00 : 0xFF; gb->accessed_oam_row = -1; gb->magic = (uintptr_t)'SAME'; } -void GB_switch_model_and_reset(GB_gameboy_t *gb, bool is_cgb) +void GB_switch_model_and_reset(GB_gameboy_t *gb, GB_model_t model) { - if (is_cgb) { + gb->model = model; + if (GB_is_cgb(gb)) { gb->ram = realloc(gb->ram, gb->ram_size = 0x2000 * 8); gb->vram = realloc(gb->vram, gb->vram_size = 0x2000 * 2); } @@ -508,7 +504,6 @@ void GB_switch_model_and_reset(GB_gameboy_t *gb, bool is_cgb) gb->ram = realloc(gb->ram, gb->ram_size = 0x2000); gb->vram = realloc(gb->vram, gb->vram_size = 0x2000); } - gb->is_cgb = is_cgb; GB_rewind_free(gb); GB_reset(gb); } @@ -553,7 +548,7 @@ void *GB_get_direct_access(GB_gameboy_t *gb, GB_direct_access_t access, size_t * *bank = 0; return &gb->io_registers; case GB_DIRECT_ACCESS_BOOTROM: - *size = gb->is_cgb? sizeof(gb->boot_rom) : 0x100; + *size = GB_is_cgb(gb)? sizeof(gb->boot_rom) : 0x100; *bank = 0; return &gb->boot_rom; case GB_DIRECT_ACCESS_OAM: diff --git a/Core/gb.h b/Core/gb.h index afd5c27..31840d9 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -20,7 +20,34 @@ #include "z80_cpu.h" #include "symbol_hash.h" -#define GB_STRUCT_VERSION 12 +#define GB_STRUCT_VERSION 13 + +typedef enum { +#ifdef GB_INTERNAL + GB_MODEL_FAMILY_MASK = 0xF00, + GB_MODEL_DMG_FAMILY = 0x000, +#endif + // GB_MODEL_DMG_0 = 0x000, + // GB_MODEL_DMG_A = 0x001, + GB_MODEL_DMG_B = 0x002, + // GB_MODEL_DMG_C = 0x003, + // GB_MODEL_SGB = 0x004, +#ifdef GB_INTERNAL + GB_MODEL_MGB_FAMILY = 0x100, +#endif + // GB_MODEL_MGB = 0x100, + // GB_MODEL_SGB2 = 0x101, +#ifdef GB_INTERNAL + GB_MODEL_CGB_FAMILY = 0x200, +#endif + // GB_MODEL_CGB_0 = 0x200, + // GB_MODEL_CGB_A = 0x201, + // GB_MODEL_CGB_B = 0x202, + // GB_MODEL_CGB_C = 0x203, + // GB_MODEL_CGB_D = 0x204, + GB_MODEL_CGB_E = 0x205, + GB_MODEL_AGB = 0x206, +} GB_model_t; enum { GB_REGISTER_AF, @@ -261,8 +288,8 @@ struct GB_gameboy_internal_s { uint8_t cgb_ram_bank; /* CPU and General Hardware Flags*/ + GB_model_t model; bool cgb_mode; - bool is_cgb; bool cgb_double_speed; bool halted; bool stopped; @@ -547,13 +574,13 @@ struct GB_gameboy_s { __attribute__((__format__ (__printf__, fmtarg, firstvararg))) #endif -void GB_init(GB_gameboy_t *gb); -void GB_init_cgb(GB_gameboy_t *gb); +void GB_init(GB_gameboy_t *gb, GB_model_t model); bool GB_is_inited(GB_gameboy_t *gb); bool GB_is_cgb(GB_gameboy_t *gb); +GB_model_t GB_get_model(GB_gameboy_t *gb); void GB_free(GB_gameboy_t *gb); void GB_reset(GB_gameboy_t *gb); -void GB_switch_model_and_reset(GB_gameboy_t *gb, bool is_cgb); +void GB_switch_model_and_reset(GB_gameboy_t *gb, GB_model_t model); /* Returns the time passed, in 4MHz ticks. */ uint8_t GB_run(GB_gameboy_t *gb); diff --git a/Core/memory.c b/Core/memory.c index f280c94..43cb049 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -24,7 +24,7 @@ static GB_bus_t bus_for_addr(GB_gameboy_t *gb, uint16_t addr) return GB_BUS_MAIN; } if (addr < 0xFE00) { - return gb->is_cgb? GB_BUS_RAM : GB_BUS_MAIN; + return GB_is_cgb(gb)? GB_BUS_RAM : GB_BUS_MAIN; } return GB_BUS_INTERNAL; } @@ -46,7 +46,7 @@ static uint8_t bitwise_glitch_read_increase(uint8_t a, uint8_t b, uint8_t c, uin void GB_trigger_oam_bug(GB_gameboy_t *gb, uint16_t address) { - if (gb->is_cgb) return; + if (GB_is_cgb(gb)) return; if (address >= 0xFE00 && address < 0xFF00) { if (gb->accessed_oam_row != 0xff && gb->accessed_oam_row >= 8) { @@ -65,7 +65,7 @@ void GB_trigger_oam_bug(GB_gameboy_t *gb, uint16_t address) void GB_trigger_oam_bug_read(GB_gameboy_t *gb, uint16_t address) { - if (gb->is_cgb) return; + if (GB_is_cgb(gb)) return; if (address >= 0xFE00 && address < 0xFF00) { if (gb->accessed_oam_row != 0xff && gb->accessed_oam_row >= 8) { @@ -86,7 +86,7 @@ void GB_trigger_oam_bug_read(GB_gameboy_t *gb, uint16_t address) void GB_trigger_oam_bug_read_increase(GB_gameboy_t *gb, uint16_t address) { - if (gb->is_cgb) return; + if (GB_is_cgb(gb)) return; if (address >= 0xFE00 && address < 0xFF00) { if (gb->accessed_oam_row != 0xff && gb->accessed_oam_row >= 0x20 && gb->accessed_oam_row < 0x98) { @@ -119,7 +119,7 @@ static uint8_t read_rom(GB_gameboy_t *gb, uint16_t addr) return gb->boot_rom[addr]; } - if (addr >= 0x200 && addr < 0x900 && gb->is_cgb && !gb->boot_rom_finished) { + if (addr >= 0x200 && addr < 0x900 && GB_is_cgb(gb) && !gb->boot_rom_finished) { return gb->boot_rom[addr]; } @@ -208,7 +208,7 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) } if (gb->oam_read_blocked) { - if (!gb->is_cgb) { + if (!GB_is_cgb(gb)) { if (addr < 0xFEA0) { if (gb->accessed_oam_row == 0) { gb->oam[(addr & 0xf8)] = @@ -249,7 +249,7 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) if ((gb->io_registers[GB_IO_STAT] & 0x3) >= 2) { /* Seems to be disabled in Modes 2 and 3 */ return 0xFF; } - if (gb->is_cgb) { + if (GB_is_cgb(gb)) { return (addr & 0xF0) | ((addr >> 4) & 0xF); } } @@ -275,11 +275,11 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) return gb->io_registers[GB_IO_DMG_EMULATION_INDICATION] | 0xFE; case GB_IO_PCM_12: - if (!gb->is_cgb) return 0xFF; + if (!GB_is_cgb(gb)) return 0xFF; return (gb->apu.is_active[GB_SQUARE_2] ? (gb->apu.samples[GB_SQUARE_2] << 4) : 0) | (gb->apu.is_active[GB_SQUARE_1] ? (gb->apu.samples[GB_SQUARE_1]) : 0); case GB_IO_PCM_34: - if (!gb->is_cgb) return 0xFF; + if (!GB_is_cgb(gb)) return 0xFF; return (gb->apu.is_active[GB_NOISE] ? (gb->apu.samples[GB_NOISE] << 4) : 0) | (gb->apu.is_active[GB_WAVE] ? (gb->apu.samples[GB_WAVE]) : 0); case GB_IO_JOYP: @@ -314,7 +314,7 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) } return gb->cgb_ram_bank | ~0x7; case GB_IO_VBK: - if (!gb->is_cgb) { + if (!GB_is_cgb(gb)) { return 0xFF; } return gb->cgb_vram_bank | ~0x1; @@ -322,7 +322,7 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) /* Todo: It seems that a CGB in DMG mode can access BGPI and OBPI, but not BGPD and OBPD? */ case GB_IO_BGPI: case GB_IO_OBPI: - if (!gb->is_cgb) { + if (!GB_is_cgb(gb)) { return 0xFF; } return gb->io_registers[addr & 0xFF] | 0x40; @@ -357,11 +357,11 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) } case GB_IO_UNKNOWN2: case GB_IO_UNKNOWN3: - return gb->is_cgb? gb->io_registers[addr & 0xFF] : 0xFF; + return GB_is_cgb(gb)? gb->io_registers[addr & 0xFF] : 0xFF; case GB_IO_UNKNOWN4: return gb->cgb_mode? gb->io_registers[addr & 0xFF] : 0xFF; case GB_IO_UNKNOWN5: - return gb->is_cgb? gb->io_registers[addr & 0xFF] | 0x8F : 0xFF; + return GB_is_cgb(gb)? gb->io_registers[addr & 0xFF] | 0x8F : 0xFF; default: if ((addr & 0xFF) >= GB_IO_NR10 && (addr & 0xFF) <= GB_IO_WAV_END) { return GB_apu_read(gb, addr & 0xFF); @@ -531,7 +531,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) return; } - if (gb->is_cgb) { + if (GB_is_cgb(gb)) { if (addr < 0xFEA0) { gb->oam[addr & 0xFF] = value; } @@ -599,7 +599,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) /* TODO: Probably completely wrong in double speed mode */ /* TODO: This hack is disgusting */ - if (gb->display_state == 29 && gb->is_cgb) { + if (gb->display_state == 29 && GB_is_cgb(gb)) { gb->ly_for_comparison = 153; GB_STAT_update(gb); gb->ly_for_comparison = 0; @@ -609,14 +609,14 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) /* These are the states when LY changes, let the display routine call GB_STAT_update for use so it correctly handles T-cycle accurate LYC writes */ - if (!gb->is_cgb || ( + if (!GB_is_cgb(gb) || ( gb->display_state != 6 && gb->display_state != 26 && gb->display_state != 15 && gb->display_state != 16)) { /* More hacks to make LYC write conflicts work */ - if (gb->display_state == 14 && gb->is_cgb) { + if (gb->display_state == 14 && GB_is_cgb(gb)) { gb->ly_for_comparison = 153; GB_STAT_update(gb); gb->ly_for_comparison = -1; @@ -691,7 +691,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) return; case GB_IO_DMG_EMULATION: - if (gb->is_cgb && !gb->boot_rom_finished) { + if (GB_is_cgb(gb) && !gb->boot_rom_finished) { gb->cgb_mode = value != 4; /* The real "contents" of this register aren't quite known yet. */ } return; @@ -728,7 +728,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) case GB_IO_BGPI: case GB_IO_OBPI: - if (!gb->is_cgb) { + if (!GB_is_cgb(gb)) { return; } gb->io_registers[addr & 0xFF] = value; @@ -823,7 +823,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) return; case GB_IO_RP: { - if (!gb->is_cgb) { + if (!GB_is_cgb(gb)) { return; } if ((value & 1) != (gb->io_registers[GB_IO_RP] & 1)) { diff --git a/Core/z80_cpu.c b/Core/z80_cpu.c index 721008f..26cadd6 100644 --- a/Core/z80_cpu.c +++ b/Core/z80_cpu.c @@ -77,7 +77,7 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value) assert(gb->pending_cycles); GB_conflict_t conflict = GB_CONFLICT_READ_OLD; if ((addr & 0xFF80) == 0xFF00) { - conflict = (gb->is_cgb? cgb_conflict_map : dmg_conflict_map)[addr & 0x7F]; + conflict = (GB_is_cgb(gb)? cgb_conflict_map : dmg_conflict_map)[addr & 0x7F]; } switch (conflict) { case GB_CONFLICT_READ_OLD: @@ -158,7 +158,7 @@ static void cycle_no_access(GB_gameboy_t *gb) static void cycle_oam_bug(GB_gameboy_t *gb, uint8_t register_id) { - if (gb->is_cgb) { + if (GB_is_cgb(gb)) { /* Slight optimization */ gb->pending_cycles += 4; return; @@ -1381,14 +1381,14 @@ void GB_cpu_run(GB_gameboy_t *gb) return; } - if (gb->halted && !gb->is_cgb && !gb->just_halted) { + if (gb->halted && !GB_is_cgb(gb) && !gb->just_halted) { GB_advance_cycles(gb, 2); } uint8_t interrupt_queue = gb->interrupt_enable & gb->io_registers[GB_IO_IF] & 0x1F; if (gb->halted) { - GB_advance_cycles(gb, (gb->is_cgb || gb->just_halted) ? 4 : 2); + GB_advance_cycles(gb, (GB_is_cgb(gb) || gb->just_halted) ? 4 : 2); } gb->just_halted = false; diff --git a/QuickLook/get_image_for_rom.c b/QuickLook/get_image_for_rom.c index 25f8e2b..e0482ec 100755 --- a/QuickLook/get_image_for_rom.c +++ b/QuickLook/get_image_for_rom.c @@ -47,7 +47,7 @@ static uint32_t rgb_encode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b) int get_image_for_rom(const char *filename, const char *boot_path, uint32_t *output, uint8_t *cgb_flag) { GB_gameboy_t gb; - GB_init_cgb(&gb); + GB_init(&gb, GB_MODEL_CGB_E); if (GB_load_boot_rom(&gb, boot_path)) { GB_free(&gb); return 1; diff --git a/SDL/main.c b/SDL/main.c index f3ee39e..9a1c3d6 100755 --- a/SDL/main.c +++ b/SDL/main.c @@ -26,13 +26,19 @@ static bool paused = false; static uint32_t pixel_buffer_1[160*144], pixel_buffer_2[160*144]; static uint32_t *active_pixel_buffer = pixel_buffer_1, *previous_pixel_buffer = pixel_buffer_2; - static char *filename = NULL; static bool should_free_filename = false; static char *battery_save_path_ptr; SDL_AudioDeviceID device_id; +static const GB_model_t sdl_to_internal_model[] = +{ + [MODEL_DMG] = GB_MODEL_DMG_B, + [MODEL_CGB] = GB_MODEL_CGB_E, + [MODEL_AGB] = GB_MODEL_AGB +}; + void set_filename(const char *new_filename, bool new_should_free) { if (filename && should_free_filename) { @@ -364,15 +370,10 @@ static void run(void) pending_command = GB_SDL_NO_COMMAND; restart: if (GB_is_inited(&gb)) { - GB_switch_model_and_reset(&gb, configuration.model != MODEL_DMG); + GB_switch_model_and_reset(&gb, sdl_to_internal_model[configuration.model]); } else { - if (configuration.model == MODEL_DMG) { - GB_init(&gb); - } - else { - GB_init_cgb(&gb); - } + GB_init(&gb, sdl_to_internal_model[configuration.model]); GB_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank); GB_set_pixels_output(&gb, active_pixel_buffer); @@ -454,7 +455,7 @@ int main(int argc, char **argv) signal(SIGINT, debugger_interrupt); - SDL_Init( SDL_INIT_EVERYTHING ); + SDL_Init(SDL_INIT_EVERYTHING); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); @@ -527,6 +528,9 @@ int main(int argc, char **argv) fread(&configuration, 1, sizeof(configuration), prefs_file); fclose(prefs_file); } + if (configuration.model >= MODEL_MAX) { + configuration.model = MODEL_CGB; + } atexit(save_configuration); diff --git a/Tester/main.c b/Tester/main.c index 8c33e04..be5f9e8 100755 --- a/Tester/main.c +++ b/Tester/main.c @@ -295,14 +295,14 @@ int main(int argc, char **argv) fprintf(stderr, "Testing ROM %s\n", filename); if (dmg) { - GB_init(&gb); + GB_init(&gb, GB_MODEL_DMG_B); if (GB_load_boot_rom(&gb, boot_rom_path? boot_rom_path : executable_relative_path("dmg_boot.bin"))) { perror("Failed to load boot ROM"); exit(1); } } else { - GB_init_cgb(&gb); + GB_init(&gb, GB_MODEL_CGB_E); if (GB_load_boot_rom(&gb, boot_rom_path? boot_rom_path : executable_relative_path("cgb_boot.bin"))) { perror("Failed to load boot ROM"); exit(1); diff --git a/libretro/libretro.c b/libretro/libretro.c index 275df1d..c09de57 100644 --- a/libretro/libretro.c +++ b/libretro/libretro.c @@ -52,6 +52,13 @@ enum model { MODEL_AUTO }; +static const GB_model_t libretro_to_internal_model[] = +{ + [MODEL_DMG] = GB_MODEL_DMG_B, + [MODEL_CGB] = GB_MODEL_CGB_E, + [MODEL_AGB] = GB_MODEL_AGB +}; + enum screen_layout { LAYOUT_TOP_DOWN, LAYOUT_LEFT_RIGHT @@ -317,15 +324,11 @@ static void init_for_current_model(void) for (i = 0; i < emulated_devices; i++) { - if (GB_is_inited(&gameboy[i])) - GB_switch_model_and_reset(&gameboy[i], effective_model[i] != MODEL_DMG); - - else - { - if (effective_model[i] == MODEL_DMG) - GB_init(&gameboy[i]); - else - GB_init_cgb(&gameboy[i]); + if (GB_is_inited(&gameboy[i])) { + GB_switch_model_and_reset(&gameboy[i], libretro_to_internal_model[effective_model[i]]); + } + else { + GB_init(&gameboy[i], libretro_to_internal_model[effective_model[i]]); } const char *model_name = (const char *[]){"dmg", "cgb", "agb"}[effective_model[i]]; const unsigned char *boot_code = (const unsigned char *[]){dmg_boot, cgb_boot, agb_boot}[effective_model[i]];