summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2018-06-17 01:36:58 -0400
committerPaul Duncan <pabs@pablotron.org>2018-06-17 01:36:58 -0400
commitb48f7bfb063de855881f5b3f66a4a2f8aab648b4 (patch)
tree84768fa522758d4de850222b8a9644b73a0566a5
parent9dd61937a48467e7949eb456380a00e69a8ed813 (diff)
downloadgb-c-b48f7bfb063de855881f5b3f66a4a2f8aab648b4.tar.bz2
gb-c-b48f7bfb063de855881f5b3f66a4a2f8aab648b4.zip
clocks, buttons, initial interrupts
-rwxr-xr-xgen.rb4
-rw-r--r--ops.yaml154
2 files changed, 126 insertions, 32 deletions
diff --git a/gen.rb b/gen.rb
index 6d579ca..cdf1fec 100755
--- a/gen.rb
+++ b/gen.rb
@@ -29,9 +29,9 @@ DATA['ops'].each do |set_id, ops|
# time expr
time_expr = case op['time']
when Numeric
- 'ctx->cpu.clock += %d;' % [op['time']]
+ 'clock = %d;' % [op['time']]
when Hash
- 'ctx->cpu.clock += %d; // t: %d, f: %d' % %w{f t f}.map { |k|
+ 'clock = %d; // t: %d, f: %d' % %w{f t f}.map { |k|
op['time'][k]
}
else
diff --git a/ops.yaml b/ops.yaml
index 965b9d7..1b17ac5 100644
--- a/ops.yaml
+++ b/ops.yaml
@@ -487,7 +487,7 @@ ops:
code: |
if (!FLAG(ctx, Z)) {
jr(ctx, old_pc + 1);
- ctx->cpu.clock += 4; // FIXME
+ clock = 12;
}
- id: LD HL, d16
hex: 0x21
@@ -606,7 +606,7 @@ ops:
code: |
if (FLAG(ctx, Z)) {
jr(ctx, old_pc + 1);
- ctx->cpu.clock += 4; // FIXME: 4 should not be hard-coded
+ clock = 12;
}
- id: ADD HL, HL
hex: 0x29
@@ -729,7 +729,7 @@ ops:
code: |
if (!FLAG(ctx, C)) {
jr(ctx, old_pc + 1);
- ctx->cpu.clock += 4; // FIXME
+ clock = 12;
}
- id: LD SP, d16
hex: 0x31
@@ -852,7 +852,7 @@ ops:
code: |
if (FLAG(ctx, C)) {
jr(ctx, old_pc + 1);
- ctx->cpu.clock += 4;
+ clock = 12;
}
- id: ADD HL, SP
hex: 0x39
@@ -2867,7 +2867,7 @@ ops:
code: |
if (!FLAG(ctx, Z)) {
pop_rw(ctx, RW_PC);
- ctx->cpu.clock += 12;
+ clock = 20;
}
- id: POP BC
hex: 0xC1
@@ -2903,7 +2903,7 @@ ops:
code: |
if (!FLAG(ctx, Z)) {
cpu_ww(ctx, RW_PC, mmu_rw(ctx, old_pc + 1));
- ctx->cpu.clock -= 16; // FIXME
+ clock = 16;
}
- id: JP a16
hex: 0xC3
@@ -2940,7 +2940,7 @@ ops:
code: |
if (!FLAG(ctx, Z)) {
call_a16(ctx, old_pc + 1);
- ctx->cpu.clock += 12; // FIXME
+ clock = 24;
}
- id: PUSH BC
hex: 0xC5
@@ -3006,7 +3006,7 @@ ops:
code: |
if (FLAG(ctx, Z)) {
pop_rw(ctx, RW_PC);
- ctx->cpu.clock += 12;
+ clock += 20;
}
- id: RET
hex: 0xC9
@@ -3043,7 +3043,7 @@ ops:
code: |
if (FLAG(ctx, Z)) {
cpu_ww(ctx, RW_PC, mmu_rw(ctx, old_pc + 1));
- ctx->cpu.clock -= 16; // FIXME
+ clock = 16;
}
- id: PREFIX CB
hex: 0xCB
@@ -3073,7 +3073,7 @@ ops:
code: |
if (FLAG(ctx, Z)) {
call_a16(ctx, old_pc + 1);
- ctx->cpu.clock += 12;
+ clock = 24;
}
- id: CALL a16
hex: 0xCD
@@ -3129,7 +3129,7 @@ ops:
code: |
if (!FLAG(ctx, C)) {
pop_rw(ctx, RW_PC);
- ctx->cpu.clock += 12;
+ clock = 20;
}
flags:
z:
@@ -3171,7 +3171,7 @@ ops:
code: |
if (!FLAG(ctx, C)) {
cpu_ww(ctx, RW_PC, mmu_rw(ctx, old_pc + 1));
- ctx->cpu.clock -= 16; // FIXME
+ clock = 16;
}
- id: XX
hex: 0xD3
@@ -3198,7 +3198,7 @@ ops:
code: |
if (!FLAG(ctx, C)) {
call_a16(ctx, old_pc + 1);
- ctx->cpu.clock += 12; // FIXME
+ clock = 24;
}
- id: PUSH DE
hex: 0xD5
@@ -3263,7 +3263,7 @@ ops:
code: |
if (FLAG(ctx, C)) {
pop_rw(ctx, RW_PC);
- ctx->cpu.clock += 12;
+ clock += 20;
}
- id: RETI
hex: 0xD9
@@ -3301,7 +3301,7 @@ ops:
code: |
if (FLAG(ctx, C)) {
cpu_ww(ctx, RW_PC, mmu_rw(ctx, old_pc + 1));
- ctx->cpu.clock -= 16;
+ clock = 16;
}
- id: XX
hex: 0xDB
@@ -3328,7 +3328,7 @@ ops:
code: |
if (FLAG(ctx, C)) {
call_a16(ctx, old_pc + 1);
- ctx->cpu.clock += 12;
+ clock = 24;
}
- id: XX
hex: 0xDD
@@ -3707,8 +3707,8 @@ ops:
h:
c:
code: |
- // disable interrupts
- ctx->cpu.ime = false;
+ // enable interrupts
+ ctx->cpu.ime = true;
- id: XX
hex: 0xFC
cat: "invalid"
@@ -7559,6 +7559,24 @@ templates:
STATE_LAST,
} cpu_state_t;
+ // gb-manual, p23
+ typedef enum {
+ P1_MODE_NONE,
+ P1_MODE_P14,
+ P1_MODE_P15,
+ } p1_mode_t;
+
+ typedef enum {
+ GB_BTN_UP = 1,
+ GB_BTN_DOWN = (1 << 1),
+ GB_BTN_LEFT = (1 << 2),
+ GB_BTN_RIGHT = (1 << 3),
+ GB_BTN_A = (1 << 4),
+ GB_BTN_B = (1 << 5),
+ GB_BTN_SELECT = (1 << 6),
+ GB_BTN_START = (1 << 7),
+ } gb_btn_t;
+
typedef enum {
GPU_MODE_OAM,
GPU_MODE_VRAM,
@@ -7582,8 +7600,17 @@ templates:
uint8_t *rom;
uint32_t rom_size;
- // interrupt enable flags (0xFFFF)
- uint8_t ei;
+ // enable interrupt flags (addr: 0xFFFF)
+ uint8_t ie;
+
+ // interrupts (addr: 0xFF0F)
+ // (gb-manual, p26)
+ uint8_t iv;
+
+ // buttons (addr: 0xFF00)
+ // gb-manual, p23
+ uint8_t p1_mode;
+ uint8_t btns;
// external ram (optional, 8k)
uint8_t *eram;
@@ -7607,6 +7634,23 @@ templates:
} gb_t;
static uint8_t
+ mmu_ri(
+ const gb_t * const ctx,
+ const uint8_t mask
+ ) {
+ return (ctx->mmu.iv & mask) & 0x1F;
+ }
+
+ static void
+ mmu_wi(
+ gb_t * const ctx,
+ const uint8_t flag,
+ const bool set
+ ) {
+ ctx->mmu.iv &= 0x1F & (set ? flag : ~flag);
+ }
+
+ static uint8_t
mmu_rb(
gb_t * const ctx,
const uint16_t addr
@@ -7679,7 +7723,21 @@ templates:
break;
case 0x0F00:
if (addr == 0xFFFF) {
- return ctx->mmu.ei;
+ // interrupt enabled mask
+ return ctx->mmu.ie & 0x1F;
+ } else if (addr == 0xFF0F) {
+ // interrupt flags
+ return mmu_ri(ctx, 0xFF);
+ } else if (addr == 0xFF00) {
+ // buttons (p1)
+ switch (ctx->mmu.p1_mode) {
+ case P1_MODE_P14:
+ return ctx->mmu.btns & 0xF;
+ case P1_MODE_P15:
+ return (ctx->mmu.btns & 0xF0) >> 4;
+ default:
+ return 0;
+ }
} else if (addr < 0xFF80) {
// TODO: io ports
return 0;
@@ -7771,7 +7829,21 @@ templates:
break;
case 0x0F00:
if (addr == 0xFFFF) {
- ctx->mmu.ei = val;
+ ctx->mmu.ie = (val & 0x1F);
+ } else if (addr == 0xFF0F) {
+ // write interrupt flags
+ mmu_wi(ctx, val);
+ } else if (addr == 0XFF00) {
+ switch (val) {
+ case 0x10:
+ ctx->mmu.p1_mode = P1_MODE_P14;
+ break;
+ case 0x20:
+ ctx->mmu.p1_mode = P1_MODE_P15;
+ break;
+ default:
+ ctx->mmu.p1_mode = P1_MODE_NONE;
+ }
} else if (addr < 0xFF80) {
// TODO: io ports
} else {
@@ -8714,7 +8786,7 @@ templates:
cpu_ww(ctx, RW_PC, mmu_rw(ctx, addr));
}
- void
+ static void
gpu_step(
gb_t * const ctx,
const uint16_t clock
@@ -8754,7 +8826,7 @@ templates:
ctx->gpu.mode = GPU_MODE_OAM;
} else {
// trigger vblank interrupt
- mmu_wb(ctx, 0xFF0F, mmu_rb(ctx, 0xFF0F) | 1);
+ mmu_wi(ctx, 1, true);
// set gpu mode
ctx->gpu.mode = GPU_MODE_VBLANK;
@@ -8777,17 +8849,33 @@ templates:
}
}
+ void
+ gb_btn_set(
+ gb_t * const ctx,
+ const uint8_t btn,
+ const bool set
+ ) {
+ if (set) {
+ ctx->mmu.btns |= btn;
+ } else {
+ ctx->mmu.btns &= ~btn;
+ }
+
+ // trigger p1 interrupt
+ mmu_wi(ctx, (1 << 4), true);
+ // TODO: handle HALT and STOP
+ }
+
static void
gb_handle_interrupts(
gb_t * const ctx
) {
- // handle interrupts
if (ctx->cpu.ime) {
// get interrupt vector (masked against enabled interrupts)
- const uint8_t iv = mmu_rb(ctx, 0xFFFF) & mmu_rb(ctx, 0xFF0F);
+ const uint8_t iv = mmu_rb(ctx, 0xFFFF) & mmu_ri(ctx, 0xFF);
for (uint8_t i = 0; i < 5; i++) {
- const uint8_t m = (i ? (1 << i) : 1);
+ const uint8_t m = (4 - i) ? (1 << (4 - i)) : 1;
// has this interrupt been triggered?
if (iv & m) {
@@ -8795,11 +8883,10 @@ templates:
ctx->cpu.ime = false;
// clear interrupt flag
- mmu_wb(ctx, 0xFF0F, mmu_rb(ctx, 0xFF0F) ^ m);
-
+ mmu_wi(ctx, m, false);
// trigger interrupt
- rst(ctx, 0x0040 + (8 * i));
+ rst(ctx, 0x0040 + (8 * (4 - i)));
// break out of for loop
break;
@@ -8818,6 +8905,7 @@ templates:
// 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) {
@@ -8833,4 +8921,10 @@ templates:
default:
not_implemented(ctx, old_pc, op);
}
+
+ // increment cpu clock
+ ctx->cpu.clock += clock;
+
+ // advance gpu
+ gpu_step(ctx, clock);
}