commit f1c36c3c126fe91c67dceb47dcfccf464ddbd095
parent 19e47556a4bc2d57dda7edcc557b45a03d02190d
Author: Brian Swetland <swetland@frotz.net>
Date:   Sun, 10 Jan 2016 19:16:04 -0800
debugger: transport abstraction, part 1 of n
- introduce debug_transport function table
- move transport-agnostic M3/DAP debug stuff to arm-m-debug.c
- no mass renaming of functions yet
Diffstat:
6 files changed, 339 insertions(+), 37 deletions(-)
diff --git a/Makefile b/Makefile
@@ -15,6 +15,7 @@ SRCS := tools/debugger.c \
 	tools/debugger-core.c \
 	tools/debugger-commands.c \
 	tools/gdb-bridge.c \
+	tools/arm-m-debug.c \
 	tools/linenoise.c \
 	tools/lkdebug.c \
 	tools/rswdp.c \
diff --git a/tools/arm-m-debug.c b/tools/arm-m-debug.c
@@ -0,0 +1,193 @@
+/* arm-m-debug
+ *
+ * Copyright 2011 Brian Swetland <swetland@frotz.net>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <fw/types.h>
+#include "debugger.h"
+#include "rswdp.h"
+
+#include "arm-v7m.h"
+
+// CDBG_* comes from here right now -- FIXME
+#include <protocol/rswdp.h>
+
+static volatile int ATTN;
+
+void swdp_interrupt(void) {
+	ATTN++;
+	if (write(2, "\b\b*INTERRUPT*\n", 16)) { /* do nothing */ }
+}
+
+
+int swdp_core_write(u32 n, u32 v) {
+	if (mem_wr_32(CDBG_REG_DATA, v)) {
+		return -1;
+	}
+	if (mem_wr_32(CDBG_REG_ADDR, (n & 0x1F) | 0x10000)) {
+		return -1;
+	}
+	return 0;
+}
+
+int swdp_core_read(u32 n, u32 *v) {
+	if (mem_wr_32(CDBG_REG_ADDR, n & 0x1F)) {
+		return -1;
+	}
+	if (mem_rd_32(CDBG_REG_DATA, v)) {
+		return -1;
+	}
+	return 0;
+}
+
+int swdp_core_read_all(u32 *v) {
+	unsigned n;
+	for (n = 0; n < 19; n++) {
+		if (mem_wr_32(CDBG_REG_ADDR, n & 0x1F)) {
+			return -1;
+		}
+		if (mem_rd_32(CDBG_REG_DATA, v++)) {
+			return -1;
+		}
+	}
+	return 0;
+}
+
+int swdp_step_no_ints = 0;
+
+int swdp_core_halt(void) {
+	u32 x;
+	if (mem_rd_32(CDBG_CSR, &x)) return -1;
+	x &= (CDBG_C_HALT | CDBG_C_DEBUGEN | CDBG_C_MASKINTS);
+	x |= CDBG_CSR_KEY | CDBG_C_DEBUGEN | CDBG_C_HALT;
+	return mem_wr_32(CDBG_CSR, x);
+}
+
+int swdp_core_step(void) {
+	u32 x;
+	if (mem_rd_32(CDBG_CSR, &x)) return -1;
+	x &= (CDBG_C_HALT | CDBG_C_DEBUGEN | CDBG_C_MASKINTS);
+	x |= CDBG_CSR_KEY;
+
+	if (!(x & CDBG_C_HALT)) {
+		// HALT if we're not already HALTED
+		x |= CDBG_C_HALT | CDBG_C_DEBUGEN;
+		mem_wr_32(CDBG_CSR, x);
+	}
+	if (swdp_step_no_ints) {
+		// set MASKINTS if not already set
+		if (!(x & CDBG_C_MASKINTS)) {
+			x |= CDBG_C_MASKINTS;
+			mem_wr_32(CDBG_CSR, x);
+		}
+	} else {
+		// clear MASKINTs if not already clear
+		if (x & CDBG_C_MASKINTS) {
+			x &= (~CDBG_C_MASKINTS);
+			mem_wr_32(CDBG_CSR, x);
+		}
+	}
+	// STEP
+	x &= (~CDBG_C_HALT);
+	return mem_wr_32(CDBG_CSR, x | CDBG_C_STEP);
+}
+
+int swdp_core_resume(void) {
+	u32 x;
+	if (mem_rd_32(CDBG_CSR, &x)) return -1;
+	x &= (CDBG_C_HALT | CDBG_C_DEBUGEN | CDBG_C_MASKINTS);
+	x |= CDBG_CSR_KEY | CDBG_C_DEBUGEN;
+
+	if (swdp_step_no_ints > 1) {
+		// not just on during step, but always
+		if (!(x & CDBG_C_MASKINTS)) {
+			x |= CDBG_C_MASKINTS;
+			mem_wr_32(CDBG_CSR, x);
+		}
+	} else {
+		if (x & CDBG_C_MASKINTS) {
+			x &= (~CDBG_C_MASKINTS);
+			mem_wr_32(CDBG_CSR, x);
+		}
+	}
+
+	x &= ~(CDBG_C_HALT | CDBG_C_STEP);
+	return mem_wr_32(CDBG_CSR, x);
+}
+
+int swdp_core_wait_for_halt(void) {
+	int last = ATTN;
+	u32 csr;
+	for (;;) {
+		if (mem_rd_32(CDBG_CSR, &csr))
+			return -1;
+		if (csr & CDBG_S_HALT)
+			return 0;
+		if (ATTN != last)
+			return -2;
+	}
+}
+
+int swdp_ahb_wait_for_change(u32 addr, u32 oldval) {
+	int last = ATTN;
+	u32 val;
+	do {
+		if (mem_rd_32(addr, &val))
+			return -1;
+		if (ATTN != last)
+			return -2;
+	} while (val == oldval);
+	return 0;
+}
+
+int swdp_watchpoint(unsigned n, u32 addr, u32 func) {
+	int r;
+	if (n > 3)
+		return -1;
+
+	/* enable DWT, enable all exception traps */
+	r = mem_wr_32(DEMCR, DEMCR_TRCENA | DEMCR_VC_CORERESET);
+	r |= mem_wr_32(DWT_FUNC(n), DWT_FN_DISABLED);
+	if (func != DWT_FN_DISABLED) {
+		r |= mem_wr_32(DWT_COMP(n), addr);
+		r |= mem_wr_32(DWT_MASK(n), 0);
+		r |= mem_wr_32(DWT_FUNC(n), func);
+	}
+	return r;
+}
+
+int swdp_watchpoint_pc(unsigned n, u32 addr) {
+	return swdp_watchpoint(n, addr, DWT_FN_WATCH_PC);
+}
+
+int swdp_watchpoint_rd(unsigned n, u32 addr) {
+	return swdp_watchpoint(n, addr, DWT_FN_WATCH_RD);
+}
+
+int swdp_watchpoint_wr(unsigned n, u32 addr) {
+	return swdp_watchpoint(n, addr, DWT_FN_WATCH_WR);
+}
+
+int swdp_watchpoint_rw(unsigned n, u32 addr) {
+	return swdp_watchpoint(n, addr, DWT_FN_WATCH_RW);
+}
+
+int swdp_watchpoint_disable(unsigned n) {
+	return swdp_watchpoint(n, 0, DWT_FN_DISABLED);
+}
+
diff --git a/tools/debugger-core.c b/tools/debugger-core.c
@@ -595,3 +595,18 @@ int debugger_command(char *line) {
 	return r;
 }
 
+static int _fail(void) {
+	return -1;
+}
+
+debug_transport DUMMY_TRANSPORT = {
+	.attach = (void*) _fail,
+	.clear_error = (void*) _fail,
+	.mem_rd_32 = (void*) _fail,
+	.mem_wr_32 = (void*) _fail,
+	.mem_rd_32_c = (void*) _fail,
+	.mem_wr_32_c = (void*) _fail,
+};
+
+debug_transport *ACTIVE_TRANSPORT = &SWDP_TRANSPORT;
+
diff --git a/tools/debugger.h b/tools/debugger.h
@@ -82,5 +82,54 @@ extern struct debugger_command debugger_commands[];
 int read_register(const char *name, u32 *value);
 int read_memory_word(u32 addr, u32 *value);
 
+typedef struct debug_transport {
+	// attempt to establish connection to target
+	int (*attach)(void);
+
+	// returns nonzero if target is in error state
+	// (one or more transactions have failed, attach needed)
+	int (*error)(void);
+
+	// if target is in error, clear error flag
+	// return nonzero if target was in error (attach needed)
+	int (*clear_error)(void);
+
+	// single 32bit memory access
+	int (*mem_rd_32)(u32 addr, u32 *value);
+	int (*mem_wr_32)(u32 addr, u32 value);
+
+	// multiple 32bit memory access
+	int (*mem_rd_32_c)(u32 addr, u32 *data, int count);
+	int (*mem_wr_32_c)(u32 addr, u32 *data, int count);
+} debug_transport;
+
+extern debug_transport *ACTIVE_TRANSPORT;
+
+static inline int debug_attach(void) {
+	return ACTIVE_TRANSPORT->attach();
+}
+static inline int debug_error(void) {
+	return ACTIVE_TRANSPORT->error();
+}
+static inline int debug_clear_error(void) {
+	return ACTIVE_TRANSPORT->clear_error();
+}
+static inline int mem_rd_32(u32 addr, u32 *value) {
+	return ACTIVE_TRANSPORT->mem_rd_32(addr, value);
+}
+static inline int mem_wr_32(u32 addr, u32 value) {
+	return ACTIVE_TRANSPORT->mem_wr_32(addr, value);
+}
+static inline int mem_rd_32_c(u32 addr, u32 *data, int count) {
+	return ACTIVE_TRANSPORT->mem_rd_32_c(addr, data, count);
+}
+static inline int mem_wr_32_c(u32 addr, u32 *data, int count) {
+	return ACTIVE_TRANSPORT->mem_wr_32_c(addr, data, count);
+}
+
+extern debug_transport DUMMY_TRANSPORT;
+extern debug_transport SWDP_TRANSPORT;
+extern debug_transport JTAG_TRANSPORT;
+
 #endif
 
diff --git a/tools/rswdp.c b/tools/rswdp.c
@@ -29,17 +29,10 @@
 #include "rswdp.h"
 #include "arm-v7m.h"
 
-#include <debugger.h>
+#include "debugger.h"
 
 int swd_verbose = 0;
 
-static volatile int ATTN;
-
-void swdp_interrupt(void) {
-	ATTN++;
-	if (write(2, "\b\b*INTERRUPT*\n", 16)) { /* do nothing */ }
-}
-
 static pthread_mutex_t swd_lock = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t swd_event = PTHREAD_COND_INITIALIZER;
 static pthread_t swd_thread;
@@ -70,7 +63,7 @@ static unsigned swd_version = 0x0001;
 
 static int swd_error = 0;
 
-int swdp_error(void) {
+static int _swdp_error(void) {
 	return swd_error;
 }
 
@@ -219,6 +212,20 @@ static int process_reply(struct txn *t, u32 *data, int count) {
 				rxc--;
 			}
 			continue;
+		case CMD_JTAG_DATA:
+			//xprintf(XSWD, "JTAG DATA %d bits\n", n);
+			if (((n+31)/32) > rxc) {
+				xprintf(XSWD, "reply overrun (%d bits > %d words)\n", n, rxc);
+				return -1;
+			}
+			n = (n + 31) / 32;
+			while (n > 0) {
+				//xprintf(XSWD, "JTAG %08x\n", *data);
+				*(t->rx[rxp++]) = *data++;
+				rxc--;
+				n--;
+			}
+			continue;
 		case CMD_STATUS:
 			if (op) {
 				if (swd_verbose) {
@@ -442,14 +449,14 @@ int swdp_ap_read(u32 addr, u32 *value) {
 	return q_exec(&t);
 }
 
-int swdp_ahb_read(u32 addr, u32 *value) {
+static int _swdp_ahb_read(u32 addr, u32 *value) {
 	struct txn t;
 	q_init(&t);
 	q_ahb_read(&t, addr, value);
 	return q_exec(&t);
 }
 
-int swdp_ahb_write(u32 addr, u32 value) {
+static int _swdp_ahb_write(u32 addr, u32 value) {
 	struct txn t;
 	q_init(&t);
 	q_ahb_write(&t, addr, value);
@@ -494,7 +501,7 @@ int swdp_ahb_write32(u32 addr, u32 *in, int count) {
 /* 10 txns overhead per 128 read txns - 126KB/s on 72MHz STM32F
  * 8 txns overhead per 128 write txns - 99KB/s on 72MHz STM32F
  */
-int swdp_ahb_read32(u32 addr, u32 *out, int count) {
+static int _swdp_ahb_read32(u32 addr, u32 *out, int count) {
 	struct txn t;
 
 	while (count > 0) {
@@ -543,7 +550,7 @@ int swdp_ahb_read32(u32 addr, u32 *out, int count) {
 	return 0;
 }
 
-int swdp_ahb_write32(u32 addr, u32 *in, int count) {
+static int _swdp_ahb_write32(u32 addr, u32 *in, int count) {
 	struct txn t;
 
 	while (count > 0) {
@@ -587,6 +594,7 @@ int swdp_ahb_write32(u32 addr, u32 *in, int count) {
 }
 #endif
 
+#if 0
 int swdp_core_write(u32 n, u32 v) {
 	struct txn t;
 	q_init(&t);
@@ -738,6 +746,7 @@ int swdp_watchpoint_rw(unsigned n, u32 addr) {
 int swdp_watchpoint_disable(unsigned n) {
 	return swdp_watchpoint(n, 0, DWT_FN_DISABLED);
 }
+#endif
 
 int swdp_bootloader(void) {
 	struct txn t;
@@ -746,7 +755,7 @@ int swdp_bootloader(void) {
 	return q_exec(&t);
 }
 
-int swdp_reset(void) {
+static int _swdp_reset(void) {
 	struct txn t;
 	u32 n, idcode;
 
@@ -784,7 +793,7 @@ int swdp_reset(void) {
 	return 0;
 }
 
-int swdp_clear_error(void) {
+static int _swdp_clear_error(void) {
 	if (swd_error == 0) {
 		return 0;
 	} else {
@@ -840,3 +849,30 @@ int swdp_open(void) {
 	pthread_create(&swd_thread, NULL, swd_reader, NULL);
 	return 0;
 }
+
+int jtag_io(unsigned count, u32 *tms, u32 *tdi, u32 *tdo) {
+	struct txn t;
+	q_init(&t);
+	if (count > 32768)
+		return -1;
+	t.tx[t.txc++] = RSWD_MSG(CMD_JTAG_IO, 0, count);
+	count = (count + 31) / 32;
+	while (count > 0) {
+		t.tx[t.txc++] = *tms++;
+		t.tx[t.txc++] = *tdi++;
+		t.rx[t.rxc++] = tdo++;
+		count--;
+	}
+	return q_exec(&t);
+}
+
+debug_transport SWDP_TRANSPORT = {
+	.attach = _swdp_reset,
+	.error = _swdp_error,
+	.clear_error = _swdp_clear_error,
+	.mem_rd_32 = _swdp_ahb_read,
+	.mem_wr_32 = _swdp_ahb_write,
+	.mem_rd_32_c = _swdp_ahb_read32,
+	.mem_wr_32_c = _swdp_ahb_write32,
+};
+
diff --git a/tools/rswdp.h b/tools/rswdp.h
@@ -18,12 +18,21 @@
 #ifndef _RSWDP_H__
 #define _RSWDP_H__
 
-int swdp_ahb_read(u32 addr, u32 *value);
-int swdp_ahb_write(u32 addr, u32 value);
+int swdp_open(void);
+
+void swdp_enable_tracing(int yes);
+
+void swdp_target_reset(int enable);
+
+int swdp_bootloader(void);
+int swdp_set_clock(unsigned khz);
+int swo_set_clock(unsigned khz);
+
+int jtag_io(unsigned count, u32 *tms, u32 *tdi, u32 *tdo);
+
+void swdp_interrupt(void);
 
-/* bulk reads/writes (more efficient after ~3-4 words */
-int swdp_ahb_read32(u32 addr, u32 *out, int count);
-int swdp_ahb_write32(u32 addr, u32 *out, int count);
+/* these are now above the transport layer and should be renamed... */
 
 /* return 0 when *addr != oldval, -1 on error, -2 on interrupt */
 int swdp_ahb_wait_for_change(u32 addr, u32 oldval);
@@ -34,7 +43,6 @@ int swdp_core_resume(void);
 
 /* return 0 when CPU halts, -1 if an error occurs, or -2 if interrupted */
 int swdp_core_wait_for_halt(void);
-void swdp_interrupt(void);
 
 /* access to CPU registers */
 int swdp_core_read(u32 n, u32 *v);
@@ -47,22 +55,22 @@ int swdp_watchpoint_wr(unsigned n, u32 addr);
 int swdp_watchpoint_rw(unsigned n, u32 addr);
 int swdp_watchpoint_disable(unsigned n);
 
-/* attempt to clear any error state from previous transactions */
-/* return 0 if successful (or no error state existed) */
-int swdp_clear_error(void);
-int swdp_error(void);
-
-int swdp_reset(void);
-
-int swdp_open(void);
-
-void swdp_enable_tracing(int yes);
-
-void swdp_target_reset(int enable);
-
-int swdp_bootloader(void);
-int swdp_set_clock(unsigned khz);
-int swo_set_clock(unsigned khz);
+/* these are now provided by the transport layer */
+//int swdp_reset(void);
+//int swdp_error(void);
+//int swdp_clear_error(void);
+//int swdp_ahb_read(u32 addr, u32 *value);
+//int swdp_ahb_write(u32 addr, u32 value);
+// bulk reads/writes (more efficient after ~3-4 words
+// int swdp_ahb_read32(u32 addr, u32 *out, int count);
+// int swdp_ahb_write32(u32 addr, u32 *out, int count);
+#define swdp_reset debug_attach
+#define swdp_error debug_error
+#define swdp_clear_error debug_clear_error
+#define swdp_ahb_read mem_rd_32
+#define swdp_ahb_write mem_wr_32
+#define swdp_ahb_read32 mem_rd_32_c
+#define swdp_ahb_write32 mem_wr_32_c
 
 #endif