diff blastem.c @ 184:ebcbdd1c4cc8

Fix a bunch of bugs in the CPU core, add a 68K debugger
author Mike Pavone <pavone@retrodev.com>
date Sun, 13 Jan 2013 13:01:13 -0800
parents 97aa449706c2
children b204fbed4efe
line wrap: on
line diff
--- a/blastem.c	Wed Jan 09 22:31:07 2013 -0800
+++ b/blastem.c	Sun Jan 13 13:01:13 2013 -0800
@@ -6,6 +6,7 @@
 #include "blastem.h"
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #define CARTRIDGE_WORDS 0x200000
 #define RAM_WORDS 32 * 1024
@@ -585,6 +586,232 @@
 	return context;
 }
 
+typedef struct bp_def {
+	struct bp_def * next;
+	uint32_t address;
+	uint32_t index;
+} bp_def;
+
+bp_def * breakpoints = NULL;
+uint32_t bp_index = 0;
+
+bp_def ** find_breakpoint(bp_def ** cur, uint32_t address)
+{
+	while (*cur) {
+		if ((*cur)->address == address) {
+			break;
+		}
+		cur = &((*cur)->next);
+	}
+	return cur;
+}
+
+bp_def ** find_breakpoint_idx(bp_def ** cur, uint32_t index)
+{
+	while (*cur) {
+		if ((*cur)->index == index) {
+			break;
+		}
+		cur = &((*cur)->next);
+	}
+	return cur;
+}
+
+char * find_param(char * buf)
+{
+	for (; *buf; buf++) {
+		if (*buf == ' ') {
+			if (*(buf+1)) {
+				return buf+1;
+			}
+		}
+	}
+	return NULL;
+}
+
+void strip_nl(char * buf)
+{
+	for(; *buf; buf++) {
+		if (*buf == '\n') {
+			*buf = 0;
+			return;
+		}
+	}
+}
+
+m68k_context * debugger(m68k_context * context, uint32_t address)
+{
+	static char last_cmd[1024];
+	char input_buf[1024];
+	static uint32_t branch_t;
+	static uint32_t branch_f;
+	m68kinst inst;
+	//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 (!*f_bp) {
+			remove_breakpoint(context, branch_f);
+		}
+		branch_t = branch_f = 0;
+	} else if(address == branch_f) {
+		bp_def ** t_bp = find_breakpoint(&breakpoints, branch_t);
+		if (!*t_bp) {
+			remove_breakpoint(context, branch_t);
+		}
+		branch_t = branch_f = 0;
+	}
+	//Check if this is a user set breakpoint, or just a temporary one
+	bp_def ** this_bp = find_breakpoint(&breakpoints, address);
+	if (*this_bp) {
+		printf("Breakpoint %d hit\n", (*this_bp)->index);
+	} else {
+		remove_breakpoint(context, address);
+	}
+	uint16_t * pc;
+	if (address < 0x400000) {
+		pc = cart + address/2;
+	} else if(address > 0xE00000) {
+		pc = ram + (address & 0xFFFF)/2;
+	} else {
+		fprintf(stderr, "Entered debugger at address %X\n", address);
+		exit(1);
+	}
+	uint16_t * after_pc = m68k_decode(pc, &inst, address);
+	m68k_disasm(&inst, input_buf);
+	printf("%X: %s\n", address, input_buf);
+	uint32_t after = address + (after_pc-pc)*2;
+	int debugging = 1;
+	while (debugging) {
+		fputs(">", stdout);
+		if (!fgets(input_buf, sizeof(input_buf), stdin)) {
+			fputs("fgets failed", stderr);
+			break;
+		}
+		strip_nl(input_buf);
+		//hitting enter repeats last command
+		if (input_buf[0]) {
+			strcpy(last_cmd, input_buf);
+		} else {
+			strcpy(input_buf, last_cmd);
+		}
+		char * param;
+		char format[8];
+		uint32_t value;
+		bp_def * new_bp;
+		switch(input_buf[0])
+		{
+			case 'c':
+				puts("Continuing");
+				debugging = 0;
+				break;
+			case 'b':
+				param = find_param(input_buf);
+				if (!param) {
+					fputs("b command requires a parameter\n", stderr);
+					break;
+				}
+				value = strtol(param, NULL, 16);
+				insert_breakpoint(context, value, (uint8_t *)debugger);
+				new_bp = malloc(sizeof(bp_def));
+				new_bp->next = breakpoints;
+				new_bp->address = value;
+				new_bp->index = bp_index++;
+				breakpoints = new_bp;
+				printf("Breakpoint %d set at %X\n", new_bp->index, value);
+				break;
+			case 'a':
+				param = find_param(input_buf);
+				if (!param) {
+					fputs("a command requires a parameter\n", stderr);
+					break;
+				}
+				value = strtol(param, NULL, 16);
+				insert_breakpoint(context, value, (uint8_t *)debugger);
+				debugging = 0;
+				break;
+			case 'd':
+				param = find_param(input_buf);
+				if (!param) {
+					fputs("b command requires a parameter\n", stderr);
+					break;
+				}
+				value = atoi(param);
+				this_bp = find_breakpoint_idx(&breakpoints, value);
+				if (!*this_bp) {
+					fprintf(stderr, "Breakpoint %d does not exist\n", value);
+					break;
+				}
+				new_bp = *this_bp;
+				*this_bp = (*this_bp)->next;
+				free(new_bp);
+				break;
+			case 'p':
+				strcpy(format, "%s: %d\n");
+				if (input_buf[1] == '/') {
+					switch (input_buf[2])
+					{
+					case 'x':
+					case 'X':
+					case 'd':
+					case 'c':
+						format[5] = input_buf[2];
+						break;
+					default:
+						fprintf(stderr, "Unrecognized format character: %c\n", input_buf[2]);
+					}
+				}
+				param = find_param(input_buf);
+				if (!param) {
+					fputs("p command requires a parameter\n", stderr);
+					break;
+				}
+				if (param[0] == 'd' && param[1] >= '0' && param[1] <= '7') {
+					value = context->dregs[param[1]-'0'];
+				} else if (param[0] == 'a' && param[1] >= '0' && param[1] <= '7') {
+					value = context->aregs[param[1]-'0'];
+				} else if (param[0] == 'S' && param[1] == 'R') {
+					value = (context->status << 8);
+					for (int flag = 0; flag < 5; flag++) {
+						value |= context->flags[flag] << (4-flag);
+					}
+				} else if (param[0] == '0' && param[1] == 'x') {
+					uint32_t p_addr = strtol(param+2, NULL, 16);
+					value = read_dma_value(p_addr/2);
+				} else {
+					fprintf(stderr, "Unrecognized parameter to p: %s\n", param);
+					break;
+				}
+				printf(format, param, value);
+				break;
+			case 'n':
+				//TODO: Deal with jmp, dbcc, rtr and rte
+				if (inst.op == M68K_RTS) {
+					after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1);
+				} else if(inst.op == M68K_BCC && inst.extra.cond != COND_FALSE) {
+					if (inst.extra.cond = COND_TRUE) {
+						after = inst.address + 2 + inst.src.params.immed;
+					} else {
+						branch_f = after;
+						branch_t = inst.address + 2 + inst.src.params.immed;
+						insert_breakpoint(context, branch_t, (uint8_t *)debugger);
+					}
+				}
+				insert_breakpoint(context, after, (uint8_t *)debugger);
+				debugging = 0;
+				break;
+			case 'q':
+				puts("Quitting");
+				exit(0);
+				break;
+			default:
+				fprintf(stderr, "Unrecognized debugger command %s\n", input_buf);
+				break;
+		}
+	}
+	return context;
+}
+
 int main(int argc, char ** argv)
 {
 	if (argc < 2) {
@@ -595,16 +822,27 @@
 		fprintf(stderr, "Failed to open %s for reading\n", argv[1]);
 		return 1;
 	}
-	int width = 320;
-	int height = 240;
-	if (argc > 2) {
-		width = atoi(argv[2]);
-		if (argc > 3) {
-			height = atoi(argv[3]);
-		} else {
-			height = (width/320) * 240;
+	int width = -1;
+	int height = -1;
+	int debug = 0;
+	for (int i = 2; i < argc; i++) {
+		if (argv[i][0] == '-') {
+			switch(argv[i][1]) {
+			case 'd':
+				debug = 1;
+				break;
+			default:
+				fprintf(stderr, "Unrecognized switch %s\n", argv[i]);
+				return 1;
+			}
+		} else if (width < 0) {
+			width = atoi(argv[i]);
+		} else if (height < 0) {
+			height = atoi(argv[i]);
 		}
 	}
+	width = width < 320 ? 320 : width;
+	height = height < 240 ? (width/320) * 240 : height;
 	render_init(width, height);
 	
 	x86_68k_options opts;
@@ -629,6 +867,9 @@
 	translate_m68k_stream(address, &context);*/
 	address = cart[2] << 16 | cart[3];
 	translate_m68k_stream(address, &context);
+	if (debug) {
+		insert_breakpoint(&context, address, (uint8_t *)debugger);
+	}
 	m68k_reset(&context);
 	return 0;
 }