diff options
author | Paul Duncan <pabs@pablotron.org> | 2018-06-19 17:23:17 -0400 |
---|---|---|
committer | Paul Duncan <pabs@pablotron.org> | 2018-06-19 17:23:17 -0400 |
commit | 66f7dc9c783a5efd129a4a03823f4bbe9d13614c (patch) | |
tree | c39a32c35c7cddca0a9e0e016c9e45ae4129ee2f | |
parent | 2efb1282615db1b570c52be3dabfa1b5ea619cb6 (diff) | |
download | gb-c-66f7dc9c783a5efd129a4a03823f4bbe9d13614c.tar.bz2 gb-c-66f7dc9c783a5efd129a4a03823f4bbe9d13614c.zip |
add timer implementation
-rw-r--r-- | ops.yaml | 72 |
1 files changed, 54 insertions, 18 deletions
@@ -7629,10 +7629,9 @@ templates: } gpu; struct { - uint32_t clock; // FIXME: uint16_t? - uint8_t div, - tima, - tma, + uint16_t div; + uint32_t tima; // NOTE: cannot be uint16_t because of 10-bit shift + uint8_t tma, tac; } timer; @@ -7646,6 +7645,22 @@ templates: } cpu; } gb_t; + static uint8_t + timer_get_shift( + const gb_t * const ctx + ) { + switch (ctx->timer.tac & 0x3) { + case 0: + return 10; /* CPU clock / 1024, 4096Hz */ + case 1: + return 4; /* CPU clock / 16, 262144Hz */ + case 2: + return 6; /* CPU clock / 64, 65536Hz */ + case 3: + return 8; /* CPU clock / 256, 16384Hz */ + } + } + #define PORT_P1 0xFF00 // timer registers @@ -7716,11 +7731,11 @@ templates: break; case PORT_DIV: - return ctx->timer.div; + return (ctx->timer.div & 0xFF00) >> 8; break; case PORT_TIMA: - return ctx->timer.tima; + return (ctx->timer.tima >> timer_get_shift(ctx)) & 0xFF; break; case PORT_TMA: @@ -9167,22 +9182,29 @@ templates: gb_t * const ctx, const uint16_t clock ) { - // TODO: - UNUSED(ctx); - UNUSED(clock); - // ctx->timer.clock += clock; - // ctx->timer.div += (ctx->timer.clock - // const uint16_t new_div = ((uint16_t) ctx->timer.div) + (ctx->timer.clock / 32); + // increment div clock (high byte exposed via PORT_DIV) + ctx->timer.div += clock; + + if (ctx->timer.tac & (1 << 2)) { + const uint8_t shift = timer_get_shift(ctx); + const uint32_t new_tima = ctx->timer.tima + clock; + const uint8_t old_of = (ctx->timer.tima >> (shift + 8)) & 0xFF, + new_of = (new_tima >> (shift + 8)) & 0xFF; + + if (new_of != old_of) { + // reset TIMA register to value of TMA + ctx->timer.tima = (ctx->timer.tma << shift); + + // trigger timer interrupt + mmu_wb(ctx, PORT_IF, mmu_rb(ctx, PORT_IF) & (1 << 2)); + } + } } - void - gb_step( + static uint16_t + cpu_step( gb_t * const ctx ) { - // TODO: handle halt - // handle pending interrupts - gb_handle_interrupts(ctx); - // get pc, and current op const uint16_t old_pc = cpu_rw(ctx, RW_PC), op = mmu_rb(ctx, old_pc); @@ -9205,7 +9227,21 @@ templates: // increment cpu clock ctx->cpu.clock += clock; + } + + + void + gb_step( + gb_t * const ctx + ) { + // TODO: handle halt + // handle pending interrupts + gb_handle_interrupts(ctx); + + // advance cpu + const uint16_t clock = cpu_step(ctx); + // advance timer timer_step(ctx, clock); // advance gpu |