changeset 668:5439ae7946ca

Made the Z80 core more contained by refactoring some code in blastem.c into z80_to_x86.c
author Michael Pavone <pavone@retrodev.com>
date Sat, 03 Jan 2015 18:23:04 -0800
parents 30ccf56842d6
children 7a9a7c96cb22
files backend.h blastem.c blastem.h gst.c z80_to_x86.c z80_to_x86.h
diffstat 6 files changed, 157 insertions(+), 144 deletions(-) [+]
line wrap: on
line diff
--- a/backend.h	Sat Jan 03 16:08:23 2015 -0800
+++ b/backend.h	Sat Jan 03 18:23:04 2015 -0800
@@ -12,6 +12,7 @@
 
 #define INVALID_OFFSET 0xFFFFFFFF
 #define EXTENSION_WORD 0xFFFFFFFE
+#define CYCLE_NEVER 0xFFFFFFFF
 
 #if defined(X86_32) || defined(X86_64)
 typedef struct {
--- a/blastem.c	Sat Jan 03 16:08:23 2015 -0800
+++ b/blastem.c	Sat Jan 03 18:23:04 2015 -0800
@@ -155,12 +155,6 @@
 int break_on_sync = 0;
 int save_state = 0;
 
-uint8_t reset = 1;
-uint8_t need_reset = 0;
-uint8_t busreq = 0;
-uint8_t busack = 0;
-uint32_t busack_cycle = CYCLE_NEVER;
-uint8_t new_busack = 0;
 //#define DO_DEBUG_PRINT
 #ifdef DO_DEBUG_PRINT
 #define dprintf printf
@@ -172,34 +166,18 @@
 
 #define Z80_VINT_DURATION 128
 
+void z80_next_int_pulse(z80_context * z_context)
+{
+	genesis_context * gen = z_context->system;
+	z_context->int_pulse_start = vdp_next_vint_z80(gen->vdp);
+	z_context->int_pulse_end = z_context->int_pulse_start + Z80_VINT_DURATION;
+}
+
 void sync_z80(z80_context * z_context, uint32_t mclks)
 {
 #ifndef NO_Z80
-	if (z80_enabled && !reset && !busreq) {
-		genesis_context * gen = z_context->system;
-		z_context->sync_cycle = mclks;
-		if (z_context->current_cycle < z_context->sync_cycle) {
-			if (need_reset) {
-				z80_reset(z_context);
-				need_reset = 0;
-			}
-
-			while (z_context->current_cycle < z_context->sync_cycle) {
-				if (z_context->int_pulse_end < z_context->current_cycle || z_context->int_pulse_end == CYCLE_NEVER) {
-					z_context->int_pulse_start = vdp_next_vint_z80(gen->vdp);
-					z_context->int_pulse_end = z_context->int_pulse_start + Z80_VINT_DURATION;
-				}
-				if (z_context->iff1) {
-					z_context->int_cycle = z_context->int_pulse_start < z_context->int_enable_cycle ? z_context->int_enable_cycle : z_context->int_pulse_start;
-				} else {
-					z_context->int_cycle = CYCLE_NEVER;
-				}
-				z_context->target_cycle = z_context->sync_cycle < z_context->int_cycle ? z_context->sync_cycle : z_context->int_cycle;
-				dprintf("Running Z80 from cycle %d to cycle %d. Int cycle: %d\n", z_context->current_cycle, z_context->sync_cycle, z_context->int_cycle);
-				z_context->run(z_context);
-				dprintf("Z80 ran to cycle %d\n", z_context->current_cycle);
-			}
-		}
+	if (z80_enabled) {
+		z80_run(z_context, mclks);
 	} else
 #endif
 	{
@@ -256,45 +234,8 @@
 		io_adjust_cycles(gen->ports, context->current_cycle, mclk_target);
 		io_adjust_cycles(gen->ports+1, context->current_cycle, mclk_target);
 		io_adjust_cycles(gen->ports+2, context->current_cycle, mclk_target);
-		if (busack_cycle != CYCLE_NEVER) {
-			if (busack_cycle > mclk_target) {
-				busack_cycle -= mclk_target;
-			} else {
-				busack_cycle = CYCLE_NEVER;
-				busack = new_busack;
-			}
-		}
 		context->current_cycle -= mclk_target;
-		if (z_context->current_cycle >= mclk_target) {
-			z_context->current_cycle -= mclk_target;
-		} else {
-			z_context->current_cycle = 0;
-		}
-		if (z_context->int_cycle != CYCLE_NEVER) {
-			if (z_context->int_cycle >= mclk_target) {
-				z_context->int_cycle -= mclk_target;
-			} else {
-				z_context->int_cycle = 0;
-			}
-		}
-		if (z_context->int_pulse_start != CYCLE_NEVER) {
-			if (z_context->int_pulse_end >= mclk_target) {
-				z_context->int_pulse_end -= mclk_target;
-				if (z_context->int_pulse_start >= mclk_target) {
-					z_context->int_pulse_start -= mclk_target;
-				} else {
-					z_context->int_pulse_start = 0;
-				}
-			}
-		} else {
-			z_context->int_pulse_start = CYCLE_NEVER;
-			z_context->int_pulse_end = CYCLE_NEVER;
-		}
-		if (z_context->int_enable_cycle >= mclk_target) {
-			z_context->int_enable_cycle -= mclk_target;
-		} else {
-			z_context->int_enable_cycle = 0;
-		}
+		z80_adjust_cycles(z_context, mclk_target);
 		if (mclks) {
 			vdp_run_context(v_context, mclks);
 		}
@@ -458,7 +399,7 @@
 			value = vdp_hv_counter_read(v_context);
 			//printf("HV Counter: %X at cycle %d\n", value, v_context->cycles);
 		}
-	} else if (vdp_port < 0x18){
+	} else if (vdp_port < 0x18) {
 		printf("Illegal read from PSG  port %X\n", vdp_port);
 		exit(1);
 	} else {
@@ -520,11 +461,7 @@
 {
 	genesis_context * gen = context->system;
 	if (location < 0x10000) {
-		if (busack_cycle <= context->current_cycle) {
-			busack = new_busack;
-			busack_cycle = CYCLE_NEVER;
-		}
-		if (!(busack || reset)) {
+		if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) {
 			location &= 0x7FFF;
 			if (location < 0x4000) {
 				z80_ram[location & 0x1FFF] = value;
@@ -578,54 +515,40 @@
 			}
 		} else {
 			if (location == 0x1100) {
-				if (busack_cycle <= context->current_cycle) {
-					busack = new_busack;
-					busack_cycle = CYCLE_NEVER;
-				}
 				if (value & 1) {
 					dputs("bus requesting Z80");
-
-					if(!reset && !busreq) {
-						sync_z80(gen->z80, context->current_cycle + Z80_ACK_DELAY*MCLKS_PER_Z80);
-						busack_cycle = gen->z80->current_cycle;//context->current_cycle + Z80_ACK_DELAY;
-						new_busack = Z80_REQ_ACK;
+					if (z80_enabled) {
+						z80_assert_busreq(gen->z80, context->current_cycle);
 					}
-					busreq = 1;
 				} else {
-					sync_z80(gen->z80, context->current_cycle);
-					if (busreq) {
+					if (gen->z80->busreq) {
 						dputs("releasing z80 bus");
-						#ifdef DO_DEBUG_PRINT
+#ifdef DO_DEBUG_PRINT
 						char fname[20];
 						sprintf(fname, "zram-%d", zram_counter++);
 						FILE * f = fopen(fname, "wb");
 						fwrite(z80_ram, 1, sizeof(z80_ram), f);
 						fclose(f);
-						#endif
-						busack_cycle = gen->z80->current_cycle + Z80_BUSY_DELAY;
-						new_busack = Z80_REQ_BUSY;
-						busreq = 0;
+#endif
 					}
-					//busack_cycle = CYCLE_NEVER;
-					//busack = Z80_REQ_BUSY;
-
+					if (z80_enabled) {
+						z80_clear_busreq(gen->z80, context->current_cycle);
+					}
 				}
 			} else if (location == 0x1200) {
 				sync_z80(gen->z80, context->current_cycle);
 				if (value & 1) {
-					if (reset && busreq) {
-						new_busack = 0;
-						busack_cycle = gen->z80->current_cycle + Z80_ACK_DELAY;//context->current_cycle + Z80_ACK_DELAY;
+					if (z80_enabled) {
+						z80_clear_reset(gen->z80, context->current_cycle);
+					} else {
+						gen->z80->reset = 0;
 					}
-					//TODO: Deal with the scenario in which reset is not asserted long enough
-					if (reset) {
-						need_reset = 1;
-						//TODO: Add necessary delay between release of reset and start of execution
-						gen->z80->current_cycle = context->current_cycle + 16 * MCLKS_PER_Z80;
+				} else {
+					if (z80_enabled) {
+						z80_assert_reset(gen->z80, context->current_cycle);
+					} else {
+						gen->z80->reset = 1;
 					}
-					reset = 0;
-				} else {
-					reset = 1;
 				}
 			}
 		}
@@ -653,11 +576,7 @@
 	uint8_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)) {
+		if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) {
 			location &= 0x7FFF;
 			if (location < 0x4000) {
 				value = z80_ram[location & 0x1FFF];
@@ -702,14 +621,10 @@
 			}
 		} else {
 			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);
+				value = z80_enabled ? !z80_get_busack(gen->z80, context->current_cycle) : 0;
+				dprintf("Byte read of BUSREQ returned %d @ %d (reset: %d)\n", value, context->current_cycle, gen->z80->reset);
 			} else if (location == 0x1200) {
-				value = !reset;
+				value = !gen->z80->reset;
 			} else {
 				value = 0xFF;
 				printf("Byte read of unknown IO location: %X\n", location);
@@ -1105,9 +1020,6 @@
 			insert_breakpoint(&context, pc, debugger);
 		}
 		adjust_int_cycle(gen->m68k, gen->vdp);
-#ifndef NO_Z80
-		gen->z80->native_pc =  z80_get_native_address_trans(gen->z80, gen->z80->pc);
-#endif
 		start_68k_context(&context, pc);
 	} else {
 		if (debugger) {
@@ -1364,6 +1276,7 @@
 	z80_options z_opts;
 	init_z80_opts(&z_opts, z80_map, 5, MCLKS_PER_Z80);
 	init_z80_context(&z_context, &z_opts);
+	z80_assert_reset(&z_context, 0);
 #endif
 
 	z_context.system = &gen;
--- a/blastem.h	Sat Jan 03 16:08:23 2015 -0800
+++ b/blastem.h	Sat Jan 03 18:23:04 2015 -0800
@@ -19,8 +19,6 @@
 #define RAM_FLAG_EVEN 0x1000
 #define RAM_FLAG_BOTH 0x0000
 
-#define CYCLE_NEVER 0xFFFFFFFF
-
 typedef struct {
 	m68k_context   *m68k;
 	z80_context    *z80;
@@ -42,8 +40,6 @@
 extern int break_on_sync;
 extern int save_state;
 extern tern_node * config;
-extern uint8_t busreq;
-extern uint8_t reset;
 
 #define CARTRIDGE_WORDS 0x200000
 #define RAM_WORDS 32 * 1024
--- a/gst.c	Sat Jan 03 16:08:23 2015 -0800
+++ b/gst.c	Sat Jan 03 18:23:04 2015 -0800
@@ -1,6 +1,6 @@
 /*
  Copyright 2013 Michael Pavone
- This file is part of BlastEm. 
+ This file is part of BlastEm.
  BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
 */
 #include "gst.h"
@@ -207,8 +207,8 @@
 	curpos += 2;
 	context->iff1 = context->iff2 = *curpos;
 	curpos += 2;
-	reset = !*(curpos++);
-	busreq = *curpos;
+	context->reset = !*(curpos++);
+	context->busreq = *curpos;
 	curpos += 3;
 	uint32_t bank = read_le_32(curpos);
 	if (bank < 0x400000) {
@@ -350,8 +350,8 @@
 	curpos += 2;
 	*curpos = context->iff1;
 	curpos += 2;
-	*(curpos++) = !reset;
-	*curpos = busreq;
+	*(curpos++) = !context->reset;
+	*curpos = context->busreq;
 	curpos += 3;
 	uint32_t bank = context->bank_reg << 15;
 	write_le_32(curpos, bank);
--- a/z80_to_x86.c	Sat Jan 03 16:08:23 2015 -0800
+++ b/z80_to_x86.c	Sat Jan 03 18:23:04 2015 -0800
@@ -1777,7 +1777,7 @@
 		code_ptr dst = z80_get_native_address(context, inst_start);
 		code_info code = {dst, dst+16};
 		z80_options * opts = context->options;
-		dprintf("patching code at %p for Z80 instruction at %X due to write to %X\n", code, inst_start, address);
+		dprintf("patching code at %p for Z80 instruction at %X due to write to %X\n", code.cur, inst_start, address);
 		mov_ir(&code, inst_start, opts->gen.scratch1, SZ_D);
 		call(&code, opts->retrans_stub);
 	}
@@ -2226,18 +2226,112 @@
 	context->banked_code_map = malloc(sizeof(native_map_slot));
 	memset(context->banked_code_map, 0, sizeof(native_map_slot));
 	context->options = options;
-	context->int_cycle = 0xFFFFFFFF;
-	context->int_pulse_start = 0xFFFFFFFF;
-	context->int_pulse_end = 0xFFFFFFFF;
-	context->run = options->run;
+	context->int_cycle = CYCLE_NEVER;
+	context->int_pulse_start = CYCLE_NEVER;
+	context->int_pulse_end = CYCLE_NEVER;
+}
+
+void z80_run(z80_context * context, uint32_t target_cycle)
+{
+	if (context->reset || context->busack) {
+		context->current_cycle = target_cycle;
+	} else {
+		if (context->current_cycle < target_cycle) {
+			//busreq is sampled at the end of an m-cycle
+			//we can approximate that by running for a single m-cycle after a bus request
+			context->sync_cycle = context->busreq ? context->current_cycle + 3*context->options->gen.clock_divider : target_cycle;
+			if (!context->native_pc) {
+				context->native_pc = z80_get_native_address_trans(context, context->pc);
+			}
+			while (context->current_cycle < context->sync_cycle)
+			{
+				if (context->int_pulse_end < context->current_cycle || context->int_pulse_end == CYCLE_NEVER) {
+					z80_next_int_pulse(context);
+				}
+				if (context->iff1) {
+					context->int_cycle = context->int_pulse_start < context->int_enable_cycle ? context->int_enable_cycle : context->int_pulse_start;
+				} else {
+					context->int_cycle = CYCLE_NEVER;
+				}
+				context->target_cycle = context->sync_cycle < context->int_cycle ? context->sync_cycle : context->int_cycle;
+				dprintf("Running Z80 from cycle %d to cycle %d. Int cycle: %d\n", context->current_cycle, context->sync_cycle, context->int_cycle);
+				context->options->run(context);
+				dprintf("Z80 ran to cycle %d\n", context->current_cycle);
+			}
+			if (context->busreq) {
+				context->busack = 1;
+				context->current_cycle = target_cycle;
+			}
+		}
+	}
+}
+
+void z80_assert_reset(z80_context * context, uint32_t cycle)
+{
+	z80_run(context, cycle);
+	context->reset = 1;
 }
 
-void z80_reset(z80_context * context)
+void z80_clear_reset(z80_context * context, uint32_t cycle)
+{
+	z80_run(context, cycle);
+	if (context->reset) {
+		//TODO: Handle case where reset is not asserted long enough
+		context->im = 0;
+		context->iff1 = context->iff2 = 0;
+		context->native_pc = NULL;
+		context->extra_pc = NULL;
+		context->pc = 0;
+		context->reset = 0;
+	}
+}
+
+void z80_assert_busreq(z80_context * context, uint32_t cycle)
+{
+	z80_run(context, cycle);
+	context->busreq = 1;
+}
+
+void z80_clear_busreq(z80_context * context, uint32_t cycle)
+{
+	z80_run(context, cycle);
+	context->busreq = 0;
+	context->busack = 0;
+}
+
+uint8_t z80_get_busack(z80_context * context, uint32_t cycle)
 {
-	context->im = 0;
-	context->iff1 = context->iff2 = 0;
-	context->native_pc = z80_get_native_address_trans(context, 0);
-	context->extra_pc = NULL;
+	z80_run(context, cycle);
+	return context->busack;
+}
+
+void z80_adjust_cycles(z80_context * context, uint32_t deduction)
+{
+	if (context->current_cycle < deduction) {
+		fprintf(stderr, "WARNING: Deduction of %u cycles when Z80 cycle counter is only %u\n", deduction, context->current_cycle);
+		context->current_cycle = 0;
+	} else {
+		context->current_cycle -= deduction;
+	}
+	if (context->int_enable_cycle != CYCLE_NEVER) {
+		if (context->int_enable_cycle < deduction) {
+			context->int_enable_cycle = 0;
+		} else {
+			context->int_enable_cycle -= deduction;
+		}
+	}
+	if (context->int_pulse_start != CYCLE_NEVER) {
+		if (context->int_pulse_end < deduction) {
+			context->int_pulse_start = context->int_pulse_end = CYCLE_NEVER;
+		} else {
+			context->int_pulse_end -= deduction;
+			if (context->int_pulse_start < deduction) {
+				context->int_pulse_start = 0;
+			} else {
+				context->int_pulse_start -= deduction;
+			}
+		}
+	}
 }
 
 uint32_t zbreakpoint_patch(z80_context * context, uint16_t address, code_ptr dst)
--- a/z80_to_x86.h	Sat Jan 03 16:08:23 2015 -0800
+++ b/z80_to_x86.h	Sat Jan 03 18:23:04 2015 -0800
@@ -70,15 +70,16 @@
 	void *            system;
 	uint8_t           ram_code_flags[(8 * 1024)/128/8];
 	uint32_t          int_enable_cycle;
-	z80_run_fun       run;
-  uint16_t          pc;
+	uint16_t          pc;
 	uint32_t          int_pulse_start;
 	uint32_t          int_pulse_end;
 	uint8_t           breakpoint_flags[(16 * 1024)/sizeof(uint8_t)];
 	uint8_t *         bp_handler;
 	uint8_t *         bp_stub;
 	uint8_t *         interp_code[256];
-
+	uint8_t           reset;
+	uint8_t           busreq;
+	uint8_t           busack;
 } z80_context;
 
 void translate_z80_stream(z80_context * context, uint32_t address);
@@ -87,10 +88,18 @@
 code_ptr z80_get_native_address(z80_context * context, uint32_t address);
 code_ptr z80_get_native_address_trans(z80_context * context, uint32_t address);
 z80_context * z80_handle_code_write(uint32_t address, z80_context * context);
-void z80_run(z80_context * context);
 void z80_reset(z80_context * context);
 void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler);
 void zremove_breakpoint(z80_context * context, uint16_t address);
+void z80_run(z80_context * context, uint32_t target_cycle);
+void z80_assert_reset(z80_context * context, uint32_t cycle);
+void z80_clear_reset(z80_context * context, uint32_t cycle);
+void z80_assert_busreq(z80_context * context, uint32_t cycle);
+void z80_clear_busreq(z80_context * context, uint32_t cycle);
+uint8_t z80_get_busack(z80_context * context, uint32_t cycle);
+void z80_adjust_cycles(z80_context * context, uint32_t deduction);
+//to be provided by system code
+void z80_next_int_pulse(z80_context * z_context);
 
 #endif //Z80_TO_X86_H_