Double speed STAT conflicts

This commit is contained in:
Lior Halphon 2023-03-05 00:32:24 +02:00
parent 502f64e6d7
commit 7ac920d2be
2 changed files with 36 additions and 18 deletions

View File

@ -1504,14 +1504,23 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
return;
case GB_IO_STAT:
/* Delete previous R/W bits */
gb->io_registers[GB_IO_STAT] &= 7;
/* Set them by value */
gb->io_registers[GB_IO_STAT] |= value & ~7;
/* Set unused bit to 1 */
gb->io_registers[GB_IO_STAT] |= 0x80;
GB_STAT_update(gb);
/* Annoying edge timing case */
if (gb->cgb_double_speed &&
gb->display_state == 8 &&
gb->oam_search_index == 0 &&
gb->display_cycles == 0 &&
(value & 0x20)) {
gb->mode_for_interrupt = 2;
GB_STAT_update(gb);
gb->mode_for_interrupt = -1;
}
else {
GB_STAT_update(gb);
}
return;
case GB_IO_DIV:

View File

@ -21,14 +21,15 @@ typedef enum {
GB_CONFLICT_DMG_LCDC,
GB_CONFLICT_SGB_LCDC,
GB_CONFLICT_WX,
GB_CONFLICT_CGB_LCDC,
GB_CONFLICT_LCDC_CGB,
GB_CONFLICT_NR10,
GB_CONFLICT_CGB_SCX,
GB_CONFLICT_CGB_DOUBLE_LCDC,
GB_CONFLICT_SCX_CGB,
GB_CONFLICT_LCDC_CGB_DOUBLE,
GB_CONFLICT_STAT_CGB_DOUBLE,
} conflict_t;
static const conflict_t cgb_conflict_map[0x80] = {
[GB_IO_LCDC] = GB_CONFLICT_CGB_LCDC,
[GB_IO_LCDC] = GB_CONFLICT_LCDC_CGB,
[GB_IO_IF] = GB_CONFLICT_WRITE_CPU,
[GB_IO_LYC] = GB_CONFLICT_WRITE_CPU,
[GB_IO_STAT] = GB_CONFLICT_STAT_CGB,
@ -36,17 +37,17 @@ static const conflict_t cgb_conflict_map[0x80] = {
[GB_IO_OBP0] = GB_CONFLICT_PALETTE_CGB,
[GB_IO_OBP1] = GB_CONFLICT_PALETTE_CGB,
[GB_IO_NR10] = GB_CONFLICT_NR10,
[GB_IO_SCX] = GB_CONFLICT_CGB_SCX,
[GB_IO_SCX] = GB_CONFLICT_SCX_CGB,
};
static const conflict_t cgb_double_conflict_map[0x80] = {
[GB_IO_LCDC] = GB_CONFLICT_CGB_DOUBLE_LCDC,
[GB_IO_LCDC] = GB_CONFLICT_LCDC_CGB_DOUBLE,
[GB_IO_IF] = GB_CONFLICT_WRITE_CPU,
[GB_IO_LYC] = GB_CONFLICT_READ_OLD,
[GB_IO_STAT] = GB_CONFLICT_STAT_CGB_DOUBLE,
// Unconfirmed yet
[GB_IO_STAT] = GB_CONFLICT_STAT_CGB,
[GB_IO_NR10] = GB_CONFLICT_NR10,
[GB_IO_SCX] = GB_CONFLICT_CGB_SCX,
[GB_IO_SCX] = GB_CONFLICT_SCX_CGB,
};
/* Todo: verify on an MGB */
@ -173,7 +174,7 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
case GB_CONFLICT_STAT_CGB: {
/* Todo: Verify this with SCX adjustments */
/* The LYC bit behaves differently */
uint8_t old_value = GB_read_memory(gb, addr);
uint8_t old_value = gb->io_registers[GB_IO_STAT];
GB_advance_cycles(gb, gb->pending_cycles);
GB_write_memory(gb, addr, (old_value & 0x40) | (value & ~0x40));
GB_advance_cycles(gb, 1);
@ -181,6 +182,16 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
gb->pending_cycles = 3;
break;
}
case GB_CONFLICT_STAT_CGB_DOUBLE: {
uint8_t old_value = gb->io_registers[GB_IO_STAT];
GB_advance_cycles(gb, gb->pending_cycles);
GB_write_memory(gb, addr, (value & ~8) | (old_value & 8));
GB_advance_cycles(gb, 1);
GB_write_memory(gb, addr, value);
gb->pending_cycles = 3;
break;
}
/* There is some "time travel" going on with these two values, as it appears
that there's some off-by-1-T-cycle timing issue in the PPU implementation.
@ -212,8 +223,6 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
Hacks ahead.
*/
uint8_t old_value = GB_read_memory(gb, addr);
GB_advance_cycles(gb, gb->pending_cycles - 2);
GB_display_sync(gb);
@ -255,7 +264,7 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
gb->pending_cycles = 3;
break;
case GB_CONFLICT_CGB_LCDC: {
case GB_CONFLICT_LCDC_CGB: {
uint8_t old = gb->io_registers[GB_IO_LCDC];
if ((~value & old) & GB_LCDC_TILE_SEL) {
// TODO: This is different is because my timing is off in CGB ≤ C
@ -285,7 +294,7 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
}
break;
}
case GB_CONFLICT_CGB_DOUBLE_LCDC: {
case GB_CONFLICT_LCDC_CGB_DOUBLE: {
uint8_t old = gb->io_registers[GB_IO_LCDC];
// TODO: This is wrong for CGB ≤ C for TILE_SEL, BG_EN and BG_MAP.
// PPU timings for these models appear to be wrong and it'd make more sense to fix those first than hacking
@ -332,7 +341,7 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
gb->pending_cycles = 4;
break;
case GB_CONFLICT_CGB_SCX:
case GB_CONFLICT_SCX_CGB:
if (gb->cgb_double_speed) {
GB_advance_cycles(gb, gb->pending_cycles - 2);
GB_write_memory(gb, addr, value);