diff --git a/Cocoa/Preferences.xib b/Cocoa/Preferences.xib index 6d72652..41c1cda 100644 --- a/Cocoa/Preferences.xib +++ b/Cocoa/Preferences.xib @@ -401,7 +401,7 @@ - + diff --git a/Core/apu.c b/Core/apu.c index c40ce61..e049c06 100644 --- a/Core/apu.c +++ b/Core/apu.c @@ -901,7 +901,6 @@ static inline uint16_t effective_channel4_counter(GB_gameboy_t *gb) effective_counter |= 0x20; } break; -#if 0 case GB_MODEL_CGB_D: if (effective_counter & ((gb->io_registers[GB_IO_NR43] & 8)? 0x40 : 0x80)) { // This is so weird effective_counter |= 0xFF; @@ -922,7 +921,6 @@ static inline uint16_t effective_channel4_counter(GB_gameboy_t *gb) effective_counter |= 0x10; } break; -#endif case GB_MODEL_CGB_E: if (effective_counter & ((gb->io_registers[GB_IO_NR43] & 8)? 0x40 : 0x80)) { // This is so weird effective_counter |= 0xFF; @@ -1067,7 +1065,7 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) if ((value & 0x80) == 0 && gb->apu.is_active[index]) { /* On an AGB, as well as on CGB C and earlier (TODO: Tested: 0, B and C), it behaves slightly different on double speed. */ - if (gb->model == GB_MODEL_CGB_E /* || gb->model == GB_MODEL_CGB_D */ || gb->apu.square_channels[index].sample_countdown & 1) { + if (gb->model == GB_MODEL_CGB_E || gb->model == GB_MODEL_CGB_D || gb->apu.square_channels[index].sample_countdown & 1) { if (gb->apu.square_channels[index].sample_countdown >> 1 == (gb->apu.square_channels[index].sample_length ^ 0x7FF)) { gb->apu.square_channels[index].current_sample_index--; gb->apu.square_channels[index].current_sample_index &= 7; @@ -1091,7 +1089,7 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) } else { unsigned extra_delay = 0; - if (gb->model == GB_MODEL_CGB_E /* || gb->model == GB_MODEL_CGB_D */) { + if (gb->model == GB_MODEL_CGB_E || gb->model == GB_MODEL_CGB_D) { if (!(value & 4) && !(((gb->apu.square_channels[index].sample_countdown - 1) / 2) & 0x400)) { gb->apu.square_channels[index].current_sample_index++; gb->apu.square_channels[index].current_sample_index &= 0x7; @@ -1153,10 +1151,12 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) else { gb->apu.sweep_length_addend = 0; } - gb->apu.channel_1_restart_hold = 2 - gb->apu.lf_div + GB_is_cgb(gb) * 2; - if (gb->model <= GB_MODEL_CGB_C && gb->apu.lf_div) { + gb->apu.channel_1_restart_hold = 2 - gb->apu.lf_div + (GB_is_cgb(gb) && gb->model != GB_MODEL_CGB_D) * 2; + /* + if (GB_is_cgb(gb) && gb->model <= GB_MODEL_CGB_C && gb->apu.lf_div) { + // TODO: This if makes channel_1_sweep_restart_2 fail on CGB-C mode gb->apu.channel_1_restart_hold += 2; - } + }*/ gb->apu.square_sweep_countdown = ((gb->io_registers[GB_IO_NR10] >> 4) & 7) ^ 7; } } diff --git a/Core/display.c b/Core/display.c index ef1dde6..8a4c7f9 100644 --- a/Core/display.c +++ b/Core/display.c @@ -483,18 +483,29 @@ static void add_object_from_index(GB_gameboy_t *gb, unsigned index) } } -static uint8_t data_for_tile_sel_glitch(GB_gameboy_t *gb, bool *should_use) +static uint8_t data_for_tile_sel_glitch(GB_gameboy_t *gb, bool *should_use, bool *cgb_d_glitch) { /* Based on Matt Currie's research here: https://github.com/mattcurrie/mealybug-tearoom-tests/blob/master/the-comprehensive-game-boy-ppu-documentation.md#tile_sel-bit-4 */ - *should_use = true; + *cgb_d_glitch = false; + if (gb->io_registers[GB_IO_LCDC] & 0x10) { - *should_use = !(gb->current_tile & 0x80); - /* if (gb->model != GB_MODEL_CGB_D) */ return gb->current_tile; - // TODO: CGB D behaves differently + if (gb->model != GB_MODEL_CGB_D) { + *should_use = !(gb->current_tile & 0x80); + return gb->current_tile; + } + *cgb_d_glitch = true; + *should_use = false; + gb->io_registers[GB_IO_LCDC] &= ~0x10; + if (gb->fetcher_state == 3) { + *should_use = false; + *cgb_d_glitch = true; + return 0; + } + return 0; } return gb->data_for_sel_glitch; } @@ -694,8 +705,9 @@ static void advance_fetcher_state_machine(GB_gameboy_t *gb) case GB_FETCHER_GET_TILE_DATA_LOWER: { bool use_glitched = false; + bool cgb_d_glitch = false; if (gb->tile_sel_glitch) { - gb->current_tile_data[0] = data_for_tile_sel_glitch(gb, &use_glitched); + gb->current_tile_data[0] = data_for_tile_sel_glitch(gb, &use_glitched, &cgb_d_glitch); } uint8_t y_flip = 0; uint16_t tile_address = 0; @@ -721,13 +733,19 @@ static void advance_fetcher_state_machine(GB_gameboy_t *gb) gb->current_tile_data[0] = 0xFF; } } - else { + if ((gb->io_registers[GB_IO_LCDC] & 0x10) && gb->tile_sel_glitch) { gb->data_for_sel_glitch = gb->vram[tile_address + ((y & 7) ^ y_flip) * 2]; if (gb->vram_ppu_blocked) { gb->data_for_sel_glitch = 0xFF; } } + else if (cgb_d_glitch) { + gb->data_for_sel_glitch = gb->vram[gb->current_tile * 0x10 + ((y & 7) ^ y_flip) * 2]; + if (gb->vram_ppu_blocked) { + gb->data_for_sel_glitch = 0xFF; + } + } } gb->fetcher_state++; break; @@ -736,8 +754,9 @@ static void advance_fetcher_state_machine(GB_gameboy_t *gb) /* Todo: Verified for DMG (Tested: SGB2), CGB timing is wrong. */ bool use_glitched = false; + bool cgb_d_glitch = false; if (gb->tile_sel_glitch) { - gb->current_tile_data[1] = data_for_tile_sel_glitch(gb, &use_glitched); + gb->current_tile_data[1] = data_for_tile_sel_glitch(gb, &use_glitched, &cgb_d_glitch); } uint16_t tile_address = 0; @@ -756,7 +775,7 @@ static void advance_fetcher_state_machine(GB_gameboy_t *gb) if (gb->current_tile_attributes & 0x40) { y_flip = 0x7; } - gb->last_tile_data_address = tile_address + ((y & 7) ^ y_flip) * 2 + 1; + gb->last_tile_data_address = tile_address + ((y & 7) ^ y_flip) * 2 + 1 - cgb_d_glitch; if (!use_glitched) { gb->current_tile_data[1] = gb->vram[gb->last_tile_data_address]; @@ -764,12 +783,16 @@ static void advance_fetcher_state_machine(GB_gameboy_t *gb) gb->current_tile_data[1] = 0xFF; } } - else { - if ((gb->io_registers[GB_IO_LCDC] & 0x10) && gb->tile_sel_glitch) { - gb->data_for_sel_glitch = gb->vram[gb->last_tile_data_address]; - if (gb->vram_ppu_blocked) { - gb->data_for_sel_glitch = 0xFF; - } + if ((gb->io_registers[GB_IO_LCDC] & 0x10) && gb->tile_sel_glitch) { + gb->data_for_sel_glitch = gb->vram[gb->last_tile_data_address]; + if (gb->vram_ppu_blocked) { + gb->data_for_sel_glitch = 0xFF; + } + } + else if (cgb_d_glitch) { + gb->data_for_sel_glitch = gb->vram[gb->current_tile * 0x10 + ((y & 7) ^ y_flip) * 2 + 1]; + if (gb->vram_ppu_blocked) { + gb->data_for_sel_glitch = 0xFF; } } } diff --git a/Core/gb.c b/Core/gb.c index 6bd1f50..8d2545d 100644 --- a/Core/gb.c +++ b/Core/gb.c @@ -1473,12 +1473,23 @@ static void reset_ram(GB_gameboy_t *gb) } } break; + case GB_MODEL_CGB_D: + for (unsigned i = 0; i < gb->ram_size; i++) { + gb->ram[i] = GB_random(); + if (i & 0x800) { + gb->ram[i] &= GB_random(); + } + else { + gb->ram[i] |= GB_random(); + } + } + break; } /* HRAM */ switch (gb->model) { case GB_MODEL_CGB_C: - // case GB_MODEL_CGB_D: + case GB_MODEL_CGB_D: case GB_MODEL_CGB_E: case GB_MODEL_AGB: for (unsigned i = 0; i < sizeof(gb->hram); i++) { @@ -1508,6 +1519,7 @@ static void reset_ram(GB_gameboy_t *gb) /* OAM */ switch (gb->model) { case GB_MODEL_CGB_C: + case GB_MODEL_CGB_D: case GB_MODEL_CGB_E: case GB_MODEL_AGB: /* Zero'd out by boot ROM anyway*/ @@ -1538,6 +1550,7 @@ static void reset_ram(GB_gameboy_t *gb) /* Wave RAM */ switch (gb->model) { case GB_MODEL_CGB_C: + case GB_MODEL_CGB_D: case GB_MODEL_CGB_E: case GB_MODEL_AGB: /* Initialized by CGB-A and newer, 0s in CGB-0*/ @@ -1610,6 +1623,7 @@ static void request_boot_rom(GB_gameboy_t *gb) type = GB_BOOT_ROM_SGB2; break; case GB_MODEL_CGB_C: + case GB_MODEL_CGB_D: case GB_MODEL_CGB_E: type = GB_BOOT_ROM_CGB; break; diff --git a/Core/gb.h b/Core/gb.h index 0a1b358..bd42409 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -134,7 +134,7 @@ typedef enum { // GB_MODEL_CGB_A = 0x201, // GB_MODEL_CGB_B = 0x202, GB_MODEL_CGB_C = 0x203, - // GB_MODEL_CGB_D = 0x204, + GB_MODEL_CGB_D = 0x204, GB_MODEL_CGB_E = 0x205, GB_MODEL_AGB = 0x206, } GB_model_t; diff --git a/Core/memory.c b/Core/memory.c index 43cc98f..a4b1fca 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -496,13 +496,11 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) case GB_MODEL_AGB: return (addr & 0xF0) | ((addr >> 4) & 0xF); - /* case GB_MODEL_CGB_D: if (addr > 0xfec0) { addr |= 0xf0; } return gb->extra_oam[addr - 0xfea0]; - */ case GB_MODEL_CGB_C: /* @@ -1005,14 +1003,12 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) gb->oam[addr & 0xFF] = value; } switch (gb->model) { - /* case GB_MODEL_CGB_D: if (addr > 0xfec0) { addr |= 0xf0; } gb->extra_oam[addr - 0xfea0] = value; break; - */ case GB_MODEL_CGB_C: /* case GB_MODEL_CGB_B: diff --git a/Core/save_state.c b/Core/save_state.c index cdbde2b..e543702 100644 --- a/Core/save_state.c +++ b/Core/save_state.c @@ -596,6 +596,7 @@ static int save_state_internal(GB_gameboy_t *gb, virtual_file_t *file, bool appe case GB_MODEL_CGB_C: bess_core.full_model = BE32('CCC '); break; + case GB_MODEL_CGB_D: bess_core.full_model = BE32('CCD '); break; case GB_MODEL_CGB_E: bess_core.full_model = BE32('CCE '); break; case GB_MODEL_AGB: bess_core.full_model = BE32('CA '); break; // SameBoy doesn't emulate a specific AGB revision yet }