Fixed and accurate emulation of object at x=0 timings

This commit is contained in:
Lior Halphon 2022-05-11 02:15:56 +03:00
parent a68f749c3a
commit 4521bb4767
2 changed files with 19 additions and 22 deletions

View File

@ -555,6 +555,13 @@ static void render_pixel_if_possible(GB_gameboy_t *gb)
bool draw_oam = false;
bool bg_enabled = true, bg_priority = false;
// Rendering (including scrolling adjustment) does not occur as long as an object at x=0 is pending
if (gb->n_visible_objs != 0 &&
(gb->io_registers[GB_IO_LCDC] & 2 || GB_is_cgb(gb)) &&
gb->objects_x[gb->n_visible_objs - 1] == 0) {
return;
}
if (unlikely(gb->wx_triggered && !fifo_size(&gb->bg_fifo))) return;
fifo_item = fifo_pop(&gb->bg_fifo);
@ -1304,6 +1311,13 @@ static inline uint16_t mode3_batching_length(GB_gameboy_t *gb)
return 0;
}
static inline uint8_t x_for_object_match(GB_gameboy_t *gb)
{
uint8_t ret = gb->position_in_line + 8;
if (ret > (uint8_t)-16) return 0;
return ret;
}
/*
TODO: It seems that the STAT register's mode bits are always "late" by 4 T-cycles.
The PPU logic can be greatly simplified if that delay is simply emulated.
@ -1353,7 +1367,7 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force)
GB_STATE(gb, display, 24);
GB_STATE(gb, display, 26);
GB_STATE(gb, display, 27);
GB_STATE(gb, display, 28);
// GB_STATE(gb, display, 28);
GB_STATE(gb, display, 29);
GB_STATE(gb, display, 30);
GB_STATE(gb, display, 31);
@ -1562,12 +1576,9 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force)
fifo_clear(&gb->oam_fifo);
/* 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 = -16;
gb->lcd_x = 0;
gb->extra_penalty_for_object_at_0 = MIN((gb->io_registers[GB_IO_SCX] & 7), 5);
/* The actual rendering cycle */
gb->fetcher_state = 0;
if ((gb->mode3_batching_length = mode3_batching_length(gb))) {
@ -1657,15 +1668,14 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force)
On the CGB, this bit is checked only when the pixel is actually popped from the FIFO. */
while (gb->n_visible_objs != 0 &&
(gb->position_in_line < 160 || gb->position_in_line >= (uint8_t)(-8)) &&
gb->objects_x[gb->n_visible_objs - 1] < (uint8_t)(gb->position_in_line + 8)) {
gb->objects_x[gb->n_visible_objs - 1] < x_for_object_match(gb)) {
gb->n_visible_objs--;
}
gb->during_object_fetch = true;
while (gb->n_visible_objs != 0 &&
(gb->io_registers[GB_IO_LCDC] & 2 || GB_is_cgb(gb)) &&
gb->objects_x[gb->n_visible_objs - 1] == (uint8_t)(gb->position_in_line + 8)) {
gb->objects_x[gb->n_visible_objs - 1] == x_for_object_match(gb)) {
while (gb->fetcher_state < 5 || fifo_size(&gb->bg_fifo) == 0) {
advance_fetcher_state_machine(gb, &cycles);
@ -1676,18 +1686,6 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force)
}
}
/* Todo: Measure if penalty occurs before or after waiting for the fetcher. */
if (gb->extra_penalty_for_object_at_0 != 0) {
if (gb->objects_x[gb->n_visible_objs - 1] == 0) {
gb->cycles_for_line += gb->extra_penalty_for_object_at_0;
GB_SLEEP(gb, display, 28, gb->extra_penalty_for_object_at_0);
gb->extra_penalty_for_object_at_0 = 0;
if (gb->object_fetch_aborted) {
goto abort_fetching_object;
}
}
}
/* TODO: Can this be deleted? { */
advance_fetcher_state_machine(gb, &cycles);
gb->cycles_for_line++;

View File

@ -623,7 +623,6 @@ struct GB_gameboy_internal_s {
uint8_t n_visible_objs;
uint8_t oam_search_index;
uint8_t accessed_oam_row;
uint8_t extra_penalty_for_object_at_0;
uint8_t mode_for_interrupt;
bool lyc_interrupt_line;
bool cgb_palettes_blocked;