From 1b48fbe6a2ea7ee2a1f1b2b8b0b89b343ef6d8d2 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Tue, 26 Apr 2016 02:19:51 -0500 Subject: [PATCH] Add Z80 INT support and VDP frame interrupts. --- src/io.c | 11 +++++++++++ src/io.h | 1 + src/vdp.c | 19 ++++++++++++++++++- src/vdp.h | 1 + src/z80.c | 22 ++++++++++++++++++++++ 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/io.c b/src/io.c index fc89e8a..40ee924 100644 --- a/src/io.c +++ b/src/io.c @@ -11,12 +11,23 @@ void io_init(IO *io, VDP *vdp) io->vdp = vdp; } +/* + "Power on" the IO object. +*/ void io_power(IO *io) { io->except = false; } /* + Return whether the IRQ line is currently active. +*/ +bool io_check_irq(IO *io) +{ + return vdp_assert_irq(io->vdp); +} + +/* Read and return a byte from the given port. */ uint8_t io_port_read(IO *io, uint8_t port) diff --git a/src/io.h b/src/io.h index 350a5f7..8be1cc1 100644 --- a/src/io.h +++ b/src/io.h @@ -20,5 +20,6 @@ typedef struct { void io_init(IO*, VDP*); void io_power(IO*); +bool io_check_irq(IO*); uint8_t io_port_read(IO*, uint8_t); void io_port_write(IO*, uint8_t, uint8_t); diff --git a/src/vdp.c b/src/vdp.c index 4a89642..eb67aed 100644 --- a/src/vdp.c +++ b/src/vdp.c @@ -60,6 +60,14 @@ void vdp_power(VDP *vdp) } /* + Return whether frame-completion interrupts are enabled. +*/ +static bool should_frame_interrupt(const VDP *vdp) +{ + return vdp->regs[0x01] & 0x20; +} + +/* Return the base address of the pattern name table. */ static uint16_t get_pnt_base(const VDP *vdp) @@ -115,7 +123,8 @@ void vdp_simulate_line(VDP *vdp) if (vdp->v_counter >= 0x18 && vdp->v_counter < 0xA8) { // TODO: draw current line } - // TODO: if (...) IRQ + if (vdp->v_counter == 0xC0) + vdp->stat_int = true; advance_scanline(vdp); } @@ -225,6 +234,14 @@ void vdp_write_data(VDP *vdp, uint8_t byte) } /* + Return whether the VDP is currently asserting an interrupt. +*/ +bool vdp_assert_irq(VDP *vdp) +{ + return vdp->stat_int && should_frame_interrupt(vdp); +} + +/* @DEBUG_LEVEL Print out all register values to stdout. */ diff --git a/src/vdp.h b/src/vdp.h index 5d30bb3..46b8d22 100644 --- a/src/vdp.h +++ b/src/vdp.h @@ -41,5 +41,6 @@ uint8_t vdp_read_control(VDP*); uint8_t vdp_read_data(VDP*); void vdp_write_control(VDP*, uint8_t); void vdp_write_data(VDP*, uint8_t); +bool vdp_assert_irq(VDP*); void vdp_dump_registers(const VDP*); diff --git a/src/z80.c b/src/z80.c index 593d1e1..1ad5d89 100644 --- a/src/z80.c +++ b/src/z80.c @@ -274,6 +274,24 @@ static inline uint8_t get_interrupt_mode(const Z80 *z80) } /* + Handle an active IRQ line. Return the number of cycles consumed. +*/ +static inline uint8_t handle_interrupt(Z80 *z80) +{ + z80->regfile.iff1 = z80->regfile.iff2 = 0; + stack_push(z80, z80->regfile.pc); + + if (get_interrupt_mode(z80) < 2) { + z80->regfile.pc = 0x0038; + return 13; + } else { + uint16_t addr = (z80->regfile.i << 8) + 0xFF; + z80->regfile.pc = mmu_read_double(z80->mmu, addr); + return 19; + } +} + +/* Increment the refresh counter register, R. */ static inline void increment_refresh_counter(Z80 *z80) @@ -324,6 +342,10 @@ bool z80_do_cycles(Z80 *z80, double cycles) { cycles += z80->pending_cycles; while (cycles > 0 && !z80->except) { + if (io_check_irq(z80->io) && z80->regfile.iff1) { + cycles -= handle_interrupt(z80); + continue; + } uint8_t opcode = mmu_read_byte(z80->mmu, z80->regfile.pc); increment_refresh_counter(z80); if (TRACE_LEVEL)