Browse Source

Add VDP line interrupts; fix bugs; refactor flags.

master
Ben Kurtovic 8 years ago
parent
commit
4431f29005
2 changed files with 59 additions and 26 deletions
  1. +57
    -24
      src/vdp.c
  2. +2
    -2
      src/vdp.h

+ 57
- 24
src/vdp.c View File

@@ -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));
}

/*


+ 2
- 2
src/vdp.h View File

@@ -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;


Loading…
Cancel
Save