changeset 2393:5f4917b9ecfa

Add debugger save command
author Michael Pavone <pavone@retrodev.com>
date Tue, 05 Dec 2023 21:29:21 -0800
parents a71176b9903d
children 340299a76db7
files debug.c debug.h
diffstat 2 files changed, 195 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/debug.c	Wed Nov 29 23:06:50 2023 -0800
+++ b/debug.c	Tue Dec 05 21:29:21 2023 -0800
@@ -3002,6 +3002,160 @@
 	return 1;
 }
 
+static uint8_t cmd_save(debug_root *root, parsed_command *cmd)
+{
+	char size = cmd->format ? cmd->format[0] : 'b';
+	if (size != 'b' && size != 'w' && size != 'l') {
+		fprintf(stderr, "Invalid size %s\n", cmd->format);
+		return 1;
+	}
+	FILE *f = fopen(cmd->args[0].raw, "wb");
+	if (!f) {
+		fprintf(stderr, "Failed to open %s for writing\n", cmd->args[0].raw);
+		return 1;
+	}
+	uint32_t start = 0;
+	debug_val val;
+	debug_array * arr = NULL;
+	if (cmd->args[1].parsed->type == EXPR_MEM) {
+		
+		if (!eval_expr(root, cmd->args[1].parsed->left, &val)) {
+			fprintf(stderr, "Failed to eval start index\n");
+			goto cleanup;
+		}
+		if (!debug_cast_int(val, &start)) {
+			fprintf(stderr, "Start index must evaluate to integer\n");
+			goto cleanup;
+		}
+		if (cmd->args[1].parsed->right) {
+			if (!eval_expr(root, cmd->args[1].parsed->right, &val)) {
+				fprintf(stderr, "Failed to eval array name in argument %s\n", cmd->args[1].raw);
+				goto cleanup;
+			}
+			arr = get_array(val);
+			if (!arr) {
+				fprintf(stderr, "Name in argument %s did not evaluate to an array\n", cmd->args[1].raw);
+				goto cleanup;
+			}
+		}
+	} else {
+		if (!eval_expr(root, cmd->args[1].parsed, &val)) {
+			fprintf(stderr, "Failed to eval %s\n", cmd->args[1].raw);
+			goto cleanup;
+		}
+		arr = get_array(val);
+		if (!arr) {
+			fprintf(stderr, "Argument %s did not evaluate to an array\n", cmd->args[1].raw);
+			goto cleanup;
+		}
+	}
+	uint32_t count = 0;
+	if (cmd->num_args > 2) {
+		if (!eval_expr(root, cmd->args[2].parsed, &val)) {
+			fprintf(stderr, "Failed to eval %s\n", cmd->args[2].raw);
+			goto cleanup;
+		}
+		if (!debug_cast_int(val, &count)) {
+			fprintf(stderr, "Count must evaluate to integer\n");
+			goto cleanup;
+		}
+	} else if (arr) {
+		count = arr->size < start ? 0 : arr->size - start;
+	} else {
+		count = root->chunk_end(root, start) - start;
+		if (size == 'l') {
+			count /= 4;
+		} else if (size == 'w') {
+			count /= 2;
+		}
+	}
+	union {
+		uint8_t b[1024];
+		uint16_t w[512];
+		uint32_t l[256];
+	} buffer;
+	uint32_t cur = start;
+	if (size == 'l') {
+		while (count)
+		{
+			uint32_t n = count < 256 ? count : 256;
+			count -= n;
+			for (uint32_t i = 0; i < n ; i++)
+			{
+				if (arr) {
+					val = arr->get(arr, cur++);
+					if (!debug_cast_int(val, buffer.l + i)) {
+						n = i;
+						count = 0;
+					}
+				} else {
+					buffer.l[i] = cur;
+					cur += 4;
+					if (!root->read_mem(root, buffer.l + i, 'l')) {
+						n = i;
+						count = 0;
+					}
+				}
+			}
+			fwrite(buffer.l, sizeof(uint32_t), n, f);
+		}
+	} else if (size == 'w') {
+		while (count)
+		{
+			uint32_t n = count < 512 ? count : 512;
+			count -= n;
+			uint32_t tmp;
+			for (uint32_t i = 0; i < n ; i++)
+			{
+				if (arr) {
+					val = arr->get(arr, cur++);
+					if (!debug_cast_int(val, &tmp)) {
+						n = i;
+						count = 0;
+					}
+				} else {
+					tmp = cur;
+					cur += 2;
+					if (!root->read_mem(root, &tmp, 'w')) {
+						n = i;
+						count = 0;
+					}
+				}
+				buffer.w[i] = tmp;
+			}
+			fwrite(buffer.w, sizeof(uint16_t), n, f);
+		}
+	} else {
+		while (count)
+		{
+			uint32_t n = count < 1024 ? count : 1024;
+			count -= n;
+			uint32_t tmp;
+			for (uint32_t i = 0; i < n ; i++)
+			{
+				if (arr) {
+					val = arr->get(arr, cur++);
+					if (!debug_cast_int(val, &tmp)) {
+						n = i;
+						count = 0;
+					}
+				} else {
+					tmp = cur++;
+					if (!root->read_mem(root, &tmp, 'b')) {
+						n = i;
+						count = 0;
+					}
+				}
+				buffer.b[i] = tmp;
+			}
+			fwrite(buffer.b, sizeof(uint8_t), n, f);
+		}
+	}
+cleanup:
+	fclose(f);
+	return 1;
+}
+
 static uint8_t cmd_delete_m68k(debug_root *root, parsed_command *cmd)
 {
 	uint32_t index;
@@ -3644,6 +3798,17 @@
 		.min_args = 0,
 		.max_args = 1,
 		.raw_args = 1
+	},
+	{
+		.names = (const char *[]){
+			"save", NULL
+		},
+		.usage = "save[/SIZE] FILENAME ARRAY [COUNT]",
+		.desc = "Saves COUNT elements of size SIZE from the array or memory region specified by ARRAY to a file",
+		.impl = cmd_save,
+		.min_args = 2,
+		.max_args = 3,
+		.skip_eval = 1
 	}
 };
 #define NUM_COMMON (sizeof(common_commands)/sizeof(*common_commands))
@@ -4223,6 +4388,19 @@
 	return debug_int(vdp->frame);
 }
 
+static uint32_t m68k_chunk_end(debug_root *root, uint32_t start_address)
+{
+	m68k_context *m68k = root->cpu_context;
+	memmap_chunk const *chunk = find_map_chunk(start_address, &m68k->options->gen, 0, NULL);
+	if (!chunk) {
+		return start_address;
+	}
+	if (chunk->mask == m68k->options->gen.address_mask) {
+		return chunk->end;
+	}
+	return (start_address & ~chunk->mask) + chunk->mask + 1;
+}
+
 debug_root *find_m68k_root(m68k_context *context)
 {
 	debug_root *root = find_root(context);
@@ -4231,6 +4409,7 @@
 		add_commands(root, m68k_commands, NUM_68K);
 		root->read_mem = read_m68k;
 		root->write_mem = write_m68k;
+		root->chunk_end = m68k_chunk_end;
 		root->disasm = create_68000_disasm();
 		m68k_names(root);
 		debug_var *var;
@@ -4611,6 +4790,19 @@
 	root->variables = tern_insert_ptr(root->variables, "PC", var);
 }
 
+static uint32_t z80_chunk_end(debug_root *root, uint32_t start_address)
+{
+	z80_context *z80 = root->cpu_context;
+	memmap_chunk const *chunk = find_map_chunk(start_address, &z80->options->gen, 0, NULL);
+	if (!chunk) {
+		return start_address;
+	}
+	if (chunk->mask == z80->options->gen.address_mask) {
+		return chunk->end;
+	}
+	return (start_address & ~chunk->mask) + chunk->mask + 1;
+}
+
 debug_root *find_z80_root(z80_context *context)
 {
 	debug_root *root = find_root(context);
@@ -4647,6 +4839,7 @@
 		root->read_mem = read_z80;
 		root->write_mem = write_z80;
 		root->disasm = create_z80_disasm();
+		root->chunk_end = z80_chunk_end;
 	}
 	return root;
 }
--- a/debug.h	Wed Nov 29 23:06:50 2023 -0800
+++ b/debug.h	Tue Dec 05 21:29:21 2023 -0800
@@ -177,6 +177,7 @@
 typedef debug_var *(*resolver)(debug_root *root, const char *name);
 typedef uint8_t (*reader)(debug_root *root, uint32_t *out, char size);
 typedef uint8_t (*writer)(debug_root *root, uint32_t address, uint32_t value, char size);
+typedef uint32_t (*find_chunk_end)(debug_root *root, uint32_t start_address);
 
 struct debug_root {
 	void           *cpu_context;
@@ -189,6 +190,7 @@
 	disasm_context *disasm;
 	reader         read_mem;
 	writer         write_mem;
+	find_chunk_end chunk_end;
 	parsed_command last_cmd;
 	debug_val      retval;
 	uint32_t       bp_index;