Improve PPU timings in CGB revision 0 to C. These revisions are no longer marked as experimental.

This commit is contained in:
Lior Halphon 2024-07-08 00:00:27 +03:00
parent a4525c3336
commit c3e3fb91cc
6 changed files with 75 additions and 99 deletions

View File

@ -455,10 +455,10 @@
<font key="font" metaFont="menu"/>
<menu key="menu" autoenablesItems="NO" id="bbF-hB-Hv7">
<items>
<menuItem title="CPU CGB 0 (Experimental)" tag="512" id="2Uk-u3-6Gw"/>
<menuItem title="CPU CGB A (Experimental)" tag="513" id="axv-yk-RWM"/>
<menuItem title="CPU CGB B (Experimental)" tag="514" id="NtJ-oo-IM2"/>
<menuItem title="CPU CGB C (Experimental)" tag="515" id="9YL-u8-12z"/>
<menuItem title="CPU CGB 0" tag="512" id="2Uk-u3-6Gw"/>
<menuItem title="CPU CGB A" tag="513" id="axv-yk-RWM"/>
<menuItem title="CPU CGB B" tag="514" id="NtJ-oo-IM2"/>
<menuItem title="CPU CGB C" tag="515" id="9YL-u8-12z"/>
<menuItem title="CPU CGB D" tag="516" id="c76-oF-fkU"/>
<menuItem title="CPU CGB E" state="on" tag="517" id="3lF-1Q-2SS"/>
</items>

View File

@ -429,7 +429,6 @@ void GB_STAT_update(GB_gameboy_t *gb)
bool previous_interrupt_line = gb->stat_interrupt_line;
/* Set LY=LYC bit */
/* TODO: This behavior might not be correct for CGB revisions other than C and E */
if (gb->ly_for_comparison != (uint16_t)-1 || gb->model <= GB_MODEL_CGB_C) {
if (gb->ly_for_comparison == gb->io_registers[GB_IO_LYC]) {
gb->lyc_interrupt_line = true;
@ -734,11 +733,6 @@ static inline void dma_sync(GB_gameboy_t *gb, unsigned *cycles)
}
}
/* All verified CGB timings are based on CGB CPU E. CGB CPUs >= D are known to have
slightly different timings than CPUs <= C.
Todo: Add support to CPU C and older */
static inline uint8_t fetcher_y(GB_gameboy_t *gb)
{
return gb->wx_triggered? gb->window_y : gb->current_line + gb->io_registers[GB_IO_SCY];
@ -1464,7 +1458,6 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force)
GB_STATE(gb, display, 27);
GB_STATE(gb, display, 28);
GB_STATE(gb, display, 29);
GB_STATE(gb, display, 30);
GB_STATE(gb, display, 31);
GB_STATE(gb, display, 32);
GB_STATE(gb, display, 33);
@ -1538,8 +1531,8 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force)
GB_SLEEP(gb, display, 37, 2);
gb->cgb_palettes_blocked = true;
gb->cycles_for_line += (GB_is_cgb(gb) && gb->model <= GB_MODEL_CGB_C)? 2 : 3;
GB_SLEEP(gb, display, 38, (GB_is_cgb(gb) && gb->model <= GB_MODEL_CGB_C)? 2 : 3);
gb->cycles_for_line += 3;
GB_SLEEP(gb, display, 38, 3);
gb->vram_read_blocked = true;
gb->vram_write_blocked = true;
@ -1665,12 +1658,8 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force)
GB_STAT_update(gb);
uint8_t idle_cycles = 3;
if (GB_is_cgb(gb) && gb->model <= GB_MODEL_CGB_C) {
idle_cycles = 2;
}
gb->cycles_for_line += idle_cycles;
GB_SLEEP(gb, display, 10, idle_cycles);
gb->cycles_for_line += 3;
GB_SLEEP(gb, display, 10, 3);
gb->cgb_palettes_blocked = true;
gb->cycles_for_line += 2;
@ -1902,11 +1891,6 @@ skip_slow_mode_3:
}
gb->wx_triggered = false;
if (GB_is_cgb(gb) && gb->model <= GB_MODEL_CGB_C) {
gb->cycles_for_line++;
GB_SLEEP(gb, display, 30, 1);
}
if (!gb->cgb_double_speed) {
gb->io_registers[GB_IO_STAT] &= ~3;
gb->mode_for_interrupt = 0;

View File

@ -205,9 +205,16 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
}
case GB_CONFLICT_PALETTE_CGB: {
GB_advance_cycles(gb, gb->pending_cycles - 2);
GB_write_memory(gb, addr, value);
gb->pending_cycles = 6;
if (gb->model >= GB_MODEL_CGB_D) {
GB_advance_cycles(gb, gb->pending_cycles - 2);
GB_write_memory(gb, addr, value);
gb->pending_cycles = 6;
}
else {
GB_advance_cycles(gb, gb->pending_cycles - 1);
GB_write_memory(gb, addr, value);
gb->pending_cycles = 5;
}
break;
}
@ -263,25 +270,13 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
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
if (gb->model > GB_MODEL_CGB_C) {
GB_advance_cycles(gb, gb->pending_cycles);
GB_write_memory(gb, addr, value ^ GB_LCDC_TILE_SEL); // Write with the old TILE_SET first
gb->tile_sel_glitch = true;
GB_advance_cycles(gb, 1);
gb->tile_sel_glitch = false;
GB_write_memory(gb, addr, value);
gb->pending_cycles = 3;
}
else {
GB_advance_cycles(gb, gb->pending_cycles - 1);
GB_write_memory(gb, addr, value ^ GB_LCDC_TILE_SEL); // Write with the old TILE_SET first
gb->tile_sel_glitch = true;
GB_advance_cycles(gb, 1);
gb->tile_sel_glitch = false;
GB_write_memory(gb, addr, value);
gb->pending_cycles = 4;
}
GB_advance_cycles(gb, gb->pending_cycles);
GB_write_memory(gb, addr, value ^ GB_LCDC_TILE_SEL); // Write with the old TILE_SET first
gb->tile_sel_glitch = true;
GB_advance_cycles(gb, 1);
gb->tile_sel_glitch = false;
GB_write_memory(gb, addr, value);
gb->pending_cycles = 3;
}
else {
GB_advance_cycles(gb, gb->pending_cycles);
@ -292,10 +287,7 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
}
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
// around them.
// TODO: Verify for CGB ≤ C for BG_EN and OBJ_EN.
// TODO: This condition is different from single speed mode. Why? What about odd modes?
if ((value ^ old) & GB_LCDC_TILE_SEL) {
GB_advance_cycles(gb, gb->pending_cycles - 2);

View File

@ -982,10 +982,10 @@ static void cycle_cgb_revision_backwards(unsigned index)
static const char *current_cgb_revision_string(unsigned index)
{
return GB_inline_const(const char *[], {
"CPU CGB 0 (Exp.)",
"CPU CGB A (Exp.)",
"CPU CGB B (Exp.)",
"CPU CGB C (Exp.)",
"CPU CGB 0",
"CPU CGB A",
"CPU CGB B",
"CPU CGB C",
"CPU CGB D",
"CPU CGB E",
})

View File

@ -203,12 +203,12 @@ static NSString const *typeLightTemp = @"typeLightTemp";
@{@"type": typeRadio, @"pref": @"GBSGBModel", @"title": @"Super Game Boy 2", @"value": @(GB_MODEL_SGB2),},
]),
QUICK_SUBMENU(@"Game Boy Color", @[
@{@"type": typeRadio, @"pref": @"GBCGBModel", @"title": @"CPU CGB 0 (Experimental)", @"value": @(GB_MODEL_CGB_0),},
@{@"type": typeRadio, @"pref": @"GBCGBModel", @"title": @"CPU CGB A (Experimental)", @"value": @(GB_MODEL_CGB_A),},
@{@"type": typeRadio, @"pref": @"GBCGBModel", @"title": @"CPU CGB B (Experimental)", @"value": @(GB_MODEL_CGB_B),},
@{@"type": typeRadio, @"pref": @"GBCGBModel", @"title": @"CPU CGB C (Experimental)", @"value": @(GB_MODEL_CGB_C),},
@{@"type": typeRadio, @"pref": @"GBCGBModel", @"title": @"CPU CGB D", @"value": @(GB_MODEL_CGB_D),},
@{@"type": typeRadio, @"pref": @"GBCGBModel", @"title": @"CPU CGB E", @"value": @(GB_MODEL_CGB_E),},
@{@"type": typeRadio, @"pref": @"GBCGBModel", @"title": @"CPU CGB 0", @"value": @(GB_MODEL_CGB_0),},
@{@"type": typeRadio, @"pref": @"GBCGBModel", @"title": @"CPU CGB A", @"value": @(GB_MODEL_CGB_A),},
@{@"type": typeRadio, @"pref": @"GBCGBModel", @"title": @"CPU CGB B", @"value": @(GB_MODEL_CGB_B),},
@{@"type": typeRadio, @"pref": @"GBCGBModel", @"title": @"CPU CGB C", @"value": @(GB_MODEL_CGB_C),},
@{@"type": typeRadio, @"pref": @"GBCGBModel", @"title": @"CPU CGB D", @"value": @(GB_MODEL_CGB_D),},
@{@"type": typeRadio, @"pref": @"GBCGBModel", @"title": @"CPU CGB E", @"value": @(GB_MODEL_CGB_E),},
]),
QUICK_SUBMENU(@"Game Boy Advance", @[
@{@"type": typeDisabled, @"title": @"CPU AGB 0 (Early GBA)",},

View File

@ -81,19 +81,19 @@ struct retro_core_option_v2_definition option_defs_us[] = {
NULL,
"system",
{
{ "Auto", "Auto Detect DMG/CGB" },
{ "Auto (SGB)", "Auto Detect DMG/SGB/CGB" },
{ "Game Boy", "Game Boy (DMG-CPU B)" },
{ "Game Boy Pocket", "Game Boy Pocket/Light" },
{ "Game Boy Color 0", "Game Boy Color (CPU CGB 0) (Experimental)" },
{ "Game Boy Color A", "Game Boy Color (CPU CGB A) (Experimental)" },
{ "Game Boy Color B", "Game Boy Color (CPU CGB B) (Experimental)" },
{ "Game Boy Color C", "Game Boy Color (CPU CGB C) (Experimental)" },
{ "Game Boy Color D", "Game Boy Color (CPU CGB D)" },
{ "Game Boy Color", "Game Boy Color (CPU CGB E)" },
{ "Game Boy Advance", "Game Boy Advance (CPU AGB A)" },
{ "Game Boy Player", "Game Boy Player (CPU AGB A)" },
{ "Super Game Boy", "Super Game Boy NTSC" },
{ "Auto", "Auto Detect DMG/CGB" },
{ "Auto (SGB)", "Auto Detect DMG/SGB/CGB" },
{ "Game Boy", "Game Boy (DMG-CPU B)" },
{ "Game Boy Pocket", "Game Boy Pocket/Light" },
{ "Game Boy Color 0", "Game Boy Color (CPU CGB 0)" },
{ "Game Boy Color A", "Game Boy Color (CPU CGB A)" },
{ "Game Boy Color B", "Game Boy Color (CPU CGB B)" },
{ "Game Boy Color C", "Game Boy Color (CPU CGB C)" },
{ "Game Boy Color D", "Game Boy Color (CPU CGB D)" },
{ "Game Boy Color", "Game Boy Color (CPU CGB E)" },
{ "Game Boy Advance", "Game Boy Advance (CPU AGB A)" },
{ "Game Boy Player", "Game Boy Player (CPU AGB A)" },
{ "Super Game Boy", "Super Game Boy NTSC" },
{ "Super Game Boy PAL", NULL },
{ "Super Game Boy 2", NULL },
{ NULL, NULL },
@ -328,19 +328,19 @@ struct retro_core_option_v2_definition option_defs_us[] = {
NULL,
"system",
{
{ "Auto", "Auto Detect DMG/CGB" },
{ "Auto (SGB)", "Auto Detect DMG/SGB/CGB" },
{ "Game Boy", "Game Boy (DMG-CPU B)" },
{ "Game Boy Pocket", "Game Boy Pocket/Light" },
{ "Game Boy Color 0", "Game Boy Color (CPU CGB 0) (Experimental)" },
{ "Game Boy Color A", "Game Boy Color (CPU CGB A) (Experimental)" },
{ "Game Boy Color B", "Game Boy Color (CPU CGB B) (Experimental)" },
{ "Game Boy Color C", "Game Boy Color (CPU CGB C) (Experimental)" },
{ "Game Boy Color D", "Game Boy Color (CPU CGB D)" },
{ "Game Boy Color", "Game Boy Color (CPU CGB E)" },
{ "Game Boy Advance", "Game Boy Advance (CPU AGB A)" },
{ "Game Boy Player", "Game Boy Player (CPU AGB A)" },
{ "Super Game Boy", "Super Game Boy NTSC" },
{ "Auto", "Auto Detect DMG/CGB" },
{ "Auto (SGB)", "Auto Detect DMG/SGB/CGB" },
{ "Game Boy", "Game Boy (DMG-CPU B)" },
{ "Game Boy Pocket", "Game Boy Pocket/Light" },
{ "Game Boy Color 0", "Game Boy Color (CPU CGB 0)" },
{ "Game Boy Color A", "Game Boy Color (CPU CGB A)" },
{ "Game Boy Color B", "Game Boy Color (CPU CGB B)" },
{ "Game Boy Color C", "Game Boy Color (CPU CGB C)" },
{ "Game Boy Color D", "Game Boy Color (CPU CGB D)" },
{ "Game Boy Color", "Game Boy Color (CPU CGB E)" },
{ "Game Boy Advance", "Game Boy Advance (CPU AGB A)" },
{ "Game Boy Player", "Game Boy Player (CPU AGB A)" },
{ "Super Game Boy", "Super Game Boy NTSC" },
{ "Super Game Boy PAL", NULL },
{ "Super Game Boy 2", NULL },
{ NULL, NULL },
@ -370,19 +370,19 @@ struct retro_core_option_v2_definition option_defs_us[] = {
NULL,
"system",
{
{ "Auto", "Auto Detect DMG/CGB" },
{ "Auto (SGB)", "Auto Detect DMG/SGB/CGB" },
{ "Game Boy", "Game Boy (DMG-CPU B)" },
{ "Game Boy Pocket", "Game Boy Pocket/Light" },
{ "Game Boy Color 0", "Game Boy Color (CPU CGB 0) (Experimental)" },
{ "Game Boy Color A", "Game Boy Color (CPU CGB A) (Experimental)" },
{ "Game Boy Color B", "Game Boy Color (CPU CGB B) (Experimental)" },
{ "Game Boy Color C", "Game Boy Color (CPU CGB C) (Experimental)" },
{ "Game Boy Color D", "Game Boy Color (CPU CGB D)" },
{ "Game Boy Color", "Game Boy Color (CPU CGB E)" },
{ "Game Boy Advance", "Game Boy Advance (CPU AGB A)" },
{ "Game Boy Player", "Game Boy Player (CPU AGB A)" },
{ "Super Game Boy", "Super Game Boy NTSC" },
{ "Auto", "Auto Detect DMG/CGB" },
{ "Auto (SGB)", "Auto Detect DMG/SGB/CGB" },
{ "Game Boy", "Game Boy (DMG-CPU B)" },
{ "Game Boy Pocket", "Game Boy Pocket/Light" },
{ "Game Boy Color 0", "Game Boy Color (CPU CGB 0)" },
{ "Game Boy Color A", "Game Boy Color (CPU CGB A)" },
{ "Game Boy Color B", "Game Boy Color (CPU CGB B)" },
{ "Game Boy Color C", "Game Boy Color (CPU CGB C)" },
{ "Game Boy Color D", "Game Boy Color (CPU CGB D)" },
{ "Game Boy Color", "Game Boy Color (CPU CGB E)" },
{ "Game Boy Advance", "Game Boy Advance (CPU AGB A)" },
{ "Game Boy Player", "Game Boy Player (CPU AGB A)" },
{ "Super Game Boy", "Super Game Boy NTSC" },
{ "Super Game Boy PAL", NULL },
{ "Super Game Boy 2", NULL },
{ NULL, NULL },