Emulate another OAM timing quirk; a sprite at x = 0 has extra penalty if SCX is not 0. Fixes intr_2_mode0_timing_sprites_scx*_nops, affects #54

This commit is contained in:
Lior Halphon 2018-03-30 17:06:27 +03:00
parent 2c44ffbe39
commit 9811dceca1
2 changed files with 15 additions and 1 deletions

View File

@ -326,6 +326,7 @@ static void render_pixel_if_possible(GB_gameboy_t *gb)
if (!gb->oam_fifo_paused && fifo_size(&gb->oam_fifo)) { if (!gb->oam_fifo_paused && fifo_size(&gb->oam_fifo)) {
oam_fifo_item = fifo_pop(&gb->oam_fifo); oam_fifo_item = fifo_pop(&gb->oam_fifo);
/* Todo: Verify access timings */
if (oam_fifo_item->pixel && (gb->io_registers[GB_IO_LCDC] & 2)) { if (oam_fifo_item->pixel && (gb->io_registers[GB_IO_LCDC] & 2)) {
draw_oam = true; draw_oam = true;
bg_priority |= oam_fifo_item->bg_priority; bg_priority |= oam_fifo_item->bg_priority;
@ -341,6 +342,7 @@ static void render_pixel_if_possible(GB_gameboy_t *gb)
/* Mixing */ /* Mixing */
/* Todo: Verify access timings */
if ((gb->io_registers[GB_IO_LCDC] & 0x1) == 0) { if ((gb->io_registers[GB_IO_LCDC] & 0x1) == 0) {
if (gb->cgb_mode) { if (gb->cgb_mode) {
bg_priority = false; bg_priority = false;
@ -370,6 +372,7 @@ static void render_pixel_if_possible(GB_gameboy_t *gb)
if (draw_oam) { if (draw_oam) {
uint8_t pixel = oam_fifo_item->pixel; uint8_t pixel = oam_fifo_item->pixel;
if (!gb->cgb_mode) { if (!gb->cgb_mode) {
/* Todo: Verify access timings */
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);
} }
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];
@ -535,8 +538,10 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
gb->cycles_for_line = MODE2_LENGTH + 4; gb->cycles_for_line = MODE2_LENGTH + 4;
fifo_clear(&gb->bg_fifo); fifo_clear(&gb->bg_fifo);
fifo_clear(&gb->oam_fifo); fifo_clear(&gb->oam_fifo);
/* 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->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->cycles_for_line += 5; gb->cycles_for_line += 5;
GB_SLEEP(gb, display, 10, 5); GB_SLEEP(gb, display, 10, 5);
@ -556,8 +561,12 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
gb->obj_comperators[gb->n_visible_objs - 1] == (uint8_t)(gb->position_in_line + 8)) { gb->obj_comperators[gb->n_visible_objs - 1] == (uint8_t)(gb->position_in_line + 8)) {
if (gb->fetcher_stop_penalty == 0) { if (gb->fetcher_stop_penalty == 0) {
/* TODO: figure out why the penalty works this way and actual access timings */
/* Penalty for interrupting the fetcher */ /* Penalty for interrupting the fetcher */
gb->fetcher_stop_penalty = (uint8_t[]){5, 4, 3, 2, 1, 0, 0, 0}[gb->fetcher_state * 2 + gb->fetcher_divisor]; gb->fetcher_stop_penalty = (uint8_t[]){5, 4, 3, 2, 1, 0, 0, 0}[gb->fetcher_state * 2 + gb->fetcher_divisor];
if (gb->obj_comperators[gb->n_visible_objs - 1] == 0) {
gb->fetcher_stop_penalty += gb->extra_penalty_for_sprite_at_0;
}
} }
gb->cycles_for_line += 6; gb->cycles_for_line += 6;
@ -592,7 +601,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
} }
/* Handle window */ /* Handle window */
/* Todo: Timing not verified by test ROM */ /* Todo: Timing (Including penalty and access timings) not verified by test ROM */
if (!gb->in_window && window_enabled(gb) && if (!gb->in_window && window_enabled(gb) &&
gb->current_line >= gb->io_registers[GB_IO_WY] + gb->wy_diff && gb->current_line >= gb->io_registers[GB_IO_WY] + gb->wy_diff &&
gb->position_in_line + 7 == gb->io_registers[GB_IO_WX]) { gb->position_in_line + 7 == gb->io_registers[GB_IO_WX]) {
@ -608,6 +617,8 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
switch (gb->fetcher_state) { switch (gb->fetcher_state) {
case GB_FETCHER_GET_TILE: { case GB_FETCHER_GET_TILE: {
uint16_t map = 0x1800; uint16_t map = 0x1800;
/* Todo: Verify access timings */
if (gb->io_registers[GB_IO_LCDC] & 0x08 && !gb->in_window) { if (gb->io_registers[GB_IO_LCDC] & 0x08 && !gb->in_window) {
map = 0x1C00; map = 0x1C00;
} }
@ -628,6 +639,8 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
case GB_FETCHER_GET_TILE_DATA_LOWER: { case GB_FETCHER_GET_TILE_DATA_LOWER: {
uint8_t y_flip = 0; uint8_t y_flip = 0;
/* Todo: Verify access timings */
if (gb->io_registers[GB_IO_LCDC] & 0x10) { if (gb->io_registers[GB_IO_LCDC] & 0x10) {
gb->current_tile_address = gb->current_tile * 0x10; gb->current_tile_address = gb->current_tile * 0x10;
} }

View File

@ -428,6 +428,7 @@ struct GB_gameboy_internal_s {
uint8_t fetcher_stop_penalty; uint8_t fetcher_stop_penalty;
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_sprite_at_0;
); );
/* 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 */