GDMA/PPU conflicts

This commit is contained in:
Lior Halphon 2022-01-30 14:38:58 +02:00
parent 9e3ad31df1
commit 3a2d028efa
3 changed files with 33 additions and 4 deletions

View File

@ -696,7 +696,12 @@ static inline uint8_t vram_read(GB_gameboy_t *gb, uint16_t addr)
if (unlikely(gb->vram_ppu_blocked)) { if (unlikely(gb->vram_ppu_blocked)) {
return 0xFF; return 0xFF;
} }
if (unlikely(gb->dma_current_dest <= 0xa0 && gb->dma_current_dest > 0 && (gb->dma_current_src & 0xE000) == 0x8000)) { // TODO: what happens in the last and first M cycles? if (unlikely(gb->hdma_on)) {
gb->addr_for_hdma_conflict = addr;
return 0;
}
// TODO: what if both?
else if (unlikely(gb->dma_current_dest <= 0xa0 && gb->dma_current_dest > 0 && (gb->dma_current_src & 0xE000) == 0x8000)) { // TODO: what happens in the last and first M cycles?
// DMAing from VRAM! // DMAing from VRAM!
/* TODO: AGS has its own, very different pattern, but AGS is not currently a supported model */ /* TODO: AGS has its own, very different pattern, but AGS is not currently a supported model */
/* TODO: Research this when researching odd modes */ /* TODO: Research this when researching odd modes */

View File

@ -776,6 +776,7 @@ struct GB_gameboy_internal_s {
bool tile_sel_glitch; bool tile_sel_glitch;
bool disable_oam_corruption; // For safe memory reads bool disable_oam_corruption; // For safe memory reads
bool in_dma_read; bool in_dma_read;
uint16_t addr_for_hdma_conflict;
GB_gbs_header_t gbs_header; GB_gbs_header_t gbs_header;
) )

View File

@ -1735,17 +1735,37 @@ void GB_hdma_run(GB_gameboy_t *gb)
if (gb->model < GB_MODEL_CGB_D || gb->pc > 0x8000) { if (gb->model < GB_MODEL_CGB_D || gb->pc > 0x8000) {
gb->hdma_open_bus = 0xFF; gb->hdma_open_bus = 0xFF;
} }
GB_advance_cycles(gb, 4); gb->addr_for_hdma_conflict = 0xFFFF;
gb->hdma_current_dest &= 0x1FFF;
uint16_t vram_base = gb->cgb_vram_bank? 0x2000 : 0;
GB_advance_cycles(gb, cycles);
while (gb->hdma_on) { while (gb->hdma_on) {
uint8_t byte = gb->hdma_open_bus; uint8_t byte = gb->hdma_open_bus;
gb->addr_for_hdma_conflict = 0xFFFF;
GB_advance_cycles(gb, cycles);
if (gb->hdma_current_src < 0x8000 || if (gb->hdma_current_src < 0x8000 ||
(gb->hdma_current_src & 0xE000) == 0xC000 || (gb->hdma_current_src & 0xE000) == 0xC000 ||
(gb->hdma_current_src & 0xE000) == 0xA000) { (gb->hdma_current_src & 0xE000) == 0xA000) {
byte = GB_read_memory(gb, gb->hdma_current_src); byte = GB_read_memory(gb, gb->hdma_current_src);
} }
gb->hdma_current_src++; gb->hdma_current_src++;
GB_write_memory(gb, 0x8000 | (gb->hdma_current_dest++ & 0x1FFF), byte); if (gb->addr_for_hdma_conflict == 0xFFFF /* || gb->model == GB_MODEL_AGS */) {
GB_advance_cycles(gb, cycles); gb->vram[vram_base + gb->hdma_current_dest++] = byte;
}
else {
if (gb->model == GB_MODEL_CGB_E || gb->cgb_double_speed) {
/*
These corruptions revision (unit?) specific in single speed. They happen only on my CGB-E.
*/
gb->addr_for_hdma_conflict &= 0x1FFF;
// Can't write to even bitmap bytes in single speed mode
if (gb->cgb_double_speed || gb->addr_for_hdma_conflict >= 0x1900 || (gb->addr_for_hdma_conflict & 1)) {
gb->vram[vram_base + (gb->hdma_current_dest & gb->addr_for_hdma_conflict)] = byte;
}
}
gb->hdma_current_dest++;
}
gb->hdma_open_bus = 0xFF; gb->hdma_open_bus = 0xFF;
if ((gb->hdma_current_dest & 0xf) == 0) { if ((gb->hdma_current_dest & 0xf) == 0) {
@ -1759,4 +1779,7 @@ void GB_hdma_run(GB_gameboy_t *gb)
} }
} }
} }
if (!gb->cgb_double_speed) {
GB_advance_cycles(gb, 2);
}
} }