diff --git a/Core/debugger.c b/Core/debugger.c index fd292b7..b809262 100644 --- a/Core/debugger.c +++ b/Core/debugger.c @@ -1524,7 +1524,7 @@ static bool lcd(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugg else if (gb->display_state == 7 || gb->display_state == 8) { GB_log(gb, "Reading OAM data (%d/40)\n", gb->display_state == 8? gb->oam_search_index : 0); } - else if (gb->display_state <= 3 || gb->display_state == 24) { + else if (gb->display_state <= 3 || gb->display_state == 24 || gb->display_state == 31) { GB_log(gb, "Glitched line 0 (%d cycles to next event)\n", -gb->display_cycles / 2); } else if (gb->mode_for_interrupt == 3) { diff --git a/Core/display.c b/Core/display.c index 6141e53..05a45b7 100644 --- a/Core/display.c +++ b/Core/display.c @@ -304,6 +304,7 @@ void GB_lcd_off(GB_gameboy_t *gb) gb->vram_read_blocked = false; gb->oam_write_blocked = false; gb->vram_write_blocked = false; + gb->cgb_palettes_blocked = false; /* Reset window rendering state */ gb->wy_diff = 0; @@ -586,6 +587,13 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) GB_STATE(gb, display, 28); GB_STATE(gb, display, 29); GB_STATE(gb, display, 30); + GB_STATE(gb, display, 31); + GB_STATE(gb, display, 32); + GB_STATE(gb, display, 33); + GB_STATE(gb, display, 34); + GB_STATE(gb, display, 35); + GB_STATE(gb, display, 36); + } if (!(gb->io_registers[GB_IO_LCDC] & 0x80)) { @@ -610,23 +618,30 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) gb->vram_read_blocked = false; gb->oam_write_blocked = false; gb->vram_write_blocked = false; - gb->cycles_for_line = MODE2_LENGTH - 2; + gb->cgb_palettes_blocked = false; + gb->cycles_for_line = MODE2_LENGTH - 4; GB_STAT_update(gb); - GB_SLEEP(gb, display, 2, MODE2_LENGTH - 2); + GB_SLEEP(gb, display, 2, MODE2_LENGTH - 4); + + gb->oam_write_blocked = true; + gb->cycles_for_line += 2; + GB_STAT_update(gb); + GB_SLEEP(gb, display, 34, 2); gb->io_registers[GB_IO_STAT] &= ~3; 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); - gb->oam_write_blocked = true; - gb->vram_write_blocked = !GB_is_cgb(gb); + gb->vram_read_blocked = !GB_is_cgb(gb) || gb->cgb_double_speed; + gb->vram_write_blocked = !GB_is_cgb(gb) || gb->cgb_double_speed; + gb->cgb_palettes_blocked = !GB_is_cgb(gb); GB_STAT_update(gb); gb->cycles_for_line += 2; GB_SLEEP(gb, display, 24, 2); gb->vram_read_blocked = true; gb->vram_write_blocked = true; + gb->cgb_palettes_blocked = true; /* TODO: How does the window affect this line? */ gb->cycles_for_line += MODE3_LENGTH + (gb->io_registers[GB_IO_SCX] & 7) - 2; @@ -650,6 +665,10 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) gb->oam_write_blocked = false; gb->vram_write_blocked = false; + gb->cycles_for_line += 2; + GB_SLEEP(gb, display, 31, 2); + gb->cgb_palettes_blocked = false; + GB_STAT_update(gb); /* Mode 0 is shorter in the very first line */ GB_SLEEP(gb, display, 5, LINE_LENGTH - gb->cycles_for_line - 8); @@ -659,9 +678,13 @@ 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); + gb->oam_write_blocked = GB_is_cgb(gb) && !gb->cgb_double_speed; gb->accessed_oam_row = 0; - GB_SLEEP(gb, display, 6, 3); + + GB_SLEEP(gb, display, 35, 2); + gb->oam_write_blocked = GB_is_cgb(gb); + + GB_SLEEP(gb, display, 6, 1); gb->io_registers[GB_IO_LY] = gb->current_line; gb->oam_read_blocked = true; gb->ly_for_comparison = gb->current_line? -1 : 0; @@ -702,6 +725,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) if (gb->oam_search_index == 37) { gb->vram_read_blocked = !GB_is_cgb(gb); gb->vram_write_blocked = false; + gb->cgb_palettes_blocked = false; gb->oam_write_blocked = GB_is_cgb(gb); GB_STAT_update(gb); } @@ -712,6 +736,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) gb->mode_for_interrupt = 3; gb->vram_read_blocked = true; gb->vram_write_blocked = true; + gb->cgb_palettes_blocked = false; gb->oam_write_blocked = true; GB_STAT_update(gb); @@ -725,13 +750,18 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) gb->fetcher_x = ((gb->io_registers[GB_IO_SCX]) / 8) & 0x1f; gb->extra_penalty_for_sprite_at_0 = (gb->io_registers[GB_IO_SCX] & 7); - uint8_t idle_cycles = 5; + uint8_t idle_cycles = 3; if (GB_is_cgb(gb) && gb->model <= GB_MODEL_CGB_C) { - idle_cycles = 4; + idle_cycles = 2; } gb->cycles_for_line += idle_cycles; GB_SLEEP(gb, display, 10, idle_cycles); + + gb->cgb_palettes_blocked = true; + gb->cycles_for_line += 2; + GB_SLEEP(gb, display, 32, 2); + /* The actual rendering cycle */ gb->fetcher_state = 0; gb->bg_fifo_paused = false; @@ -848,9 +878,16 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) GB_STAT_update(gb); /* Todo: Measure this value */ + gb->cycles_for_line += 2; + GB_SLEEP(gb, display, 33, 2); + gb->cgb_palettes_blocked = !gb->cgb_double_speed; - gb->cycles_for_line += 12; - GB_SLEEP(gb, display, 25, 12); + gb->cycles_for_line += 2; + GB_SLEEP(gb, display, 36, 2); + gb->cgb_palettes_blocked = false; + + gb->cycles_for_line += 8; + GB_SLEEP(gb, display, 25, 8); if (gb->hdma_on_hblank) { gb->hdma_starting = true; diff --git a/Core/gb.h b/Core/gb.h index e37a159..9dea4ef 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -465,6 +465,7 @@ struct GB_gameboy_internal_s { uint8_t extra_penalty_for_sprite_at_0; uint8_t mode_for_interrupt; bool lyc_interrupt_line; + bool cgb_palettes_blocked; ); /* Unsaved data. This includes all pointers, as well as everything that shouldn't be on a save state */ diff --git a/Core/memory.c b/Core/memory.c index 39f358e..262fc4d 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -197,7 +197,7 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) } if (addr < 0xFF00) { - if (gb->oam_write_blocked) { + if (gb->oam_write_blocked && !GB_is_cgb(gb)) { GB_trigger_oam_bug_read(gb, addr); return 0xff; } @@ -357,8 +357,7 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) if (!gb->cgb_mode && gb->boot_rom_finished) { return 0xFF; } - /* TODO: Verify actual access timing */ - if (gb->vram_read_blocked) { + if (gb->cgb_palettes_blocked) { return 0xFF; } uint8_t index_reg = (addr & 0xFF) - 1; @@ -793,8 +792,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) is required. */ return; } - /* TODO: Verify actual access timing */ - if (gb->vram_write_blocked) { + if (gb->cgb_palettes_blocked) { return; } uint8_t index_reg = (addr & 0xFF) - 1;