diff options
| -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 | 
