changeset 317:e5e8b48ad157

Initial stab at horizontal interrupts and improving accuracy of vertical interrupts. Also added the VINT pending flag to status port.
author Mike Pavone <pavone@retrodev.com>
date Fri, 10 May 2013 22:57:56 -0700
parents fd7c24b97ebf
children 789f2f5f2277
files blastem.c m68k_to_x86.h runtime.S vdp.c vdp.h
diffstat 5 files changed, 127 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/blastem.c	Thu May 09 20:59:49 2013 -0700
+++ b/blastem.c	Fri May 10 22:57:56 2013 -0700
@@ -107,21 +107,39 @@
 	return 0;
 }
 
-#define VINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_68K)
-#define ZVINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_Z80)
+//TODO: Make these dependent on the video mode
+//#define VINT_CYCLE ((MCLKS_LINE * 225 + (148 + 40) * 4)/MCLKS_PER_68K)
+#define ZVINT_CYCLE ((MCLKS_LINE * 225 + (148 + 40) * 4)/MCLKS_PER_Z80)
+//#define VINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_68K)
+//#define ZVINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_Z80)
 
 void adjust_int_cycle(m68k_context * context, vdp_context * v_context)
 {
-	if (!(v_context->regs[REG_MODE_2] & 0x20 && ((context->status & 0x7) < 6)) || context->current_cycle >= VINT_CYCLE) {
-		context->int_cycle = CYCLE_NEVER;
-		context->target_cycle = context->sync_cycle;
-	} else if (context->int_cycle > VINT_CYCLE) {
-		context->int_cycle = VINT_CYCLE;
-		context->int_num = 6;
-		if (context->int_cycle < context->sync_cycle) {
-			context->target_cycle = context->int_cycle;
+	context->int_cycle = CYCLE_NEVER;
+	if ((context->status & 0x7) < 6) {
+		uint32_t next_vint = vdp_next_vint(v_context);
+		if (next_vint != CYCLE_NEVER) {
+			next_vint /= MCLKS_PER_68K;
+			context->int_cycle = next_vint;
+			context->int_num = 6;
+		}
+		if ((context->status & 0x7) < 4) {
+			uint32_t next_hint = vdp_next_hint(v_context);
+			if (next_hint != CYCLE_NEVER) {
+				next_hint /= MCLKS_PER_68K;
+				if (next_hint < context->int_cycle) {
+					context->int_cycle = next_hint;
+					context->int_num = 4;
+			
+				}
+			}
 		}
 	}
+
+	context->target_cycle = context->int_cycle < context->sync_cycle ? context->int_cycle : context->sync_cycle;
+	/*printf("Cyc: %d, Trgt: %d, Int Cyc: %d, Int: %d, Mask: %X, V: %d, H: %d, HICount: %d, HReg: %d, Line: %d\n", 
+		context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7), 
+		v_context->regs[REG_MODE_2] & 0x20, v_context->regs[REG_MODE_1] & 0x10, v_context->hint_counter, v_context->regs[REG_HINT], v_context->cycles / MCLKS_LINE);*/
 }
 
 int break_on_sync = 0;
@@ -196,6 +214,10 @@
 		//printf("running VDP for %d cycles\n", mclks - v_context->cycles);
 		vdp_run_context(v_context, mclks);
 	}
+	if (context->int_ack) {
+		vdp_int_ack(v_context, context->int_ack);
+		context->int_ack = 0;
+	}
 	adjust_int_cycle(context, v_context);
 	if (break_on_sync && address) {
 		break_on_sync = 0;
--- a/m68k_to_x86.h	Thu May 09 20:59:49 2013 -0700
+++ b/m68k_to_x86.h	Fri May 10 22:57:56 2013 -0700
@@ -28,7 +28,7 @@
 typedef struct {
 	uint8_t         flags[5];
 	uint8_t         status;
-	uint16_t        reserved;
+	uint16_t        int_ack;
 	uint32_t        dregs[8];
 	uint32_t        aregs[9];
 	uint32_t		target_cycle; //cycle at which the next synchronization or interrupt occurs
--- a/runtime.S	Thu May 09 20:59:49 2013 -0700
+++ b/runtime.S	Fri May 10 22:57:56 2013 -0700
@@ -42,6 +42,7 @@
 	or %cl, 5(%rsi)
 	/* calculate interrupt vector address */
 	mov 92(%rsi), %ecx
+	mov %cx, 6(%rsi) /* interrupt acknowlege */
 	shl $2, %ecx
 	add $0x60, %ecx
 	call m68k_read_long_scratch1
--- a/vdp.c	Thu May 09 20:59:49 2013 -0700
+++ b/vdp.c	Fri May 10 22:57:56 2013 -0700
@@ -1028,18 +1028,34 @@
 		if (!line) {
 			latch_mode(context);
 		}
+		uint32_t linecyc = context->cycles % MCLKS_LINE;
+		if (linecyc == 0) {
+			if (line <= 1 || line >= active_lines) {
+				context->hint_counter = context->regs[REG_HINT];
+			} else if (context->hint_counter) {
+				context->hint_counter--;
+			} else {
+				context->flags2 |= FLAG2_HINT_PENDING;
+				context->hint_counter = context->regs[REG_HINT];
+			}
+		} else if(line == active_lines) {
+			uint32_t intcyc = context->latched_mode & BIT_H40 ? (148 + 40) * 4 :  (132 + 28) * 5;;
+			if (linecyc == intcyc) {
+				context->flags2 |= FLAG2_VINT_PENDING;
+			}
+		}
 		if (line < active_lines && context->regs[REG_MODE_2] & DISPLAY_ENABLE) {
 			//first sort-of active line is treated as 255 internally
 			//it's used for gathering sprite info for line 
 			line = (line - 1) & 0xFF;
-			uint32_t linecyc = context->cycles % MCLKS_LINE;
 			
 			//Convert to slot number
 			if (context->latched_mode & BIT_H40){
 				//TODO: Deal with nasty clock switching during HBLANK
+				uint32_t clock_inc = MCLKS_LINE-linecyc < 16 ? MCLKS_LINE-linecyc : 16;
 				linecyc = linecyc/16;
 				vdp_h40(line, linecyc, context);
-				context->cycles += 16;
+				context->cycles += clock_inc;
 			} else {
 				linecyc = linecyc/20;
 				vdp_h32(line, linecyc, context);
@@ -1053,8 +1069,9 @@
 				check_render_bg(context, line);
 			}
 			if (context->latched_mode & BIT_H40){
+				uint32_t clock_inc = MCLKS_LINE-linecyc < 16 ? MCLKS_LINE-linecyc : 16;
 				//TODO: Deal with nasty clock switching during HBLANK
-				context->cycles += 16;
+				context->cycles += clock_inc;
 			} else {
 				context->cycles += 20;
 			}
@@ -1173,6 +1190,9 @@
 	if (context->fifo_cur == context->fifo_end) {
 		value |= 0x100;
 	}
+	if (context->flags2 & FLAG2_VINT_PENDING) {
+		value |- 0x80;
+	}
 	if (context->flags & FLAG_DMA_RUN) {
 		value |= 0x2;
 	}
@@ -1180,6 +1200,9 @@
 	if (line >= (context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE)) {
 		value |= 0x8;
 	}
+	if (context->latched_mode & BIT_PAL) {//Not sure about this, need to verify
+		value |= 0x1;
+	}
 	//TODO: Lots of other bits in status port
 	return value;
 }
@@ -1268,6 +1291,57 @@
 	}
 }
 
+uint32_t vdp_next_hint(vdp_context * context)
+{
+	if (!(context->regs[REG_MODE_1] & 0x10)) {
+		return 0xFFFFFFFF;
+	}
+	if (context->flags2 & FLAG2_HINT_PENDING) {
+		return context->cycles;
+	}
+	uint32_t active_lines = context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE;
+	uint32_t line = context->cycles / MCLKS_LINE;
+	if (line >= active_lines) {
+		return 0xFFFFFFFF;
+	}
+	uint32_t linecyc = context->cycles % MCLKS_LINE;
+	uint32_t hcycle = context->cycles + context->hint_counter * MCLKS_LINE + MCLKS_LINE - linecyc;
+	if (!line) {
+		hcycle += MCLKS_LINE;
+	}
+	return hcycle;
+}
+
+uint32_t vdp_next_vint(vdp_context * context)
+{
+	if (!(context->regs[REG_MODE_2] & 0x20)) {
+		return 0xFFFFFFFF;
+	}
+	if (context->flags2 & FLAG2_VINT_PENDING) {
+		return context->cycles;
+	}
+	uint32_t active_lines = context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE;
+	uint32_t vcycle =  MCLKS_LINE * active_lines;
+	if (context->latched_mode & BIT_H40) {
+		vcycle += (148 + 40) * 4;
+	} else {
+		vcycle += (132 + 28) * 5;
+	}
+	if (vcycle < context->cycles) {
+		return 0xFFFFFFFF;
+	}
+	return vcycle;
+}
+
+void vdp_int_ack(vdp_context * context, uint16_t int_num)
+{
+	if (int_num == 6) {
+		context->flags2 &= ~FLAG2_VINT_PENDING;
+	} else if(int_num ==4) {
+		context->flags2 &= ~FLAG2_HINT_PENDING;
+	}
+}
+
 #define GST_VDP_REGS 0xFA
 #define GST_VDP_MEM 0x12478
 
--- a/vdp.h	Thu May 09 20:59:49 2013 -0700
+++ b/vdp.h	Fri May 10 22:57:56 2013 -0700
@@ -30,14 +30,17 @@
 
 #define MCLKS_LINE 3420
 
-#define FLAG_DOT_OFLOW 0x1
-#define FLAG_CAN_MASK  0x2
-#define FLAG_MASKED    0x4
-#define FLAG_WINDOW    0x8
-#define FLAG_PENDING   0x10
-#define FLAG_UNUSED_SLOT 0x20
-#define FLAG_DMA_RUN   0x40
-#define FLAG_DMA_PROG  0x80
+#define FLAG_DOT_OFLOW     0x01
+#define FLAG_CAN_MASK      0x02
+#define FLAG_MASKED        0x04
+#define FLAG_WINDOW        0x08
+#define FLAG_PENDING       0x10
+#define FLAG_UNUSED_SLOT   0x20
+#define FLAG_DMA_RUN       0x40
+#define FLAG_DMA_PROG      0x80
+
+#define FLAG2_VINT_PENDING 0x01
+#define FLAG2_HINT_PENDING 0x02
 
 #define DISPLAY_ENABLE 0x40
 
@@ -115,6 +118,8 @@
 	uint16_t    dma_val;
 	uint8_t     v_offset;
 	uint8_t     dma_cd;
+	uint8_t     hint_counter;
+	uint8_t     flags2;
 	uint8_t     *tmp_buf_a;
 	uint8_t     *tmp_buf_b;
 } vdp_context;
@@ -133,5 +138,8 @@
 uint16_t vdp_data_port_read(vdp_context * context);
 uint16_t vdp_hv_counter_read(vdp_context * context);
 void vdp_adjust_cycles(vdp_context * context, uint32_t deduction);
+uint32_t vdp_next_hint(vdp_context * context);
+uint32_t vdp_next_vint(vdp_context * context);
+void vdp_int_ack(vdp_context * context, uint16_t int_num);
 
 #endif //VDP_H_