changeset 2107:f80c6111e1ae

Move some debugger state to a per-CPU structure. Add m command for returning to main CPU from sub CPU
author Michael Pavone <pavone@retrodev.com>
date Sat, 12 Feb 2022 15:20:43 -0800
parents d2989e32c026
children 68d61ba1b762
files debug.c debug.h gdb_remote.c
diffstat 3 files changed, 149 insertions(+), 94 deletions(-) [+]
line wrap: on
line diff
--- a/debug.c	Sat Feb 12 14:50:59 2022 -0800
+++ b/debug.c	Sat Feb 12 15:20:43 2022 -0800
@@ -19,10 +19,28 @@
 #define Z80_OPTS options
 #endif
 
-static bp_def * breakpoints = NULL;
-static bp_def * zbreakpoints = NULL;
-static uint32_t bp_index = 0;
-static uint32_t zbp_index = 0;
+
+
+static debug_root roots[5];
+static uint32_t num_roots;
+#define MAX_DEBUG_ROOTS (sizeof(roots)/sizeof(*roots))
+
+debug_root *find_root(void *cpu)
+{
+	for (uint32_t i = 0; i < num_roots; i++)
+	{
+		if (roots[i].cpu_context == cpu) {
+			return roots + i;
+		}
+	}
+	if (num_roots < MAX_DEBUG_ROOTS) {
+		num_roots++;
+		memset(roots + num_roots - 1, 0, sizeof(debug_root));
+		roots[num_roots-1].cpu_context = cpu;
+		return roots + num_roots - 1;
+	}
+	return NULL;
+}
 
 bp_def ** find_breakpoint(bp_def ** cur, uint32_t address)
 {
@@ -46,11 +64,6 @@
 	return cur;
 }
 
-disp_def * displays = NULL;
-disp_def * zdisplays = NULL;
-uint32_t disp_index = 0;
-uint32_t zdisp_index = 0;
-
 void add_display(disp_def ** head, uint32_t *index, char format_char, char * param)
 {
 	disp_def * ndisp = malloc(sizeof(*ndisp));
@@ -373,13 +386,15 @@
 {
 	static char last_cmd[1024];
 	char input_buf[1024];
-	static uint16_t branch_t;
-	static uint16_t branch_f;
 	z80inst inst;
 	genesis_context *system = context->system;
 	init_terminal();
 	//Check if this is a user set breakpoint, or just a temporary one
-	bp_def ** this_bp = find_breakpoint(&zbreakpoints, address);
+	debug_root *root = find_root(context);
+	if (!root) {
+		return context;
+	}
+	bp_def ** this_bp = find_breakpoint(&root->breakpoints, address);
 	if (*this_bp) {
 		printf("Z80 Breakpoint %d hit\n", (*this_bp)->index);
 	} else {
@@ -389,7 +404,7 @@
 	if (!pc) {
 		fatal_error("Failed to get native pointer on entering Z80 debugger at address %X\n", address);
 	}
-	for (disp_def * cur = zdisplays; cur; cur = cur->next) {
+	for (disp_def * cur = root->displays; cur; cur = cur->next) {
 		zdebugger_print(context, cur->format_char, cur->param);
 	}
 	uint8_t * after_pc = z80_decode(pc, &inst);
@@ -435,11 +450,11 @@
 				value = strtol(param, NULL, 16);
 				zinsert_breakpoint(context, value, (uint8_t *)zdebugger);
 				new_bp = malloc(sizeof(bp_def));
-				new_bp->next = zbreakpoints;
+				new_bp->next = root->breakpoints;
 				new_bp->address = value;
-				new_bp->index = zbp_index++;
+				new_bp->index = root->bp_index++;
 				new_bp->commands = NULL;
-				zbreakpoints = new_bp;
+				root->breakpoints = new_bp;
 				printf("Z80 Breakpoint %d set at %X\n", new_bp->index, value);
 				break;
 			case 'c':
@@ -461,7 +476,7 @@
 						break;
 					}
 					zdebugger_print(context, format_char, param);
-					add_display(&zdisplays, &zdisp_index, format_char, param);
+					add_display(&root->displays, &root->disp_index, format_char, param);
 				} else if (input_buf[1] == 'e' || input_buf[1] == ' ') {
 					param = find_param(input_buf);
 					if (!param) {
@@ -470,7 +485,7 @@
 					}
 					if (param[0] >= '0' && param[0] <= '9') {
 						value = atoi(param);
-						this_bp = find_breakpoint_idx(&zbreakpoints, value);
+						this_bp = find_breakpoint_idx(&root->breakpoints, value);
 						if (!*this_bp) {
 							fprintf(stderr, "Breakpoint %d does not exist\n", value);
 							break;
@@ -485,7 +500,7 @@
 							fputs("delete display command requires a parameter\n", stderr);
 							break;
 						}
-						remove_display(&zdisplays, atoi(param));
+						remove_display(&root->displays, atoi(param));
 					}
 				}
 				break;
@@ -643,21 +658,23 @@
 		//Z80 debug commands
 		switch(input_buf[1])
 		{
-		case 'b':
+		case 'b': {
 			param = find_param(input_buf);
 			if (!param) {
 				fputs("zb command requires a parameter\n", stderr);
 				break;
 			}
 			value = strtol(param, NULL, 16);
+			debug_root *zroot = find_root(gen->z80);
 			zinsert_breakpoint(gen->z80, value, (uint8_t *)zdebugger);
 			new_bp = malloc(sizeof(bp_def));
-			new_bp->next = zbreakpoints;
+			new_bp->next = zroot->breakpoints;
 			new_bp->address = value;
-			new_bp->index = zbp_index++;
-			zbreakpoints = new_bp;
+			new_bp->index = zroot->bp_index++;
+			zroot->breakpoints = new_bp;
 			printf("Z80 Breakpoint %d set at %X\n", new_bp->index, value);
 			break;
+		}
 		case 'p':
 			param = find_param(input_buf);
 			if (!param) {
@@ -675,8 +692,26 @@
 	return 1;
 }
 
-static uint32_t branch_t;
-static uint32_t branch_f;
+int run_subcpu_debugger_command(m68k_context *context, uint32_t address, char *input_buf)
+{
+	segacd_context *cd = context->system;
+	switch (input_buf[0])
+	{
+	case 'm':
+		if (input_buf[1]) {
+			//TODO: filter out commands that are unsafe to run when we don't have the current Main CPU address
+			return run_debugger_command(cd->genesis->m68k, 0, input_buf + 1, (m68kinst){}, 0);
+		} else {
+			cd->genesis->header.enter_debugger = 1;
+			return 0;
+		}
+		break;
+	default:
+		fprintf(stderr, "Unrecognized debugger command %s\nUse '?' for help.\n", input_buf);
+		break;
+	}
+	return 1;
+}
 
 int run_debugger_command(m68k_context *context, uint32_t address, char *input_buf, m68kinst inst, uint32_t after)
 {
@@ -685,6 +720,10 @@
 	genesis_context *system = context->system;
 	uint32_t value;
 	bp_def *new_bp, **this_bp;
+	debug_root *root = find_root(context);
+	if (!root) {
+		return 0;
+	}
 	switch(input_buf[0])
 	{
 		case 'c':
@@ -698,7 +737,7 @@
 					fputs("com command requires a parameter\n", stderr);
 					break;
 				}
-				bp_def **target = find_breakpoint_idx(&breakpoints, atoi(param));
+				bp_def **target = find_breakpoint_idx(&root->breakpoints, atoi(param));
 				if (!target) {
 					fprintf(stderr, "Breakpoint %s does not exist!\n", param);
 					break;
@@ -765,11 +804,11 @@
 				value = strtol(param, NULL, 16);
 				insert_breakpoint(context, value, debugger);
 				new_bp = malloc(sizeof(bp_def));
-				new_bp->next = breakpoints;
+				new_bp->next = root->breakpoints;
 				new_bp->address = value;
-				new_bp->index = bp_index++;
+				new_bp->index = root->bp_index++;
 				new_bp->commands = NULL;
-				breakpoints = new_bp;
+				root->breakpoints = new_bp;
 				printf("68K Breakpoint %d set at %X\n", new_bp->index, value);
 			}
 			break;
@@ -797,7 +836,7 @@
 					break;
 				}
 				debugger_print(context, format_char, param, address);
-				add_display(&displays, &disp_index, format_char, param);
+				add_display(&root->displays, &root->disp_index, format_char, param);
 			} else {
 				param = find_param(input_buf);
 				if (!param) {
@@ -805,7 +844,7 @@
 					break;
 				}
 				value = atoi(param);
-				this_bp = find_breakpoint_idx(&breakpoints, value);
+				this_bp = find_breakpoint_idx(&root->breakpoints, value);
 				if (!*this_bp) {
 					fprintf(stderr, "Breakpoint %d does not exist\n", value);
 					break;
@@ -842,18 +881,18 @@
 				after = m68k_read_long(context->aregs[7] + 2, context);
 			} else if(m68k_is_noncall_branch(&inst)) {
 				if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
-					branch_f = after;
-					branch_t = m68k_branch_target(&inst, context->dregs, context->aregs);
-					insert_breakpoint(context, branch_t, debugger);
+					root->branch_f = after;
+					root->branch_t = m68k_branch_target(&inst, context->dregs, context->aregs);
+					insert_breakpoint(context, root->branch_t, debugger);
 				} else if(inst.op == M68K_DBCC) {
 					if ( inst.extra.cond == COND_FALSE) {
 						if (context->dregs[inst.dst.params.regs.pri] & 0xFFFF) {
 							after = m68k_branch_target(&inst, context->dregs, context->aregs);
 						}
 					} else {
-						branch_t = after;
-						branch_f = m68k_branch_target(&inst, context->dregs, context->aregs);
-						insert_breakpoint(context, branch_f, debugger);
+						root->branch_t = after;
+						root->branch_f = m68k_branch_target(&inst, context->dregs, context->aregs);
+						insert_breakpoint(context, root->branch_f, debugger);
 					}
 				} else {
 					after = m68k_branch_target(&inst, context->dregs, context->aregs);
@@ -868,12 +907,12 @@
 				after = m68k_read_long(context->aregs[7] + 2, context);
 			} else if(m68k_is_noncall_branch(&inst)) {
 				if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
-					branch_t = m68k_branch_target(&inst, context->dregs, context->aregs)  & 0xFFFFFF;
-					if (branch_t < after) {
-							branch_t = 0;
+					root->branch_t = m68k_branch_target(&inst, context->dregs, context->aregs)  & 0xFFFFFF;
+					if (root->branch_t < after) {
+							root->branch_t = 0;
 					} else {
-						branch_f = after;
-						insert_breakpoint(context, branch_t, debugger);
+						root->branch_f = after;
+						insert_breakpoint(context, root->branch_t, debugger);
 					}
 				} else if(inst.op == M68K_DBCC) {
 					uint32_t target = m68k_branch_target(&inst, context->dregs, context->aregs)  & 0xFFFFFF;
@@ -881,9 +920,9 @@
 						if (inst.extra.cond == COND_FALSE) {
 							after = target;
 						} else {
-							branch_f = target;
-							branch_t = after;
-							insert_breakpoint(context, branch_f, debugger);
+							root->branch_f = target;
+							root->branch_t = after;
+							insert_breakpoint(context, root->branch_f, debugger);
 						}
 					}
 				} else {
@@ -953,18 +992,18 @@
 					after = m68k_read_long(context->aregs[7] + 2, context);
 				} else if(m68k_is_branch(&inst)) {
 					if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
-						branch_f = after;
-						branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
-						insert_breakpoint(context, branch_t, debugger);
+						root->branch_f = after;
+						root->branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
+						insert_breakpoint(context, root->branch_t, debugger);
 					} else if(inst.op == M68K_DBCC) {
 						if (inst.extra.cond == COND_FALSE) {
 							if (context->dregs[inst.dst.params.regs.pri] & 0xFFFF) {
 								after = m68k_branch_target(&inst, context->dregs, context->aregs);
 							}
 						} else {
-							branch_t = after;
-							branch_f = m68k_branch_target(&inst, context->dregs, context->aregs);
-							insert_breakpoint(context, branch_f, debugger);
+							root->branch_t = after;
+							root->branch_f = m68k_branch_target(&inst, context->dregs, context->aregs);
+							insert_breakpoint(context, root->branch_f, debugger);
 						}
 					} else {
 						after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
@@ -987,7 +1026,7 @@
 			} else {
 				//presumably Sega CD sub CPU
 				//TODO: consider making this more generic
-				fprintf(stderr, "Unrecognized debugger command %s\nUse '?' for help.\n", input_buf);
+				return run_subcpu_debugger_command(context, address, input_buf);
 			}
 			break;
 		}
@@ -1051,20 +1090,24 @@
 		genesis_context *gen = context->system;
 		vdp_force_update_framebuffer(gen->vdp);
 	}
+	debug_root *root = find_root(context);
+	if (!root) {
+		return;
+	}
 	//probably not necessary, but let's play it safe
 	address &= 0xFFFFFF;
-	if (address == branch_t) {
-		bp_def ** f_bp = find_breakpoint(&breakpoints, branch_f);
+	if (address == root->branch_t) {
+		bp_def ** f_bp = find_breakpoint(&root->breakpoints, root->branch_f);
 		if (!*f_bp) {
-			remove_breakpoint(context, branch_f);
+			remove_breakpoint(context, root->branch_f);
 		}
-		branch_t = branch_f = 0;
-	} else if(address == branch_f) {
-		bp_def ** t_bp = find_breakpoint(&breakpoints, branch_t);
+		root->branch_t = root->branch_f = 0;
+	} else if(address == root->branch_f) {
+		bp_def ** t_bp = find_breakpoint(&root->breakpoints, root->branch_t);
 		if (!*t_bp) {
-			remove_breakpoint(context, branch_t);
+			remove_breakpoint(context, root->branch_t);
 		}
-		branch_t = branch_f = 0;
+		root->branch_t = root->branch_f = 0;
 	}
 
 	uint16_t * pc = get_native_pointer(address, (void **)context->mem_pointers, &context->options->gen);
@@ -1075,7 +1118,7 @@
 	uint32_t after = address + (after_pc-pc)*2;
 	int debugging = 1;
 	//Check if this is a user set breakpoint, or just a temporary one
-	bp_def ** this_bp = find_breakpoint(&breakpoints, address);
+	bp_def ** this_bp = find_breakpoint(&root->breakpoints, address);
 	if (*this_bp) {
 
 		if ((*this_bp)->commands)
@@ -1100,7 +1143,7 @@
 	} else {
 		remove_breakpoint(context, address);
 	}
-	for (disp_def * cur = displays; cur; cur = cur->next) {
+	for (disp_def * cur = root->displays; cur; cur = cur->next) {
 		debugger_print(context, cur->format_char, cur->param, address);
 	}
 	m68k_disasm(&inst, input_buf);
--- a/debug.h	Sat Feb 12 14:50:59 2022 -0800
+++ b/debug.h	Sat Feb 12 15:20:43 2022 -0800
@@ -23,6 +23,17 @@
 	uint32_t      index;
 } bp_def;
 
+typedef struct {
+	void     *cpu_context;
+	bp_def   *breakpoints;
+	disp_def *displays;
+	uint32_t bp_index;
+	uint32_t disp_index;
+	uint32_t branch_t;
+	uint32_t branch_f;
+} debug_root;
+
+debug_root *find_root(void *cpu);
 bp_def ** find_breakpoint(bp_def ** cur, uint32_t address);
 bp_def ** find_breakpoint_idx(bp_def ** cur, uint32_t index);
 void add_display(disp_def ** head, uint32_t *index, char format_char, char * param);
--- a/gdb_remote.c	Sat Feb 12 14:50:59 2022 -0800
+++ b/gdb_remote.c	Sat Feb 12 15:20:43 2022 -0800
@@ -50,13 +50,6 @@
 uint32_t resume_pc;
 
 
-static uint16_t branch_t;
-static uint16_t branch_f;
-
-static bp_def * breakpoints = NULL;
-static uint32_t bp_index = 0;
-
-
 void hex_32(uint32_t num, char * out)
 {
 	for (int32_t shift = 28; shift >= 0; shift -= 4)
@@ -171,6 +164,10 @@
 {
 	char send_buf[512];
 	dfprintf(stderr, "Received command %s\n", command);
+	debug_root *root = find_root(context);
+	if (!root) {
+		fatal_error("Could not find debug root for CPU %p\n", context);
+	}
 	switch(*command)
 	{
 
@@ -202,13 +199,13 @@
 			after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1);
 		} else if(m68k_is_branch(&inst)) {
 			if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
-				branch_f = after;
-				branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
-				insert_breakpoint(context, branch_t, gdb_debug_enter);
+				root->branch_f = after;
+				root->branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
+				insert_breakpoint(context, root->branch_t, gdb_debug_enter);
 			} else if(inst.op == M68K_DBCC && inst.extra.cond != COND_FALSE) {
-				branch_t = after;
-				branch_f = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
-				insert_breakpoint(context, branch_f, gdb_debug_enter);
+				root->branch_t = after;
+				root->branch_f = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
+				insert_breakpoint(context, root->branch_f, gdb_debug_enter);
 			} else {
 				after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
 			}
@@ -233,10 +230,10 @@
 			uint32_t address = strtoul(command+3, NULL, 16);
 			insert_breakpoint(context, address, gdb_debug_enter);
 			bp_def *new_bp = malloc(sizeof(bp_def));
-			new_bp->next = breakpoints;
+			new_bp->next = root->breakpoints;
 			new_bp->address = address;
-			new_bp->index = bp_index++;
-			breakpoints = new_bp;
+			new_bp->index = root->bp_index++;
+			root->breakpoints = new_bp;
 			gdb_send_command("OK");
 		} else {
 			//watchpoints are not currently supported
@@ -249,7 +246,7 @@
 		if (type < '2') {
 			uint32_t address = strtoul(command+3, NULL, 16);
 			remove_breakpoint(context, address);
-			bp_def **found = find_breakpoint(&breakpoints, address);
+			bp_def **found = find_breakpoint(&root->breakpoints, address);
 			if (*found)
 			{
 				bp_def * to_remove = *found;
@@ -430,13 +427,13 @@
 					after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1);
 				} else if(m68k_is_branch(&inst)) {
 					if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
-						branch_f = after;
-						branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
-						insert_breakpoint(context, branch_t, gdb_debug_enter);
+						root->branch_f = after;
+						root->branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
+						insert_breakpoint(context, root->branch_t, gdb_debug_enter);
 					} else if(inst.op == M68K_DBCC && inst.extra.cond != COND_FALSE) {
-						branch_t = after;
-						branch_f = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
-						insert_breakpoint(context, branch_f, gdb_debug_enter);
+						root->branch_t = after;
+						root->branch_f = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
+						insert_breakpoint(context, root->branch_f, gdb_debug_enter);
 					} else {
 						after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
 					}
@@ -473,21 +470,25 @@
 		gdb_send_command("S05");
 		expect_break_response = 0;
 	}
-	if ((pc & 0xFFFFFF) == branch_t) {
-		bp_def ** f_bp = find_breakpoint(&breakpoints, branch_f);
+	debug_root *root = find_root(context);
+	if (!root) {
+		fatal_error("Could not find debug root for CPU %p\n", context);
+	}
+	if ((pc & 0xFFFFFF) == root->branch_t) {
+		bp_def ** f_bp = find_breakpoint(&root->breakpoints, root->branch_f);
 		if (!*f_bp) {
-			remove_breakpoint(context, branch_f);
+			remove_breakpoint(context, root->branch_f);
 		}
-		branch_t = branch_f = 0;
-	} else if((pc & 0xFFFFFF) == branch_f) {
-		bp_def ** t_bp = find_breakpoint(&breakpoints, branch_t);
+		root->branch_t = root->branch_f = 0;
+	} else if((pc & 0xFFFFFF) == root->branch_f) {
+		bp_def ** t_bp = find_breakpoint(&root->breakpoints, root->branch_t);
 		if (!*t_bp) {
-			remove_breakpoint(context, branch_t);
+			remove_breakpoint(context, root->branch_t);
 		}
-		branch_t = branch_f = 0;
+		root->branch_t = root->branch_f = 0;
 	}
 	//Check if this is a user set breakpoint, or just a temporary one
-	bp_def ** this_bp = find_breakpoint(&breakpoints, pc & 0xFFFFFF);
+	bp_def ** this_bp = find_breakpoint(&root->breakpoints, pc & 0xFFFFFF);
 	if (!*this_bp) {
 		remove_breakpoint(context, pc & 0xFFFFFF);
 	}