Fixed lcdon_write_timing.

This commit is contained in:
Lior Halphon 2017-06-18 21:27:07 +03:00
parent 86c9f9d89d
commit abf7efcc5a
3 changed files with 50 additions and 21 deletions

View File

@ -266,8 +266,10 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles)
gb->hdma_steps_left = 0xff; gb->hdma_steps_left = 0xff;
} }
gb->oam_blocked = false; gb->oam_read_blocked = false;
gb->vram_blocked = false; gb->vram_read_blocked = false;
gb->oam_write_blocked = false;
gb->vram_write_blocked = false;
/* Keep sending vblanks to user even if the screen is off */ /* Keep sending vblanks to user even if the screen is off */
gb->display_cycles += cycles; gb->display_cycles += cycles;
@ -319,8 +321,11 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles)
ly_for_comparison = gb->io_registers[GB_IO_LY] = 0; ly_for_comparison = gb->io_registers[GB_IO_LY] = 0;
/* Todo: verify timing */ /* Todo: verify timing */
gb->oam_blocked = true; gb->oam_read_blocked = true;
gb->vram_blocked = false; gb->vram_read_blocked = false;
gb->oam_write_blocked = true;
gb->vram_write_blocked = false;
/* Reset window rendering state */ /* Reset window rendering state */
gb->current_window_line = 0xFF; gb->current_window_line = 0xFF;
@ -353,22 +358,28 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles)
/* Handle line 0 right after turning the LCD on */ /* Handle line 0 right after turning the LCD on */
else if (gb->first_scanline) { else if (gb->first_scanline) {
/* OAM and VRAM blocking is not delayed in the very first scanline */ /* OAM and VRAM blocking is not rushed in the very first scanline */
if (gb->display_cycles == atomic_increase) { if (gb->display_cycles == atomic_increase) {
gb->io_registers[GB_IO_STAT] &= ~3; gb->io_registers[GB_IO_STAT] &= ~3;
gb->oam_blocked = false; gb->oam_read_blocked = false;
gb->vram_blocked = false; gb->vram_read_blocked = false;
gb->oam_write_blocked = false;
gb->vram_write_blocked = false;
} }
else if (gb->display_cycles == MODE2_LENGTH) { else if (gb->display_cycles == MODE2_LENGTH) {
gb->io_registers[GB_IO_STAT] &= ~3; gb->io_registers[GB_IO_STAT] &= ~3;
gb->io_registers[GB_IO_STAT] |= 3; gb->io_registers[GB_IO_STAT] |= 3;
gb->oam_blocked = true; gb->oam_read_blocked = true;
gb->vram_blocked = true; gb->vram_read_blocked = true;
gb->oam_write_blocked = true;
gb->vram_write_blocked = true;
} }
else if (gb->display_cycles == MODE2_LENGTH + MODE3_LENGTH) { else if (gb->display_cycles == MODE2_LENGTH + MODE3_LENGTH) {
gb->io_registers[GB_IO_STAT] &= ~3; gb->io_registers[GB_IO_STAT] &= ~3;
gb->oam_blocked = false; gb->oam_read_blocked = false;
gb->vram_blocked = false; gb->vram_read_blocked = false;
gb->oam_write_blocked = false;
gb->vram_write_blocked = false;
} }
} }
@ -377,13 +388,27 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles)
unsigned position_in_line = gb->display_cycles % LINE_LENGTH; unsigned position_in_line = gb->display_cycles % LINE_LENGTH;
/* Handle OAM and VRAM blocking */ /* Handle OAM and VRAM blocking */
/* Todo: verify CGB timing for write blocking */
if (position_in_line == stat_delay - oam_blocking_rush || if (position_in_line == stat_delay - oam_blocking_rush ||
// In case stat_delay is 0 // In case stat_delay is 0
(position_in_line == LINE_LENGTH + stat_delay - oam_blocking_rush && gb->io_registers[GB_IO_LY] != 143)) { (position_in_line == LINE_LENGTH + stat_delay - oam_blocking_rush && gb->io_registers[GB_IO_LY] != 143)) {
gb->oam_blocked = true; gb->oam_read_blocked = true;
gb->oam_write_blocked = gb->is_cgb;
} }
else if (position_in_line == MODE2_LENGTH + stat_delay - vram_blocking_rush) { else if (position_in_line == MODE2_LENGTH + stat_delay - vram_blocking_rush) {
gb->vram_blocked = true; gb->vram_read_blocked = true;
gb->vram_write_blocked = gb->is_cgb;
}
if (position_in_line == stat_delay) {
gb->oam_write_blocked = true;
}
else if (!gb->is_cgb && position_in_line == MODE2_LENGTH + stat_delay - oam_blocking_rush) {
gb->oam_write_blocked = false;
}
else if (position_in_line == MODE2_LENGTH + stat_delay) {
gb->vram_write_blocked = true;
gb->oam_write_blocked = true;
} }
/* Handle everything else */ /* Handle everything else */
@ -411,8 +436,10 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles)
} }
else if (position_in_line == MODE2_LENGTH + MODE3_LENGTH + stat_delay + scx_delay) { else if (position_in_line == MODE2_LENGTH + MODE3_LENGTH + stat_delay + scx_delay) {
gb->io_registers[GB_IO_STAT] &= ~3; gb->io_registers[GB_IO_STAT] &= ~3;
gb->vram_blocked = false; gb->oam_read_blocked = false;
gb->oam_blocked = false; gb->vram_read_blocked = false;
gb->oam_write_blocked = false;
gb->vram_write_blocked = false;
if (gb->hdma_on_hblank) { if (gb->hdma_on_hblank) {
gb->hdma_on = true; gb->hdma_on = true;
gb->hdma_cycles = 0; gb->hdma_cycles = 0;

View File

@ -376,8 +376,10 @@ struct GB_gameboy_internal_s {
GB_FRAMESKIP_SECOND_FRAME_RENDERED, GB_FRAMESKIP_SECOND_FRAME_RENDERED,
} frame_skip_state; } frame_skip_state;
bool first_scanline; // The very first scan line after turning the LCD behaves differently. bool first_scanline; // The very first scan line after turning the LCD behaves differently.
bool oam_blocked; bool oam_read_blocked;
bool vram_blocked; bool vram_read_blocked;
bool oam_write_blocked;
bool vram_write_blocked;
); );
/* 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

@ -60,7 +60,7 @@ static uint8_t read_mbc_rom(GB_gameboy_t *gb, uint16_t addr)
static uint8_t read_vram(GB_gameboy_t *gb, uint16_t addr) static uint8_t read_vram(GB_gameboy_t *gb, uint16_t addr)
{ {
if (gb->vram_blocked) { if (gb->vram_read_blocked) {
return 0xFF; return 0xFF;
} }
return gb->vram[(addr & 0x1FFF) + (uint16_t) gb->cgb_vram_bank * 0x2000]; return gb->vram[(addr & 0x1FFF) + (uint16_t) gb->cgb_vram_bank * 0x2000];
@ -115,7 +115,7 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
} }
if (addr < 0xFEA0) { if (addr < 0xFEA0) {
if (gb->oam_blocked || (gb->dma_steps_left && (gb->dma_cycles > 0 || gb->is_dma_restarting))) { if (gb->oam_read_blocked || (gb->dma_steps_left && (gb->dma_cycles > 0 || gb->is_dma_restarting))) {
return 0xFF; return 0xFF;
} }
return gb->oam[addr & 0xFF]; return gb->oam[addr & 0xFF];
@ -338,7 +338,7 @@ static void write_mbc(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
static void write_vram(GB_gameboy_t *gb, uint16_t addr, uint8_t value) static void write_vram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
{ {
if (gb->vram_blocked) { if (gb->vram_write_blocked) {
//GB_log(gb, "Wrote %02x to %04x (VRAM) during mode 3\n", value, addr); //GB_log(gb, "Wrote %02x to %04x (VRAM) during mode 3\n", value, addr);
return; return;
} }
@ -385,7 +385,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
} }
if (addr < 0xFEA0) { if (addr < 0xFEA0) {
if (gb->oam_blocked|| (gb->dma_steps_left && (gb->dma_cycles > 0 || gb->is_dma_restarting))) { if (gb->oam_write_blocked|| (gb->dma_steps_left && (gb->dma_cycles > 0 || gb->is_dma_restarting))) {
return; return;
} }
gb->oam[addr & 0xFF] = value; gb->oam[addr & 0xFF] = value;