@@ -11,12 +11,23 @@ void io_init(IO *io, VDP *vdp) | |||||
io->vdp = vdp; | io->vdp = vdp; | ||||
} | } | ||||
/* | |||||
"Power on" the IO object. | |||||
*/ | |||||
void io_power(IO *io) | void io_power(IO *io) | ||||
{ | { | ||||
io->except = false; | 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. | Read and return a byte from the given port. | ||||
*/ | */ | ||||
uint8_t io_port_read(IO *io, uint8_t port) | uint8_t io_port_read(IO *io, uint8_t port) | ||||
@@ -20,5 +20,6 @@ typedef struct { | |||||
void io_init(IO*, VDP*); | void io_init(IO*, VDP*); | ||||
void io_power(IO*); | void io_power(IO*); | ||||
bool io_check_irq(IO*); | |||||
uint8_t io_port_read(IO*, uint8_t); | uint8_t io_port_read(IO*, uint8_t); | ||||
void io_port_write(IO*, uint8_t, uint8_t); | void io_port_write(IO*, uint8_t, uint8_t); |
@@ -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. | Return the base address of the pattern name table. | ||||
*/ | */ | ||||
static uint16_t get_pnt_base(const VDP *vdp) | 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) { | if (vdp->v_counter >= 0x18 && vdp->v_counter < 0xA8) { | ||||
// TODO: draw current line | // TODO: draw current line | ||||
} | } | ||||
// TODO: if (...) IRQ | |||||
if (vdp->v_counter == 0xC0) | |||||
vdp->stat_int = true; | |||||
advance_scanline(vdp); | 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 | @DEBUG_LEVEL | ||||
Print out all register values to stdout. | Print out all register values to stdout. | ||||
*/ | */ | ||||
@@ -41,5 +41,6 @@ uint8_t vdp_read_control(VDP*); | |||||
uint8_t vdp_read_data(VDP*); | uint8_t vdp_read_data(VDP*); | ||||
void vdp_write_control(VDP*, uint8_t); | void vdp_write_control(VDP*, uint8_t); | ||||
void vdp_write_data(VDP*, uint8_t); | void vdp_write_data(VDP*, uint8_t); | ||||
bool vdp_assert_irq(VDP*); | |||||
void vdp_dump_registers(const VDP*); | void vdp_dump_registers(const VDP*); |
@@ -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. | Increment the refresh counter register, R. | ||||
*/ | */ | ||||
static inline void increment_refresh_counter(Z80 *z80) | static inline void increment_refresh_counter(Z80 *z80) | ||||
@@ -324,6 +342,10 @@ bool z80_do_cycles(Z80 *z80, double cycles) | |||||
{ | { | ||||
cycles += z80->pending_cycles; | cycles += z80->pending_cycles; | ||||
while (cycles > 0 && !z80->except) { | 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); | uint8_t opcode = mmu_read_byte(z80->mmu, z80->regfile.pc); | ||||
increment_refresh_counter(z80); | increment_refresh_counter(z80); | ||||
if (TRACE_LEVEL) | if (TRACE_LEVEL) | ||||