From 3890aae0d46d13896c645325b3156c807fe49711 Mon Sep 17 00:00:00 2001 From: Paul Duncan Date: Tue, 19 Jun 2018 19:08:16 -0400 Subject: add STATE_RUN and STATE_HALT support to timer_step() and cpu_step() --- ops.yaml | 175 ++++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 112 insertions(+), 63 deletions(-) diff --git a/ops.yaml b/ops.yaml index 7acf2f1..a9fde28 100644 --- a/ops.yaml +++ b/ops.yaml @@ -7658,6 +7658,9 @@ templates: return 6; /* CPU clock / 64, 65536Hz */ case 3: return 8; /* CPU clock / 256, 16384Hz */ + default: + // never reached + return 0; } } @@ -9128,6 +9131,69 @@ templates: } } + static void + timer_step( + gb_t * const ctx, + const uint16_t clock + ) { + // 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)); + } + } + } + + static uint16_t + cpu_step( + gb_t * const ctx + ) { + if (ctx->cpu.state == STATE_RUN) { + // get pc, and current op + const uint16_t old_pc = cpu_rw(ctx, RW_PC), + op = mmu_rb(ctx, old_pc); + uint16_t clock = 0; + + // exec op + switch (op) { + <%= switches['main'] %> + case 0xCB: + switch (mmu_rb(ctx, old_pc + 1)) { + <%= switches['cb'] %> + default: + not_implemented(ctx, old_pc, op); + } + + break; + default: + not_implemented(ctx, old_pc, op); + } + + // increment cpu clock + ctx->cpu.clock += clock; + + // return clock + return clock; + } else if (ctx->cpu.state == STATE_HALT || ctx->cpu.state == STATE_STOP) { + // return 4 clock step + return 4; + } else { + // return 4 clock step + return 0; + } + } + void gb_btn_set( gb_t * const ctx, @@ -9149,92 +9215,75 @@ templates: gb_handle_interrupts( gb_t * const ctx ) { - if (ctx->cpu.ime) { + if (ctx->cpu.state == STATE_RUN) { + if (ctx->cpu.ime) { + // get interrupt vector (masked against enabled interrupts) + const uint8_t iv = mmu_rb(ctx, PORT_IE) & mmu_rb(ctx, PORT_IF); + bool done = false; + + for (uint8_t i = 0; !done && (i < 5); i++) { + const uint8_t mask = i ? (1 << i) : 1; + + // has this interrupt been triggered? + if (iv & mask) { + // disable ime + ctx->cpu.ime = false; + + // clear flag + mmu_wb(ctx, PORT_IF, mmu_rb(ctx, PORT_IF) ^ mask); + + // jump to handler + rst(ctx, 0x0040 + (8 * i)); + + // FIXME: according to url below, this should take 5 cycles + // (src: http://gbdev.gg8.se/wiki/articles/Interrupts) + + // break out of for loop + done = true; + } + } + } + } else if (ctx->cpu.state == STATE_HALT) { // get interrupt vector (masked against enabled interrupts) const uint8_t iv = mmu_rb(ctx, PORT_IE) & mmu_rb(ctx, PORT_IF); + bool done = false; - for (uint8_t i = 0; i < 5; i++) { + for (uint8_t i = 0; !done && (i < 5); i++) { const uint8_t mask = i ? (1 << i) : 1; // has this interrupt been triggered? if (iv & mask) { - // disable ime - ctx->cpu.ime = false; - - // clear flag - mmu_wb(ctx, PORT_IF, mmu_rb(ctx, PORT_IF) ^ mask); - - // jump to handler - rst(ctx, 0x0040 + (8 * i)); + // wake cpu + ctx->cpu.state = STATE_RUN; // FIXME: according to url below, this should take 5 cycles // (src: http://gbdev.gg8.se/wiki/articles/Interrupts) // break out of for loop - break; - } - } - } - } - - static void - timer_step( - gb_t * const ctx, - const uint16_t clock - ) { - // 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; + done = true; - if (new_of != old_of) { - // reset TIMA register to value of TMA - ctx->timer.tima = (ctx->timer.tma << shift); + if (ctx->cpu.ime) { + // disable ime + ctx->cpu.ime = false; - // trigger timer interrupt - mmu_wb(ctx, PORT_IF, mmu_rb(ctx, PORT_IF) & (1 << 2)); - } - } - } + // clear flag + mmu_wb(ctx, PORT_IF, mmu_rb(ctx, PORT_IF) ^ mask); - static uint16_t - cpu_step( - gb_t * const ctx - ) { - // get pc, and current op - const uint16_t old_pc = cpu_rw(ctx, RW_PC), - op = mmu_rb(ctx, old_pc); - uint16_t clock = 0; - - // exec op - switch (op) { - <%= switches['main'] %> - case 0xCB: - switch (mmu_rb(ctx, old_pc + 1)) { - <%= switches['cb'] %> - default: - not_implemented(ctx, old_pc, op); + // jump to handler + rst(ctx, 0x0040 + (8 * i)); + } + } } - - break; - default: - not_implemented(ctx, old_pc, op); + } else if (ctx->cpu.state == STATE_STOP) { + // TODO: handle STATE_STOP + } else { } - - // increment cpu clock - ctx->cpu.clock += clock; } - void gb_step( gb_t * const ctx ) { - // TODO: handle halt // handle pending interrupts gb_handle_interrupts(ctx); -- cgit v1.2.3