diff blastem.c @ 343:467bfa17004a

Mostly working runtime generation of memory map read/write functions
author Mike Pavone <pavone@retrodev.com>
date Sat, 18 May 2013 11:44:42 -0700
parents 13f994c88c34
children b46771135442
line wrap: on
line diff
--- a/blastem.c	Thu May 16 09:37:53 2013 -0700
+++ b/blastem.c	Sat May 18 11:44:42 2013 -0700
@@ -235,12 +235,18 @@
 
 m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value)
 {
+	if (vdp_port & 0x2700E0) {
+		printf("machine freeze due to write to address %X\n", 0xC00000 | vdp_port);
+		exit(1);
+	}
+	vdp_port &= 0x1F;
 	//printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle);
 	sync_components(context, 0);
 	vdp_context * v_context = context->video_context;
 	if (vdp_port < 0x10) {
 		int blocked;
 		if (vdp_port < 4) {
+			uint32_t before_cycle = v_context->cycles;
 			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);
@@ -293,25 +299,46 @@
 	return context;
 }
 
-m68k_context * vdp_port_read(uint32_t vdp_port, m68k_context * context)
+m68k_context * vdp_port_write_b(uint32_t vdp_port, m68k_context * context, uint8_t value)
+{
+	return vdp_port_write(vdp_port, context, value | value << 8);
+}
+
+uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context)
 {
+	if (vdp_port & 0x2700E0) {
+		printf("machine freeze due to read from address %X\n", 0xC00000 | vdp_port);
+		exit(1);
+	}
+	vdp_port &= 0x1F;
+	uint16_t value;
 	sync_components(context, 0);
 	vdp_context * v_context = context->video_context;
 	if (vdp_port < 0x10) {
 		if (vdp_port < 4) {
-			context->value = vdp_data_port_read(v_context);
+			value = vdp_data_port_read(v_context);
 		} else if(vdp_port < 8) {
-			context->value = vdp_control_port_read(v_context);
+			value = vdp_control_port_read(v_context);
 		} else {
-			context->value = vdp_hv_counter_read(v_context);
-			//printf("HV Counter: %X at cycle %d\n", context->value, v_context->cycles);
+			value = vdp_hv_counter_read(v_context);
+			//printf("HV Counter: %X at cycle %d\n", value, v_context->cycles);
 		}
 		context->current_cycle = v_context->cycles/MCLKS_PER_68K;
 	} else {
 		printf("Illegal read from PSG or test register port %X\n", vdp_port);
 		exit(1);
 	}
-	return context;
+	return value;
+}
+
+uint8_t vdp_port_read_b(uint32_t vdp_port, m68k_context * context)
+{
+	uint16_t value = vdp_port_read(vdp_port, context);
+	if (vdp_port & 1) {
+		return value;
+	} else {
+		return value >> 8;
+	}
 }
 
 #define TH 0x40
@@ -351,7 +378,7 @@
 	pad->output = value;
 }
 
-void io_data_read(io_port * pad, m68k_context * context)
+uint8_t io_data_read(io_port * pad, m68k_context * context)
 {
 	uint8_t control = pad->control | 0x80;
 	uint8_t th = control & pad->output;
@@ -377,10 +404,11 @@
 			input = pad->input[GAMEPAD_TH0] | 0xC;
 		}
 	}
-	context->value = ((~input) & (~control)) | (pad->output & control);
+	uint8_t value = ((~input) & (~control)) | (pad->output & control);
 	/*if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) {
-		printf ("value: %X\n", context->value);
+		printf ("value: %X\n", value);
 	}*/
+	return value;
 }
 
 uint32_t zram_counter = 0;
@@ -596,8 +624,9 @@
 #define NO_DISK 0x20
 uint8_t version_reg = NO_DISK | USA;
 
-m68k_context * io_read(uint32_t location, m68k_context * context)
+uint8_t io_read(uint32_t location, m68k_context * context)
 {
+	uint8_t value;
 	genesis_context *gen = context->system;
 	if (location < 0x10000) {
 		if (busack_cycle <= context->current_cycle) {
@@ -607,15 +636,83 @@
 		if (!(busack==Z80_REQ_BUSY || reset)) {
 			location &= 0x7FFF;
 			if (location < 0x4000) {
-				context->value = z80_ram[location & 0x1FFF];
+				value = z80_ram[location & 0x1FFF];
 			} else if (location < 0x6000) {
 				ym_run(gen->ym, context->current_cycle);
-				context->value = ym_read_status(gen->ym);
+				value = ym_read_status(gen->ym);
 			} else {
-				context->value = 0xFF;
+				value = 0xFF;
+			}
+		} else {
+			value = 0xFF;
+		}
+	} else {
+		location &= 0x1FFF;
+		if (location < 0x100) {
+			switch(location/2)
+			{
+			case 0x0:
+				//version bits should be 0 for now since we're not emulating TMSS
+				value = version_reg;
+				break;
+			case 0x1:
+				value = io_data_read(&gamepad_1, context);
+				break;
+			case 0x2:
+				value = io_data_read(&gamepad_2, context);
+				break;
+			case 0x3://PORT C Data
+				break;
+			case 0x4:
+				value = gamepad_1.control;
+				break;
+			case 0x5:
+				value = gamepad_2.control;
+				break;
+			default:
+				value = 0xFF;
 			}
 		} else {
-			context->value = 0xFF;
+			if (location == 0x1100) {
+				if (busack_cycle <= context->current_cycle) {
+					busack = new_busack;
+					busack_cycle = CYCLE_NEVER;
+				}
+				value = Z80_RES_BUSACK || busack;
+				dprintf("Byte read of BUSREQ returned %d @ %d (reset: %d, busack: %d, busack_cycle %d)\n", value, context->current_cycle, reset, busack, busack_cycle);
+			} else if (location == 0x1200) {
+				value = !reset;
+			} else {
+				value = 0xFF;
+				printf("Byte read of unknown IO location: %X\n", location);
+			}
+		}
+	}
+	return value;
+}
+
+uint16_t io_read_w(uint32_t location, m68k_context * context)
+{
+	uint16_t value;
+	genesis_context * gen = context->system;
+	if (location < 0x10000) {
+		if (busack_cycle <= context->current_cycle) {
+			busack = new_busack;
+			busack_cycle = CYCLE_NEVER;
+		}
+		if (!(busack==Z80_REQ_BUSY || reset)) {
+			location &= 0x7FFF;
+			if (location < 0x4000) {
+				value = z80_ram[location & 0x1FFE];
+			} else if (location < 0x6000) {
+				ym_run(gen->ym, context->current_cycle);
+				value = ym_read_status(gen->ym);	
+			} else {
+				value = 0xFF;
+			}
+			value = value | (value << 8);
+		} else {
+			value = 0xFFFF;
 		}
 	} else {
 		location &= 0x1FFF;
@@ -625,111 +722,47 @@
 			case 0x0:
 				//version bits should be 0 for now since we're not emulating TMSS
 				//Not sure about the other bits
-				context->value = version_reg;
+				value = version_reg;
 				break;
 			case 0x1:
-				io_data_read(&gamepad_1, context);
+				value = io_data_read(&gamepad_1, context);
 				break;
 			case 0x2:
-				io_data_read(&gamepad_2, context);
+				value = io_data_read(&gamepad_2, context);
 				break;
 			case 0x3://PORT C Data
 				break;
 			case 0x4:
-				context->value = gamepad_1.control;
+				value = gamepad_1.control;
 				break;
 			case 0x5:
-				context->value = gamepad_2.control;
+				value = gamepad_2.control;
+				break;
+			case 0x6:
+				//PORT C Control
+				value = 0;
 				break;
+			default:
+				value = 0;
 			}
+			value = value | (value << 8);
+			//printf("Word read to %X returned %d\n", location, value);
 		} else {
 			if (location == 0x1100) {
 				if (busack_cycle <= context->current_cycle) {
 					busack = new_busack;
 					busack_cycle = CYCLE_NEVER;
 				}
-				context->value = Z80_RES_BUSACK || busack;
-				dprintf("Byte read of BUSREQ returned %d @ %d (reset: %d, busack: %d, busack_cycle %d)\n", context->value, context->current_cycle, reset, busack, busack_cycle);
+				value = (Z80_RES_BUSACK || busack) << 8;
+				//printf("Word read of BUSREQ returned %d\n", value);
 			} else if (location == 0x1200) {
-				context->value = !reset;
-			} else {
-				printf("Byte read of unknown IO location: %X\n", location);
-			}
-		}
-	}
-	return context;
-}
-
-m68k_context * io_read_w(uint32_t location, m68k_context * context)
-{
-	genesis_context * gen = context->system;
-	if (location < 0x10000) {
-		if (busack_cycle <= context->current_cycle) {
-			busack = new_busack;
-			busack_cycle = CYCLE_NEVER;
-		}
-		if (!(busack==Z80_REQ_BUSY || reset)) {
-			location &= 0x7FFF;
-			uint16_t value;
-			if (location < 0x4000) {
-				value = z80_ram[location & 0x1FFE];
-			} else if (location < 0x6000) {
-				ym_run(gen->ym, context->current_cycle);
-				value = ym_read_status(gen->ym);	
-			} else {
-				value = 0xFF;
-			}
-			context->value = value | (value << 8);
-		} else {
-			context->value = 0xFFFF;
-		}
-	} else {
-		location &= 0x1FFF;
-		if (location < 0x100) {
-			switch(location/2)
-			{
-			case 0x0:
-				//version bits should be 0 for now since we're not emulating TMSS
-				//Not sure about the other bits
-				context->value = 0;
-				break;
-			case 0x1:
-				io_data_read(&gamepad_1, context);
-				break;
-			case 0x2:
-				io_data_read(&gamepad_2, context);
-				break;
-			case 0x3://PORT C Data
-				break;
-			case 0x4:
-				context->value = gamepad_1.control;
-				break;
-			case 0x5:
-				context->value = gamepad_2.control;
-				break;
-			case 0x6:
-				//PORT C Control
-				context->value = 0;
-				break;
-			}
-			context->value = context->value | (context->value << 8);
-			//printf("Word read to %X returned %d\n", location, context->value);
-		} else {
-			if (location == 0x1100) {
-				if (busack_cycle <= context->current_cycle) {
-					busack = new_busack;
-					busack_cycle = CYCLE_NEVER;
-				}
-				context->value = (Z80_RES_BUSACK || busack) << 8;
-				//printf("Word read of BUSREQ returned %d\n", context->value);
-			} else if (location == 0x1200) {
-				context->value = (!reset) << 8;
+				value = (!reset) << 8;
 			} else {
 				printf("Word read of unknown IO location: %X\n", location);
 			}
 		}
 	}
-	return context;
+	return value;
 }
 
 z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t value)
@@ -1000,7 +1033,19 @@
 	m68k_context context;
 	x86_68k_options opts;
 	gen->m68k = &context;
-	init_x86_68k_opts(&opts);
+	memmap_chunk memmap[] = {
+		{0,        0x400000,  0xFFFFFF, 0, MMAP_READ | MMAP_WRITE,             cart,
+		           NULL,          NULL,         NULL,            NULL},
+		{0xE00000, 0x1000000, 0xFFFF,   0, MMAP_READ | MMAP_WRITE | MMAP_CODE, ram, 
+		           NULL,          NULL,         NULL,            NULL},
+		{0xC00000, 0xE00000,  0x1FFFFF, 0, 0,                                  NULL,
+		           (read_16_fun)vdp_port_read,  (write_16_fun)vdp_port_write,
+		           (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b},
+		{0xA00000, 0xA12000,  0x1FFFF,  0, 0,                                  NULL,
+		           (read_16_fun)io_read_w,      (write_16_fun)io_write_w,
+		           (read_8_fun)io_read,         (write_8_fun)io_write}
+	};
+	init_x86_68k_opts(&opts, memmap, sizeof(memmap)/sizeof(memmap_chunk));
 	opts.address_log = address_log;
 	init_68k_context(&context, opts.native_code_map, &opts);
 	
@@ -1068,11 +1113,11 @@
 
 void detect_region()
 {
-	if (detect_specific_region('U')) {
+	if (detect_specific_region('U')|| detect_specific_region('B') || detect_specific_region('4')) {
 		version_reg = NO_DISK | USA;
 	} else if (detect_specific_region('J')) {
 		version_reg = NO_DISK | JAP;
-	} if (detect_specific_region('E') || detect_specific_region('A') || detect_specific_region('B') || detect_specific_region('4')) {
+	} else if (detect_specific_region('E') || detect_specific_region('A')) {
 		version_reg = NO_DISK | EUR;
 	}
 }