Fixed and accurate emulation of object at x=0 timings
This commit is contained in:
parent
a68f749c3a
commit
4521bb4767
@ -554,6 +554,13 @@ static void render_pixel_if_possible(GB_gameboy_t *gb)
|
|||||||
const GB_fifo_item_t *oam_fifo_item = NULL;
|
const GB_fifo_item_t *oam_fifo_item = NULL;
|
||||||
bool draw_oam = false;
|
bool draw_oam = false;
|
||||||
bool bg_enabled = true, bg_priority = 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;
|
if (unlikely(gb->wx_triggered && !fifo_size(&gb->bg_fifo))) return;
|
||||||
|
|
||||||
@ -1304,6 +1311,13 @@ static inline uint16_t mode3_batching_length(GB_gameboy_t *gb)
|
|||||||
return 0;
|
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.
|
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.
|
The PPU logic can be greatly simplified if that delay is simply emulated.
|
||||||
@ -1326,7 +1340,7 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force)
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GB_BATCHABLE_STATE_MACHINE(gb, display, cycles, 2, !force) {
|
GB_BATCHABLE_STATE_MACHINE(gb, display, cycles, 2, !force) {
|
||||||
GB_STATE(gb, display, 1);
|
GB_STATE(gb, display, 1);
|
||||||
GB_STATE(gb, display, 2);
|
GB_STATE(gb, display, 2);
|
||||||
@ -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, 24);
|
||||||
GB_STATE(gb, display, 26);
|
GB_STATE(gb, display, 26);
|
||||||
GB_STATE(gb, display, 27);
|
GB_STATE(gb, display, 27);
|
||||||
GB_STATE(gb, display, 28);
|
// GB_STATE(gb, display, 28);
|
||||||
GB_STATE(gb, display, 29);
|
GB_STATE(gb, display, 29);
|
||||||
GB_STATE(gb, display, 30);
|
GB_STATE(gb, display, 30);
|
||||||
GB_STATE(gb, display, 31);
|
GB_STATE(gb, display, 31);
|
||||||
@ -1562,11 +1576,8 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force)
|
|||||||
fifo_clear(&gb->oam_fifo);
|
fifo_clear(&gb->oam_fifo);
|
||||||
/* Fill the FIFO with 8 pixels of "junk", it's going to be dropped anyway. */
|
/* 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);
|
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->position_in_line = -16;
|
||||||
gb->lcd_x = 0;
|
gb->lcd_x = 0;
|
||||||
|
|
||||||
gb->extra_penalty_for_object_at_0 = MIN((gb->io_registers[GB_IO_SCX] & 7), 5);
|
|
||||||
|
|
||||||
/* The actual rendering cycle */
|
/* The actual rendering cycle */
|
||||||
gb->fetcher_state = 0;
|
gb->fetcher_state = 0;
|
||||||
@ -1655,17 +1666,16 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force)
|
|||||||
/* Handle objects */
|
/* Handle objects */
|
||||||
/* When the object enabled bit is off, this proccess is skipped entirely on the DMG, but not on the CGB.
|
/* When the object enabled bit is off, this proccess is skipped entirely on the DMG, but not on the CGB.
|
||||||
On the CGB, this bit is checked only when the pixel is actually popped from the FIFO. */
|
On the CGB, this bit is checked only when the pixel is actually popped from the FIFO. */
|
||||||
|
|
||||||
while (gb->n_visible_objs != 0 &&
|
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] < x_for_object_match(gb)) {
|
||||||
gb->objects_x[gb->n_visible_objs - 1] < (uint8_t)(gb->position_in_line + 8)) {
|
|
||||||
gb->n_visible_objs--;
|
gb->n_visible_objs--;
|
||||||
}
|
}
|
||||||
|
|
||||||
gb->during_object_fetch = true;
|
gb->during_object_fetch = true;
|
||||||
while (gb->n_visible_objs != 0 &&
|
while (gb->n_visible_objs != 0 &&
|
||||||
(gb->io_registers[GB_IO_LCDC] & 2 || GB_is_cgb(gb)) &&
|
(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) {
|
while (gb->fetcher_state < 5 || fifo_size(&gb->bg_fifo) == 0) {
|
||||||
advance_fetcher_state_machine(gb, &cycles);
|
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? { */
|
/* TODO: Can this be deleted? { */
|
||||||
advance_fetcher_state_machine(gb, &cycles);
|
advance_fetcher_state_machine(gb, &cycles);
|
||||||
gb->cycles_for_line++;
|
gb->cycles_for_line++;
|
||||||
|
@ -623,7 +623,6 @@ struct GB_gameboy_internal_s {
|
|||||||
uint8_t n_visible_objs;
|
uint8_t n_visible_objs;
|
||||||
uint8_t oam_search_index;
|
uint8_t oam_search_index;
|
||||||
uint8_t accessed_oam_row;
|
uint8_t accessed_oam_row;
|
||||||
uint8_t extra_penalty_for_object_at_0;
|
|
||||||
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;
|
||||||
|
Loading…
Reference in New Issue
Block a user