From 37ca174f37c9326472cbb02e31683e871d0602d0 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Thu, 3 Feb 2022 21:00:37 +0200 Subject: [PATCH] OAM DMA/GDMA conflicts --- Core/memory.c | 151 ++++++++++++++++++++++++++------------------------ 1 file changed, 79 insertions(+), 72 deletions(-) diff --git a/Core/memory.c b/Core/memory.c index bd50fe2..2bfbe7d 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -473,6 +473,42 @@ static inline void sync_ppu_if_needed(GB_gameboy_t *gb, uint8_t register_accesse } } +static uint8_t read_oam(GB_gameboy_t *gb, uint8_t addr) +{ + if (addr < 0xa0) { + return gb->oam[addr]; + } + + switch (gb->model) { + case GB_MODEL_CGB_E: + case GB_MODEL_AGB_A: + return (addr & 0xF0) | (addr >> 4); + + case GB_MODEL_CGB_D: + if (addr > 0xc0) { + addr |= 0xf0; + } + return gb->extra_oam[addr - 0xa0]; + + case GB_MODEL_CGB_C: + case GB_MODEL_CGB_B: + case GB_MODEL_CGB_A: + case GB_MODEL_CGB_0: + addr &= ~0x18; + return gb->extra_oam[addr - 0xa0]; + + case GB_MODEL_DMG_B: + case GB_MODEL_MGB: + case GB_MODEL_SGB_NTSC: + case GB_MODEL_SGB_PAL: + case GB_MODEL_SGB_NTSC_NO_SFC: + case GB_MODEL_SGB_PAL_NO_SFC: + case GB_MODEL_SGB2: + case GB_MODEL_SGB2_NO_SFC: + return 0; + } +} + static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) { if (addr < 0xFE00) { @@ -552,46 +588,7 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) return 0xff; } - if (addr < 0xFEA0) { - return gb->oam[addr & 0xFF]; - } - - if (gb->oam_read_blocked) { - return 0xFF; - } - - switch (gb->model) { - case GB_MODEL_CGB_E: - case GB_MODEL_AGB_A: - return (addr & 0xF0) | ((addr >> 4) & 0xF); - - case GB_MODEL_CGB_D: - if (addr > 0xfec0) { - addr |= 0xf0; - } - return gb->extra_oam[addr - 0xfea0]; - - case GB_MODEL_CGB_C: - case GB_MODEL_CGB_B: - case GB_MODEL_CGB_A: - case GB_MODEL_CGB_0: - addr &= ~0x18; - return gb->extra_oam[addr - 0xfea0]; - - case GB_MODEL_DMG_B: - case GB_MODEL_MGB: - case GB_MODEL_SGB_NTSC: - case GB_MODEL_SGB_PAL: - case GB_MODEL_SGB_NTSC_NO_SFC: - case GB_MODEL_SGB_PAL_NO_SFC: - case GB_MODEL_SGB2: - case GB_MODEL_SGB2_NO_SFC: - break; - } - } - - if (addr < 0xFF00) { - return 0; + return read_oam(gb, addr); } if (addr < 0xFF80) { @@ -1200,6 +1197,40 @@ static void write_banked_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value) gb->ram[(addr & 0x0FFF) + gb->cgb_ram_bank * 0x1000] = value; } +static void write_oam(GB_gameboy_t *gb, uint8_t addr, uint8_t value) +{ + if (addr < 0xa0) { + gb->oam[addr] = value; + return; + } + switch (gb->model) { + case GB_MODEL_CGB_D: + if (addr > 0xc0) { + addr |= 0xf0; + } + gb->extra_oam[addr - 0xa0] = value; + break; + case GB_MODEL_CGB_C: + case GB_MODEL_CGB_B: + case GB_MODEL_CGB_A: + case GB_MODEL_CGB_0: + addr &= ~0x18; + gb->extra_oam[addr - 0xa0] = value; + break; + case GB_MODEL_CGB_E: + case GB_MODEL_AGB_A: + case GB_MODEL_DMG_B: + case GB_MODEL_MGB: + case GB_MODEL_SGB_NTSC: + case GB_MODEL_SGB_PAL: + case GB_MODEL_SGB_NTSC_NO_SFC: + case GB_MODEL_SGB_PAL_NO_SFC: + case GB_MODEL_SGB2: + case GB_MODEL_SGB2_NO_SFC: + break; + } +} + static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) { if (addr < 0xFE00) { @@ -1221,37 +1252,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) } if (GB_is_cgb(gb)) { - if (addr < 0xFEA0) { - gb->oam[addr & 0xFF] = value; - return; - } - switch (gb->model) { - case GB_MODEL_CGB_D: - if (addr > 0xfec0) { - addr |= 0xf0; - } - gb->extra_oam[addr - 0xfea0] = value; - break; - case GB_MODEL_CGB_C: - case GB_MODEL_CGB_B: - case GB_MODEL_CGB_A: - case GB_MODEL_CGB_0: - addr &= ~0x18; - gb->extra_oam[addr - 0xfea0] = value; - break; - case GB_MODEL_CGB_E: - case GB_MODEL_AGB_A: - break; - case GB_MODEL_DMG_B: - case GB_MODEL_MGB: - case GB_MODEL_SGB_NTSC: - case GB_MODEL_SGB_PAL: - case GB_MODEL_SGB_NTSC_NO_SFC: - case GB_MODEL_SGB_PAL_NO_SFC: - case GB_MODEL_SGB2: - case GB_MODEL_SGB2_NO_SFC: - unreachable(); - } + write_oam(gb, addr, value); return; } @@ -1702,7 +1703,10 @@ void GB_dma_run(GB_gameboy_t *gb) gb->dma_current_dest++; break; } - if (gb->dma_current_src < 0xe000) { + if (unlikely(gb->hdma_in_progress && (gb->hdma_steps_left > 1 || (gb->hdma_current_dest & 0xF) != 0xF))) { + gb->dma_current_dest++; + } + else if (gb->dma_current_src < 0xe000) { gb->oam[gb->dma_current_dest++] = GB_read_memory(gb, gb->dma_current_src); } else { @@ -1744,6 +1748,9 @@ void GB_hdma_run(GB_gameboy_t *gb) (gb->hdma_current_src & 0xE000) == 0xA000) { byte = GB_read_memory(gb, gb->hdma_current_src); } + if (unlikely(GB_is_dma_active(gb)) && (gb->dma_cycles_modulo == 0 || gb->cgb_double_speed)) { + write_oam(gb, gb->hdma_current_src, byte); + } gb->hdma_current_src++; if (gb->addr_for_hdma_conflict == 0xFFFF /* || (gb->model == GB_MODEL_AGS && gb->cgb_double_speed) */) { gb->vram[vram_base + (gb->hdma_current_dest++ & 0x1FFF)] = byte;