changeset 623:66cc60215e5c

Fix most of the breakage caused by the vcounter/hcounter changes
author Michael Pavone <pavone@retrodev.com>
date Wed, 18 Jun 2014 16:30:19 -0700
parents b76d2a628ab9
children 788545f4064f
files blastem.c vdp.c vdp.h
diffstat 3 files changed, 168 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- a/blastem.c	Tue Jun 17 19:01:01 2014 -0700
+++ b/blastem.c	Wed Jun 18 16:30:19 2014 -0700
@@ -33,7 +33,7 @@
 
 #define MAX_SOUND_CYCLES 100000
 
-uint32_t mclks_per_frame = MCLKS_LINE*LINES_NTSC;
+uint32_t mclk_target = 0;
 
 uint16_t cart[CARTRIDGE_WORDS];
 uint16_t ram[RAM_WORDS];
@@ -231,15 +231,15 @@
 	z80_context * z_context = gen->z80;
 	uint32_t mclks = context->current_cycle * MCLKS_PER_68K;
 	sync_z80(z_context, mclks);
-	if (mclks >= mclks_per_frame) {
+	if (mclks >= mclk_target) {
 		sync_sound(gen, mclks);
-		gen->ym->current_cycle -= mclks_per_frame;
-		gen->psg->cycles -= mclks_per_frame;
+		gen->ym->current_cycle -= mclk_target;
+		gen->psg->cycles -= mclk_target;
 		if (gen->ym->write_cycle != CYCLE_NEVER) {
-			gen->ym->write_cycle = gen->ym->write_cycle >= mclks_per_frame/MCLKS_PER_68K ? gen->ym->write_cycle - mclks_per_frame/MCLKS_PER_68K : 0;
+			gen->ym->write_cycle = gen->ym->write_cycle >= mclk_target/MCLKS_PER_68K ? gen->ym->write_cycle - mclk_target/MCLKS_PER_68K : 0;
 		}
 		//printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks);
-		vdp_run_context(v_context, mclks_per_frame);
+		vdp_run_context(v_context, mclk_target);
 
 		if (!headless) {
 			break_on_sync |= wait_render_frame(v_context, frame_limit);
@@ -250,28 +250,29 @@
 			}
 		}
 		frame++;
-		mclks -= mclks_per_frame;
-		vdp_adjust_cycles(v_context, mclks_per_frame);
-		io_adjust_cycles(gen->ports, context->current_cycle, mclks_per_frame/MCLKS_PER_68K);
-		io_adjust_cycles(gen->ports+1, context->current_cycle, mclks_per_frame/MCLKS_PER_68K);
-		io_adjust_cycles(gen->ports+2, context->current_cycle, mclks_per_frame/MCLKS_PER_68K);
+		mclks -= mclk_target;
+		vdp_adjust_cycles(v_context, mclk_target);
+		io_adjust_cycles(gen->ports, context->current_cycle, mclk_target/MCLKS_PER_68K);
+		io_adjust_cycles(gen->ports+1, context->current_cycle, mclk_target/MCLKS_PER_68K);
+		io_adjust_cycles(gen->ports+2, context->current_cycle, mclk_target/MCLKS_PER_68K);
 		if (busack_cycle != CYCLE_NEVER) {
-			if (busack_cycle > mclks_per_frame/MCLKS_PER_68K) {
-				busack_cycle -= mclks_per_frame/MCLKS_PER_68K;
+			if (busack_cycle > mclk_target/MCLKS_PER_68K) {
+				busack_cycle -= mclk_target/MCLKS_PER_68K;
 			} else {
 				busack_cycle = CYCLE_NEVER;
 				busack = new_busack;
 			}
 		}
-		context->current_cycle -= mclks_per_frame/MCLKS_PER_68K;
-		if (z_context->current_cycle >= mclks_per_frame/MCLKS_PER_Z80) {
-			z_context->current_cycle -= mclks_per_frame/MCLKS_PER_Z80;
+		context->current_cycle -= mclk_target/MCLKS_PER_68K;
+		if (z_context->current_cycle >= mclk_target/MCLKS_PER_Z80) {
+			z_context->current_cycle -= mclk_target/MCLKS_PER_Z80;
 		} else {
 			z_context->current_cycle = 0;
 		}
 		if (mclks) {
 			vdp_run_context(v_context, mclks);
 		}
+		mclk_target = vdp_cycles_to_frame_end(v_context);
 	} else {
 		//printf("running VDP for %d cycles\n", mclks - v_context->cycles);
 		vdp_run_context(v_context, mclks);
@@ -317,10 +318,10 @@
 			gen->bus_busy = 1;
 			while (vdp_data_port_write(v_context, value) < 0) {
 				while(v_context->flags & FLAG_DMA_RUN) {
-					vdp_run_dma_done(v_context, mclks_per_frame);
-					if (v_context->cycles >= mclks_per_frame) {
+					vdp_run_dma_done(v_context, mclk_target);
+					if (v_context->cycles >= mclk_target) {
 						context->current_cycle = v_context->cycles / MCLKS_PER_68K;
-						if (context->current_cycle * MCLKS_PER_68K < mclks_per_frame) {
+						if (context->current_cycle * MCLKS_PER_68K < mclk_target) {
 							++context->current_cycle;
 						}
 						sync_components(context, 0);
@@ -334,10 +335,10 @@
 			if (blocked) {
 				while (blocked) {
 					while(v_context->flags & FLAG_DMA_RUN) {
-						vdp_run_dma_done(v_context, mclks_per_frame);
-						if (v_context->cycles >= mclks_per_frame) {
+						vdp_run_dma_done(v_context, mclk_target);
+						if (v_context->cycles >= mclk_target) {
 							context->current_cycle = v_context->cycles / MCLKS_PER_68K;
-							if (context->current_cycle * MCLKS_PER_68K < mclks_per_frame) {
+							if (context->current_cycle * MCLKS_PER_68K < mclk_target) {
 								++context->current_cycle;
 							}
 							sync_components(context, 0);
@@ -966,7 +967,7 @@
 	context.system = gen;
 	//cartridge ROM
 	context.mem_pointers[0] = cart;
-	context.target_cycle = context.sync_cycle = mclks_per_frame/MCLKS_PER_68K;
+	context.target_cycle = context.sync_cycle = mclk_target/MCLKS_PER_68K;
 	//work RAM
 	context.mem_pointers[1] = ram;
 	//save RAM/map
@@ -1210,7 +1211,6 @@
 	height = height < 240 ? (width/320) * 240 : height;
 	uint32_t fps = 60;
 	if (version_reg & 0x40) {
-		mclks_per_frame = MCLKS_LINE * LINES_PAL;
 		fps = 50;
 	}
 	if (!headless) {
@@ -1221,7 +1221,8 @@
 	memset(&gen, 0, sizeof(gen));
 	gen.master_clock = gen.normal_clock = fps == 60 ? MCLKS_NTSC : MCLKS_PAL;
 
-	init_vdp_context(&v_context);
+	init_vdp_context(&v_context, version_reg & 0x40);
+	mclk_target = vdp_cycles_to_frame_end(&v_context);
 
 	ym2612_context y_context;
 	ym_init(&y_context, render_sample_rate(), gen.master_clock, MCLKS_PER_YM, render_audio_buffer(), ym_log ? YM_OPT_WAVE_LOG : 0);
@@ -1236,7 +1237,7 @@
 
 	z_context.system = &gen;
 	z_context.mem_pointers[0] = z80_ram;
-	z_context.sync_cycle = z_context.target_cycle = mclks_per_frame/MCLKS_PER_Z80;
+	z_context.sync_cycle = z_context.target_cycle = mclk_target/MCLKS_PER_Z80;
 	z_context.int_cycle = CYCLE_NEVER;
 	z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart;
 
--- a/vdp.c	Tue Jun 17 19:01:01 2014 -0700
+++ b/vdp.c	Wed Jun 18 16:30:19 2014 -0700
@@ -46,7 +46,7 @@
 
 uint8_t color_map_init_done;
 
-void init_vdp_context(vdp_context * context)
+void init_vdp_context(vdp_context * context, uint8_t region_pal)
 {
 	memset(context, 0, sizeof(*context));
 	context->vdpmem = malloc(VRAM_SIZE);
@@ -133,6 +133,9 @@
 			context->debugcolors[color] = render_map_color(r, g, b);
 		}
 	}
+	if (region_pal) {
+		context->flags2 |= FLAG2_REGION_PAL;
+	}
 }
 
 int is_refresh(vdp_context * context, uint32_t slot)
@@ -1428,7 +1431,7 @@
 			latch_mode(context);
 		}
 		uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40;
-		if (is_h40 && slot == 167 || !is_h40 && slot == 134) {
+		if (is_h40 && slot == HBLANK_START_H40 || !is_h40 && slot == 134) {
 			if (line >= inactive_start) {
 				context->hint_counter = context->regs[REG_HINT];
 			} else if (context->hint_counter) {
@@ -1467,7 +1470,7 @@
 		if (context->regs[REG_MODE_2] & DISPLAY_ENABLE && active_slot) {
 			//run VDP rendering for a slot or a line
 			if (is_h40) {
-				if (slot == 167 && line < inactive_start && (target_cycles - context->cycles) >= MCLKS_LINE) {
+				if (slot == HBLANK_START_H40 && line < inactive_start && (target_cycles - context->cycles) >= MCLKS_LINE) {
 					vdp_h40_line(line, context);
 					inccycles = MCLKS_LINE;
 					context->vcounter++;
@@ -1493,7 +1496,7 @@
 			context->hslot++;
 			context->hslot &= 0xFF;
 			if (is_h40) {
-				if (context->hslot == 167) {
+				if (context->hslot == HBLANK_START_H40) {
 					context->vcounter++;
 				} else if (context->hslot == 183) {
 					context->hslot = 229;
@@ -1507,10 +1510,17 @@
 			}
 
 		}
-		if (context->vcounter == 0xEA) {
-			context->vcounter += 0xFA;
-		} else {
-			context->vcounter &= 0x1FF;
+		context->vcounter &= 0x1FF;
+		if (context->flags2 & FLAG2_REGION_PAL) {
+			if (context->latched_mode & 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;
 		}
 		context->cycles += inccycles;
 	}
@@ -1757,6 +1767,7 @@
 			line |= 1;
 		}
 	}
+	printf("hv_counter_read line: %d, horiz: %d, cycles: %d\n", line, linecyc, context->cycles);
 	return (line << 8) | linecyc;
 }
 
@@ -1782,6 +1793,88 @@
 	}
 }
 
+uint32_t vdp_cycles_next_line(vdp_context * context)
+{
+	if (context->regs[REG_MODE_4] & BIT_H40) {
+		if (context->hslot < HBLANK_START_H40) {
+			return (HBLANK_START_H40 - context->hslot) * MCLKS_SLOT_H40;
+		} else if (context->hslot < 183) {
+			return MCLKS_LINE - (context->hslot - HBLANK_START_H40) * MCLKS_SLOT_H40;
+		} else {
+			return (256-context->hslot + HBLANK_START_H40) * MCLKS_SLOT_H40;
+		}
+	} else {
+		if (context->hslot < HBLANK_START_H32) {
+			return (HBLANK_START_H32 - context->hslot) * MCLKS_SLOT_H32;
+		} else if (context->hslot < 148) {
+			return MCLKS_LINE - (context->hslot - HBLANK_START_H32) * MCLKS_SLOT_H32;
+		} else {
+			return (256-context->hslot + HBLANK_START_H32) * MCLKS_SLOT_H32;
+		}
+	}
+}
+
+uint32_t vdp_cycles_to_line(vdp_context * context, uint32_t target)
+{
+	uint32_t jump_start, jump_dst;
+	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;
+		}
+	}
+	uint32_t lines;
+	if (context->vcounter < target) {
+		if (target < jump_start) {
+			lines = target - context->vcounter;
+		} else {
+			lines = jump_start - context->vcounter + target - jump_dst;
+		}
+	} else {
+		if (context->vcounter < jump_start) {
+			lines = jump_start - context->vcounter + 512 - jump_dst;
+		} else {
+			lines = 512 - context->vcounter;
+		}
+		if (target < jump_start) {
+			lines += target;
+		} else {
+			lines += jump_start + target - jump_dst;
+		}
+	}
+	return MCLKS_LINE * (lines - 1) + vdp_cycles_next_line(context);
+}
+
+uint32_t vdp_cycles_to_frame_end(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 context->cycles + vdp_cycles_to_line(context, frame_end);
+}
+
 uint32_t vdp_next_hint(vdp_context * context)
 {
 	if (!(context->regs[REG_MODE_1] & BIT_HINT_EN)) {
@@ -1791,13 +1884,14 @@
 		return context->cycles;
 	}
 	uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START;
-	uint32_t line = context->cycles / MCLKS_LINE;
-	if (line >= inactive_start) {
-		return 0xFFFFFFFF;
+	uint32_t hint_line;
+	if (context->vcounter >= inactive_start) {
+		hint_line = context->regs[REG_HINT];
+	} else {
+		hint_line = context->vcounter + context->hint_counter + 1;
 	}
-	uint32_t linecyc = context->cycles % MCLKS_LINE;
-	uint32_t hcycle = context->cycles + context->hint_counter * MCLKS_LINE + MCLKS_LINE - linecyc;
-	return hcycle;
+
+	return context->cycles + vdp_cycles_to_line(context, hint_line);
 }
 
 uint32_t vdp_next_vint(vdp_context * context)
@@ -1808,29 +1902,44 @@
 	if (context->flags2 & FLAG2_VINT_PENDING) {
 		return context->cycles;
 	}
-	uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START;
-	uint32_t vcycle =  MCLKS_LINE * inactive_start;
-	if (context->regs[REG_MODE_4] & BIT_H40) {
-		vcycle += VINT_SLOT_H40 * MCLKS_SLOT_H40;
-	} else {
-		vcycle += VINT_SLOT_H32 * MCLKS_SLOT_H32;
-	}
-	if (vcycle < context->cycles) {
-		return 0xFFFFFFFF;
-	}
-	return vcycle;
+
+
+	return vdp_next_vint_z80(context);
 }
 
 uint32_t vdp_next_vint_z80(vdp_context * context)
 {
 	uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START;
-	uint32_t vcycle =  MCLKS_LINE * inactive_start;
+	if (context->vcounter == inactive_start) {
+		if (context->regs[REG_MODE_4] & BIT_H40) {
+			if (context->hslot >= HBLANK_START_H40) {
+				if (context->hslot < 183) {
+					return context->cycles + (VINT_SLOT_H40 + 183 - context->hslot + 256 - 229) * MCLKS_SLOT_H40;
+				} else {
+					return context->cycles + (VINT_SLOT_H40 + 256 - context->hslot) * MCLKS_SLOT_H40;
+				}
+			} else if (context->hslot < VINT_SLOT_H40) {
+				return context->cycles + (VINT_SLOT_H40 - context->hslot) * MCLKS_SLOT_H40;
+			}
+		} else {
+			if (context->hslot >= HBLANK_START_H32) {
+				if (context->hslot < 148) {
+					return context->cycles + (VINT_SLOT_H32 + 148 - context->hslot + 256 - 233) * MCLKS_SLOT_H32;
+				} else {
+					return context->cycles + (VINT_SLOT_H32 + 256 - context->hslot) * MCLKS_SLOT_H32;
+				}
+			} else if (context->hslot < VINT_SLOT_H32) {
+				return context->cycles + (VINT_SLOT_H32 - context->hslot) * MCLKS_SLOT_H32;
+			}
+		}
+	}
+	int32_t cycles_to_vint = vdp_cycles_to_line(context, inactive_start);
 	if (context->regs[REG_MODE_4] & BIT_H40) {
-		vcycle += VINT_SLOT_H40 * MCLKS_SLOT_H40;
+		cycles_to_vint += (VINT_SLOT_H40 + 183 - HBLANK_START_H40 + 256 - 229) * MCLKS_SLOT_H40;
 	} else {
-		vcycle += VINT_SLOT_H32 * MCLKS_SLOT_H32;
+		cycles_to_vint += (VINT_SLOT_H32 + 148 - HBLANK_START_H32 + 256 - 233) * MCLKS_SLOT_H32;
 	}
-	return vcycle;
+	return context->cycles + cycles_to_vint;
 }
 
 void vdp_int_ack(vdp_context * context, uint16_t int_num)
--- a/vdp.h	Tue Jun 17 19:01:01 2014 -0700
+++ b/vdp.h	Wed Jun 18 16:30:19 2014 -0700
@@ -49,6 +49,7 @@
 #define FLAG2_HINT_PENDING   0x02
 #define FLAG2_READ_PENDING   0x04
 #define FLAG2_SPRITE_COLLIDE 0x08
+#define FLAG2_REGION_PAL     0x10
 
 #define DISPLAY_ENABLE 0x40
 
@@ -169,7 +170,7 @@
 	uint8_t     *tmp_buf_b;
 } vdp_context;
 
-void init_vdp_context(vdp_context * context);
+void init_vdp_context(vdp_context * context, uint8_t region_pal);
 void vdp_run_context(vdp_context * context, uint32_t target_cycles);
 //runs from current cycle count to VBLANK for the current mode, returns ending cycle count
 uint32_t vdp_run_to_vblank(vdp_context * context);
@@ -192,6 +193,7 @@
 void vdp_print_sprite_table(vdp_context * context);
 void vdp_print_reg_explain(vdp_context * context);
 void latch_mode(vdp_context * context);
+uint32_t vdp_cycles_to_frame_end(vdp_context * context);
 
 extern int32_t color_map[1 << 12];