OAM DMA/GDMA conflicts

This commit is contained in:
Lior Halphon 2022-02-03 21:00:37 +02:00
parent 76b881c2e1
commit 37ca174f37

View File

@ -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;