Emulate changing sprite height mid-fetch
This commit is contained in:
parent
7d51ba3d97
commit
8409d3bcfb
@ -680,6 +680,30 @@ static void advance_fetcher_state_machine(GB_gameboy_t *gb)
|
|||||||
gb->fetcher_state &= 7;
|
gb->fetcher_state &= 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint16_t get_object_line_address(GB_gameboy_t *gb, const GB_object_t *object)
|
||||||
|
{
|
||||||
|
/* TODO: what does the PPU read if DMA is active? */
|
||||||
|
if (gb->oam_ppu_blocked) {
|
||||||
|
static const GB_object_t blocked = {0xFF, 0xFF, 0xFF, 0xFF};
|
||||||
|
object = &blocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool height_16 = (gb->io_registers[GB_IO_LCDC] & 4) != 0; /* Todo: Which T-cycle actually reads this? */
|
||||||
|
uint8_t tile_y = (gb->current_line - object->y) & (height_16? 0xF : 7);
|
||||||
|
|
||||||
|
if (object->flags & 0x40) { /* Flip Y */
|
||||||
|
tile_y ^= height_16? 0xF : 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Todo: I'm not 100% sure an access to OAM can't trigger the OAM bug while we're accessing this */
|
||||||
|
uint16_t line_address = (height_16? object->tile & 0xFE : object->tile) * 0x10 + tile_y * 2;
|
||||||
|
|
||||||
|
if (gb->cgb_mode && (object->flags & 0x8)) { /* Use VRAM bank 2 */
|
||||||
|
line_address += 0x2000;
|
||||||
|
}
|
||||||
|
return line_address;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
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.
|
||||||
@ -736,6 +760,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
|
|||||||
GB_STATE(gb, display, 37);
|
GB_STATE(gb, display, 37);
|
||||||
GB_STATE(gb, display, 38);
|
GB_STATE(gb, display, 38);
|
||||||
GB_STATE(gb, display, 39);
|
GB_STATE(gb, display, 39);
|
||||||
|
GB_STATE(gb, display, 40);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -931,42 +956,34 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gb->cycles_for_line += 5;
|
gb->cycles_for_line += 4;
|
||||||
GB_SLEEP(gb, display, 20, 5);
|
GB_SLEEP(gb, display, 20, 4);
|
||||||
if (gb->object_fetch_aborted) {
|
if (gb->object_fetch_aborted) {
|
||||||
goto abort_fetching_object;
|
goto abort_fetching_object;
|
||||||
}
|
}
|
||||||
gb->during_object_fetch = false;
|
|
||||||
|
gb->object_low_line_address = get_object_line_address(gb, &objects[gb->visible_objs[gb->n_visible_objs - 1]]);
|
||||||
|
|
||||||
gb->cycles_for_line++;
|
gb->cycles_for_line++;
|
||||||
GB_SLEEP(gb, display, 39, 1);
|
GB_SLEEP(gb, display, 39, 1);
|
||||||
|
if (gb->object_fetch_aborted) {
|
||||||
|
goto abort_fetching_object;
|
||||||
|
}
|
||||||
|
|
||||||
|
gb->during_object_fetch = false;
|
||||||
|
gb->cycles_for_line++;
|
||||||
|
GB_SLEEP(gb, display, 40, 1);
|
||||||
|
|
||||||
/* 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) {
|
|
||||||
static const GB_object_t blocked = {0xFF, 0xFF, 0xFF, 0xFF};
|
|
||||||
object = &blocked;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool height_16 = (gb->io_registers[GB_IO_LCDC] & 4) != 0; /* Todo: Which T-cycle actually reads this? */
|
uint16_t line_address = get_object_line_address(gb, object);
|
||||||
uint8_t tile_y = (gb->current_line - object->y) & (height_16? 0xF : 7);
|
|
||||||
|
|
||||||
if (object->flags & 0x40) { /* Flip Y */
|
|
||||||
tile_y ^= height_16? 0xF : 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Todo: I'm not 100% sure an access to OAM can't trigger the OAM bug while we're accessing this */
|
|
||||||
uint16_t line_address = (height_16? object->tile & 0xFE : object->tile) * 0x10 + tile_y * 2;
|
|
||||||
|
|
||||||
if (gb->cgb_mode && (object->flags & 0x8)) { /* Use VRAM bank 2 */
|
|
||||||
line_address += 0x2000;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t palette = (object->flags & 0x10) ? 1 : 0;
|
uint8_t palette = (object->flags & 0x10) ? 1 : 0;
|
||||||
if (gb->cgb_mode) {
|
if (gb->cgb_mode) {
|
||||||
palette = object->flags & 0x7;
|
palette = object->flags & 0x7;
|
||||||
}
|
}
|
||||||
fifo_overlay_object_row(&gb->oam_fifo,
|
fifo_overlay_object_row(&gb->oam_fifo,
|
||||||
gb->vram_ppu_blocked? 0xFF : gb->vram[line_address],
|
gb->vram_ppu_blocked? 0xFF : gb->vram[gb->object_low_line_address],
|
||||||
gb->vram_ppu_blocked? 0xFF : gb->vram[line_address + 1],
|
gb->vram_ppu_blocked? 0xFF : gb->vram[line_address + 1],
|
||||||
palette,
|
palette,
|
||||||
object->flags & 0x80,
|
object->flags & 0x80,
|
||||||
|
@ -520,6 +520,7 @@ struct GB_gameboy_internal_s {
|
|||||||
bool cgb_palettes_ppu_blocked;
|
bool cgb_palettes_ppu_blocked;
|
||||||
bool object_fetch_aborted;
|
bool object_fetch_aborted;
|
||||||
bool during_object_fetch;
|
bool during_object_fetch;
|
||||||
|
uint16_t object_low_line_address;
|
||||||
);
|
);
|
||||||
|
|
||||||
/* 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 */
|
||||||
|
@ -265,6 +265,7 @@ int GB_load_state(GB_gameboy_t *gb, const char *path)
|
|||||||
gb->bg_fifo.write_end &= 0xF;
|
gb->bg_fifo.write_end &= 0xF;
|
||||||
gb->oam_fifo.read_end &= 0xF;
|
gb->oam_fifo.read_end &= 0xF;
|
||||||
gb->oam_fifo.write_end &= 0xF;
|
gb->oam_fifo.write_end &= 0xF;
|
||||||
|
gb->object_low_line_address &= gb->vram_size & ~1;
|
||||||
|
|
||||||
if (gb->object_priority == GB_OBJECT_PRIORITY_UNDEFINED) {
|
if (gb->object_priority == GB_OBJECT_PRIORITY_UNDEFINED) {
|
||||||
gb->object_priority = gb->cgb_mode? GB_OBJECT_PRIORITY_INDEX : GB_OBJECT_PRIORITY_X;
|
gb->object_priority = gb->cgb_mode? GB_OBJECT_PRIORITY_INDEX : GB_OBJECT_PRIORITY_X;
|
||||||
@ -374,6 +375,7 @@ int GB_load_state_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t le
|
|||||||
gb->bg_fifo.write_end &= 0xF;
|
gb->bg_fifo.write_end &= 0xF;
|
||||||
gb->oam_fifo.read_end &= 0xF;
|
gb->oam_fifo.read_end &= 0xF;
|
||||||
gb->oam_fifo.write_end &= 0xF;
|
gb->oam_fifo.write_end &= 0xF;
|
||||||
|
gb->object_low_line_address &= gb->vram_size & ~1;
|
||||||
|
|
||||||
if (gb->object_priority == GB_OBJECT_PRIORITY_UNDEFINED) {
|
if (gb->object_priority == GB_OBJECT_PRIORITY_UNDEFINED) {
|
||||||
gb->object_priority = gb->cgb_mode? GB_OBJECT_PRIORITY_INDEX : GB_OBJECT_PRIORITY_X;
|
gb->object_priority = gb->cgb_mode? GB_OBJECT_PRIORITY_INDEX : GB_OBJECT_PRIORITY_X;
|
||||||
|
Loading…
Reference in New Issue
Block a user