diff --git a/src/dmg.c b/src/dmg.c index 026f759..d139e64 100644 --- a/src/dmg.c +++ b/src/dmg.c @@ -81,7 +81,7 @@ u8 dmg_read(void *_dmg, u16 address) return dmg->zero_page[address - 0xff80]; } else if (address == 0xff00) { return get_button_state(dmg); - } else if (address == 0xff04) { + } else if (address == REG_TIMER_DIV) { counter++; return counter; } else if (address == 0xff0f) { @@ -246,6 +246,31 @@ static void render_objs(struct dmg *dmg) } } +static void timer_step(struct dmg *dmg) +{ + if (!(dmg_read(dmg, REG_TIMER_CONTROL) & TIMER_CONTROL_ENABLED)) { + return; + } + + int passed = dmg->cpu->cycle_count - dmg->last_timer_update; + // TODO + if (passed < 10000) { + return; + } + + u8 counter = dmg_read(dmg, REG_TIMER_COUNT); + u8 modulo = dmg_read(dmg, REG_TIMER_MOD); + + counter++; + if (!counter) { + counter = modulo; + dmg_request_interrupt(dmg, INT_TIMER); + } + + dmg_write(dmg, REG_TIMER_COUNT, counter); + dmg->last_timer_update = dmg->cpu->cycle_count; +} + void dmg_step(void *_dmg) { struct dmg *dmg = (struct dmg *) _dmg; @@ -253,9 +278,9 @@ void dmg_step(void *_dmg) // order of dependencies? i think cpu needs to step first then update // all other hw cpu_step(dmg->cpu); + timer_step(dmg); // each line takes 456 cycles - int cycle_diff = dmg->cpu->cycle_count - dmg->last_lcd_update; if (cycle_diff >= 456) { diff --git a/src/dmg.h b/src/dmg.h index 3419fd9..c86477f 100644 --- a/src/dmg.h +++ b/src/dmg.h @@ -15,6 +15,13 @@ #define BUTTON_SELECT (1 << 2) #define BUTTON_START (1 << 3) +#define REG_TIMER_DIV 0xFF04 +#define REG_TIMER_COUNT 0xFF05 +#define REG_TIMER_MOD 0xFF06 +#define REG_TIMER_CONTROL 0xFF07 + +#define TIMER_CONTROL_ENABLED (1 << 2) + struct cpu; struct rom; struct lcd; @@ -27,6 +34,7 @@ struct dmg { u8 video_ram[0x2000]; u8 zero_page[0x80]; u32 last_lcd_update; + u32 last_timer_update; int joypad_selected; int action_selected; // non-0 if A/B/start/select selected, 0 for directions u8 interrupt_enabled;