From ffa53eda202b2a673b970b1ec8105566fff22d38 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Fri, 14 Jan 2022 17:09:39 +0200 Subject: [PATCH] DMA during mode 3 emulation --- Core/display.c | 20 ++++++++++++++++---- Core/memory.c | 9 +++++---- Core/timing.c | 4 ++-- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/Core/display.c b/Core/display.c index e89eb59..7ff1687 100644 --- a/Core/display.c +++ b/Core/display.c @@ -844,13 +844,13 @@ static void advance_fetcher_state_machine(GB_gameboy_t *gb) } } -static uint8_t oam_read(GB_gameboy_t *gb, uint8_t addr) +static inline uint8_t oam_read(GB_gameboy_t *gb, uint8_t addr) { if (unlikely(gb->oam_ppu_blocked)) { return 0xFF; } - if (unlikely(GB_is_dma_active(gb))) { - + if (unlikely(gb->dma_current_dest > 0 && gb->dma_current_dest <= 0xa0)) { // TODO: what happens in the last and first M cycles? + return gb->oam[((gb->dma_current_dest - 1) & ~1) | (addr & 1)]; } return gb->oam[addr]; } @@ -1611,6 +1611,18 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force) goto abort_fetching_object; } + if (unlikely(GB_is_dma_active(gb) || gb->dma_current_src == 0xFF)) { + unsigned offset = cycles - gb->display_cycles; // Time passed in 8MHz ticks + if (offset) { + if (!gb->cgb_double_speed) { + offset >>= 1; // Convert to T-cycles + } + unsigned old = gb->dma_cycles; + gb->dma_cycles = offset; + GB_dma_run(gb); + gb->dma_cycles += old - offset; + } + } gb->object_low_line_address = get_object_line_address(gb, gb->objects_y[gb->n_visible_objs - 1], @@ -1618,7 +1630,7 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force) gb->object_flags = oam_read(gb, gb->visible_objs[gb->n_visible_objs - 1] * 4 + 3) ); - gb->cycles_for_line++; + gb->cycles_for_line += 1; GB_SLEEP(gb, display, 39, 1); if (gb->object_fetch_aborted) { goto abort_fetching_object; diff --git a/Core/memory.c b/Core/memory.c index 5e23168..8409490 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -252,6 +252,7 @@ void GB_trigger_oam_bug_read(GB_gameboy_t *gb, uint16_t address) static bool is_addr_in_dma_use(GB_gameboy_t *gb, uint16_t addr) { if (!GB_is_dma_active(gb) || addr >= 0xfe00) return false; + if (gb->dma_current_dest == 0xFF) return false; // Warm up if (addr >= 0xfe00) return false; if (gb->dma_current_src == addr) return false; // Shortcut for DMA access flow if (gb->dma_current_src > 0xe000 && (gb->dma_current_src & ~0x2000) == addr) return false; @@ -1459,8 +1460,8 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) return; case GB_IO_DMA: - gb->dma_cycles = -3; - gb->dma_current_dest = 0; + gb->dma_cycles = 0; + gb->dma_current_dest = 0xFF; gb->dma_current_src = value << 8; gb->io_registers[GB_IO_DMA] = value; return; @@ -1681,12 +1682,12 @@ void GB_write_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) bool GB_is_dma_active(GB_gameboy_t *gb) { - return gb->dma_current_dest < 0xa1; + return gb->dma_current_dest != 0xa1; } void GB_dma_run(GB_gameboy_t *gb) { - if (gb->dma_current_dest >= 0xa1) return; + if (gb->dma_current_dest == 0xa1) return; while (unlikely(gb->dma_cycles >= 4)) { gb->dma_cycles -= 4; if (gb->dma_current_dest >= 0xa0) { diff --git a/Core/timing.c b/Core/timing.c index c5d328f..e9b527c 100644 --- a/Core/timing.c +++ b/Core/timing.c @@ -428,12 +428,12 @@ void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles) gb->rumble_on_cycles += gb->rumble_strength & 3; gb->rumble_off_cycles += (gb->rumble_strength & 3) ^ 3; + GB_apu_run(gb, false); + GB_display_run(gb, cycles, false); if (unlikely(!gb->stopped)) { // TODO: Verify what happens in STOP mode GB_dma_run(gb); GB_hdma_run(gb); } - GB_apu_run(gb, false); - GB_display_run(gb, cycles, false); ir_run(gb, cycles); rtc_run(gb, cycles); }