Pixel accurate emulation of Prehistorik Man on a CGB-CPU-E
This commit is contained in:
parent
ca01ff6f79
commit
593cb7c107
@ -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,22 +92,30 @@ 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;
|
||||||
|
|
||||||
|
/* The DMG STAT-write bug is basically the STAT register being read as FF for a single T-cycle */
|
||||||
|
case GB_CONFLICT_STAT_DMG:
|
||||||
|
GB_advance_cycles(gb, gb->pending_cycles);
|
||||||
|
/* State 7 is the edge between HBlank and OAM mode, and it behaves a bit weird.
|
||||||
|
The OAM interrupt seems to be blocked by HBlank interrupts in that case, despite
|
||||||
|
the timing not making much sense for that.
|
||||||
|
This is a hack to simulate this effect */
|
||||||
|
if (gb->display_state == 7 && (gb->io_registers[GB_IO_STAT] & 0x28) == 0x08) {
|
||||||
|
GB_write_memory(gb, addr, ~0x20);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GB_write_memory(gb, addr, 0xFF);
|
||||||
|
}
|
||||||
|
GB_advance_cycles(gb, 1);
|
||||||
|
GB_write_memory(gb, addr, value);
|
||||||
|
gb->pending_cycles = 3;
|
||||||
|
return;
|
||||||
|
|
||||||
case GB_CONFLICT_STAT_CGB: {
|
case GB_CONFLICT_STAT_CGB: {
|
||||||
/* The LYC bit behaves differently */
|
/* The LYC bit behaves differently */
|
||||||
uint8_t old_value = GB_read_memory(gb, addr);
|
uint8_t old_value = GB_read_memory(gb, addr);
|
||||||
@ -115,23 +127,27 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The DMG STAT-write bug is basically the STAT register being read as FF for a single T-cycle */
|
/* There is some "time travel" going on with these two values, as it appears
|
||||||
case GB_CONFLICT_STAT_DMG:
|
that there's some off-by-1-T-cycle timing issue in the PPU implementation.
|
||||||
GB_advance_cycles(gb, gb->pending_cycles);
|
|
||||||
/* State 7 is the edge between HBlank and OAM mode, and it behaves a bit weird.
|
This is should be accurate for every measureable scenario, though. */
|
||||||
The OAM interrupt seems to be blocked by HBlank interrupts in that case, despite
|
|
||||||
the timing not making much sense for that.
|
case GB_CONFLICT_PALETTE_DMG: {
|
||||||
This is a hack to simulate this effect */
|
GB_advance_cycles(gb, gb->pending_cycles - 2);
|
||||||
if (gb->display_state == 7 && (gb->io_registers[GB_IO_STAT] & 0x28) == 0x08) {
|
uint8_t old_value = GB_read_memory(gb, addr);
|
||||||
GB_write_memory(gb, addr, ~0x20);
|
GB_write_memory(gb, addr, value | old_value);
|
||||||
}
|
|
||||||
else {
|
|
||||||
GB_write_memory(gb, addr, 0xFF);
|
|
||||||
}
|
|
||||||
GB_advance_cycles(gb, 1);
|
GB_advance_cycles(gb, 1);
|
||||||
GB_write_memory(gb, addr, value);
|
GB_write_memory(gb, addr, value);
|
||||||
gb->pending_cycles = 3;
|
gb->pending_cycles = 5;
|
||||||
return;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user