DMA during mode 3 emulation

This commit is contained in:
Lior Halphon 2022-01-14 17:09:39 +02:00
parent 4ce8e77796
commit ffa53eda20
3 changed files with 23 additions and 10 deletions

View File

@ -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)) { if (unlikely(gb->oam_ppu_blocked)) {
return 0xFF; 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]; return gb->oam[addr];
} }
@ -1611,6 +1611,18 @@ void GB_display_run(GB_gameboy_t *gb, unsigned cycles, bool force)
goto abort_fetching_object; 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->object_low_line_address = get_object_line_address(gb,
gb->objects_y[gb->n_visible_objs - 1], 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->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); GB_SLEEP(gb, display, 39, 1);
if (gb->object_fetch_aborted) { if (gb->object_fetch_aborted) {
goto abort_fetching_object; goto abort_fetching_object;

View File

@ -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) 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_is_dma_active(gb) || addr >= 0xfe00) return false;
if (gb->dma_current_dest == 0xFF) return false; // Warm up
if (addr >= 0xfe00) return false; if (addr >= 0xfe00) return false;
if (gb->dma_current_src == addr) return false; // Shortcut for DMA access flow 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; 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; return;
case GB_IO_DMA: case GB_IO_DMA:
gb->dma_cycles = -3; gb->dma_cycles = 0;
gb->dma_current_dest = 0; gb->dma_current_dest = 0xFF;
gb->dma_current_src = value << 8; gb->dma_current_src = value << 8;
gb->io_registers[GB_IO_DMA] = value; gb->io_registers[GB_IO_DMA] = value;
return; 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) 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) 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)) { while (unlikely(gb->dma_cycles >= 4)) {
gb->dma_cycles -= 4; gb->dma_cycles -= 4;
if (gb->dma_current_dest >= 0xa0) { if (gb->dma_current_dest >= 0xa0) {

View File

@ -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_on_cycles += gb->rumble_strength & 3;
gb->rumble_off_cycles += (gb->rumble_strength & 3) ^ 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 if (unlikely(!gb->stopped)) { // TODO: Verify what happens in STOP mode
GB_dma_run(gb); GB_dma_run(gb);
GB_hdma_run(gb); GB_hdma_run(gb);
} }
GB_apu_run(gb, false);
GB_display_run(gb, cycles, false);
ir_run(gb, cycles); ir_run(gb, cycles);
rtc_run(gb, cycles); rtc_run(gb, cycles);
} }