changeset 1167:e758ddbf0624

Initial work on emulating top and bottom border area
author Michael Pavone <pavone@retrodev.com>
date Sun, 15 Jan 2017 15:07:24 -0800
parents 73e36dac5be7
children fa73a77ddf92
files render_sdl.c vdp.c vdp.h
diffstat 3 files changed, 127 insertions(+), 85 deletions(-) [+]
line wrap: on
line diff
--- a/render_sdl.c	Tue Jan 10 23:45:59 2017 -0800
+++ b/render_sdl.c	Sun Jan 15 15:07:24 2017 -0800
@@ -187,7 +187,7 @@
 }
 #endif
 
-static uint32_t texture_buf[512 * 256];
+static uint32_t texture_buf[512 * 513];
 static void render_alloc_surfaces()
 {
 	static uint8_t texture_init;
@@ -210,6 +210,7 @@
 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 			if (i < 2) {
+				//TODO: Fixme for PAL + invalid display mode
 				glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, texture_buf);
 			} else {
 				uint32_t blank = 255 << 24;
@@ -242,7 +243,7 @@
 	} else {
 #endif
 		
-		//height=480 to fit interlaced output
+		//TODO: Fixme for PAL + invalid display mode
 		sdl_textures[0] = sdl_textures[1] = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 320, 480);
 #ifndef DISABLE_OPENGL
 	}
--- a/vdp.c	Tue Jan 10 23:45:59 2017 -0800
+++ b/vdp.c	Sun Jan 15 15:07:24 2017 -0800
@@ -41,6 +41,20 @@
 #define VBLANK_START_H32 (LINE_CHANGE_H32+2)
 #define FIFO_LATENCY    3
 
+#define BORDER_TOP_V24     27
+#define BORDER_TOP_V28     11
+#define BORDER_TOP_V24_PAL 54
+#define BORDER_TOP_V28_PAL 38
+#define BORDER_TOP_V30_PAL 30
+
+#define BORDER_BOT_V24     24
+#define BORDER_BOT_V28     8
+#define BORDER_BOT_V24_PAL 48
+#define BORDER_BOT_V28_PAL 32
+#define BORDER_BOT_V30_PAL 24
+
+#define INVALID_LINE 0x200
+
 static int32_t color_map[1 << 12];
 static uint16_t mode4_address_map[0x4000];
 static uint32_t planar_to_chunky[256];
@@ -54,6 +68,40 @@
 	{127, 0, 127}    //Sprites
 };
 
+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->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;
+			}
+		} else {
+			context->inactive_start = NTSC_INACTIVE_START;
+			if (context->flags2 & FLAG2_REGION_PAL) {
+				context->border_top = BORDER_TOP_V28_PAL;
+				context->border_bot = BORDER_BOT_V28_PAL;
+			} else {
+				context->border_top = BORDER_TOP_V28;
+				context->border_bot = BORDER_TOP_V28;
+			}
+		}
+	} else {
+		context->inactive_start = MODE4_INACTIVE_START;
+		if (context->flags2 & FLAG2_REGION_PAL) {
+			context->border_top = BORDER_TOP_V24_PAL;
+			context->border_bot = BORDER_BOT_V24_PAL;
+		} else {
+			context->border_top = BORDER_TOP_V24;
+			context->border_bot = BORDER_BOT_V24;
+		}
+	}
+}
+
 static uint8_t color_map_init_done;
 
 void init_vdp_context(vdp_context * context, uint8_t region_pal)
@@ -67,7 +115,7 @@
 		context->output = malloc(LINEBUF_SIZE);
 		context->output_pitch = 0;
 	} else {
-		context->output = render_get_framebuffer(FRAMEBUFFER_ODD, &context->output_pitch);
+		context->fb = render_get_framebuffer(FRAMEBUFFER_ODD, &context->output_pitch);
 	}
 	context->linebuf = malloc(LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2);
 	memset(context->linebuf, 0, LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2);
@@ -163,6 +211,10 @@
 	if (region_pal) {
 		context->flags2 |= FLAG2_REGION_PAL;
 	}
+	update_video_params(context);
+	if (!headless) {
+		context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * context->border_top);
+	}
 }
 
 void vdp_free(vdp_context *context)
@@ -1115,15 +1167,28 @@
 
 static void render_map_output(uint32_t line, int32_t col, vdp_context * context)
 {
+	uint32_t *dst;
+	if (line == 0x1FF) {
+		if (!col) {
+			return;
+		}
+		col -= 2;
+		dst = context->output + col * 8;
+		uint32_t color = context->colors[context->regs[REG_BG_COLOR]];
+		for (int i = 0; i < 16; i++)
+		{
+			*(dst++) = color;
+		}
+		return;
+	}
 	if (line >= 240) {
 		return;
 	}
-	render_map(context->col_2, context->tmp_buf_b, context->buf_b_off+8, context);
-	uint32_t *dst;
 	uint8_t *sprite_buf,  *plane_a, *plane_b;
 	int plane_a_off, plane_b_off;
 	if (col)
 	{
+		render_map(context->col_2, context->tmp_buf_b, context->buf_b_off+8, context);
 		col-=2;
 		dst = context->output + col * 8;
 		if (context->debug < 2) {
@@ -1373,7 +1438,7 @@
 static void vdp_advance_line(vdp_context *context)
 {
 	context->vcounter++;
-	context->vcounter &= 0x1FF;
+	
 	uint8_t is_mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5;
 	if (is_mode_5) {
 		if (context->flags2 & FLAG2_REGION_PAL) {
@@ -1390,29 +1455,34 @@
 	} else if (context->vcounter == 0xDB) {
 		context->vcounter = 0x1D5;
 	}
-	uint32_t inactive_start = (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START);
-	if (!is_mode_5) {
-		inactive_start = MODE4_INACTIVE_START;
-	}
-	if (!headless) {
-		if (!context->vcounter && !context->output) {
-			context->output = render_get_framebuffer(context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD, &context->output_pitch);
-			context->h40_lines = 0;
-		} else if (context->vcounter == inactive_start) { //TODO: Change this once border emulation is added
-			context->output = NULL;
-			render_framebuffer_updated(context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN: FRAMEBUFFER_ODD, context->h40_lines > inactive_start / 2 ? 320 : 256);
+	if (headless) {
+		context->vcounter &= 0x1FF;
+	} else {
+		if (context->vcounter == context->inactive_start) {
+			render_framebuffer_updated(context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN: FRAMEBUFFER_ODD, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? 320 : 256);
 			if (context->double_res) {
 				context->flags2 ^= FLAG2_EVEN_FIELD;
 			}
-		} else if (context->output) {
-			context->output = (uint32_t *)(((char *)context->output) + context->output_pitch);
-			if (context->regs[REG_MODE_4] & BIT_H40) {
-				context->h40_lines++;
-			}
+			context->fb = render_get_framebuffer(context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD, &context->output_pitch);
+			context->h40_lines = 0;
+			context->frame++;
+		}
+		context->vcounter &= 0x1FF;
+		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);
+		} else {
+			output_line = INVALID_LINE;
+		}		
+		context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * output_line);
+		if (output_line != INVALID_LINE && (context->regs[REG_MODE_4] & BIT_H40)) {
+			context->h40_lines++;
 		}
 	}
 
-	if (context->vcounter > inactive_start) {
+	if (context->vcounter > context->inactive_start) {
 		context->hint_counter = context->regs[REG_HINT];
 	} else if (context->hint_counter) {
 		context->hint_counter--;
@@ -1673,7 +1743,7 @@
 		scan_sprite_table(context->vcounter, context);//Just a guess
 		CHECK_LIMIT
 	case 0:
-		if (context->vcounter == (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START)) {
+		if (context->vcounter == context->inactive_start) {
 			context->flags2 |= FLAG2_VINT_PENDING;
 			context->pending_vint_start = context->cycles;
 		}
@@ -1721,7 +1791,7 @@
 	case 164:
 		render_sprite_cells(context);
 		vdp_advance_line(context);
-		if (context->vcounter == (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START)) {
+		if (context->vcounter == context->inactive_start) {
 			context->hslot++;
 			context->cycles += slot_cycles;
 			return;
@@ -1876,7 +1946,7 @@
 	case 132:
 		render_sprite_cells(context);
 		vdp_advance_line(context);
-		if (context->vcounter == (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START)) {
+		if (context->vcounter == context->inactive_start) {
 			context->hslot++;
 			context->cycles += slot_cycles;
 			return;
@@ -2016,6 +2086,7 @@
 void latch_mode(vdp_context * context)
 {
 	context->latched_mode = context->regs[REG_MODE_2] & BIT_PAL;
+	update_video_params(context);
 }
 
 static void check_render_bg(vdp_context * context, int32_t line, uint32_t slot)
@@ -2031,7 +2102,9 @@
 		}
 	}
 	if (starti >= 0) {
-		uint32_t color = context->colors[context->regs[REG_BG_COLOR]];
+		uint32_t color = (context->regs[REG_MODE_2] & BIT_MODE_5)
+			? context->colors[context->regs[REG_BG_COLOR]]
+			: context->colors[CRAM_SIZE * 3 + 0x10 + (context->regs[REG_BG_COLOR] & 0xF)];
 		uint32_t * start = context->output + starti;
 		for (int i = 0; i < 2; i++) {
 			*(start++) = color;
@@ -2042,22 +2115,17 @@
 
 void vdp_run_context(vdp_context * context, uint32_t target_cycles)
 {
+	uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40;
+	uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5;
 	while(context->cycles < target_cycles)
 	{
-		uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40;
-		uint8_t active_slot, mode_5;
-		uint32_t inactive_start;
-		if (context->regs[REG_MODE_2] & BIT_MODE_5) {
-			//Mode 5 selected
-			mode_5 = 1;
-			inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START;
+		uint8_t active_slot;
+		if (mode_5) {
 			//line 0x1FF is basically active even though it's not displayed
-			active_slot = (context->vcounter < inactive_start || context->vcounter == 0x1FF) && (context->regs[REG_MODE_2] & DISPLAY_ENABLE);
+			active_slot = (context->vcounter < context->inactive_start || context->vcounter == 0x1FF) && (context->regs[REG_MODE_2] & DISPLAY_ENABLE);
 		} else {
-			mode_5 = 0;
-			inactive_start = MODE4_INACTIVE_START;
 			//display is effectively disabled if neither mode 5 nor mode 4 are selected
-			active_slot = context->vcounter < inactive_start && (context->regs[REG_MODE_2] & DISPLAY_ENABLE) && (context->regs[REG_MODE_1] & BIT_MODE_4);
+			active_slot = context->vcounter < context->inactive_start && (context->regs[REG_MODE_2] & DISPLAY_ENABLE) && (context->regs[REG_MODE_1] & BIT_MODE_4);
 		}
 		
 		if (active_slot) {
@@ -2097,7 +2165,7 @@
 					context->sprite_draws = MAX_DRAWS_H32_MODE4;
 				}
 			}
-			if(context->vcounter == inactive_start) {
+			if(context->vcounter == context->inactive_start) {
 				uint32_t intslot = context->regs[REG_MODE_4] & BIT_H40 ? VINT_SLOT_H40 :  VINT_SLOT_H32;
 				if (context->hslot == intslot) {
 					context->flags2 |= FLAG2_VINT_PENDING;
@@ -2119,7 +2187,7 @@
 			if (!is_refresh(context, context->hslot)) {
 				external_slot(context);
 			}
-			if (context->vcounter < inactive_start) {
+			if (context->vcounter < (context->inactive_start + context->border_bot) || context->vcounter > 0x200 - context->border_top) {
 				check_render_bg(context, context->vcounter, context->hslot);
 			}
 			if (context->flags & FLAG_DMA_RUN && !is_refresh(context, context->hslot)) {
@@ -2130,18 +2198,12 @@
 			if (is_h40) {
 				if (context->hslot == LINE_CHANGE_H40) {
 					vdp_advance_line(context);
-					if (context->vcounter == (inactive_start + 8)) {
-						context->frame++;
-					}
 				} else if (context->hslot == 183) {
 					context->hslot = 229;
 				}
 			} else {
 				if (context->hslot == (mode_5 ? LINE_CHANGE_H32 : LINE_CHANGE_MODE4)) {
 					vdp_advance_line(context);
-					if (context->vcounter == (inactive_start + 8)) {
-						context->frame++;
-					}
 				} else if (context->hslot == 148) {
 					context->hslot = 233;
 				}
@@ -2152,8 +2214,10 @@
 
 uint32_t vdp_run_to_vblank(vdp_context * context)
 {
-	uint32_t target_cycles = ((context->latched_mode & BIT_PAL) ? PAL_INACTIVE_START : NTSC_INACTIVE_START) * MCLKS_LINE;
-	vdp_run_context(context, target_cycles);
+	uint32_t old_frame = context->frame;
+	while (context->frame == old_frame) {
+		vdp_run_context(context, MCLKS_LINE);
+	}
 	return context->cycles;
 }
 
@@ -2275,6 +2339,9 @@
 						context->flags2 &= ~FLAG2_EVEN_FIELD;
 					}
 				}
+				if (reg == REG_MODE_2) {
+					update_video_params(context);
+				}
 			}
 		} else if (mode_5) {
 			context->flags |= FLAG_PENDING;
@@ -2412,11 +2479,7 @@
 	}
 	uint32_t line= context->vcounter;
 	uint32_t slot = context->hslot;
-	uint32_t inactive_start = (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START);
-	if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) {
-		inactive_start = MODE4_INACTIVE_START;
-	}
-	if ((line >= inactive_start && line < 0x1FF) || !(context->regs[REG_MODE_2] & BIT_DISP_EN)) {
+	if ((line >= context->inactive_start && line < 0x1FF) || !(context->regs[REG_MODE_2] & BIT_DISP_EN)) {
 		value |= 0x8;
 	}
 	if (context->regs[REG_MODE_4] & BIT_H40) {
@@ -2592,28 +2655,9 @@
 	return MCLKS_LINE * (lines - 1) + vdp_cycles_next_line(context);
 }
 
-static uint32_t vdp_frame_end_line(vdp_context * context)
-{
-	uint32_t frame_end;
-	if (context->flags2 & FLAG2_REGION_PAL) {
-		if (context->latched_mode & BIT_PAL) {
-			frame_end = PAL_INACTIVE_START + 8;
-		} else {
-			frame_end = NTSC_INACTIVE_START + 8;
-		}
-	} else {
-		if (context->latched_mode & BIT_PAL) {
-			frame_end = 512;
-		} else {
-			frame_end = NTSC_INACTIVE_START + 8;
-		}
-	}
-	return frame_end;
-}
-
 uint32_t vdp_cycles_to_frame_end(vdp_context * context)
 {
-	return context->cycles + vdp_cycles_to_line(context, vdp_frame_end_line(context));
+	return context->cycles + vdp_cycles_to_line(context, context->inactive_start);
 }
 
 uint32_t vdp_next_hint(vdp_context * context)
@@ -2624,12 +2668,9 @@
 	if (context->flags2 & FLAG2_HINT_PENDING) {
 		return context->pending_hint_start;
 	}
-	uint32_t inactive_start = (context->regs[REG_MODE_2] & BIT_MODE_5)
-		? (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START)
-		: MODE4_INACTIVE_START;
 	uint32_t hint_line;
-	if (context->vcounter + context->hint_counter >= inactive_start) {
-		if (context->regs[REG_HINT] > inactive_start) {
+	if (context->vcounter + context->hint_counter >= context->inactive_start) {
+		if (context->regs[REG_HINT] > context->inactive_start) {
 			return 0xFFFFFFFF;
 		}
 		hint_line = context->regs[REG_HINT];
@@ -2655,11 +2696,7 @@
 
 uint32_t vdp_next_vint_z80(vdp_context * context)
 {
-	uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START;
-	if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) {
-		inactive_start = MODE4_INACTIVE_START;
-	}
-	if (context->vcounter == inactive_start) {
+	if (context->vcounter == context->inactive_start) {
 		if (context->regs[REG_MODE_2] & BIT_MODE_5) {
 			if (context->regs[REG_MODE_4] & BIT_H40) {
 				if (context->hslot >= LINE_CHANGE_H40 && context->hslot <= VINT_SLOT_H40) {
@@ -2696,7 +2733,7 @@
 			}
 		}
 	}
-	int32_t cycles_to_vint = vdp_cycles_to_line(context, inactive_start);
+	int32_t cycles_to_vint = vdp_cycles_to_line(context, context->inactive_start);
 	if (context->regs[REG_MODE_2] & BIT_MODE_5) {
 		if (context->regs[REG_MODE_4] & BIT_H40) {
 			cycles_to_vint += MCLKS_LINE - (LINE_CHANGE_H40 + (256 - VINT_SLOT_H40)) * MCLKS_SLOT_H40;
--- a/vdp.h	Tue Jan 10 23:45:59 2017 -0800
+++ b/vdp.h	Sun Jan 15 15:07:24 2017 -0800
@@ -155,6 +155,7 @@
 	uint8_t     *linebuf;
 	//pointer to current line in framebuffer
 	uint32_t    *output;
+	uint32_t    *fb;
 	system_header  *system;
 	uint16_t    cram[CRAM_SIZE];
 	uint32_t    colors[CRAM_SIZE*4];
@@ -164,13 +165,16 @@
 	uint32_t    output_pitch;
 	uint32_t    frame;
 	uint16_t    vcounter;
+	uint16_t    inactive_start;
+	uint16_t    border_top;
+	uint16_t    border_bot;
 	uint16_t    hscroll_a;
 	uint16_t    hscroll_b;
+	uint16_t     h40_lines;
 	uint8_t     hslot; //hcounter/2
 	uint8_t     latched_mode;
 	uint8_t	    sprite_index;
 	uint8_t     sprite_draws;
-	uint8_t     h40_lines;
 	int8_t      slot_counter;
 	int8_t      cur_slot;
 	sprite_draw sprite_draw_list[MAX_DRAWS];