diff --git a/Core/display.c b/Core/display.c index 05a45b70..d18c70dd 100644 --- a/Core/display.c +++ b/Core/display.c @@ -393,7 +393,9 @@ static void render_pixel_if_possible(GB_gameboy_t *gb) pixel = ((gb->io_registers[GB_IO_BGP] >> (pixel << 1)) & 3); } if (gb->sgb) { - gb->sgb->screen_buffer[gb->position_in_line + gb->current_line * WIDTH] = pixel; + if (gb->current_lcd_line < LINES) { + gb->sgb->screen_buffer[gb->position_in_line + gb->current_lcd_line * WIDTH] = pixel; + } } else { gb->screen[gb->position_in_line + gb->current_line * WIDTH] = gb->background_palettes_rgb[fifo_item->palette * 4 + pixel]; @@ -407,7 +409,9 @@ static void render_pixel_if_possible(GB_gameboy_t *gb) pixel = ((gb->io_registers[oam_fifo_item->palette? GB_IO_OBP1 : GB_IO_OBP0] >> (pixel << 1)) & 3); } if (gb->sgb) { - gb->sgb->screen_buffer[gb->position_in_line + gb->current_line * WIDTH] =pixel; + if (gb->current_lcd_line < LINES) { + gb->sgb->screen_buffer[gb->position_in_line + gb->current_lcd_line * WIDTH] = pixel; + } } else { gb->screen[gb->position_in_line + gb->current_line * WIDTH] = gb->sprite_palettes_rgb[oam_fifo_item->palette * 4 + pixel]; @@ -609,6 +613,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) } /* Todo: Merge this with the normal line routine */ + /* Todo: Needs actual rendering, affects SGB emulation */ /* Handle the very first line 0 */ gb->current_line = 0; gb->ly_for_comparison = 0; @@ -642,7 +647,10 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) gb->vram_read_blocked = true; gb->vram_write_blocked = true; gb->cgb_palettes_blocked = true; - + gb->current_lcd_line++; // TODO: Verify timing + if (gb->current_lcd_line == LINES) { + display_vblank(gb); + } /* TODO: How does the window affect this line? */ gb->cycles_for_line += MODE3_LENGTH + (gb->io_registers[GB_IO_SCX] & 7) - 2; GB_SLEEP(gb, display, 3, MODE3_LENGTH + (gb->io_registers[GB_IO_SCX] & 7) - 2); @@ -747,6 +755,10 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) fifo_push_bg_row(&gb->bg_fifo, 0, 0, 0, false, false); /* Todo: find out actual access time of SCX */ gb->position_in_line = - (gb->io_registers[GB_IO_SCX] & 7) - 8; + gb->current_lcd_line++; // Todo: unverified timing + if (gb->current_lcd_line == LINES) { + display_vblank(gb); + } 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); @@ -961,6 +973,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) gb->wy_diff = 0; gb->window_disabled_while_active = false; gb->current_line = 0; + gb->current_lcd_line = -1; // TODO: not the correct timing } } diff --git a/Core/gb.h b/Core/gb.h index 9dea4ef3..66df9c96 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -432,6 +432,7 @@ struct GB_gameboy_internal_s { /* The LCDC will skip the first frame it renders after turning it on. On the CGB, a frame is not skipped if the previous frame was skipped as well. See https://www.reddit.com/r/EmuDev/comments/6exyxu/ */ + /* TODO: Drop this and properly emulate the dropped vreset signal*/ enum { GB_FRAMESKIP_LCD_TURNED_ON, // On a DMG, the LCD renders a blank screen during this state, // on a CGB, the previous frame is repeated (which might be @@ -466,6 +467,7 @@ struct GB_gameboy_internal_s { uint8_t mode_for_interrupt; bool lyc_interrupt_line; bool cgb_palettes_blocked; + uint8_t current_lcd_line; // The LCD can go out of sync since the vsync signal is skipped in some cases. ); /* 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 bf01d202..980e92cd 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -702,7 +702,10 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) if ((value & 0x80) && !(gb->io_registers[GB_IO_LCDC] & 0x80)) { gb->display_cycles = 0; gb->display_state = 0; - if (gb->frame_skip_state == GB_FRAMESKIP_SECOND_FRAME_RENDERED) { + if (GB_is_sgb(gb)) { + gb->frame_skip_state = GB_FRAMESKIP_SECOND_FRAME_RENDERED; + } + else if (gb->frame_skip_state == GB_FRAMESKIP_SECOND_FRAME_RENDERED) { gb->frame_skip_state = GB_FRAMESKIP_LCD_TURNED_ON; } }