changeset 1325:58bfbed6cdb5

Fairly major rework of how active/passive is handled along with how the V30 mode bit is handled. Allows the vertical border extension trick in Overdrive 2 to work right
author Michael Pavone <pavone@retrodev.com>
date Fri, 21 Apr 2017 01:22:52 -0700
parents 2fc444b69351
children 071e761bcdcf
files gst.c vdp.c vdp.h
diffstat 3 files changed, 151 insertions(+), 73 deletions(-) [+]
line wrap: on
line diff
--- a/gst.c	Fri Apr 21 01:19:40 2017 -0700
+++ b/gst.c	Fri Apr 21 01:22:52 2017 -0700
@@ -230,7 +230,6 @@
 	{
 		vdp_control_port_write(context, 0x8000 | (i << 8) | tmp_buf[i]);
 	}
-	latch_mode(context);
 	if (fread(tmp_buf, 1, CRAM_SIZE*2, state_file) != CRAM_SIZE*2) {
 		fputs("Failed to read CRAM from savestate\n", stderr);
 		return 0;
--- a/vdp.c	Fri Apr 21 01:19:40 2017 -0700
+++ b/vdp.c	Fri Apr 21 01:22:52 2017 -0700
@@ -55,6 +55,12 @@
 
 #define INVALID_LINE 0x200
 
+enum {
+	INACTIVE = 0,
+	PREPARING, //used for line 0x1FF
+	ACTIVE
+};
+
 static int32_t color_map[1 << 12];
 static uint16_t mode4_address_map[0x4000];
 static uint32_t planar_to_chunky[256];
@@ -71,14 +77,16 @@
 static void update_video_params(vdp_context *context)
 {
 	if (context->regs[REG_MODE_2] & BIT_MODE_5) {
-		if (context->latched_mode & BIT_PAL) {
+		if (context->regs[REG_MODE_2] & BIT_PAL) {
 			if (context->flags2 & FLAG2_REGION_PAL) {
 				context->inactive_start = PAL_INACTIVE_START;
 				context->border_top = BORDER_TOP_V30_PAL;
 				context->border_bot = BORDER_BOT_V30_PAL;
 			} else {
-				context->inactive_start = 0x200;
-				context->border_top = context->border_bot = 0;
+				//the behavior here is rather weird and needs more investigation
+				context->inactive_start = 0xF0;
+				context->border_top = 1;
+				context->border_bot = 3;
 			}
 		} else {
 			context->inactive_start = NTSC_INACTIVE_START;
@@ -90,6 +98,14 @@
 				context->border_bot = BORDER_TOP_V28;
 			}
 		}
+		if (context->state == INACTIVE) {
+			//Undo forced INACTIVE state due to neither Mode 4 nor Mode 5 being active
+			if (context->vcounter < context->inactive_start) {
+				context->state = ACTIVE;
+			} else if (context->vcounter == 0x1FF) {
+				context->state = PREPARING;
+			}
+		}
 	} else {
 		context->inactive_start = MODE4_INACTIVE_START;
 		if (context->flags2 & FLAG2_REGION_PAL) {
@@ -99,6 +115,20 @@
 			context->border_top = BORDER_TOP_V24;
 			context->border_bot = BORDER_BOT_V24;
 		}
+		if (!(context->regs[REG_MODE_1] & BIT_MODE_4)){
+			context->state = INACTIVE;
+		} else if (context->state == INACTIVE) {
+			//Undo forced INACTIVE state due to neither Mode 4 nor Mode 5 being active
+			if (context->vcounter < context->inactive_start) {
+				context->state = ACTIVE;
+			}
+			/*
+			FIXME: uncomment this once mode 4 renderer is updated to handle this
+			else if (context->vcounter == 0x1FF) {
+				context->state = PREPARING;
+			}
+			*/
+		}
 	}
 }
 
@@ -507,6 +537,11 @@
 	//TODO: Window Group, DMA Group
 }
 
+static uint8_t is_active(vdp_context *context)
+{
+	return context->state != INACTIVE && (context->regs[REG_MODE_2] & BIT_DISP_EN) != 0;
+}
+
 static void scan_sprite_table(uint32_t line, vdp_context * context)
 {
 	if (context->sprite_index && context->slot_counter) {
@@ -1201,7 +1236,7 @@
 static void render_map_output(uint32_t line, int32_t col, vdp_context * context)
 {
 	uint32_t *dst;
-	if (line == 0x1FF) {
+	if (context->state == PREPARING) {
 		if (!col) {
 			return;
 		}
@@ -1223,9 +1258,7 @@
 		}
 		return;
 	}
-	if (line >= 240) {
-		return;
-	}
+	line &= 0xFF;
 	render_map(context->col_2, context->tmp_buf_b, context->buf_b_off+8, context);
 	uint8_t *sprite_buf,  *plane_a, *plane_b;
 	int plane_a_off, plane_b_off;
@@ -1305,12 +1338,21 @@
 					{
 					case 1:
 						pixel &= *sprite_buf;
+						if (output_disabled && pixel) {
+							src = DBG_SRC_S;
+						}
 						break;
 					case 2:
 						pixel &= *plane_a;
+						if (output_disabled && pixel) {
+							src = DBG_SRC_A;
+						}
 						break;
 					case 3:
 						pixel &= *plane_b;
+						if (output_disabled && pixel) {
+							src = DBG_SRC_B;
+						}
 						break;
 					}
 
@@ -1349,12 +1391,21 @@
 					{
 					case 1:
 						pixel &= *sprite_buf;
+						if (output_disabled && pixel) {
+							src = DBG_SRC_S;
+						}
 						break;
 					case 2:
 						pixel &= *plane_a;
+						if (output_disabled && pixel) {
+							src = DBG_SRC_A;
+						}
 						break;
 					case 3:
 						pixel &= *plane_b;
+						if (output_disabled && pixel) {
+							src = DBG_SRC_B;
+						}
 						break;
 					}
 					uint32_t outpixel;
@@ -1539,25 +1590,31 @@
 	uint8_t is_mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5;
 	if (is_mode_5) {
 		if (context->flags2 & FLAG2_REGION_PAL) {
-			if (context->latched_mode & BIT_PAL) {
+			if (context->regs[REG_MODE_2] & BIT_PAL) {
 				if (context->vcounter == 0x10B) {
 					context->vcounter = 0x1D2;
 				}
 			} else if (context->vcounter == 0x103){
 				context->vcounter = 0x1CA;
 			}
-		} else if (!(context->latched_mode & BIT_PAL) &&  context->vcounter == 0xEB) {
-			context->vcounter = 0x1E5;
-		}
-		if (context->vcounter == 0x200 - context->border_top) {
-			latch_mode(context);
+		} else {
+			if (context->regs[REG_MODE_2] & BIT_PAL) {
+				if (context->vcounter == 0x100) {
+					context->vcounter = 0x1FA;
+				}
+			} else if (context->vcounter == 0xEB) {
+				context->vcounter = 0x1E5;
+			}
 		}
 	} else if (context->vcounter == 0xDB) {
 		context->vcounter = 0x1D5;
 	}
 	context->vcounter &= 0x1FF;
+	if (context->state == PREPARING) {
+		context->state = ACTIVE;
+	}
 
-	if (context->vcounter > context->inactive_start) {
+	if (context->state != ACTIVE) {
 		context->hint_counter = context->regs[REG_HINT];
 	} else if (context->hint_counter) {
 		context->hint_counter--;
@@ -1576,7 +1633,11 @@
 		}
 		context->vcounter &= 0x1FF;
 	} else {
-		if (context->vcounter == (context->inactive_start & 0x1FF)) {
+		uint16_t lines_max = (context->flags2 & FLAG2_REGION_PAL) 
+			? 240 + BORDER_TOP_V30_PAL + BORDER_BOT_V30_PAL 
+			: 224 + BORDER_TOP_V28 + BORDER_BOT_V28;
+
+		if (context->output_lines == lines_max) {
 			render_framebuffer_updated(context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN: FRAMEBUFFER_ODD, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER));
 			if (context->double_res) {
 				context->flags2 ^= FLAG2_EVEN_FIELD;
@@ -1584,15 +1645,16 @@
 			context->fb = render_get_framebuffer(context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD, &context->output_pitch);
 			context->h40_lines = 0;
 			context->frame++;
+			context->output_lines = 0;
 		}
 		uint32_t output_line;
-		if (context->vcounter < context->inactive_start + context->border_bot) {
-			output_line = context->border_top + context->vcounter;
-		} else if (context->vcounter > 0x200 - context->border_top) {
-			output_line = context->vcounter - (0x200 - context->border_top);
+		if (context->vcounter < context->inactive_start + context->border_bot && context->output_lines > 0) {
+			output_line = context->output_lines++;//context->border_top + context->vcounter;
+		} else if (context->vcounter >= 0x200 - context->border_top) {
+			output_line = context->output_lines++;//context->vcounter - (0x200 - context->border_top);
 		} else {
 			output_line = INVALID_LINE;
-		}		
+		}
 		context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * output_line);
 #ifdef DEBUG_FB_FILL
 		for (int i = 0; i < LINEBUF_SIZE; i++)
@@ -1770,7 +1832,7 @@
 	for (;;)
 	{
 	case 165:
-		if (context->vcounter == 0x1FF) {
+		if (context->state == PREPARING) {
 			uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
 			uint32_t *dst;
 			if (headless) {
@@ -1787,7 +1849,7 @@
 		}
 		CHECK_LIMIT
 	case 166:
-		if (context->vcounter == 0x1FF) {
+		if (context->state == PREPARING) {
 			uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
 			uint32_t *dst;
 			if (headless) {
@@ -1805,7 +1867,7 @@
 		CHECK_LIMIT
 	//sprite attribute table scan starts
 	case 167:
-		if (context->vcounter == 0x1FF) {
+		if (context->state == PREPARING) {
 			uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
 			uint32_t *dst;
 			if (headless) {
@@ -1977,7 +2039,7 @@
 	for (;;)
 	{
 	case 133:
-		if (context->vcounter == 0x1FF) {
+		if (context->state == PREPARING) {
 			uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
 			uint32_t *dst;
 			if (headless) {
@@ -1994,7 +2056,7 @@
 		}
 		CHECK_LIMIT
 	case 134:
-		if (context->vcounter == 0x1FF) {
+		if (context->state == PREPARING) {
 			uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
 			uint32_t *dst;
 			if (headless) {
@@ -2012,7 +2074,7 @@
 		CHECK_LIMIT
 	//sprite attribute table scan starts
 	case 135: //FIXME - Here
-		if (context->vcounter == 0x1FF) {
+		if (context->state == PREPARING) {
 			uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
 			uint32_t *dst;
 			if (headless) {
@@ -2288,12 +2350,6 @@
 	}
 }
 
-void latch_mode(vdp_context * context)
-{
-	context->latched_mode = context->regs[REG_MODE_2] & BIT_PAL;
-	update_video_params(context);
-}
-
 static void vdp_inactive(vdp_context *context, uint32_t target_cycles, uint8_t is_h40, uint8_t mode_5)
 {
 	uint8_t buf_clear_slot, index_reset_slot, bg_end_slot, vint_slot, line_change, jump_start, jump_dest;
@@ -2340,7 +2396,13 @@
 		bg_color = render_map_color(0, 0, 0);
 		jump_start = 147;
 		jump_dest = 233;
-		active_line = 0;
+		if (context->regs[REG_MODE_1] & BIT_MODE_4) {
+			//FIXME: This is actually 0x1FF like in Mode 5
+			active_line = 0;
+		} else {
+			//never active unless either mode 4 or mode 5 is turned on
+			active_line = 0x200;
+		}
 	}
 	uint32_t *dst = (
 		context->vcounter < context->inactive_start + context->border_bot 
@@ -2414,6 +2476,7 @@
 		if (context->hslot == line_change) {
 			vdp_advance_line(context);
 			if (context->vcounter == active_line) {
+				context->state = PREPARING;
 				return;
 			}
 		}
@@ -2426,16 +2489,11 @@
 	uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5;
 	while(context->cycles < target_cycles)
 	{
-		uint8_t active_slot;
-		if (mode_5) {
-			//line 0x1FF is basically active even though it's not displayed
-			active_slot = (context->vcounter < context->inactive_start || context->vcounter == 0x1FF) && (context->regs[REG_MODE_2] & DISPLAY_ENABLE);
-		} else {
-			//display is effectively disabled if neither mode 5 nor mode 4 are selected
-			active_slot = context->vcounter < context->inactive_start && (context->regs[REG_MODE_2] & DISPLAY_ENABLE) && (context->regs[REG_MODE_1] & BIT_MODE_4);
+		if (context->state == ACTIVE && context->vcounter == context->inactive_start) {
+			context->state = INACTIVE;
 		}
 		
-		if (active_slot) {
+		if (is_active(context)) {
 			if (mode_5) {
 				if (is_h40) {
 					vdp_h40(context, target_cycles);
@@ -2725,9 +2783,8 @@
 	if ((context->regs[REG_MODE_4] & BIT_INTERLACE) && !(context->flags2 & FLAG2_EVEN_FIELD)) {
 		value |= 0x10;
 	}
-	uint32_t line= context->vcounter;
 	uint32_t slot = context->hslot;
-	if ((line >= context->inactive_start && line < 0x1FF) || !(context->regs[REG_MODE_2] & BIT_DISP_EN)) {
+	if (!is_active(context)) {
 		value |= 0x8;
 	}
 	if (context->regs[REG_MODE_4] & BIT_H40) {
@@ -2856,34 +2913,39 @@
 	}
 }
 
+static void get_jump_params(vdp_context *context, uint32_t *jump_start, uint32_t *jump_dst)
+{
+	if (context->regs[REG_MODE_2] & BIT_MODE_5) {
+		if (context->flags2 & FLAG2_REGION_PAL) {
+			if (context->regs[REG_MODE_2] & BIT_PAL) {
+				*jump_start = 0x10B;
+				*jump_dst = 0x1D2;
+			} else {
+				*jump_start = 0x103;
+				*jump_dst = 0x1CA;
+			}
+		} else {
+			if (context->regs[REG_MODE_2] & BIT_PAL) {
+				*jump_start = 0x100;
+				*jump_dst = 0x1FA;
+			} else {
+				*jump_start = 0xEB;
+				*jump_dst = 0x1E5;
+			}
+		}
+	} else {
+		*jump_start = 0xDB;
+		*jump_dst = 0x1D5;
+	}
+}
+
 static uint32_t vdp_cycles_to_line(vdp_context * context, uint32_t target)
 {
 	uint32_t jump_start, jump_dst;
-	if (context->regs[REG_MODE_2] & BIT_MODE_5) {
-		if (context->flags2 & FLAG2_REGION_PAL) {
-			if (context->latched_mode & BIT_PAL) {
-				jump_start = 0x10B;
-				jump_dst = 0x1D2;
-			} else {
-				jump_start = 0x103;
-				jump_dst = 0x1CA;
-			}
-		} else {
-			if (context->latched_mode & BIT_PAL) {
-				jump_start = 0;
-				jump_dst = 0;
-			} else {
-				jump_start = 0xEB;
-				jump_dst = 0x1E5;
-			}
-		}
-	} else {
-		jump_start = 0xDB;
-		jump_dst = 0x1D5;
-	}
+	get_jump_params(context, &jump_start, &jump_dst);
 	uint32_t lines;
 	if (context->vcounter < target) {
-		if (target < jump_start) {
+		if (target < jump_start || context->vcounter > jump_start) {
 			lines = target - context->vcounter;
 		} else {
 			lines = jump_start - context->vcounter + target - jump_dst;
@@ -2917,15 +2979,31 @@
 		return context->pending_hint_start;
 	}
 	uint32_t hint_line;
-	if (context->vcounter + context->hint_counter >= context->inactive_start) {
-		if (context->regs[REG_HINT] > context->inactive_start) {
+	if (context->state != ACTIVE) {
+		hint_line = context->regs[REG_HINT];
+		if (hint_line > context->inactive_start) {
 			return 0xFFFFFFFF;
 		}
-		hint_line = context->regs[REG_HINT];
 	} else {
 		hint_line = context->vcounter + context->hint_counter + 1;
+		if (context->vcounter < context->inactive_start) {
+			if (hint_line > context->inactive_start) {
+				hint_line = context->regs[REG_HINT];
+				if (hint_line > context->inactive_start) {
+					return 0xFFFFFFFF;
+				}
+			}
+		} else {
+			uint32_t jump_start, jump_dst;
+			get_jump_params(context, &jump_start, &jump_dst);
+			if (hint_line >= jump_start && context->vcounter < jump_dst) {
+				hint_line = (hint_line + jump_dst - jump_start) & 0x1FF;
+			}
+			if (hint_line < context->vcounter && hint_line > context->inactive_start) {
+				return 0xFFFFFFFF;
+			}
+		}
 	}
-
 	return context->cycles + vdp_cycles_to_line(context, hint_line);
 }
 
--- a/vdp.h	Fri Apr 21 01:19:40 2017 -0700
+++ b/vdp.h	Fri Apr 21 01:22:52 2017 -0700
@@ -177,9 +177,9 @@
 	uint16_t    border_bot;
 	uint16_t    hscroll_a;
 	uint16_t    hscroll_b;
-	uint16_t     h40_lines;
+	uint16_t    h40_lines;
+	uint16_t    output_lines;
 	uint8_t     hslot; //hcounter/2
-	uint8_t     latched_mode;
 	uint8_t	    sprite_index;
 	uint8_t     sprite_draws;
 	int8_t      slot_counter;
@@ -204,6 +204,7 @@
 	uint8_t     debug;
 	uint8_t     debug_pal;
 	uint8_t     pending_byte;
+	uint8_t     state;
 	uint8_t     *tmp_buf_a;
 	uint8_t     *tmp_buf_b;
 } vdp_context;