changeset 26:083347ccd508

Implemented vblank interrupts and fixed a bug in exception vector address calculation
author Michael Pavone <pavone@retrodev.com>
date Fri, 01 Apr 2016 21:34:38 -0700
parents fb14515266f4
children 351a0d0cce3b
files src/cpu.c src/main.c src/vdp.c src/vdp.h vint.s16
diffstat 5 files changed, 106 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/src/cpu.c	Thu Mar 31 23:25:52 2016 -0700
+++ b/src/cpu.c	Fri Apr 01 21:34:38 2016 -0700
@@ -129,7 +129,7 @@
 	context->exception_pc = context->regs[REG_PC] - 2;
 	context->exception_sr = context->regs[REG_SR];
 	context->regs[REG_SR] &= ~(STATUS_INT0_ENABLE | STATUS_INT1_ENABLE);
-	context->regs[REG_PC] = cpu_read_16(context, context->vector_base + context->exception);
+	context->regs[REG_PC] = cpu_read_16(context, context->vector_base + context->exception * 2);
 	context->state = STATE_NEED_FETCH;
 }
 
--- a/src/main.c	Thu Mar 31 23:25:52 2016 -0700
+++ b/src/main.c	Fri Apr 01 21:34:38 2016 -0700
@@ -134,7 +134,10 @@
 	}
 	if (mask & 2) {
 		vdp_run(&system->video, context->cycles);
-		//TODO: VBlank interrupt
+		uint32_t vnext = vdp_next_interrupt(&system->video);
+		if (vnext < next) {
+			next = vnext;
+		}
 	}
 	return next;
 }
@@ -148,7 +151,9 @@
 		bits |= 1;
 	}
 	vdp_run(&system->video, context->cycles);
-	//TODO: VBlank interrupt
+	if (vdp_interrupt_pending(&system->video)) {
+		bits |= 2;
+	}
 	return bits;
 }
 
@@ -158,8 +163,9 @@
 	if (which == 0) {
 		timer_run(&system->timer, context->cycles);
 		system->timer.pending = 0;
+	} else {
+		vdp_ack_interrupt(&system->video);
 	}
-	//TODO: VBlank interrupt
 }
 
 memory_region regions[] = {
--- a/src/vdp.c	Thu Mar 31 23:25:52 2016 -0700
+++ b/src/vdp.c	Fri Apr 01 21:34:38 2016 -0700
@@ -146,6 +146,8 @@
 				context->framebuffer = system_get_framebuffer(&context->pitch);
 				//pitch is in terms of bytes, but we want it in terms of pixels
 				context->pitch /= sizeof(uint16_t);
+				//clear pending interrupt flag since VBlank is over
+				context->status &= ~VDP_STATUS_PENDING_VINT;
 			}
 			uint16_t *dest = context->framebuffer + (context->vcounter - 9) * context->pitch + context->hcounter;
 			if (context->status & VDP_STATUS_ENABLED && context->vcounter > 16 && context->vcounter < 241) {
@@ -159,6 +161,9 @@
 				*dest = *context->cram;
 			}
 		} else if(!context->hcounter && context->vcounter == 249) {
+			if (context->status & VDP_STATUS_ENABLED) {
+				context->status |= VDP_STATUS_PENDING_VINT;
+			}
 			system_framebuffer_updated();
 			context->framebuffer = NULL;
 		}
@@ -220,3 +225,30 @@
 		context->status &= ~VDP_STATUS_ENABLED;
 	}
 }
+
+uint32_t vdp_next_interrupt(vdp *context)
+{
+	if (context->status & VDP_STATUS_PENDING_VINT) {
+		return 0;
+	} else if (context->status & VDP_STATUS_ENABLED) {
+		uint32_t next_line = context->vcounter + 1;
+		uint32_t next_line_cyc = context->cycles + ((416 - context->hcounter) >> 1) * context->clock_inc;
+		if (context->vcounter < 249) {
+			return next_line_cyc + (249 - next_line) * 832;
+		} else {
+			return next_line_cyc + (249 + 262 - next_line) * 832;
+		}
+	} else {
+		return 0xFFFFFFFF;
+	}
+}
+
+void vdp_ack_interrupt(vdp *context)
+{
+	context->status &= ~VDP_STATUS_PENDING_VINT;
+}
+
+uint8_t vdp_interrupt_pending(vdp *context)
+{
+	return (context->status & VDP_STATUS_PENDING_VINT) != 0;
+}
--- a/src/vdp.h	Thu Mar 31 23:25:52 2016 -0700
+++ b/src/vdp.h	Fri Apr 01 21:34:38 2016 -0700
@@ -51,16 +51,20 @@
 	FIFO_DEST_CRAM
 };
 
-#define VDP_STATUS_FIFO        1
-#define VDP_STATUS_VRAM        2
-#define VDP_STATUS_SRAM        4
-#define VDP_STATUS_ENABLED     8
-#define VDP_STATUS_SPRITE_SCAN 16
+#define VDP_STATUS_FIFO         1
+#define VDP_STATUS_VRAM         2
+#define VDP_STATUS_SRAM         4
+#define VDP_STATUS_ENABLED      8
+#define VDP_STATUS_SPRITE_SCAN  16
+#define VDP_STATUS_PENDING_VINT 32
 
 void vdp_init(vdp *context, uint32_t clock_div);
 void vdp_run(vdp *context, uint32_t target);
 void vdp_write_address(vdp *context, uint16_t value);
 void vdp_write_data(vdp *context, uint16_t value);
 void vdp_write_hscroll(vdp *context, uint16_t value);
+uint32_t vdp_next_interrupt(vdp *context);
+void vdp_ack_interrupt(vdp *context);
+uint8_t vdp_interrupt_pending(vdp *context);
 
 #endif //VDP_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vint.s16	Fri Apr 01 21:34:38 2016 -0700
@@ -0,0 +1,55 @@
+	ldim vectors, r0
+	setvbr r0
+	;current color value
+	ldim 0, r0
+	;color increment
+	ldim $11, r3
+	ldimh $1, r3
+	;color max
+	ldim $FF, r5
+	ldimh $F, r5
+	;counter
+	ldim 1, r4
+	;Palette RAM address
+	ldim 0, r1
+	ldimh $FF, r1
+	;enable interrupt
+	ori 2, sr
+	;enable display
+	ldim 0, r2
+	ldimh $80, r2
+	outi $D, r2
+wait
+	bra wait
+	;shouldn't get here, disable display so it's clear something broke
+	ldimh $0, r2
+	outi $D, r2
+	bra wait
+
+vectors:
+	dc.w 0
+	dc.w vint_handler
+	
+vint_handler
+	addi -1, r4
+	bne done
+	outi $E, r1
+	outi $F, r0
+	cmp r0, r5
+	beq down
+resume
+	add r3, r0, r0
+	beq up
+	ldim 5, r4
+done
+	reti r13
+down
+	ldim $EF, r3
+	ldimh $FE, r3
+	bra resume
+up
+	ldim $11, r3
+	ldimh $1, r3
+	ldim 5, r4
+	reti r13
+	
\ No newline at end of file