Emulate missing Vreset signal (SGB only for now) and ICD2 desyncing

This commit is contained in:
Lior Halphon 2019-02-15 17:04:48 +02:00
parent 42ef41182d
commit 9d0aadb83f
3 changed files with 22 additions and 4 deletions

View File

@ -393,7 +393,9 @@ static void render_pixel_if_possible(GB_gameboy_t *gb)
pixel = ((gb->io_registers[GB_IO_BGP] >> (pixel << 1)) & 3); pixel = ((gb->io_registers[GB_IO_BGP] >> (pixel << 1)) & 3);
} }
if (gb->sgb) { 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 { else {
gb->screen[gb->position_in_line + gb->current_line * WIDTH] = gb->background_palettes_rgb[fifo_item->palette * 4 + pixel]; 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); pixel = ((gb->io_registers[oam_fifo_item->palette? GB_IO_OBP1 : GB_IO_OBP0] >> (pixel << 1)) & 3);
} }
if (gb->sgb) { 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 { else {
gb->screen[gb->position_in_line + gb->current_line * WIDTH] = gb->sprite_palettes_rgb[oam_fifo_item->palette * 4 + pixel]; 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: Merge this with the normal line routine */
/* Todo: Needs actual rendering, affects SGB emulation */
/* Handle the very first line 0 */ /* Handle the very first line 0 */
gb->current_line = 0; gb->current_line = 0;
gb->ly_for_comparison = 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_read_blocked = true;
gb->vram_write_blocked = true; gb->vram_write_blocked = true;
gb->cgb_palettes_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? */ /* TODO: How does the window affect this line? */
gb->cycles_for_line += MODE3_LENGTH + (gb->io_registers[GB_IO_SCX] & 7) - 2; 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); 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); fifo_push_bg_row(&gb->bg_fifo, 0, 0, 0, false, false);
/* Todo: find out actual access time of SCX */ /* Todo: find out actual access time of SCX */
gb->position_in_line = - (gb->io_registers[GB_IO_SCX] & 7) - 8; 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->fetcher_x = ((gb->io_registers[GB_IO_SCX]) / 8) & 0x1f;
gb->extra_penalty_for_sprite_at_0 = (gb->io_registers[GB_IO_SCX] & 7); 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->wy_diff = 0;
gb->window_disabled_while_active = false; gb->window_disabled_while_active = false;
gb->current_line = 0; gb->current_line = 0;
gb->current_lcd_line = -1; // TODO: not the correct timing
} }
} }

View File

@ -432,6 +432,7 @@ struct GB_gameboy_internal_s {
/* The LCDC will skip the first frame it renders after turning it on. /* 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. 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/ */ See https://www.reddit.com/r/EmuDev/comments/6exyxu/ */
/* TODO: Drop this and properly emulate the dropped vreset signal*/
enum { enum {
GB_FRAMESKIP_LCD_TURNED_ON, // On a DMG, the LCD renders a blank screen during this state, 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 // 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; uint8_t mode_for_interrupt;
bool lyc_interrupt_line; bool lyc_interrupt_line;
bool cgb_palettes_blocked; 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 */ /* Unsaved data. This includes all pointers, as well as everything that shouldn't be on a save state */

View File

@ -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)) { if ((value & 0x80) && !(gb->io_registers[GB_IO_LCDC] & 0x80)) {
gb->display_cycles = 0; gb->display_cycles = 0;
gb->display_state = 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; gb->frame_skip_state = GB_FRAMESKIP_LCD_TURNED_ON;
} }
} }