commit a39f3c4121238004adebf3e114914960af4d994c
parent 4065c06561d6c97a92e23decbc2ece50e4bc0754
Author: Brian Swetland <swetland@frotz.net>
Date:   Wed, 24 Jun 2015 01:02:57 -0700
gdb-bridge: more breakpoints!
- use flashpatch breakpoints for memory below 02000000, if available
- obtain fp bp and dwt bp count from control registers
- todo: refactor all of this into a nicer breakpoint/watchpoint manager
- todo: integrate with target detection and loss
Diffstat:
| M | tools/gdb-bridge.c |  |  | 98 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ | 
1 file changed, 91 insertions(+), 7 deletions(-)
diff --git a/tools/gdb-bridge.c b/tools/gdb-bridge.c
@@ -363,20 +363,104 @@ void write_memory(u32 addr, unsigned char *data, int len) {
 	}
 }
 
-#define MAXBP 4
-static u32 bp_addr[MAXBP];
-static u32 bp_state[MAXBP];
+#define DWT_CTRL	0xE0001000
+
+#define FP_CTRL		0xE0002000
+#define FP_REMAP	0xE0002004
+#define FP_COMP(n)	(0xE0002008 + ((n) * 4))
+
+#define MAXFP 16 
+static u32 maxfp = 0;
+static u32 fp_addr[MAXFP] = { 0, };
+static u32 fp_state[MAXFP] = { 0, };
+
+#define MAXBP 16
+static u32 maxbp; 
+static u32 bp_addr[MAXBP] = { 0, };
+static u32 bp_state[MAXBP] = { 0, };
+
+int handle_flashpatch(int add, u32 addr, u32 kind) {
+	u32 x;
+	int n;
+	if (swdp_ahb_read(FP_CTRL, &x)) {
+		zprintf("GDB: cannot read flashpatch ctrl\n");
+		return -1;
+	}
+	n = ((x & 0xF0) >> 4) | ((x & 0x7000) >> 4);
+	if (n != maxfp) {
+		zprintf("GDB: %d flashpatch breakpoint registers\n", n);
+		if (n > 16) n = 16;
+		if (maxfp != 0) {
+			zprintf("GDB: previously %d registers...\n", maxfp);
+		}
+		maxfp = n;
+	}
+	for (n = 0; n < maxfp; n++) {
+		if (fp_state[n] && (fp_addr[n] == addr)) {
+			if (add) {
+				goto add0;
+			} else {
+				fp_state[n] = 0;
+				swdp_ahb_write(FP_COMP(n), 0);
+				zprintf("GDB: - FP BP @ %08x\n", addr);
+				return 0;
+			}
+		}
+	}
+	if (!add) {
+		// no breakpoint to remove
+		return -1;
+	}
+	for (n = 0; n < maxfp; n++) {
+		if (fp_state[n] == 0) {
+			goto add1;
+		}
+	}
+	return -1;
+add1:
+	swdp_ahb_write(FP_CTRL,3);
+	if (addr & 2) {
+		// breakpoint on low half-word, enable
+		swdp_ahb_write(FP_COMP(n), 0x80000001 | (addr & 0x1FFFFFFC));
+	} else {
+		// breakpoint on high half-word, enable
+		swdp_ahb_write(FP_COMP(n), 0x40000001 | (addr & 0x1FFFFFFC));
+	}
+	fp_state[n] = 1;
+	fp_addr[n] = addr;
+add0:
+	zprintf("GDB: + FP BP @ %08x\n", addr);
+	return 0;
+}
 
 int handle_breakpoint(int add, u32 addr, u32 kind) {
+	u32 x;
 	int n;
+
+	if ((addr < 0x20000000) && (!handle_flashpatch(add,addr,kind))) {
+		return 0;
+	}
+	if (swdp_ahb_read(DWT_CTRL, &x)) {
+		zprintf("GDB: cannot read dwt ctrl\n");
+		return -1;
+	}
+	n = x >> 28;
+	if (n != maxbp) {
+		zprintf("GDB: %d dwt breakpoint registers\n", n);
+		if (maxbp != 0) {
+			zprintf("GDB: previously %d registers...\n", maxbp);
+		}
+		maxbp = n;
+	}
+
 	if (add) {
-		for (n = 0; n < MAXBP; n++) {
+		for (n = 0; n < maxbp; n++) {
 			if (bp_state[n] && (bp_addr[n] == addr)) {
 				// already setup
 				return 0;
 			}
 		}
-		for (n = 0; n < MAXBP; n++) {
+		for (n = 0; n < maxbp; n++) {
 			if (bp_state[n] == 0) {
 				bp_addr[n] = addr;
 				bp_state[n] = 1;
@@ -385,13 +469,13 @@ int handle_breakpoint(int add, u32 addr, u32 kind) {
 				return 0;
 			}
 		}
-		if (n == MAXBP) {
+		if (n == maxbp) {
 			zprintf("GDB: Out of hardware breakpoints.\n");
 			return 1;
 		}
 		return 0;
 	} else {
-		for (n = 0; n < MAXBP; n++) {
+		for (n = 0; n < maxbp; n++) {
 			if (bp_state[n] && (bp_addr[n] == addr)) {
 				bp_state[n] = 0;
 				swdp_watchpoint_disable(n);