Improved DMA accuracy, mooneyegb test ROMs no longer crash miserably. (but still fail)
This commit is contained in:
parent
fad1007427
commit
47e3300b66
@ -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 (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, 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, mbc )) goto error;
|
||||||
if (!DUMP_SECTION(gb, f, hram )) goto error;
|
if (!DUMP_SECTION(gb, f, hram )) goto error;
|
||||||
if (!DUMP_SECTION(gb, f, timing )) 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 (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, 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, mbc )) goto error;
|
||||||
if (!READ_SECTION(&save, f, hram )) goto error;
|
if (!READ_SECTION(&save, f, hram )) goto error;
|
||||||
if (!READ_SECTION(&save, f, timing )) goto error;
|
if (!READ_SECTION(&save, f, timing )) goto error;
|
||||||
|
11
Core/gb.h
11
Core/gb.h
@ -224,13 +224,18 @@ typedef struct GB_gameboy_s {
|
|||||||
bool infrared_input;
|
bool infrared_input;
|
||||||
);
|
);
|
||||||
|
|
||||||
/* HDMA */
|
/* DMA and HDMA */
|
||||||
GB_SECTION(hdma,
|
GB_SECTION(dma,
|
||||||
bool hdma_on;
|
bool hdma_on;
|
||||||
bool hdma_on_hblank;
|
bool hdma_on_hblank;
|
||||||
uint8_t hdma_steps_left;
|
uint8_t hdma_steps_left;
|
||||||
uint16_t hdma_cycles;
|
uint16_t hdma_cycles;
|
||||||
uint16_t hdma_current_src, hdma_current_dest;
|
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 */
|
/* MBC */
|
||||||
@ -278,7 +283,7 @@ typedef struct GB_gameboy_s {
|
|||||||
uint32_t display_cycles;
|
uint32_t display_cycles;
|
||||||
uint32_t div_cycles;
|
uint32_t div_cycles;
|
||||||
uint32_t tima_cycles;
|
uint32_t tima_cycles;
|
||||||
uint32_t dma_cycles;
|
GB_PADDING(uint32_t, dma_cycles);
|
||||||
GB_aligned_double apu_cycles;
|
GB_aligned_double apu_cycles;
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -10,6 +10,36 @@
|
|||||||
typedef uint8_t GB_read_function_t(GB_gameboy_t *gb, uint16_t addr);
|
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 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)
|
static uint8_t read_rom(GB_gameboy_t *gb, uint16_t addr)
|
||||||
{
|
{
|
||||||
if (addr < 0x100 && !gb->boot_rom_finished) {
|
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 (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 0xFF;
|
||||||
}
|
}
|
||||||
return gb->oam[addr & 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)
|
uint8_t GB_read_memory(GB_gameboy_t *gb, uint16_t addr)
|
||||||
{
|
{
|
||||||
GB_debugger_test_read_watchpoint(gb, addr);
|
GB_debugger_test_read_watchpoint(gb, addr);
|
||||||
if (addr < 0xFF00 && gb->dma_cycles) {
|
if (is_addr_in_dma_use(gb, addr)) {
|
||||||
/* Todo: can we access IO registers during DMA? */
|
addr = gb->dma_current_src;
|
||||||
return 0xFF;
|
|
||||||
}
|
}
|
||||||
return read_map[addr >> 12](gb, addr);
|
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 (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;
|
return;
|
||||||
}
|
}
|
||||||
gb->oam[addr & 0xFF] = value;
|
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:
|
case GB_IO_DMA:
|
||||||
if (value <= 0xF1) { /* According to Pan Docs */
|
if (value <= 0xF1) { /* According to Pan Docs */
|
||||||
for (uint8_t i = 0xA0; i--;) {
|
gb->dma_cycles = 0;
|
||||||
gb->oam[i] = GB_read_memory(gb, (value << 8) + i);
|
gb->dma_current_dest = 0;
|
||||||
}
|
gb->dma_current_src = value << 8;
|
||||||
|
gb->dma_steps_left = 0xa0;
|
||||||
}
|
}
|
||||||
/* else { what? } */
|
/* else { what? } */
|
||||||
/* Todo: measure this value */
|
|
||||||
gb->dma_cycles = 640;
|
|
||||||
return;
|
return;
|
||||||
case GB_IO_SVBK:
|
case GB_IO_SVBK:
|
||||||
if (!gb->cgb_mode) {
|
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)
|
void GB_write_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||||
{
|
{
|
||||||
GB_debugger_test_write_watchpoint(gb, addr, value);
|
GB_debugger_test_write_watchpoint(gb, addr, value);
|
||||||
if (addr < 0xFF00 && gb->dma_cycles) {
|
if (is_addr_in_dma_use(gb, addr)) {
|
||||||
/* Todo: can we access IO registers during DMA? */
|
/* Todo: What should happen? Will this affect DMA? Will data be written? What and where? */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
write_map[addr >> 12](gb, addr, value);
|
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)
|
void GB_hdma_run(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
if (!gb->hdma_on) return;
|
if (!gb->hdma_on) return;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
uint8_t GB_read_memory(GB_gameboy_t *gb, uint16_t addr);
|
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_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);
|
void GB_hdma_run(GB_gameboy_t *gb);
|
||||||
|
|
||||||
#endif /* memory_h */
|
#endif /* memory_h */
|
||||||
|
@ -17,13 +17,7 @@ static void GB_ir_run(GB_gameboy_t *gb)
|
|||||||
void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles)
|
void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles)
|
||||||
{
|
{
|
||||||
// Affected by speed boost
|
// Affected by speed boost
|
||||||
if (gb->dma_cycles > cycles){
|
gb->dma_cycles += cycles;
|
||||||
gb->dma_cycles -= cycles;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
gb->dma_cycles = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
gb->div_cycles += cycles;
|
gb->div_cycles += cycles;
|
||||||
gb->tima_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->apu_cycles += cycles;
|
||||||
gb->cycles_since_ir_change += cycles;
|
gb->cycles_since_ir_change += cycles;
|
||||||
gb->cycles_since_input_ir_change += cycles;
|
gb->cycles_since_input_ir_change += cycles;
|
||||||
|
GB_dma_run(gb);
|
||||||
GB_hdma_run(gb);
|
GB_hdma_run(gb);
|
||||||
GB_timers_run(gb);
|
GB_timers_run(gb);
|
||||||
GB_apu_run(gb);
|
GB_apu_run(gb);
|
||||||
|
Loading…
Reference in New Issue
Block a user