diff m68k_core.c @ 1329:85a90964b557

Fix interaction between 68K debugger and instruction retranslation due to self modifying code or bank switching
author Michael Pavone <pavone@retrodev.com>
date Mon, 24 Apr 2017 20:49:31 -0700
parents c9dc2603b087
children f1607874dbee
line wrap: on
line diff
--- a/m68k_core.c	Sun Apr 23 00:54:33 2017 -0700
+++ b/m68k_core.c	Mon Apr 24 20:49:31 2017 -0700
@@ -780,6 +780,49 @@
 	return 0xFFFF;
 }
 
+static m68k_debug_handler find_breakpoint(m68k_context *context, uint32_t address)
+{
+	for (uint32_t i = 0; i < context->num_breakpoints; i++)
+	{
+		if (context->breakpoints[i].address == address) {
+			return context->breakpoints[i].handler;
+		}
+	}
+	return NULL;
+}
+
+void insert_breakpoint(m68k_context * context, uint32_t address, m68k_debug_handler bp_handler)
+{
+	if (!find_breakpoint(context, address)) {
+		if (context->bp_storage == context->num_breakpoints) {
+			context->bp_storage *= 2;
+			if (context->bp_storage < 4) {
+				context->bp_storage = 4;
+			}
+			context->breakpoints = realloc(context->breakpoints, context->bp_storage * sizeof(m68k_breakpoint));
+		}
+		context->breakpoints[context->num_breakpoints++] = (m68k_breakpoint){
+			.handler = bp_handler,
+			.address = address
+		};
+		m68k_breakpoint_patch(context, address, bp_handler, NULL);
+	}
+}
+
+m68k_context *m68k_bp_dispatcher(m68k_context *context, uint32_t address)
+{
+	m68k_debug_handler handler = find_breakpoint(context, address);
+	if (handler) {
+		handler(context, address);
+	} else {
+		//spurious breakoint?
+		warning("Spurious breakpoing at %X\n", address);
+		remove_breakpoint(context, address);
+	}
+	
+	return context;
+}
+
 typedef enum {
 	RAW_FUNC = 1,
 	BINARY_ARITH,
@@ -895,13 +938,21 @@
 	RAW_IMPL(M68K_TAS, translate_m68k_tas),
 };
 
-static void translate_m68k(m68k_options * opts, m68kinst * inst)
+static void translate_m68k(m68k_context *context, m68kinst * inst)
 {
+	m68k_options * opts = context->options;
 	if (inst->address & 1) {
 		translate_m68k_odd(opts, inst);
 		return;
 	}
+	code_ptr start = opts->gen.code.cur;
 	check_cycles_int(&opts->gen, inst->address);
+	
+	m68k_debug_handler bp;
+	if ((bp = find_breakpoint(context, inst->address))) {
+		m68k_breakpoint_patch(context, inst->address, bp, start);
+	}
+	
 	//log_address(&opts->gen, inst->address, "M68K: %X @ %d\n");
 	if (
 		(inst->src.addr_mode > MODE_AREG && inst->src.addr_mode < MODE_IMMEDIATE) 
@@ -981,7 +1032,7 @@
 			//make sure the beginning of the code for an instruction is contiguous
 			check_code_prologue(code);
 			code_ptr start = code->cur;
-			translate_m68k(opts, &instbuf);
+			translate_m68k(context, &instbuf);
 			code_ptr after = code->cur;
 			map_native_address(context, instbuf.address, start, m68k_size, after-start);
 		} while(!m68k_is_terminal(&instbuf) && !(address & 1));
@@ -1009,7 +1060,7 @@
 		//make sure we have enough code space for the max size instruction
 		check_alloc_code(code, MAX_NATIVE_SIZE);
 		code_ptr native_start = code->cur;
-		translate_m68k(opts, &instbuf);
+		translate_m68k(context, &instbuf);
 		code_ptr native_end = code->cur;
 		/*uint8_t is_terminal = m68k_is_terminal(&instbuf);
 		if ((native_end - native_start) <= orig_size) {
@@ -1025,7 +1076,7 @@
 				tmp.last = code->last;
 				code->cur = orig_code.cur;
 				code->last = orig_code.last;
-				translate_m68k(opts, &instbuf);
+				translate_m68k(context, &instbuf);
 				native_end = orig_code.cur = code->cur;
 				code->cur = tmp.cur;
 				code->last = tmp.last;
@@ -1056,7 +1107,7 @@
 	} else {
 		code_info tmp = *code;
 		*code = orig_code;
-		translate_m68k(opts, &instbuf);
+		translate_m68k(context, &instbuf);
 		orig_code = *code;
 		*code = tmp;
 		if (!m68k_is_terminal(&instbuf)) {
@@ -1079,7 +1130,20 @@
 
 void remove_breakpoint(m68k_context * context, uint32_t address)
 {
+	for (uint32_t i = 0; i < context->num_breakpoints; i++)
+	{
+		if (context->breakpoints[i].address == address) {
+			if (i != (context->num_breakpoints-1)) {
+				context->breakpoints[i] = context->breakpoints[context->num_breakpoints-1];
+			}
+			context->num_breakpoints--;
+			break;
+		}
+	}
 	code_ptr native = get_native_address(context->options, address);
+	if (!native) {
+		return;
+	}
 	code_info tmp = context->options->gen.code;
 	context->options->gen.code.cur = native;
 	context->options->gen.code.last = native + MAX_NATIVE_SIZE;