Improved DMA accuracy, mooneyegb test ROMs no longer crash miserably. (but still fail)

This commit is contained in:
Lior Halphon 2016-08-03 23:31:10 +03:00
parent fad1007427
commit 47e3300b66
5 changed files with 66 additions and 24 deletions

View File

@ -230,7 +230,7 @@ int GB_save_state(GB_gameboy_t *gb, const char *path)
if (fwrite(GB_GET_SECTION(gb, header), 1, GB_SECTION_SIZE(header), f) != GB_SECTION_SIZE(header)) goto error;
if (!DUMP_SECTION(gb, f, core_state)) goto error;
if (!DUMP_SECTION(gb, f, hdma )) goto error;
if (!DUMP_SECTION(gb, f, dma )) goto error;
if (!DUMP_SECTION(gb, f, mbc )) goto error;
if (!DUMP_SECTION(gb, f, hram )) goto error;
if (!DUMP_SECTION(gb, f, timing )) goto error;
@ -297,7 +297,7 @@ int GB_load_state(GB_gameboy_t *gb, const char *path)
if (fread(GB_GET_SECTION(&save, header), 1, GB_SECTION_SIZE(header), f) != GB_SECTION_SIZE(header)) goto error;
if (!READ_SECTION(&save, f, core_state)) goto error;
if (!READ_SECTION(&save, f, hdma )) goto error;
if (!READ_SECTION(&save, f, dma )) goto error;
if (!READ_SECTION(&save, f, mbc )) goto error;
if (!READ_SECTION(&save, f, hram )) goto error;
if (!READ_SECTION(&save, f, timing )) goto error;

View File

@ -224,13 +224,18 @@ typedef struct GB_gameboy_s {
bool infrared_input;
);
/* HDMA */
GB_SECTION(hdma,
/* DMA and HDMA */
GB_SECTION(dma,
bool hdma_on;
bool hdma_on_hblank;
uint8_t hdma_steps_left;
uint16_t hdma_cycles;
uint16_t hdma_current_src, hdma_current_dest;
uint8_t dma_steps_left;
uint8_t dma_current_dest;
uint16_t dma_current_src;
uint16_t dma_cycles;
);
/* MBC */
@ -278,7 +283,7 @@ typedef struct GB_gameboy_s {
uint32_t display_cycles;
uint32_t div_cycles;
uint32_t tima_cycles;
uint32_t dma_cycles;
GB_PADDING(uint32_t, dma_cycles);
GB_aligned_double apu_cycles;
);

View File

@ -10,6 +10,36 @@
typedef uint8_t GB_read_function_t(GB_gameboy_t *gb, uint16_t addr);
typedef void GB_write_function_t(GB_gameboy_t *gb, uint16_t addr, uint8_t value);
typedef enum {
GB_BUS_MAIN, /* In DMG: Cart and RAM. In CGB: Cart only */
GB_BUS_RAM, /* In CGB only. */
GB_BUS_VRAM,
GB_BUS_INTERNAL, /* Anything in highram. Might not be the most correct name. */
} GB_bus_t;
static GB_bus_t bus_for_addr(GB_gameboy_t *gb, uint16_t addr)
{
if (addr < 0x8000) {
return GB_BUS_MAIN;
}
if (addr < 0xA000) {
return GB_BUS_VRAM;
}
if (addr < 0xC000) {
return GB_BUS_MAIN;
}
if (addr < 0xFE00) {
return gb->is_cgb? GB_BUS_RAM : GB_BUS_MAIN;
}
return GB_BUS_INTERNAL;
}
static bool is_addr_in_dma_use(GB_gameboy_t *gb, uint16_t addr)
{
if (!gb->dma_steps_left) return false;
return bus_for_addr(gb, addr) == bus_for_addr(gb, gb->dma_current_src);
}
static uint8_t read_rom(GB_gameboy_t *gb, uint16_t addr)
{
if (addr < 0x100 && !gb->boot_rom_finished) {
@ -76,7 +106,7 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
}
if (addr < 0xFEA0) {
if ((gb->io_registers[GB_IO_STAT] & 0x3) >= 2) {
if ((gb->io_registers[GB_IO_STAT] & 0x3) >= 2 || gb->dma_steps_left) {
return 0xFF;
}
return gb->oam[addr & 0xFF];
@ -202,9 +232,8 @@ static GB_read_function_t * const read_map[] =
uint8_t GB_read_memory(GB_gameboy_t *gb, uint16_t addr)
{
GB_debugger_test_read_watchpoint(gb, addr);
if (addr < 0xFF00 && gb->dma_cycles) {
/* Todo: can we access IO registers during DMA? */
return 0xFF;
if (is_addr_in_dma_use(gb, addr)) {
addr = gb->dma_current_src;
}
return read_map[addr >> 12](gb, addr);
}
@ -297,7 +326,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
}
if (addr < 0xFEA0) {
if ((gb->io_registers[GB_IO_STAT] & 0x3) >= 2) {
if ((gb->io_registers[GB_IO_STAT] & 0x3) >= 2 || gb->dma_steps_left) {
return;
}
gb->oam[addr & 0xFF] = value;
@ -371,13 +400,13 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
case GB_IO_DMA:
if (value <= 0xF1) { /* According to Pan Docs */
for (uint8_t i = 0xA0; i--;) {
gb->oam[i] = GB_read_memory(gb, (value << 8) + i);
}
gb->dma_cycles = 0;
gb->dma_current_dest = 0;
gb->dma_current_src = value << 8;
gb->dma_steps_left = 0xa0;
}
/* else { what? } */
/* Todo: measure this value */
gb->dma_cycles = 640;
return;
case GB_IO_SVBK:
if (!gb->cgb_mode) {
@ -501,13 +530,25 @@ static GB_write_function_t * const write_map[] =
void GB_write_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
{
GB_debugger_test_write_watchpoint(gb, addr, value);
if (addr < 0xFF00 && gb->dma_cycles) {
/* Todo: can we access IO registers during DMA? */
if (is_addr_in_dma_use(gb, addr)) {
/* Todo: What should happen? Will this affect DMA? Will data be written? What and where? */
return;
}
write_map[addr >> 12](gb, addr, value);
}
void GB_dma_run(GB_gameboy_t *gb)
{
while (gb->dma_cycles >= 4 && gb->dma_steps_left) {
/* Todo: measure this value */
gb->dma_cycles -= 4;
gb->dma_steps_left--;
gb->oam[gb->dma_current_dest++] = GB_read_memory(gb, gb->dma_current_src);
/* dma_current_src must be the correct value during GB_read_memory */
gb->dma_current_src++;
}
}
void GB_hdma_run(GB_gameboy_t *gb)
{
if (!gb->hdma_on) return;

View File

@ -4,6 +4,7 @@
uint8_t GB_read_memory(GB_gameboy_t *gb, uint16_t addr);
void GB_write_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value);
void GB_dma_run(GB_gameboy_t *gb);
void GB_hdma_run(GB_gameboy_t *gb);
#endif /* memory_h */

View File

@ -17,13 +17,7 @@ static void GB_ir_run(GB_gameboy_t *gb)
void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles)
{
// Affected by speed boost
if (gb->dma_cycles > cycles){
gb->dma_cycles -= cycles;
}
else {
gb->dma_cycles = 0;
}
gb->dma_cycles += cycles;
gb->div_cycles += cycles;
gb->tima_cycles += cycles;
@ -37,6 +31,7 @@ void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles)
gb->apu_cycles += cycles;
gb->cycles_since_ir_change += cycles;
gb->cycles_since_input_ir_change += cycles;
GB_dma_run(gb);
GB_hdma_run(gb);
GB_timers_run(gb);
GB_apu_run(gb);