summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2018-06-19 19:08:16 -0400
committerPaul Duncan <pabs@pablotron.org>2018-06-19 19:08:16 -0400
commit3890aae0d46d13896c645325b3156c807fe49711 (patch)
treee819f360b360f9f81d6ec3c4ff359512ff2a78d5
parent66f7dc9c783a5efd129a4a03823f4bbe9d13614c (diff)
downloadgb-c-3890aae0d46d13896c645325b3156c807fe49711.tar.bz2
gb-c-3890aae0d46d13896c645325b3156c807fe49711.zip
add STATE_RUN and STATE_HALT support to timer_step() and cpu_step()
-rw-r--r--ops.yaml175
1 files 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);