diff --git a/Core/display.c b/Core/display.c index 4bfae7ac..94d7f77b 100644 --- a/Core/display.c +++ b/Core/display.c @@ -603,14 +603,15 @@ static void advance_fetcher_state_machine(GB_gameboy_t *gb) /* This value is cached on the CGB-D and newer, so it cannot be used to mix tiles together */ gb->fetcher_y = y; } - gb->current_tile = gb->vram[map + x + y / 8 * 32]; + gb->last_tile_index_address = map + x + y / 8 * 32; + gb->current_tile = gb->vram[gb->last_tile_index_address]; if (gb->vram_ppu_blocked) { gb->current_tile = 0xFF; } if (GB_is_cgb(gb)) { /* The CGB actually accesses both the tile index AND the attributes in the same T-cycle. - This probably means the CGB has a 16-bit data bus for the VRAM. */ - gb->current_tile_attributes = gb->vram[map + x + y / 8 * 32 + 0x2000]; + This probably means the CGB has a 16-bit data bus for the VRAM. */ + gb->current_tile_attributes = gb->vram[gb->last_tile_index_address + 0x2000]; if (gb->vram_ppu_blocked) { gb->current_tile_attributes = 0xFF; } @@ -667,8 +668,9 @@ static void advance_fetcher_state_machine(GB_gameboy_t *gb) if (gb->current_tile_attributes & 0x40) { y_flip = 0x7; } + gb->last_tile_data_address = tile_address + ((y & 7) ^ y_flip) * 2 + 1; gb->current_tile_data[1] = - gb->vram[tile_address + ((y & 7) ^ y_flip) * 2 + 1]; + gb->vram[gb->last_tile_data_address]; if (gb->vram_ppu_blocked) { gb->current_tile_data[1] = 0xFF; } diff --git a/Core/gb.h b/Core/gb.h index 27b95b33..68c4ea9b 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -538,6 +538,8 @@ struct GB_gameboy_internal_s { uint8_t window_tile_x; uint8_t lcd_x; // The LCD can go out of sync since the push signal is skipped in some cases. bool is_odd_frame; + uint16_t last_tile_data_address; + uint16_t last_tile_index_address; ); /* Unsaved data. This includes all pointers, as well as everything that shouldn't be on a save state */ diff --git a/Core/memory.c b/Core/memory.c index 7f7686a4..3f924bc7 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -146,6 +146,18 @@ static uint8_t read_vram(GB_gameboy_t *gb, uint16_t addr) if (gb->vram_read_blocked) { return 0xFF; } + if (gb->display_state == 22 && GB_is_cgb(gb) && !gb->cgb_double_speed) { + if (addr & 0x1000) { + addr = gb->last_tile_index_address; + } + else if (gb->last_tile_data_address & 0x1000) { + /* TODO: This is case is more complicated then the rest and differ between revisions + It's probably affected by how VRAM is layed out, might be easier after a decap is done*/ + } + else { + addr = gb->last_tile_data_address; + } + } return gb->vram[(addr & 0x1FFF) + (uint16_t) gb->cgb_vram_bank * 0x2000]; } @@ -551,6 +563,19 @@ static void write_vram(GB_gameboy_t *gb, uint16_t addr, uint8_t value) //GB_log(gb, "Wrote %02x to %04x (VRAM) during mode 3\n", value, addr); return; } + /* TODO: not verified */ + if (gb->display_state == 22 && GB_is_cgb(gb) && !gb->cgb_double_speed) { + if (addr & 0x1000) { + addr = gb->last_tile_index_address; + } + else if (gb->last_tile_data_address & 0x1000) { + /* TODO: This is case is more complicated then the rest and differ between revisions + It's probably affected by how VRAM is layed out, might be easier after a decap is done */ + } + else { + addr = gb->last_tile_data_address; + } + } gb->vram[(addr & 0x1FFF) + (uint16_t) gb->cgb_vram_bank * 0x2000] = value; }