mdebug

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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:
MMakefile | 1+
Atools/arm-m-debug.c | 193+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtools/debugger-core.c | 15+++++++++++++++
Mtools/debugger.h | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Mtools/rswdp.c | 66+++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mtools/rswdp.h | 52++++++++++++++++++++++++++++++----------------------
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