Pixel accurate emulation of Prehistorik Man on a CGB-CPU-E

This commit is contained in:
Lior Halphon 2018-06-08 18:44:03 +03:00
parent ca01ff6f79
commit 593cb7c107

View File

@ -11,13 +11,13 @@ typedef enum {
GB_CONFLICT_READ_OLD, GB_CONFLICT_READ_OLD,
/* If the CPU writes while another component reads, it reads the new value */ /* If the CPU writes while another component reads, it reads the new value */
GB_CONFLICT_READ_NEW, GB_CONFLICT_READ_NEW,
/* If the CPU writes while another component reads, it reads a bitwise OR between the new and old values */
GB_CONFLICT_READ_OR,
/* If the CPU and another component write at the same time, the CPU's value "wins" */ /* If the CPU and another component write at the same time, the CPU's value "wins" */
GB_CONFLICT_WRITE_CPU, GB_CONFLICT_WRITE_CPU,
/* Register specific values */ /* Register specific values */
GB_CONFLICT_STAT_CGB, GB_CONFLICT_STAT_CGB,
GB_CONFLICT_STAT_DMG, GB_CONFLICT_STAT_DMG,
GB_CONFLICT_PALETTE_DMG,
GB_CONFLICT_PALETTE_CGB,
} GB_conflict_t; } GB_conflict_t;
/* Todo: How does double speed mode affect these? */ /* Todo: How does double speed mode affect these? */
@ -25,6 +25,10 @@ static const GB_conflict_t cgb_conflict_map[0x80] = {
[GB_IO_IF] = GB_CONFLICT_WRITE_CPU, [GB_IO_IF] = GB_CONFLICT_WRITE_CPU,
[GB_IO_LYC] = GB_CONFLICT_WRITE_CPU, [GB_IO_LYC] = GB_CONFLICT_WRITE_CPU,
[GB_IO_STAT] = GB_CONFLICT_STAT_CGB, [GB_IO_STAT] = GB_CONFLICT_STAT_CGB,
[GB_IO_BGP] = GB_CONFLICT_PALETTE_CGB,
[GB_IO_OBP0] = GB_CONFLICT_PALETTE_CGB,
[GB_IO_OBP1] = GB_CONFLICT_PALETTE_CGB,
/* Todo: most values not verified, and probably differ between revisions */ /* Todo: most values not verified, and probably differ between revisions */
}; };
@ -37,9 +41,9 @@ static const GB_conflict_t dmg_conflict_map[0x80] = {
[GB_IO_STAT] = GB_CONFLICT_STAT_DMG, [GB_IO_STAT] = GB_CONFLICT_STAT_DMG,
/* Todo: these are GB_CONFLICT_READ_NEW on MGB/SGB2 */ /* Todo: these are GB_CONFLICT_READ_NEW on MGB/SGB2 */
[GB_IO_BGP] = GB_CONFLICT_READ_OR, [GB_IO_BGP] = GB_CONFLICT_PALETTE_DMG,
[GB_IO_OBP0] = GB_CONFLICT_READ_OR, [GB_IO_OBP0] = GB_CONFLICT_PALETTE_DMG,
[GB_IO_OBP1] = GB_CONFLICT_READ_OR, [GB_IO_OBP1] = GB_CONFLICT_PALETTE_DMG,
/* Todo: these were not verified at all */ /* Todo: these were not verified at all */
[GB_IO_WY] = GB_CONFLICT_READ_NEW, [GB_IO_WY] = GB_CONFLICT_READ_NEW,
@ -88,33 +92,12 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
gb->pending_cycles = 5; gb->pending_cycles = 5;
return; return;
case GB_CONFLICT_READ_OR: {
GB_advance_cycles(gb, gb->pending_cycles - 2);
uint8_t old_value = GB_read_memory(gb, addr);
GB_write_memory(gb, addr, value | old_value);
GB_advance_cycles(gb, 1);
GB_write_memory(gb, addr, value);
gb->pending_cycles = 5;
return;
}
case GB_CONFLICT_WRITE_CPU: case GB_CONFLICT_WRITE_CPU:
GB_advance_cycles(gb, gb->pending_cycles + 1); GB_advance_cycles(gb, gb->pending_cycles + 1);
GB_write_memory(gb, addr, value); GB_write_memory(gb, addr, value);
gb->pending_cycles = 3; gb->pending_cycles = 3;
return; return;
case GB_CONFLICT_STAT_CGB: {
/* The LYC bit behaves differently */
uint8_t old_value = GB_read_memory(gb, addr);
GB_advance_cycles(gb, gb->pending_cycles);
GB_write_memory(gb, addr, (old_value & 0x40) | (value & ~0x40));
GB_advance_cycles(gb, 1);
GB_write_memory(gb, addr, value);
gb->pending_cycles = 3;
return;
}
/* The DMG STAT-write bug is basically the STAT register being read as FF for a single T-cycle */ /* The DMG STAT-write bug is basically the STAT register being read as FF for a single T-cycle */
case GB_CONFLICT_STAT_DMG: case GB_CONFLICT_STAT_DMG:
GB_advance_cycles(gb, gb->pending_cycles); GB_advance_cycles(gb, gb->pending_cycles);
@ -132,6 +115,39 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
GB_write_memory(gb, addr, value); GB_write_memory(gb, addr, value);
gb->pending_cycles = 3; gb->pending_cycles = 3;
return; return;
case GB_CONFLICT_STAT_CGB: {
/* The LYC bit behaves differently */
uint8_t old_value = GB_read_memory(gb, addr);
GB_advance_cycles(gb, gb->pending_cycles);
GB_write_memory(gb, addr, (old_value & 0x40) | (value & ~0x40));
GB_advance_cycles(gb, 1);
GB_write_memory(gb, addr, value);
gb->pending_cycles = 3;
return;
}
/* 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.
This is should be accurate for every measureable scenario, though. */
case GB_CONFLICT_PALETTE_DMG: {
GB_advance_cycles(gb, gb->pending_cycles - 2);
uint8_t old_value = GB_read_memory(gb, addr);
GB_write_memory(gb, addr, value | old_value);
GB_advance_cycles(gb, 1);
GB_write_memory(gb, addr, value);
gb->pending_cycles = 5;
return;
}
case GB_CONFLICT_PALETTE_CGB: {
GB_advance_cycles(gb, gb->pending_cycles - 2);
GB_write_memory(gb, addr, value);
gb->pending_cycles = 6;
return;
}
} }
} }