From 4431f29005c4f43032fac82f2c459262ea8df6ca Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sun, 1 May 2016 23:53:56 -0500 Subject: [PATCH] Add VDP line interrupts; fix bugs; refactor flags. --- src/vdp.c | 81 ++++++++++++++++++++++++++++++++++++++++++++------------------- src/vdp.h | 4 ++-- 2 files changed, 59 insertions(+), 26 deletions(-) diff --git a/src/vdp.c b/src/vdp.c index 2baae00..37d41a9 100644 --- a/src/vdp.c +++ b/src/vdp.c @@ -7,6 +7,12 @@ #include "vdp.h" #include "util.h" +#define FLAG_CONTROL 0x01 +#define FLAG_FRAME_INT 0x02 +#define FLAG_LINE_INT 0x04 +#define FLAG_SPR_OVF 0x08 +#define FLAG_SPR_COL 0x10 + #define CODE_VRAM_READ 0 #define CODE_VRAM_WRITE 1 #define CODE_REG_WRITE 2 @@ -24,8 +30,6 @@ void vdp_init(VDP *vdp) vdp->pixels = NULL; vdp->vram = cr_malloc(sizeof(uint8_t) * VDP_VRAM_SIZE); vdp->cram = cr_malloc(sizeof(uint8_t) * VDP_CRAM_SIZE); - memset(vdp->vram, 0x00, VDP_VRAM_SIZE); - memset(vdp->cram, 0x00, VDP_CRAM_SIZE); } /* @@ -34,6 +38,7 @@ void vdp_init(VDP *vdp) void vdp_free(VDP *vdp) { free(vdp->vram); + free(vdp->cram); } /* @@ -41,6 +46,9 @@ void vdp_free(VDP *vdp) */ void vdp_power(VDP *vdp) { + memset(vdp->vram, 0x00, VDP_VRAM_SIZE); + memset(vdp->cram, 0x00, VDP_CRAM_SIZE); + vdp->regs[0x00] = 0x00; vdp->regs[0x01] = 0x00; vdp->regs[0x02] = 0xFF; @@ -57,15 +65,23 @@ void vdp_power(VDP *vdp) vdp->v_counter = 0; vdp->v_count_jump = false; + vdp->flags = 0; vdp->control_code = 0; vdp->control_addr = 0; - vdp->control_flag = false; - vdp->stat_int = vdp->stat_ovf = vdp->stat_col = 0; + vdp->line_count = 0x01; vdp->read_buf = 0; vdp->cram_latch = 0; } /* + Return whether line-completion interrupts are enabled. +*/ +static bool should_line_interrupt(const VDP *vdp) +{ + return vdp->regs[0x00] & 0x10; +} + +/* Return whether frame-completion interrupts are enabled. */ static bool should_frame_interrupt(const VDP *vdp) @@ -237,6 +253,23 @@ static void draw_scanline(VDP *vdp) } /* + Update the line counter, which triggers line interrupts. +*/ +static void update_line_counter(VDP *vdp) +{ + if (vdp->v_counter < 0xC0) { + if (vdp->line_count == 0x00) { + vdp->flags |= FLAG_LINE_INT; + vdp->line_count = vdp->regs[0x0A]; + } else { + vdp->line_count--; + } + } else { + vdp->line_count = vdp->regs[0x0A]; + } +} + +/* Advance the V counter for the next scanline. */ static void advance_scanline(VDP *vdp) @@ -258,7 +291,8 @@ void vdp_simulate_line(VDP *vdp) if (vdp->v_counter >= 0x18 && vdp->v_counter < 0xA8) draw_scanline(vdp); if (vdp->v_counter == 0xC0) - vdp->stat_int = true; + vdp->flags |= FLAG_FRAME_INT; + update_line_counter(vdp); advance_scanline(vdp); } @@ -269,19 +303,20 @@ void vdp_simulate_line(VDP *vdp) 7 6 5 4 3 2 1 0 F 9S C * * * * * - - F: Interrupt flag: set when the effective display area is completed + - F: Frame interrupt: set when the effective display area is completed - 9S: 9th sprite / Sprite overflow: more than eight sprites on a scanline - - C: Collision flag: two sprites have an overlapping pixel + - C: Sprite collision: two sprites have an overlapping pixel - *: Unused - The control flag is also reset. + The control and line interrupt flags are also reset. */ uint8_t vdp_read_control(VDP *vdp) { uint8_t status = - (vdp->stat_int << 8) + (vdp->stat_ovf << 7) + (vdp->stat_col << 6); - vdp->stat_int = vdp->stat_ovf = vdp->stat_col = 0; - vdp->control_flag = false; + (!!(vdp->flags & FLAG_FRAME_INT) << 7) + + (!!(vdp->flags & FLAG_SPR_OVF) << 6) + + (!!(vdp->flags & FLAG_SPR_COL) << 5); + vdp->flags = 0; return status; } @@ -296,8 +331,8 @@ uint8_t vdp_read_data(VDP *vdp) { uint8_t buffer = vdp->read_buf; vdp->read_buf = vdp->vram[vdp->control_addr]; - vdp->control_addr = (vdp->control_addr + 1) % 0x3FFF; - vdp->control_flag = false; + vdp->control_addr = (vdp->control_addr + 1) & 0x3FFF; + vdp->flags &= ~FLAG_CONTROL; return buffer; } @@ -316,9 +351,9 @@ uint8_t vdp_read_data(VDP *vdp) */ void vdp_write_control(VDP *vdp, uint8_t byte) { - if (!vdp->control_flag) { // First byte + vdp->flags ^= FLAG_CONTROL; + if (vdp->flags & FLAG_CONTROL) { // First byte vdp->control_addr = (vdp->control_addr & 0x3F00) + byte; - vdp->control_flag = true; return; } @@ -327,14 +362,12 @@ void vdp_write_control(VDP *vdp, uint8_t byte) if (vdp->control_code == CODE_VRAM_READ) { vdp->read_buf = vdp->vram[vdp->control_addr]; - vdp->control_addr = (vdp->control_addr + 1) % 0x3FFF; + vdp->control_addr = (vdp->control_addr + 1) & 0x3FFF; } else if (vdp->control_code == CODE_REG_WRITE) { uint8_t reg = byte & 0x0F; if (reg <= VDP_REGS) vdp->regs[reg] = vdp->control_addr & 0xFF; } - - vdp->control_flag = false; } /* @@ -345,8 +378,8 @@ static void write_cram(VDP *vdp, uint8_t byte) if (!(vdp->control_addr % 2)) { vdp->cram_latch = byte; } else { - vdp->cram[(vdp->control_addr - 1) % 0x3F] = vdp->cram_latch; - vdp->cram[ vdp->control_addr % 0x3F] = byte % 0x0F; + vdp->cram[(vdp->control_addr - 1) & 0x3F] = vdp->cram_latch; + vdp->cram[ vdp->control_addr & 0x3F] = byte & 0x0F; } } @@ -364,8 +397,8 @@ void vdp_write_data(VDP *vdp, uint8_t byte) else vdp->vram[vdp->control_addr] = byte; - vdp->control_addr = (vdp->control_addr + 1) % 0x3FFF; - vdp->control_flag = false; + vdp->control_addr = (vdp->control_addr + 1) & 0x3FFF; + vdp->flags &= ~FLAG_CONTROL; vdp->read_buf = byte; } @@ -374,8 +407,8 @@ void vdp_write_data(VDP *vdp, uint8_t byte) */ bool vdp_assert_irq(VDP *vdp) { - // TODO: line interrupts - return vdp->stat_int && should_frame_interrupt(vdp); + return (vdp->flags & FLAG_FRAME_INT && should_frame_interrupt(vdp)) || + (vdp->flags & FLAG_LINE_INT && should_line_interrupt(vdp)); } /* diff --git a/src/vdp.h b/src/vdp.h index 7adb197..c8dbc29 100644 --- a/src/vdp.h +++ b/src/vdp.h @@ -24,10 +24,10 @@ typedef struct { uint8_t v_counter; bool v_count_jump; + uint8_t flags; uint8_t control_code; uint16_t control_addr; - bool control_flag; - bool stat_int, stat_ovf, stat_col; + uint8_t line_count; uint8_t read_buf; uint8_t cram_latch; } VDP;