diff vdp.c @ 2227:eaaf28af3c94

Implement VDP read latency and invalid write delays revealed by Ti_'s instruction timing ROM
author Michael Pavone <pavone@retrodev.com>
date Mon, 05 Sep 2022 22:18:25 -0700
parents 1cccc57c069a
children 3888c7ed4e36
line wrap: on
line diff
--- a/vdp.c	Mon Sep 05 12:00:02 2022 -0700
+++ b/vdp.c	Mon Sep 05 22:18:25 2022 -0700
@@ -40,6 +40,7 @@
 #define VBLANK_START_H40 (LINE_CHANGE_H40+2)
 #define VBLANK_START_H32 (LINE_CHANGE_H32+2)
 #define FIFO_LATENCY    3
+#define READ_LATENCY    3
 
 #define BORDER_TOP_V24     27
 #define BORDER_TOP_V28     11
@@ -1019,6 +1020,11 @@
 			}
 
 			break;
+		default:
+			if (!(context->cd & 4) && !start->partial && (context->regs[REG_MODE_2] & (BIT_128K_VRAM|BIT_MODE_5)) != (BIT_128K_VRAM|BIT_MODE_5)) {
+				start->partial = 1;
+				return;
+			}
 		}
 		context->fifo_read = (context->fifo_read+1) & (FIFO_SIZE-1);
 		if (context->fifo_read == context->fifo_write) {
@@ -1040,7 +1046,7 @@
 
 			context->flags |= FLAG_READ_FETCHED;
 		}
-	} else if (!(context->cd & 1) && !(context->flags & (FLAG_READ_FETCHED|FLAG_PENDING))) {
+	} else if (!(context->cd & 1) && !(context->flags & (FLAG_READ_FETCHED|FLAG_PENDING)) && context->read_latency <= context->cycles) {
 		switch(context->cd & 0xF)
 		{
 		case VRAM_READ:
@@ -3785,7 +3791,7 @@
 	return hv;
 }
 
-int vdp_control_port_write(vdp_context * context, uint16_t value)
+int vdp_control_port_write(vdp_context * context, uint16_t value, uint32_t cpu_cycle)
 {
 	//printf("control port write: %X at %d\n", value, context->cycles);
 	if (context->flags & FLAG_DMA_RUN) {
@@ -3805,6 +3811,9 @@
 		//Should these be taken care of here or after the first write?
 		context->flags &= ~FLAG_READ_FETCHED;
 		context->flags2 &= ~FLAG2_READ_PENDING;
+		if (!(context->cd & 1)) {
+			context->read_latency = cpu_cycle + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)*READ_LATENCY;
+		}
 		//printf("New Address: %X, New CD: %X\n", context->address, context->cd);
 		if (context->cd & 0x20) {
 			//
@@ -3918,7 +3927,7 @@
 		uint16_t full_val = value << 8 | context->pending_byte;
 		context->flags2 &= ~FLAG2_BYTE_PENDING;
 		//TODO: Deal with fact that Vbus->VDP DMA doesn't do anything in PBC mode
-		vdp_control_port_write(context, full_val);
+		vdp_control_port_write(context, full_val, context->cycles);
 		if (context->cd == VRAM_READ) {
 			context->cd = VRAM_READ8;
 		}
@@ -4056,7 +4065,7 @@
 	return value;
 }
 
-uint16_t vdp_data_port_read(vdp_context * context)
+uint16_t vdp_data_port_read(vdp_context * context, uint32_t *cpu_cycle, uint32_t cpu_divider)
 {
 	if (context->flags & FLAG_PENDING) {
 		context->flags &= ~FLAG_PENDING;
@@ -4081,10 +4090,27 @@
 		context->system->enter_debugger = 1;
 		return context->prefetch;
 	}
+	uint32_t starting_cycle = context->cycles;
 	while (!(context->flags & FLAG_READ_FETCHED)) {
 		vdp_run_context_full(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20));
 	}
 	context->flags &= ~FLAG_READ_FETCHED;
+	//TODO: Make some logic analyzer captures to better characterize what's happening with read latency here
+	if (context->cycles != starting_cycle) {
+		uint32_t delta = context->cycles - *cpu_cycle;
+		uint32_t cpu_delta = delta / cpu_divider;
+		if (delta % cpu_divider) {
+			cpu_delta++;
+		}
+		*cpu_cycle += cpu_delta * cpu_divider;
+		if (*cpu_cycle - context->cycles < 2) {
+			context->read_latency = context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)*(READ_LATENCY - 1);
+		} else {
+			context->read_latency = context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)*READ_LATENCY;
+		}
+	} else {
+		context->read_latency = *cpu_cycle + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)*(READ_LATENCY - 1);
+	}
 	return context->prefetch;
 }
 
@@ -4121,6 +4147,11 @@
 			idx = (idx+1) & (FIFO_SIZE-1);
 		} while(idx != context->fifo_write);
 	}
+	if (context->read_latency >= deduction) {
+		context->read_latency -= deduction;
+	} else {
+		context->read_latency = 0;
+	}
 }
 
 static uint32_t vdp_cycles_hslot_wrap_h40(vdp_context * context)