Disgusting hacks to emulate disabling objects while an object is being fetched

This commit is contained in:
Lior Halphon 2020-02-21 15:14:33 +02:00
parent 56118d2a67
commit 91404edd13
3 changed files with 51 additions and 1 deletions

View File

@ -912,6 +912,9 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
advance_fetcher_state_machine(gb); advance_fetcher_state_machine(gb);
gb->cycles_for_line++; gb->cycles_for_line++;
GB_SLEEP(gb, display, 27, 1); GB_SLEEP(gb, display, 27, 1);
if (!(gb->io_registers[GB_IO_LCDC] & 2) && !GB_is_cgb(gb)) {
goto abort_fetching_object;
}
} }
/* Todo: Measure if penalty occurs before or after waiting for the fetcher. */ /* Todo: Measure if penalty occurs before or after waiting for the fetcher. */
@ -920,11 +923,19 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
gb->cycles_for_line += gb->extra_penalty_for_sprite_at_0; gb->cycles_for_line += gb->extra_penalty_for_sprite_at_0;
GB_SLEEP(gb, display, 28, gb->extra_penalty_for_sprite_at_0); GB_SLEEP(gb, display, 28, gb->extra_penalty_for_sprite_at_0);
gb->extra_penalty_for_sprite_at_0 = 0; gb->extra_penalty_for_sprite_at_0 = 0;
if (gb->object_fetch_aborted) {
gb->object_fetch_aborted = false;
goto abort_fetching_object;
}
} }
} }
gb->cycles_for_line += 6; gb->cycles_for_line += 6;
GB_SLEEP(gb, display, 20, 6); GB_SLEEP(gb, display, 20, 6);
if (gb->object_fetch_aborted) {
gb->object_fetch_aborted = false;
goto abort_fetching_object;
}
/* TODO: what does the PPU read if DMA is active? */ /* TODO: what does the PPU read if DMA is active? */
const GB_object_t *object = &objects[gb->visible_objs[gb->n_visible_objs - 1]]; const GB_object_t *object = &objects[gb->visible_objs[gb->n_visible_objs - 1]];
if (gb->oam_ppu_blocked) { if (gb->oam_ppu_blocked) {
@ -961,6 +972,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
gb->n_visible_objs--; gb->n_visible_objs--;
} }
abort_fetching_object:
/* Handle window */ /* Handle window */
/* Todo: Timing (Including penalty and access timings) 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) &&

View File

@ -518,6 +518,7 @@ struct GB_gameboy_internal_s {
bool oam_ppu_blocked; bool oam_ppu_blocked;
bool vram_ppu_blocked; bool vram_ppu_blocked;
bool cgb_palettes_ppu_blocked; bool cgb_palettes_ppu_blocked;
bool object_fetch_aborted;
); );
/* 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

@ -195,14 +195,51 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
} }
case GB_CONFLICT_DMG_LCDC: { case GB_CONFLICT_DMG_LCDC: {
/* Seems to be affected by screen? Both my DMG (B, blob) and Game Boy Light behave this way though. */ /* Similar to the palette registers, these interact directly with the LCD, so they appear to be affected by it. Both my DMG (B, blob) and Game Boy Light behave this way though.
Additionally, LCDC.1 is very nasty because on the it is read both by the FIFO when popping pixels,
and the sprite-fetching state machine, and both behave differently when it comes to access conflicts.
Hacks ahead.
*/
uint8_t old_value = GB_read_memory(gb, addr); uint8_t old_value = GB_read_memory(gb, addr);
GB_advance_cycles(gb, gb->pending_cycles - 2); GB_advance_cycles(gb, gb->pending_cycles - 2);
if (gb->current_lcd_line == 108) {
}
/* Handle disabling objects while already fetching an object */
if ((old_value & 2) && !(value & 2)) {
if (gb->display_state == 27) {
old_value &= ~2;
}
else if (gb->display_state == 20 || gb->display_state == 28) {
gb->cycles_for_line -= gb->display_cycles;
gb->display_cycles = 0;
gb->object_fetch_aborted = true;
}
}
if (/* gb->model != GB_MODEL_MGB && */ gb->position_in_line == 0 && (old_value & 2) && !(value & 2)) { if (/* gb->model != GB_MODEL_MGB && */ gb->position_in_line == 0 && (old_value & 2) && !(value & 2)) {
old_value &= ~2; old_value &= ~2;
} }
GB_write_memory(gb, addr, old_value | (value & 1)); GB_write_memory(gb, addr, old_value | (value & 1));
GB_advance_cycles(gb, 1); GB_advance_cycles(gb, 1);
/* Handle disabling objects while already fetching an object */
if ((old_value & 2) && !(value & 2)) {
if (gb->display_state == 27) {
old_value &= ~2;
}
else if (gb->display_state == 20 || gb->display_state == 28) {
gb->cycles_for_line -= gb->display_cycles;
gb->display_cycles = 0;
gb->object_fetch_aborted = true;
}
}
GB_write_memory(gb, addr, value); GB_write_memory(gb, addr, value);
gb->pending_cycles = 5; gb->pending_cycles = 5;
return; return;