Improvements to GDMA
This commit is contained in:
parent
81e2ec08e0
commit
26656de44f
@ -1779,7 +1779,7 @@ skip_slow_mode_3:
|
|||||||
GB_SLEEP(gb, display, 25, 8);
|
GB_SLEEP(gb, display, 25, 8);
|
||||||
|
|
||||||
if (gb->hdma_on_hblank) {
|
if (gb->hdma_on_hblank) {
|
||||||
gb->hdma_starting = true;
|
gb->hdma_on = true;
|
||||||
}
|
}
|
||||||
GB_SLEEP(gb, display, 11, LINE_LENGTH - gb->cycles_for_line - 2);
|
GB_SLEEP(gb, display, 11, LINE_LENGTH - gb->cycles_for_line - 2);
|
||||||
/*
|
/*
|
||||||
|
@ -1128,7 +1128,7 @@ exit:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t GB_run(GB_gameboy_t *gb)
|
unsigned GB_run(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
gb->vblank_just_occured = false;
|
gb->vblank_just_occured = false;
|
||||||
|
|
||||||
|
@ -421,7 +421,6 @@ struct GB_gameboy_internal_s {
|
|||||||
bool hdma_on;
|
bool hdma_on;
|
||||||
bool hdma_on_hblank;
|
bool hdma_on_hblank;
|
||||||
uint8_t hdma_steps_left;
|
uint8_t hdma_steps_left;
|
||||||
int16_t hdma_cycles; // in 8MHz units
|
|
||||||
uint16_t hdma_current_src, hdma_current_dest;
|
uint16_t hdma_current_src, hdma_current_dest;
|
||||||
|
|
||||||
uint8_t dma_current_dest;
|
uint8_t dma_current_dest;
|
||||||
@ -431,8 +430,7 @@ struct GB_gameboy_internal_s {
|
|||||||
int8_t dma_cycles_modulo;
|
int8_t dma_cycles_modulo;
|
||||||
bool dma_ppu_vram_conflict;
|
bool dma_ppu_vram_conflict;
|
||||||
uint16_t dma_ppu_vram_conflict_addr;
|
uint16_t dma_ppu_vram_conflict_addr;
|
||||||
uint8_t last_opcode_read; /* Required to emulate HDMA reads from Exxx */
|
uint8_t hdma_open_bus; /* Required to emulate HDMA reads from Exxx */
|
||||||
bool hdma_starting;
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/* MBC */
|
/* MBC */
|
||||||
@ -767,7 +765,7 @@ struct GB_gameboy_internal_s {
|
|||||||
bool disable_rendering;
|
bool disable_rendering;
|
||||||
uint8_t boot_rom[0x900];
|
uint8_t boot_rom[0x900];
|
||||||
bool vblank_just_occured; // For slow operations involving syscalls; these should only run once per vblank
|
bool vblank_just_occured; // For slow operations involving syscalls; these should only run once per vblank
|
||||||
uint8_t cycles_since_run; // How many cycles have passed since the last call to GB_run(), in 8MHz units
|
unsigned cycles_since_run; // How many cycles have passed since the last call to GB_run(), in 8MHz units
|
||||||
double clock_multiplier;
|
double clock_multiplier;
|
||||||
GB_rumble_mode_t rumble_mode;
|
GB_rumble_mode_t rumble_mode;
|
||||||
uint32_t rumble_on_cycles;
|
uint32_t rumble_on_cycles;
|
||||||
@ -808,7 +806,7 @@ void GB_reset(GB_gameboy_t *gb);
|
|||||||
void GB_switch_model_and_reset(GB_gameboy_t *gb, GB_model_t model);
|
void GB_switch_model_and_reset(GB_gameboy_t *gb, GB_model_t model);
|
||||||
|
|
||||||
/* Returns the time passed, in 8MHz ticks. */
|
/* Returns the time passed, in 8MHz ticks. */
|
||||||
uint8_t GB_run(GB_gameboy_t *gb);
|
unsigned GB_run(GB_gameboy_t *gb);
|
||||||
/* Returns the time passed since the last frame, in nanoseconds */
|
/* Returns the time passed since the last frame, in nanoseconds */
|
||||||
uint64_t GB_run_frame(GB_gameboy_t *gb);
|
uint64_t GB_run_frame(GB_gameboy_t *gb);
|
||||||
|
|
||||||
|
@ -475,11 +475,6 @@ static inline void sync_ppu_if_needed(GB_gameboy_t *gb, uint8_t register_accesse
|
|||||||
|
|
||||||
static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
|
static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (gb->hdma_on) {
|
|
||||||
return gb->last_opcode_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addr < 0xFE00) {
|
if (addr < 0xFE00) {
|
||||||
return read_banked_ram(gb, addr);
|
return read_banked_ram(gb, addr);
|
||||||
}
|
}
|
||||||
@ -1534,6 +1529,10 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
|||||||
gb->hdma_current_src &= 0xF0;
|
gb->hdma_current_src &= 0xF0;
|
||||||
gb->hdma_current_src |= value << 8;
|
gb->hdma_current_src |= value << 8;
|
||||||
}
|
}
|
||||||
|
/* Range 0xE*** like 0xF*** and can't overflow (with 0x800 bytes) to anything meaningful */
|
||||||
|
if (gb->hdma_current_src >= 0xE000) {
|
||||||
|
gb->hdma_current_src |= 0xF000;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
case GB_IO_HDMA2:
|
case GB_IO_HDMA2:
|
||||||
if (gb->cgb_mode) {
|
if (gb->cgb_mode) {
|
||||||
@ -1545,6 +1544,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
|||||||
if (gb->cgb_mode) {
|
if (gb->cgb_mode) {
|
||||||
gb->hdma_current_dest &= 0xF0;
|
gb->hdma_current_dest &= 0xF0;
|
||||||
gb->hdma_current_dest |= value << 8;
|
gb->hdma_current_dest |= value << 8;
|
||||||
|
gb->hdma_current_dest &= 0x1FF0;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case GB_IO_HDMA4:
|
case GB_IO_HDMA4:
|
||||||
@ -1570,7 +1570,6 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
|||||||
if (gb->hdma_current_dest + (gb->hdma_steps_left << 4) > 0xFFFF) {
|
if (gb->hdma_current_dest + (gb->hdma_steps_left << 4) > 0xFFFF) {
|
||||||
gb->hdma_steps_left = (0x10000 - gb->hdma_current_dest) >> 4;
|
gb->hdma_steps_left = (0x10000 - gb->hdma_current_dest) >> 4;
|
||||||
}
|
}
|
||||||
gb->hdma_cycles = -12;
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Todo: what happens when starting a transfer during a transfer?
|
/* Todo: what happens when starting a transfer during a transfer?
|
||||||
@ -1731,24 +1730,32 @@ void GB_dma_run(GB_gameboy_t *gb)
|
|||||||
|
|
||||||
void GB_hdma_run(GB_gameboy_t *gb)
|
void GB_hdma_run(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
if (likely(!gb->hdma_on)) return;
|
unsigned cycles = gb->cgb_double_speed? 4 : 2;
|
||||||
|
/* This is a bit cart, revision and unit specific. TODO: what if PC is in cart RAM? */
|
||||||
while (gb->hdma_cycles >= 0x4) {
|
if (gb->model < GB_MODEL_CGB_D || gb->pc > 0x8000) {
|
||||||
gb->hdma_cycles -= 0x4;
|
gb->hdma_open_bus = 0xFF;
|
||||||
|
}
|
||||||
GB_write_memory(gb, 0x8000 | (gb->hdma_current_dest++ & 0x1FFF), GB_read_memory(gb, (gb->hdma_current_src++)));
|
GB_advance_cycles(gb, 4);
|
||||||
|
while (gb->hdma_on) {
|
||||||
|
uint8_t byte = gb->hdma_open_bus;
|
||||||
|
if (gb->hdma_current_src < 0x8000 ||
|
||||||
|
(gb->hdma_current_src & 0xE000) == 0xC000 ||
|
||||||
|
(gb->hdma_current_src & 0xE000) == 0xA000) {
|
||||||
|
byte = GB_read_memory(gb, gb->hdma_current_src);
|
||||||
|
}
|
||||||
|
gb->hdma_current_src++;
|
||||||
|
GB_write_memory(gb, 0x8000 | (gb->hdma_current_dest++ & 0x1FFF), byte);
|
||||||
|
GB_advance_cycles(gb, cycles);
|
||||||
|
gb->hdma_open_bus = 0xFF;
|
||||||
|
|
||||||
if ((gb->hdma_current_dest & 0xf) == 0) {
|
if ((gb->hdma_current_dest & 0xf) == 0) {
|
||||||
if (--gb->hdma_steps_left == 0) {
|
if (--gb->hdma_steps_left == 0) {
|
||||||
gb->hdma_on = false;
|
gb->hdma_on = false;
|
||||||
gb->hdma_on_hblank = false;
|
gb->hdma_on_hblank = false;
|
||||||
gb->hdma_starting = false;
|
|
||||||
gb->io_registers[GB_IO_HDMA5] &= 0x7F;
|
gb->io_registers[GB_IO_HDMA5] &= 0x7F;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (gb->hdma_on_hblank) {
|
else if (gb->hdma_on_hblank) {
|
||||||
gb->hdma_on = false;
|
gb->hdma_on = false;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1580,9 +1580,8 @@ static opcode_t *opcodes[256] = {
|
|||||||
};
|
};
|
||||||
void GB_cpu_run(GB_gameboy_t *gb)
|
void GB_cpu_run(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
if (gb->hdma_on) {
|
if (unlikely(gb->hdma_on && (gb->stopped || gb->halted))) {
|
||||||
GB_advance_cycles(gb, 4);
|
GB_hdma_run(gb);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (gb->stopped) {
|
if (gb->stopped) {
|
||||||
GB_timing_sync(gb);
|
GB_timing_sync(gb);
|
||||||
@ -1635,7 +1634,7 @@ void GB_cpu_run(GB_gameboy_t *gb)
|
|||||||
gb->speed_switch_halt_countdown = 0;
|
gb->speed_switch_halt_countdown = 0;
|
||||||
uint16_t call_addr = gb->pc;
|
uint16_t call_addr = gb->pc;
|
||||||
|
|
||||||
gb->last_opcode_read = cycle_read(gb, gb->pc++);
|
cycle_read(gb, gb->pc++);
|
||||||
cycle_oam_bug_pc(gb);
|
cycle_oam_bug_pc(gb);
|
||||||
gb->pc--;
|
gb->pc--;
|
||||||
GB_trigger_oam_bug(gb, gb->sp); /* Todo: test T-cycle timing */
|
GB_trigger_oam_bug(gb, gb->sp); /* Todo: test T-cycle timing */
|
||||||
@ -1674,22 +1673,22 @@ void GB_cpu_run(GB_gameboy_t *gb)
|
|||||||
}
|
}
|
||||||
/* Run mode */
|
/* Run mode */
|
||||||
else if (!gb->halted) {
|
else if (!gb->halted) {
|
||||||
gb->last_opcode_read = cycle_read(gb, gb->pc++);
|
uint8_t opcode = gb->hdma_open_bus = cycle_read(gb, gb->pc++);
|
||||||
|
if (unlikely(gb->hdma_on)) {
|
||||||
|
GB_hdma_run(gb);
|
||||||
|
}
|
||||||
if (unlikely(gb->execution_callback)) {
|
if (unlikely(gb->execution_callback)) {
|
||||||
gb->execution_callback(gb, gb->pc - 1, gb->last_opcode_read);
|
gb->execution_callback(gb, gb->pc - 1, opcode);
|
||||||
}
|
}
|
||||||
if (unlikely(gb->halt_bug)) {
|
if (unlikely(gb->halt_bug)) {
|
||||||
gb->pc--;
|
gb->pc--;
|
||||||
gb->halt_bug = false;
|
gb->halt_bug = false;
|
||||||
}
|
}
|
||||||
opcodes[gb->last_opcode_read](gb, gb->last_opcode_read);
|
opcodes[opcode](gb, opcode);
|
||||||
|
}
|
||||||
|
else if (gb->hdma_on) {
|
||||||
|
GB_hdma_run(gb);
|
||||||
}
|
}
|
||||||
|
|
||||||
flush_pending_cycles(gb);
|
flush_pending_cycles(gb);
|
||||||
|
|
||||||
if (gb->hdma_starting) {
|
|
||||||
gb->hdma_starting = false;
|
|
||||||
gb->hdma_on = true;
|
|
||||||
gb->hdma_cycles = -8;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -420,7 +420,6 @@ void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles)
|
|||||||
if (likely(gb->io_registers[GB_IO_LCDC] & 0x80)) {
|
if (likely(gb->io_registers[GB_IO_LCDC] & 0x80)) {
|
||||||
gb->double_speed_alignment += cycles;
|
gb->double_speed_alignment += cycles;
|
||||||
}
|
}
|
||||||
gb->hdma_cycles += cycles;
|
|
||||||
gb->apu_output.sample_cycles += cycles * gb->apu_output.sample_rate;
|
gb->apu_output.sample_cycles += cycles * gb->apu_output.sample_rate;
|
||||||
gb->cycles_since_last_sync += cycles;
|
gb->cycles_since_last_sync += cycles;
|
||||||
gb->cycles_since_run += cycles;
|
gb->cycles_since_run += cycles;
|
||||||
@ -432,7 +431,6 @@ void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles)
|
|||||||
GB_display_run(gb, cycles, 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);
|
|
||||||
}
|
}
|
||||||
ir_run(gb, cycles);
|
ir_run(gb, cycles);
|
||||||
rtc_run(gb, cycles);
|
rtc_run(gb, cycles);
|
||||||
|
Loading…
Reference in New Issue
Block a user