summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2018-06-19 17:23:17 -0400
committerPaul Duncan <pabs@pablotron.org>2018-06-19 17:23:17 -0400
commit66f7dc9c783a5efd129a4a03823f4bbe9d13614c (patch)
treec39a32c35c7cddca0a9e0e016c9e45ae4129ee2f
parent2efb1282615db1b570c52be3dabfa1b5ea619cb6 (diff)
downloadgb-c-66f7dc9c783a5efd129a4a03823f4bbe9d13614c.tar.bz2
gb-c-66f7dc9c783a5efd129a4a03823f4bbe9d13614c.zip
add timer implementation
-rw-r--r--ops.yaml72
1 files changed, 54 insertions, 18 deletions
diff --git a/ops.yaml b/ops.yaml
index 4e32ce8..7acf2f1 100644
--- a/ops.yaml
+++ b/ops.yaml
@@ -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