From b48f7bfb063de855881f5b3f66a4a2f8aab648b4 Mon Sep 17 00:00:00 2001 From: Paul Duncan Date: Sun, 17 Jun 2018 01:36:58 -0400 Subject: clocks, buttons, initial interrupts --- gen.rb | 4 +- ops.yaml | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++------------- 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; @@ -7606,6 +7633,23 @@ templates: } cpu; } 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, @@ -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); } -- cgit v1.2.3