Initial emulation of "SCX banging" to prolong mode 3
This commit is contained in:
parent
cb73e0b91a
commit
a68f749c3a
@ -433,6 +433,7 @@ void GB_STAT_update(GB_gameboy_t *gb)
|
||||
|
||||
void GB_lcd_off(GB_gameboy_t *gb)
|
||||
{
|
||||
gb->cycles_for_line = 0;
|
||||
gb->display_state = 0;
|
||||
gb->display_cycles = 0;
|
||||
/* When the LCD is disabled, state is constant */
|
||||
@ -566,6 +567,17 @@ static void render_pixel_if_possible(GB_gameboy_t *gb)
|
||||
bg_priority |= oam_fifo_item->bg_priority;
|
||||
}
|
||||
}
|
||||
|
||||
// (gb->position_in_line + 16 < 8) is (gb->position_in_line < -8) in unsigned logic
|
||||
if (((uint8_t)(gb->position_in_line + 16) < 8)) {
|
||||
if ((gb->position_in_line & 7) == (gb->io_registers[GB_IO_SCX] & 7)) {
|
||||
gb->position_in_line = -8;
|
||||
}
|
||||
else if (gb->position_in_line == (uint8_t) -9) {
|
||||
gb->position_in_line = -16;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Drop pixels for scrollings */
|
||||
if (gb->position_in_line >= 160 || (gb->disable_rendering && !gb->sgb)) {
|
||||
@ -771,6 +783,9 @@ static void advance_fetcher_state_machine(GB_gameboy_t *gb, unsigned *cycles)
|
||||
if (gb->wx_triggered) {
|
||||
x = gb->window_tile_x;
|
||||
}
|
||||
else if ((uint8_t)(gb->position_in_line + 16) < 8) {
|
||||
x = gb->io_registers[GB_IO_SCX] >> 3;
|
||||
}
|
||||
else {
|
||||
/* TODO: There is some CGB timing error around here.
|
||||
Adjusting SCX by 7 or less shouldn't have an effect on a CGB,
|
||||
@ -1295,6 +1310,13 @@ static inline uint16_t mode3_batching_length(GB_gameboy_t *gb)
|
||||
*/
|
||||
void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force)
|
||||
{
|
||||
if (unlikely((gb->io_registers[GB_IO_LCDC] & 0x80) && (signed)(gb->cycles_for_line * 2 + cycles + gb->display_cycles) > LINE_LENGTH * 2)) {
|
||||
unsigned first_batch = (LINE_LENGTH * 2 - gb->cycles_for_line * 2 + gb->display_cycles);
|
||||
GB_display_run(gb, first_batch, force);
|
||||
cycles -= first_batch;
|
||||
gb->display_state = 9;
|
||||
gb->display_cycles = 0;
|
||||
}
|
||||
gb->cycles_since_vblank_callback += cycles / 2;
|
||||
|
||||
/* The PPU does not advance while in STOP mode on the DMG */
|
||||
@ -1314,7 +1336,7 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force)
|
||||
GB_STATE(gb, display, 6);
|
||||
GB_STATE(gb, display, 7);
|
||||
GB_STATE(gb, display, 8);
|
||||
// GB_STATE(gb, display, 9);
|
||||
GB_STATE(gb, display, 9);
|
||||
GB_STATE(gb, display, 10);
|
||||
GB_STATE(gb, display, 11);
|
||||
GB_STATE(gb, display, 12);
|
||||
@ -1346,6 +1368,7 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force)
|
||||
GB_STATE(gb, display, 40);
|
||||
GB_STATE(gb, display, 41);
|
||||
GB_STATE(gb, display, 42);
|
||||
GB_STATE(gb, display, 43);
|
||||
}
|
||||
|
||||
if (!(gb->io_registers[GB_IO_LCDC] & 0x80)) {
|
||||
@ -1414,7 +1437,33 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force)
|
||||
gb->wx_triggered = false;
|
||||
gb->wx166_glitch = false;
|
||||
goto mode_3_start;
|
||||
|
||||
|
||||
// Mode 3 abort, state 9
|
||||
display9: {
|
||||
// TODO: Timing of things in this scenario is almost completely untested
|
||||
if (gb->current_line < 144 && !GB_is_sgb(gb) && !gb->disable_rendering) {
|
||||
GB_log(gb, "The ROM is preventing line %d from fully rendering, this could damage a real device's LCD display.\n", gb->current_line);
|
||||
uint32_t *dest = NULL;
|
||||
if (gb->border_mode != GB_BORDER_ALWAYS) {
|
||||
dest = gb->screen + gb->lcd_x + gb->current_line * WIDTH;
|
||||
}
|
||||
else {
|
||||
dest = gb->screen + gb->lcd_x + gb->current_line * BORDERED_WIDTH + (BORDERED_WIDTH - WIDTH) / 2 + (BORDERED_HEIGHT - LINES) / 2 * BORDERED_WIDTH;
|
||||
}
|
||||
uint32_t color = GB_is_cgb(gb)? GB_convert_rgb15(gb, 0x7FFF, false) : gb->background_palettes_rgb[4];
|
||||
while (gb->lcd_x < 160) {
|
||||
*(dest++) = color;
|
||||
gb->lcd_x++;
|
||||
}
|
||||
}
|
||||
gb->current_line++;
|
||||
gb->vram_read_blocked = false;
|
||||
gb->vram_write_blocked = false;
|
||||
gb->wx_triggered = false;
|
||||
gb->wx166_glitch = false;
|
||||
gb->cycles_for_line = 0;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
/* Lines 0 - 143 */
|
||||
gb->window_y = -1;
|
||||
@ -1514,7 +1563,7 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force)
|
||||
/* Fill the FIFO with 8 pixels of "junk", it's going to be dropped anyway. */
|
||||
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->position_in_line = -16;
|
||||
gb->lcd_x = 0;
|
||||
|
||||
gb->extra_penalty_for_object_at_0 = MIN((gb->io_registers[GB_IO_SCX] & 7), 5);
|
||||
@ -1785,7 +1834,17 @@ skip_slow_mode_3:
|
||||
GB_SLEEP(gb, display, 36, 2);
|
||||
gb->cgb_palettes_blocked = false;
|
||||
|
||||
GB_SLEEP(gb, display, 11, LINE_LENGTH - gb->cycles_for_line - 2);
|
||||
if (gb->cycles_for_line > LINE_LENGTH - 2) {
|
||||
gb->cycles_for_line = 0;
|
||||
GB_SLEEP(gb, display, 43, LINE_LENGTH - gb->cycles_for_line);
|
||||
goto display9;
|
||||
}
|
||||
|
||||
{
|
||||
uint16_t cycles_for_line = gb->cycles_for_line;
|
||||
gb->cycles_for_line = 0;
|
||||
GB_SLEEP(gb, display, 11, LINE_LENGTH - cycles_for_line - 2);
|
||||
}
|
||||
/*
|
||||
TODO: Verify double speed timing
|
||||
TODO: Timing differs on a DMG
|
||||
@ -1794,6 +1853,7 @@ skip_slow_mode_3:
|
||||
(gb->io_registers[GB_IO_WY] == gb->current_line)) {
|
||||
gb->wy_triggered = true;
|
||||
}
|
||||
gb->cycles_for_line = 0;
|
||||
GB_SLEEP(gb, display, 31, 2);
|
||||
if (gb->current_line != LINES - 1) {
|
||||
gb->mode_for_interrupt = 2;
|
||||
|
@ -1432,6 +1432,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
gb->display_cycles = 0;
|
||||
gb->display_state = 0;
|
||||
gb->double_speed_alignment = 0;
|
||||
gb->cycles_for_line = 0;
|
||||
if (GB_is_sgb(gb)) {
|
||||
gb->frame_skip_state = GB_FRAMESKIP_SECOND_FRAME_RENDERED;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user