changeset 2358:4b2ac43c106e

Give debugger expression engine access to VDP and Sub CPU values. Add basic variable support
author Michael Pavone <pavone@retrodev.com>
date Sat, 28 Oct 2023 00:52:10 -0700
parents 344c6a3fe8a8
children 04d29635d238
files debug.c debug.h vdp.c vdp.h
diffstat 4 files changed, 109 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/debug.c	Fri Oct 27 23:49:04 2023 -0700
+++ b/debug.c	Sat Oct 28 00:52:10 2023 -0700
@@ -633,6 +633,10 @@
 				return 1;
 			}
 			tern_val v;
+			if (tern_find(root->variables, e->op.v.str, &v)) {
+				*out = v.intval;
+				return 1;
+			}
 			if (tern_find(root->symbols, e->op.v.str, &v)) {
 				*out = v.intval;
 				return 1;
@@ -825,6 +829,8 @@
 		*out = context->current_cycle;
 	} else if (!strcasecmp(name, "pc")) {
 		*out = root->address;
+	} else if (!strcasecmp(name, "sp")) {
+		*out = context->aregs[7];
 	} else if (!strcasecmp(name, "usp")) {
 		*out = context->status & 0x20 ? context->aregs[8] : context->aregs[7];
 	} else if (!strcasecmp(name, "ssp")) {
@@ -847,6 +853,8 @@
 		for (int flag = 0; flag < 5; flag++) {
 			context->flags[flag] = (value & (1 << (4 - flag))) != 0;
 		}
+	} else if (!strcasecmp(name, "sp")) {
+		context->aregs[7] = value;
 	} else if (!strcasecmp(name, "usp")) {
 		context->aregs[context->status & 0x20 ? 8 : 7] = value;
 	} else if (!strcasecmp(name, "ssp")) {
@@ -857,8 +865,50 @@
 	return 1;
 }
 
+static uint8_t resolve_vdp(debug_root *root, const char *name, uint32_t *out)
+{
+	m68k_context *m68k = root->cpu_context;
+	genesis_context *gen = m68k->system;
+	vdp_context *vdp = gen->vdp;
+	if (!strcasecmp(name, "vcounter")) {
+		*out = vdp->vcounter;
+	} else if (!strcasecmp(name, "hcounter")) {
+		*out = vdp->hslot;
+	} else if (!strcasecmp(name, "address")) {
+		*out = vdp->address;
+	}else if (!strcasecmp(name, "cd")) {
+		*out = vdp->cd;
+	} else if (!strcasecmp(name, "status")) {
+		*out = vdp_status(vdp);
+	} else {
+		return 0;
+	}
+	return 1;
+}
+
 static uint8_t resolve_genesis(debug_root *root, const char *name, uint32_t *out)
 {
+
+	for (const char *cur = name; *cur; ++cur)
+	{
+		if (*cur == ':') {
+			if (cur - name == 3 && !memcmp(name, "vdp", 3)) {
+				return resolve_vdp(root, cur + 1, out);
+			} else if (cur - name == 3 && !memcmp(name, "sub", 3)) {
+				m68k_context *m68k = root->cpu_context;
+				genesis_context *gen = m68k->system;
+				if (gen->expansion) {
+					segacd_context *cd = gen->expansion;
+					root = find_m68k_root(cd->m68k);
+					return root->resolve(root, cur + 1, out);
+				} else {
+					return 0;
+				}
+			} else {
+				return 0;
+			}
+		}
+	}
 	if (resolve_m68k(root, name, out)) {
 		return 1;
 	}
@@ -1618,7 +1668,12 @@
 	}
 	if (name) {
 		if (!root->set(root, name, value)) {
-			fprintf(stderr, "Failed to set %s\n", name);
+			tern_val v;
+			if (tern_find(root->variables, name, &v)) {
+				root->variables = tern_insert_int(root->variables, name, value);
+			} else {
+				fprintf(stderr, "Failed to set %s\n", name);
+			}
 		}
 	} else if (!root->write_mem(root, address, value, size)) {
 		fprintf(stderr, "Failed to write to address %X\n", address);
@@ -1626,6 +1681,24 @@
 	return 1;
 }
 
+static uint8_t cmd_variable(debug_root *root, parsed_command *cmd)
+{
+	if (cmd->args[0].parsed->type != EXPR_SCALAR || cmd->args[0].parsed->op.type != TOKEN_NAME) {
+		fprintf(stderr, "First argument to variable must be a name, got %s\n", expr_type_names[cmd->args[0].parsed->type]);
+		return 1;
+	}
+	uint32_t value = 0;
+	if (cmd->num_args > 1) {
+		if (!eval_expr(root, cmd->args[1].parsed, &cmd->args[1].value)) {
+			fprintf(stderr, "Failed to eval %s\n", cmd->args[1].raw);
+			return 1;
+		}
+		value = cmd->args[1].value;
+	}
+	root->variables = tern_insert_int(root->variables, cmd->args[0].parsed->op.v.str, value);
+	return 1;
+}
+
 static uint8_t cmd_frames(debug_root *root, parsed_command *cmd)
 {
 	current_system->enter_debugger_frames = cmd->args[0].value;
@@ -2148,6 +2221,17 @@
 	},
 	{
 		.names = (const char *[]){
+			"variable", NULL
+		},
+		.usage = "variable NAME [VALUE]",
+		.desc = "Create a new variable called NAME and set it to VALUE or 0 if no value provided",
+		.impl = cmd_variable,
+		.min_args = 1,
+		.max_args = 2,
+		.skip_eval = 1
+	},
+	{
+		.names = (const char *[]){
 			"frames", NULL
 		},
 		.usage = "frames EXPRESSION",
--- a/debug.h	Fri Oct 27 23:49:04 2023 -0700
+++ b/debug.h	Sat Oct 28 00:52:10 2023 -0700
@@ -117,6 +117,7 @@
 	disp_def       *displays;
 	tern_node      *commands;
 	tern_node      *symbols;
+	tern_node      *variables;
 	disasm_context *disasm;
 	resolver       resolve;
 	reader         read_mem;
--- a/vdp.c	Fri Oct 27 23:49:04 2023 -0700
+++ b/vdp.c	Sat Oct 28 00:52:10 2023 -0700
@@ -716,13 +716,10 @@
 	       context->address, context->cd, cd_name(context->cd),
 		   (context->flags & FLAG_PENDING) ? "word" : (context->flags2 & FLAG2_BYTE_PENDING) ? "byte" : "none",
 		   context->vcounter, context->hslot*2, (context->flags2 & FLAG2_VINT_PENDING) ? "true" : "false",
-		   (context->flags2 & FLAG2_HINT_PENDING) ? "true" : "false", vdp_control_port_read(context));
+		   (context->flags2 & FLAG2_HINT_PENDING) ? "true" : "false", vdp_status(context));
 	printf("\nDebug Register: %X | Output disabled: %s, Force Layer: %d\n", context->test_port,
 		(context->test_port & TEST_BIT_DISABLE)  ? "true" : "false", context->test_port >> 7 & 3
 	);
-	//restore flags as calling vdp_control_port_read can change them
-	context->flags = old_flags;
-	context->flags2 = old_flags2;
 }
 
 static uint8_t is_active(vdp_context *context)
@@ -4831,10 +4828,8 @@
 	context->test_port = value;
 }
 
-uint16_t vdp_control_port_read(vdp_context * context)
+uint16_t vdp_status(vdp_context *context)
 {
-	context->flags &= ~FLAG_PENDING;
-	context->flags2 &= ~FLAG2_BYTE_PENDING;
 	//Bits 15-10 are not fixed like Charles MacDonald's doc suggests, but instead open bus values that reflect 68K prefetch
 	uint16_t value = context->system->get_open_bus_value(context->system) & 0xFC00;
 	if (context->fifo_read < 0) {
@@ -4848,11 +4843,9 @@
 	}
 	if (context->flags & FLAG_DOT_OFLOW) {
 		value |= 0x40;
-		context->flags &= ~FLAG_DOT_OFLOW;
 	}
 	if (context->flags2 & FLAG2_SPRITE_COLLIDE) {
 		value |= 0x20;
-		context->flags2 &= ~FLAG2_SPRITE_COLLIDE;
 	}
 	if ((context->regs[REG_MODE_4] & BIT_INTERLACE) && !(context->flags2 & FLAG2_EVEN_FIELD)) {
 		value |= 0x10;
@@ -4876,6 +4869,14 @@
 	if (context->flags2 & FLAG2_REGION_PAL) {
 		value |= 0x1;
 	}
+	return value;
+}
+
+uint16_t vdp_control_port_read(vdp_context * context)
+{
+	uint16_t value = vdp_status(context);
+	context->flags &= ~(FLAG_DOT_OFLOW|FLAG_PENDING);
+	context->flags2 &= ~(FLAG2_SPRITE_COLLIDE|FLAG2_BYTE_PENDING);
 	//printf("status read at cycle %d returned %X\n", context->cycles, value);
 	return value;
 }
--- a/vdp.h	Fri Oct 27 23:49:04 2023 -0700
+++ b/vdp.h	Sat Oct 28 00:52:10 2023 -0700
@@ -172,7 +172,15 @@
 	VDP_TMS9918A
 };
 
+typedef struct vdp_context vdp_context;
+typedef void (*vdp_hook_fun)(vdp_context *);
+
 typedef struct {
+	vdp_hook_fun handler;
+	void         *data;
+} vdp_hook;
+
+struct vdp_context {
 	system_header  *system;
 	//pointer to current line in framebuffer
 	uint32_t       *output;
@@ -181,6 +189,9 @@
 	uint8_t        *done_composite;
 	uint32_t       *debug_fbs[NUM_DEBUG_TYPES];
 	char           *kmod_msg_buffer;
+	vdp_hook       dma_hook;
+	vdp_hook       vdpreg_hook;
+	vdp_hook       data_hook;
 	uint32_t       kmod_buffer_storage;
 	uint32_t       kmod_buffer_length;
 	uint32_t       timer_start_cycle;
@@ -258,7 +269,7 @@
 	uint8_t        cram_latch;
 	int32_t        color_map[1 << 12];
 	uint8_t        vdpmem[];
-} vdp_context;
+};
 
 
 
@@ -306,5 +317,6 @@
 uint16_t read_dma_value(uint32_t address);
 void vdp_dma_started(void);
 void vdp_replay_event(vdp_context *context, uint8_t event, event_reader *reader);
+uint16_t vdp_status(vdp_context *context);
 
 #endif //VDP_H_