xdebug

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

commit 8b32b4503eb319559015dd5f4e8345700061e627
parent dcda1dd57df990409115278339c19e22065a1a3c
Author: Brian Swetland <swetland@frotz.net>
Date:   Mon, 27 Feb 2023 18:39:28 -0800

api-ize the DAP transport and tidy up the makefile

- move transport code into transport.[ch]
- improve makefile (build source by source, use autodeps)

Diffstat:
M.gitignore | 2+-
MMakefile | 23+++++++++++++++++------
Asrc/transport.c | 415+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/transport.h | 34++++++++++++++++++++++++++++++++++
Msrc/xdebug.c | 399+------------------------------------------------------------------------------
5 files changed, 472 insertions(+), 401 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,2 +1,2 @@ .*.swp -bin/ +out/ diff --git a/Makefile b/Makefile @@ -1,13 +1,24 @@ -all: bin/xdebug +all: out/xdebug -SRCS := src/xdebug.c src/usb.c -DEPS := src/arm-debug.h src/cmsis-dap-protocol.h src/usb.h +CFLAGS := -Wall -g -O1 -bin/xdebug: $(SRCS) $(DEPS) +SRCS := src/xdebug.c src/transport.c src/usb.c +LIBS := -lusb-1.0 + +OBJS := $(addprefix out/,$(patsubst %.c,%.o,$(filter %.c,$(SRCS)))) + +out/xdebug: $(OBJS) + @mkdir -p $(dir $@) + gcc -o $@ -Wall -g -O1 $(OBJS) $(LIBS) + + +$(OBJS): out/%.o: %.c $(XDEPS) @mkdir -p $(dir $@) - gcc -o $@ -Wall -g -O1 $(SRCS) -lusb-1.0 + gcc $(CFLAGS) -c $< -MD -MP -MT $@ -MF $(@:%o=%d) -o $@ + +-include $(OBJS:%o=%d) clean: - rm -f bin/ + rm -f out/ diff --git a/src/transport.c b/src/transport.c @@ -0,0 +1,415 @@ +// Copyright 2023, Brian Swetland <swetland@frotz.net> +// Licensed under the Apache License, Version 2.0. + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include "usb.h" +#include "arm-debug.h" +#include "cmsis-dap-protocol.h" +#include "transport.h" + +struct debug_context { + usb_handle* usb; + unsigned connected; + + // dap protocol info + uint32_t max_packet_count; + uint32_t max_packet_size; + + // configured DP.SELECT register value + uint32_t dp_select; + // last known state of DP.SELECT on the target + uint32_t dp_select_cache; + + // transfer queue state + uint8_t txbuf[1024]; + uint32_t* rxptr[256]; + uint8_t *txnext; + uint32_t** rxnext; + uint32_t txavail; + uint32_t rxavail; + uint32_t qerror; +}; + + +typedef struct debug_context DC; + + +int dap_get_info(DC* dc, unsigned di, void *out, unsigned minlen, unsigned maxlen) { + uint8_t buf[256 + 2]; + buf[0] = DAP_Info; + buf[1] = di; + if (usb_write(dc->usb, buf, 2) != 2) { + return -1; + } + int sz = usb_read(dc->usb, buf, 256 + 2); + if ((sz < 2) || (buf[0] != DAP_Info)) { + return -1; + } + //printf("0x%02x > 0x%02x 0x%02x\n", di, buf[0], buf[1]); + if ((buf[1] < minlen) || (buf[1] > maxlen)) { + return -1; + } + memcpy(out, buf + 2, buf[1]); + return buf[1]; +} + +void dump(const char* str, const void* ptr, unsigned len) { + const uint8_t* x = ptr; + fprintf(stderr, "%s", str); + while (len > 0) { + fprintf(stderr, " %02x", *x++); + len--; + } + fprintf(stderr, "\n"); +} + +int dap_cmd(DC* dc, const void* tx, unsigned txlen, void* rx, unsigned rxlen) { + uint8_t cmd = ((const uint8_t*) tx)[0]; + dump("TX>", tx, txlen); + if (usb_write(dc->usb, tx, txlen) != txlen) { + fprintf(stderr, "dap_cmd(0x%02x): usb write error\n", cmd); + return -1; + } + int sz = usb_read(dc->usb, rx, rxlen); + if (sz < 1) { + fprintf(stderr, "dap_cmd(0x%02x): usb read error\n", cmd); + return -1; + } + dump("RX>", rx, rxlen); + if (((uint8_t*) rx)[0] != cmd) { + fprintf(stderr, "dap_cmd(0x%02x): unsupported (0x%02x)\n", + cmd, ((uint8_t*) rx)[0]); + return -1; + } + // fprintf(stderr, "dap_cmd(0x%02x): sz %u\n", cmd, sz); + return sz; +} + +int dap_cmd_std(DC* dc, const char* name, uint8_t* io, + unsigned txlen, unsigned rxlen) { + if (dap_cmd(dc, io, txlen, io, rxlen) < 0) { + return -1; + } + if (io[1] != 0) { + fprintf(stderr, "%s status 0x%02x\n", name, io[1]); + return -1; + } + return 0; +} + +int dap_connect(DC* dc) { + uint8_t io[2] = { DAP_Connect, PORT_SWD }; + return dap_cmd_std(dc, "dap_connect()", io, 2, 2); +} + +int dap_swd_configure(DC* dc, unsigned cfg) { + uint8_t io[2] = { DAP_SWD_Configure, cfg }; + return dap_cmd_std(dc, "dap_swd_configure()", io, 2, 2); +} + +int dap_transfer_configure(DC* dc, unsigned idle, unsigned wait, unsigned match) { + uint8_t io[6] = { DAP_TransferConfigure, idle, wait, wait >> 8, match, match >> 8}; + return dap_cmd_std(dc, "dap_transfer_configure()", io, 6, 2); +} + + +static void dc_q_clear(DC* dc) { + // fprintf(stderr, "Q CLEAR\n"); + dc->txnext = dc->txbuf + 3; + dc->rxnext = dc->rxptr; + dc->txavail = dc->max_packet_size - 3; + dc->rxavail = dc->max_packet_size - 3; + dc->qerror = 0; + dc->dp_select_cache = 0xFFFFFFFFU; + dc->txbuf[0] = DAP_Transfer; + dc->txbuf[1] = 0; // Index 0 for SWD + dc->txbuf[2] = 0; // Count 0 initially +} + +int dc_q_exec(DC* dc) { + // fprintf(stderr, "Q EXEC\n"); + // if we're already in error, don't generate more usb traffic + if (dc->qerror) { + dc_q_clear(dc); + return -1; + } + // if we have no work to do, succeed + if (dc->txbuf[2] == 0) { + return 0; + } + int sz = dc->txnext - dc->txbuf; + dump("TX>", dc->txbuf, sz); + if (usb_write(dc->usb, dc->txbuf, sz) != sz) { + fprintf(stderr, "dc_q_exec() usb write error\n"); + return -1; + } + sz = 3 + (dc->rxnext - dc->rxptr) * 4; + uint8_t rxbuf[1024]; + memset(rxbuf, 0xEE, 1024); // DEBUG + int n = usb_read(dc->usb, rxbuf, sz); + if (n < 0) { + fprintf(stderr, "dc_q_exec() usb read error\n"); + return -1; + } + dump("RX>", rxbuf, sz); + if ((n < 3) || (rxbuf[0] != DAP_Transfer)) { + fprintf(stderr, "dc_q_exec() bad response\n"); + return -1; + } + if (rxbuf[2] != RSP_ACK_OK) { + fprintf(stderr, "dc_q_exec() error response 0x%02x\n", rxbuf[2]); + return -1; + } + + // how many response words available? + n = (n - 3) / 4; + uint8_t* rxptr = rxbuf + 3; + for (unsigned i = 0; i < n; i++) { + // fprintf(stderr, "RES %02x%02x%02x%02x @ %p\n", + // rxptr[3], rxptr[2], rxptr[1], rxptr[0], + // dc->rxptr[i]); + memcpy(dc->rxptr[i], rxptr, 4); + rxptr += 4; + } + dc_q_clear(dc); + return 0; +} + +// internal use only -- queue raw dp reads and writes +// these do not check req for correctness +static void dc_q_raw_rd(DC* dc, unsigned req, uint32_t* val) { + // fprintf(stderr, "Q RAW RD %08x @ %p\n", req, val); + if ((dc->txavail < 1) || (dc->rxavail < 4)) { + if (dc_q_exec(dc) < 0) { + dc->qerror = 1; + return; + } + } + dc->txnext[0] = req; + dc->rxnext[0] = val; + dc->txnext += 1; + dc->rxnext += 1; + dc->txbuf[2] += 1; + dc->txavail -= 1; + dc->rxavail -= 4; +} + +static void dc_q_raw_wr(DC* dc, unsigned req, uint32_t val) { + // fprintf(stderr, "Q RAW WR %08x %08x\n", req, val); + if (dc->txavail < 5) { + if (dc_q_exec(dc) < 0) { + dc->qerror = 1; + return; + } + } + dc->txnext[0] = req; + memcpy(dc->txnext + 1, &val, 4); + dc->txnext += 5; + dc->txavail -= 5; + dc->txbuf[2] += 1; +} + +// adjust DP.SELECT for desired DP access, if necessary +void dc_q_dp_sel(DC* dc, uint32_t dpaddr) { + // fprintf(stderr, "DP SEL %08x (select is %08x)\n", dpaddr, dc->dp_select_cache); + // DP address is BANK:4 REG:4 + if (dpaddr & 0xFFFFFF03U) { + fprintf(stderr, "invalid DP addr 0x%08x\n", dpaddr); + dc->qerror = 1; + return; + } + // only register 4 cares about the value of DP.SELECT.DPBANK + // so do nothing unless we're setting a register 4 variant + if ((dpaddr & 0xF) != 0x4) { + return; + } + uint32_t mask = DP_SELECT_DPBANK(0xFU); + uint32_t addr = DP_SELECT_DPBANK((dpaddr >> 4)); + uint32_t select = (dc->dp_select & mask) | addr; + if (select != dc->dp_select_cache) { + dc->dp_select_cache = select; + dc_q_raw_wr(dc, XFER_DP | XFER_WR | DP_SELECT, select); + } +} + +// adjust DP.SELECT for desired AP access, if necessary +void dc_q_ap_sel(DC* dc, uint32_t apaddr) { + // AP address is AP:8 BANK:4 REG:4 + if (apaddr & 0xFFFF0003U) { + fprintf(stderr, "invalid DP addr 0x%08x\n", apaddr); + dc->qerror = 1; + return; + } + // we always return DPBANK to 0 when adjusting AP & APBANK + // since it preceeds an AP write which will need DPBANK at 0 + uint32_t select = + DP_SELECT_AP((apaddr & 0xFF00U) << 16) | + DP_SELECT_APBANK(apaddr >> 4); + if (select != dc->dp_select_cache) { + dc->dp_select_cache = select; + dc_q_raw_wr(dc, XFER_DP | XFER_WR | DP_SELECT, select); + } +} + +// DP and AP reads and writes +// DP.SELECT will be adjusted as necessary to ensure proper addressing +void dc_q_dp_rd(DC* dc, unsigned dpaddr, uint32_t* val) { + if (dc->qerror) return; + dc_q_dp_sel(dc, dpaddr); + dc_q_raw_rd(dc, XFER_DP | XFER_RD | (dpaddr & 0x0C), val); +} + +void dc_q_dp_wr(DC* dc, unsigned dpaddr, uint32_t val) { + if (dc->qerror) return; + dc_q_dp_sel(dc, dpaddr); + dc_q_raw_wr(dc, XFER_DP | XFER_WR | (dpaddr & 0x0C), val); +} + +void dc_q_ap_rd(DC* dc, unsigned apaddr, uint32_t* val) { + if (dc->qerror) return; + dc_q_ap_sel(dc, apaddr); + dc_q_raw_rd(dc, XFER_AP | XFER_RD | (apaddr & 0x0C), val); + +} + +void dc_q_ap_wr(DC* dc, unsigned apaddr, uint32_t val) { + if (dc->qerror) return; + dc_q_ap_sel(dc, apaddr); + dc_q_raw_wr(dc, XFER_AP | XFER_WR | (apaddr & 0x0C), val); +} + + +// convenience wrappers for single reads and writes +int dc_dp_rd(DC* dc, unsigned dpaddr, uint32_t* val) { + dc_q_dp_rd(dc, dpaddr, val); + return dc_q_exec(dc); +} +int dc_dp_wr(DC* dc, unsigned dpaddr, uint32_t val) { + dc_q_dp_wr(dc, dpaddr, val); + return dc_q_exec(dc); +} +int dc_ap_rd(DC* dc, unsigned apaddr, uint32_t* val) { + dc_q_ap_rd(dc, apaddr, val); + return dc_q_exec(dc); +} +int dc_ap_wr(DC* dc, unsigned apaddr, uint32_t val) { + dc_q_ap_wr(dc, apaddr, val); + return dc_q_exec(dc); +} + +int dc_attach(DC* dc) { + uint8_t io[23] = { DAP_SWD_Sequence, 3, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 64 1s + 0x10, 0x9E, 0xE7, // JTAG to SWD magic sequence + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, // 60 1s, 4 0s + }; + if (dap_cmd(dc, io, 23, io, 2) < 0) { + return -1; + } + if (io[1] != 0) { + fprintf(stderr, "dc_attach() failure 0x%02x\n", io[1]); + return -1; + } + return 0; +} + +static usb_handle* usb_connect(void) { + usb_handle *usb; + + usb = usb_open(0x1fc9, 0x0143, 0); + if (usb == 0) { + usb = usb_open(0x2e8a, 0x000c, 42); + if (usb == 0) { + fprintf(stderr, "cannot find device\n"); + return NULL; + } + } + return usb; +} + +int dc_create(DC** out) { + DC* dc; + uint8_t buf[256 + 2]; + uint32_t n32; + uint16_t n16; + uint8_t n8; + + if ((dc = calloc(1, sizeof(DC))) == NULL) { + return -1; + } + + if ((dc->usb = usb_connect()) == NULL) { + free(dc); + return -1; + } + + dc->max_packet_count = 1; + dc->max_packet_size = 64; + dc_q_clear(dc); + + buf[0] = DAP_Info; + for (unsigned n = 0; n < 10; n++) { + int sz = dap_get_info(dc, n, buf, 0, 255); + if (sz > 0) { + buf[sz] = 0; + printf("0x%02x: '%s'\n", n, (char*) buf); + } + } + + buf[0] = 0; buf[1] = 0; + if (dap_get_info(dc, DI_Capabilities, buf, 1, 2) > 0) { + printf("Capabilities: 0x%02x 0x%02x\n", buf[0], buf[1]); + printf("Capabilities:"); + if (buf[0] & I0_SWD) printf(" SWD"); + if (buf[0] & I0_JTAG) printf(" JTAG"); + if (buf[0] & I0_SWO_UART) printf(" SWO(UART)"); + if (buf[0] & I0_SWO_Manchester) printf(" SWO(Manchester)"); + if (buf[0] & I0_Atomic_Commands) printf(" ATOMIC"); + if (buf[0] & I0_Test_Domain_Timer) printf(" TIMER"); + if (buf[0] & I0_SWO_Streaming_Trace) printf(" SWO(Streaming)"); + if (buf[0] & I0_UART_Comm_Port) printf(" UART"); + if (buf[1] & I1_USB_COM_Port) printf(" USBCOM"); + printf("\n"); + } + if (dap_get_info(dc, DI_UART_RX_Buffer_Size, &n32, 4, 4) == 4) { + printf("UART RX Buffer Size: %u\n", n32); + } + if (dap_get_info(dc, DI_UART_TX_Buffer_Size, &n32, 4, 4) == 4) { + printf("UART TX Buffer Size: %u\n", n32); + } + if (dap_get_info(dc, DI_SWO_Trace_Buffer_Size, &n32, 4, 4) == 4) { + printf("SWO Trace Buffer Size: %u\n", n32); + } + if (dap_get_info(dc, DI_Max_Packet_Count, &n8, 1, 1) == 1) { + printf("Max Packet Count: %u\n", n8); + dc->max_packet_count = n8; + } + if (dap_get_info(dc, DI_Max_Packet_Size, &n16, 2, 2) == 2) { + printf("Max Packet Size: %u\n", n16); + dc->max_packet_size = n16; + } + if ((dc->max_packet_count < 1) || (dc->max_packet_size < 64)) { + fprintf(stderr, "dc_init() impossible packet configuration\n"); + free(dc); + return -1; + } + + // clip to our buffer size + if (dc->max_packet_size > 1024) { + dc->max_packet_size = 1024; + } + + // update based on queried state + dc_q_clear(dc); + + dap_connect(dc); + dap_swd_configure(dc, CFG_Turnaround_1); + dap_transfer_configure(dc, 8, 64, 0); + + *out = dc; + return 0; +} diff --git a/src/transport.h b/src/transport.h @@ -0,0 +1,34 @@ +// Copyright 2023, Brian Swetland <swetland@frotz.net> +// Licensed under the Apache License, Version 2.0. + +#pragma once + +#include <stdint.h> + +typedef struct debug_context dctx_t; + +// queue Debug Port reads and writes +// DP.SELECT will be updated as necessary +void dc_q_dp_rd(dctx_t* dc, unsigned dpaddr, uint32_t* val); +void dc_q_dp_wr(dctx_t* dc, unsigned dpaddr, uint32_t val); + +// queue Access Port reads and writes +// DP.SELECT will be updated as necessary +void dc_q_ap_rd(dctx_t* dc, unsigned apaddr, uint32_t* val); +void dc_q_ap_wr(dctx_t* dc, unsigned apaddr, uint32_t val); + +// execute any outstanding transactions, return final status +int dc_q_exec(dctx_t* dc); + +// convenince wrappers for a single read/write and then exec +int dc_dp_rd(dctx_t* dc, unsigned dpaddr, uint32_t* val); +int dc_dp_wr(dctx_t* dc, unsigned dpaddr, uint32_t val); +int dc_ap_rd(dctx_t* dc, unsigned apaddr, uint32_t* val); +int dc_ap_wr(dctx_t* dc, unsigned apaddr, uint32_t val); + +// create debug connection +int dc_create(dctx_t** dc); + +// attempt to attach to the debug target +int dc_attach(dctx_t* dc); + diff --git a/src/xdebug.c b/src/xdebug.c @@ -6,408 +6,21 @@ #include <unistd.h> #include <string.h> -#include "usb.h" #include "arm-debug.h" #include "cmsis-dap-protocol.h" - -struct debug_context { - usb_handle* usb; - unsigned connected; - - // dap protocol info - uint32_t max_packet_count; - uint32_t max_packet_size; - - // configured DP.SELECT register value - uint32_t dp_select; - // last known state of DP.SELECT on the target - uint32_t dp_select_cache; - - // transfer queue state - uint8_t txbuf[1024]; - uint32_t* rxptr[256]; - uint8_t *txnext; - uint32_t** rxnext; - uint32_t txavail; - uint32_t rxavail; - uint32_t qerror; -}; - - -typedef struct debug_context DC; - - -int dap_get_info(DC* dc, unsigned di, void *out, unsigned minlen, unsigned maxlen) { - uint8_t buf[256 + 2]; - buf[0] = DAP_Info; - buf[1] = di; - if (usb_write(dc->usb, buf, 2) != 2) { - return -1; - } - int sz = usb_read(dc->usb, buf, 256 + 2); - if ((sz < 2) || (buf[0] != DAP_Info)) { - return -1; - } - //printf("0x%02x > 0x%02x 0x%02x\n", di, buf[0], buf[1]); - if ((buf[1] < minlen) || (buf[1] > maxlen)) { - return -1; - } - memcpy(out, buf + 2, buf[1]); - return buf[1]; -} - -void dump(const char* str, const void* ptr, unsigned len) { - const uint8_t* x = ptr; - fprintf(stderr, "%s", str); - while (len > 0) { - fprintf(stderr, " %02x", *x++); - len--; - } - fprintf(stderr, "\n"); -} - -int dap_cmd(DC* dc, const void* tx, unsigned txlen, void* rx, unsigned rxlen) { - uint8_t cmd = ((const uint8_t*) tx)[0]; - dump("TX>", tx, txlen); - if (usb_write(dc->usb, tx, txlen) != txlen) { - fprintf(stderr, "dap_cmd(0x%02x): usb write error\n", cmd); - return -1; - } - int sz = usb_read(dc->usb, rx, rxlen); - if (sz < 1) { - fprintf(stderr, "dap_cmd(0x%02x): usb read error\n", cmd); - return -1; - } - dump("RX>", rx, rxlen); - if (((uint8_t*) rx)[0] != cmd) { - fprintf(stderr, "dap_cmd(0x%02x): unsupported (0x%02x)\n", - cmd, ((uint8_t*) rx)[0]); - return -1; - } - // fprintf(stderr, "dap_cmd(0x%02x): sz %u\n", cmd, sz); - return sz; -} - -int dap_cmd_std(DC* dc, const char* name, uint8_t* io, - unsigned txlen, unsigned rxlen) { - if (dap_cmd(dc, io, txlen, io, rxlen) < 0) { - return -1; - } - if (io[1] != 0) { - fprintf(stderr, "%s status 0x%02x\n", name, io[1]); - return -1; - } - return 0; -} - -int dap_connect(DC* dc) { - uint8_t io[2] = { DAP_Connect, PORT_SWD }; - return dap_cmd_std(dc, "dap_connect()", io, 2, 2); -} - -int dap_swd_configure(DC* dc, unsigned cfg) { - uint8_t io[2] = { DAP_SWD_Configure, cfg }; - return dap_cmd_std(dc, "dap_swd_configure()", io, 2, 2); -} - -int dap_transfer_configure(DC* dc, unsigned idle, unsigned wait, unsigned match) { - uint8_t io[6] = { DAP_TransferConfigure, idle, wait, wait >> 8, match, match >> 8}; - return dap_cmd_std(dc, "dap_transfer_configure()", io, 6, 2); -} - -int swd_init(DC* dc) { - uint8_t io[23] = { DAP_SWD_Sequence, 3, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 64 1s - 0x10, 0x9E, 0xE7, // JTAG to SWD magic sequence - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, // 60 1s, 4 0s - }; - if (dap_cmd(dc, io, 23, io, 2) < 0) { - return -1; - } - if (io[1] != 0) { - fprintf(stderr, "swd_init() failure 0x%02x\n", io[1]); - return -1; - } - return 0; -} - -static void dc_q_clear(DC* dc) { - // fprintf(stderr, "Q CLEAR\n"); - dc->txnext = dc->txbuf + 3; - dc->rxnext = dc->rxptr; - dc->txavail = dc->max_packet_size - 3; - dc->rxavail = dc->max_packet_size - 3; - dc->qerror = 0; - dc->dp_select_cache = 0xFFFFFFFFU; - dc->txbuf[0] = DAP_Transfer; - dc->txbuf[1] = 0; // Index 0 for SWD - dc->txbuf[2] = 0; // Count 0 initially -} - -int dc_q_exec(DC* dc) { - // fprintf(stderr, "Q EXEC\n"); - // if we're already in error, don't generate more usb traffic - if (dc->qerror) { - dc_q_clear(dc); - return -1; - } - // if we have no work to do, succeed - if (dc->txbuf[2] == 0) { - return 0; - } - int sz = dc->txnext - dc->txbuf; - dump("TX>", dc->txbuf, sz); - if (usb_write(dc->usb, dc->txbuf, sz) != sz) { - fprintf(stderr, "dc_q_exec() usb write error\n"); - return -1; - } - sz = 3 + (dc->rxnext - dc->rxptr) * 4; - uint8_t rxbuf[1024]; - memset(rxbuf, 0xEE, 1024); // DEBUG - int n = usb_read(dc->usb, rxbuf, sz); - if (n < 0) { - fprintf(stderr, "dc_q_exec() usb read error\n"); - return -1; - } - dump("RX>", rxbuf, sz); - if ((n < 3) || (rxbuf[0] != DAP_Transfer)) { - fprintf(stderr, "dc_q_exec() bad response\n"); - return -1; - } - if (rxbuf[2] != RSP_ACK_OK) { - fprintf(stderr, "dc_q_exec() error response 0x%02x\n", rxbuf[2]); - return -1; - } - - // how many response words available? - n = (n - 3) / 4; - uint8_t* rxptr = rxbuf + 3; - for (unsigned i = 0; i < n; i++) { - // fprintf(stderr, "RES %02x%02x%02x%02x @ %p\n", - // rxptr[3], rxptr[2], rxptr[1], rxptr[0], - // dc->rxptr[i]); - memcpy(dc->rxptr[i], rxptr, 4); - rxptr += 4; - } - dc_q_clear(dc); - return 0; -} - -// internal use only -- queue raw dp reads and writes -// these do not check req for correctness -static void dc_q_raw_rd(DC* dc, unsigned req, uint32_t* val) { - // fprintf(stderr, "Q RAW RD %08x @ %p\n", req, val); - if ((dc->txavail < 1) || (dc->rxavail < 4)) { - if (dc_q_exec(dc) < 0) { - dc->qerror = 1; - return; - } - } - dc->txnext[0] = req; - dc->rxnext[0] = val; - dc->txnext += 1; - dc->rxnext += 1; - dc->txbuf[2] += 1; - dc->txavail -= 1; - dc->rxavail -= 4; -} - -static void dc_q_raw_wr(DC* dc, unsigned req, uint32_t val) { - // fprintf(stderr, "Q RAW WR %08x %08x\n", req, val); - if (dc->txavail < 5) { - if (dc_q_exec(dc) < 0) { - dc->qerror = 1; - return; - } - } - dc->txnext[0] = req; - memcpy(dc->txnext + 1, &val, 4); - dc->txnext += 5; - dc->txavail -= 5; - dc->txbuf[2] += 1; -} - -// adjust DP.SELECT for desired DP access, if necessary -void dc_q_dp_sel(DC* dc, uint32_t dpaddr) { - // fprintf(stderr, "DP SEL %08x (select is %08x)\n", dpaddr, dc->dp_select_cache); - // DP address is BANK:4 REG:4 - if (dpaddr & 0xFFFFFF03U) { - fprintf(stderr, "invalid DP addr 0x%08x\n", dpaddr); - dc->qerror = 1; - return; - } - // only register 4 cares about the value of DP.SELECT.DPBANK - // so do nothing unless we're setting a register 4 variant - if ((dpaddr & 0xF) != 0x4) { - return; - } - uint32_t mask = DP_SELECT_DPBANK(0xFU); - uint32_t addr = DP_SELECT_DPBANK((dpaddr >> 4)); - uint32_t select = (dc->dp_select & mask) | addr; - if (select != dc->dp_select_cache) { - dc->dp_select_cache = select; - dc_q_raw_wr(dc, XFER_DP | XFER_WR | DP_SELECT, select); - } -} - -// adjust DP.SELECT for desired AP access, if necessary -void dc_q_ap_sel(DC* dc, uint32_t apaddr) { - // AP address is AP:8 BANK:4 REG:4 - if (apaddr & 0xFFFF0003U) { - fprintf(stderr, "invalid DP addr 0x%08x\n", apaddr); - dc->qerror = 1; - return; - } - // we always return DPBANK to 0 when adjusting AP & APBANK - // since it preceeds an AP write which will need DPBANK at 0 - uint32_t select = - DP_SELECT_AP((apaddr & 0xFF00U) << 16) | - DP_SELECT_APBANK(apaddr >> 4); - if (select != dc->dp_select_cache) { - dc->dp_select_cache = select; - dc_q_raw_wr(dc, XFER_DP | XFER_WR | DP_SELECT, select); - } -} - -// DP and AP reads and writes -// DP.SELECT will be adjusted as necessary to ensure proper addressing -void dc_q_dp_rd(DC* dc, unsigned dpaddr, uint32_t* val) { - if (dc->qerror) return; - dc_q_dp_sel(dc, dpaddr); - dc_q_raw_rd(dc, XFER_DP | XFER_RD | (dpaddr & 0x0C), val); -} - -void dc_q_dp_wr(DC* dc, unsigned dpaddr, uint32_t val) { - if (dc->qerror) return; - dc_q_dp_sel(dc, dpaddr); - dc_q_raw_wr(dc, XFER_DP | XFER_WR | (dpaddr & 0x0C), val); -} - -void dc_q_ap_rd(DC* dc, unsigned apaddr, uint32_t* val) { - if (dc->qerror) return; - dc_q_ap_sel(dc, apaddr); - dc_q_raw_rd(dc, XFER_AP | XFER_RD | (apaddr & 0x0C), val); - -} - -void dc_q_ap_wr(DC* dc, unsigned apaddr, uint32_t val) { - if (dc->qerror) return; - dc_q_ap_sel(dc, apaddr); - dc_q_raw_wr(dc, XFER_AP | XFER_WR | (apaddr & 0x0C), val); -} - - -// convenience wrappers for single reads and writes -int dc_dp_rd(DC* dc, unsigned dpaddr, uint32_t* val) { - dc_q_dp_rd(dc, dpaddr, val); - return dc_q_exec(dc); -} -int dc_dp_wr(DC* dc, unsigned dpaddr, uint32_t val) { - dc_q_dp_wr(dc, dpaddr, val); - return dc_q_exec(dc); -} -int dc_ap_rd(DC* dc, unsigned apaddr, uint32_t* val) { - dc_q_ap_rd(dc, apaddr, val); - return dc_q_exec(dc); -} -int dc_ap_wr(DC* dc, unsigned apaddr, uint32_t val) { - dc_q_ap_wr(dc, apaddr, val); - return dc_q_exec(dc); -} - - - -int dc_init(DC* dc, usb_handle* usb) { - uint8_t buf[256 + 2]; - uint32_t n32; - uint16_t n16; - uint8_t n8; - - memset(dc, 0, sizeof(DC)); - dc->usb = usb; - dc->max_packet_count = 1; - dc->max_packet_size = 64; - dc_q_clear(dc); - - buf[0] = DAP_Info; - for (unsigned n = 0; n < 10; n++) { - int sz = dap_get_info(dc, n, buf, 0, 255); - if (sz > 0) { - buf[sz] = 0; - printf("0x%02x: '%s'\n", n, (char*) buf); - } - } - - buf[0] = 0; buf[1] = 0; - if (dap_get_info(dc, DI_Capabilities, buf, 1, 2) > 0) { - printf("Capabilities: 0x%02x 0x%02x\n", buf[0], buf[1]); - printf("Capabilities:"); - if (buf[0] & I0_SWD) printf(" SWD"); - if (buf[0] & I0_JTAG) printf(" JTAG"); - if (buf[0] & I0_SWO_UART) printf(" SWO(UART)"); - if (buf[0] & I0_SWO_Manchester) printf(" SWO(Manchester)"); - if (buf[0] & I0_Atomic_Commands) printf(" ATOMIC"); - if (buf[0] & I0_Test_Domain_Timer) printf(" TIMER"); - if (buf[0] & I0_SWO_Streaming_Trace) printf(" SWO(Streaming)"); - if (buf[0] & I0_UART_Comm_Port) printf(" UART"); - if (buf[1] & I1_USB_COM_Port) printf(" USBCOM"); - printf("\n"); - } - if (dap_get_info(dc, DI_UART_RX_Buffer_Size, &n32, 4, 4) == 4) { - printf("UART RX Buffer Size: %u\n", n32); - } - if (dap_get_info(dc, DI_UART_TX_Buffer_Size, &n32, 4, 4) == 4) { - printf("UART TX Buffer Size: %u\n", n32); - } - if (dap_get_info(dc, DI_SWO_Trace_Buffer_Size, &n32, 4, 4) == 4) { - printf("SWO Trace Buffer Size: %u\n", n32); - } - if (dap_get_info(dc, DI_Max_Packet_Count, &n8, 1, 1) == 1) { - printf("Max Packet Count: %u\n", n8); - dc->max_packet_count = n8; - } - if (dap_get_info(dc, DI_Max_Packet_Size, &n16, 2, 2) == 2) { - printf("Max Packet Size: %u\n", n16); - dc->max_packet_size = n16; - } - if ((dc->max_packet_count < 1) || (dc->max_packet_size < 64)) { - fprintf(stderr, "dc_init() impossible packet configuration\n"); - return -1; - } - - // clip to our buffer size - if (dc->max_packet_size > 1024) { - dc->max_packet_size = 1024; - } - - // update based on queried state - dc_q_clear(dc); - return 0; -} +#include "transport.h" int main(int argc, char **argv) { - usb_handle *usb; uint32_t n; - usb = usb_open(0x1fc9, 0x0143, 0); - if (usb == 0) { - usb = usb_open(0x2e8a, 0x000c, 42); - if (usb == 0) { - fprintf(stderr, "cannot find device\n"); - return -1; - } + dctx_t* dc; + if (dc_create(&dc) < 0) { + return -1; } - DC context; - DC* dc = &context; - dc_init(dc, usb); + dc_attach(dc); - dap_connect(dc); - dap_swd_configure(dc, CFG_Turnaround_1); - dap_transfer_configure(dc, 8, 64, 0); - swd_init(dc); n = 0; - dc_dp_rd(dc, DP_DPIDR, &n); printf("IDCODE %08x\n", n); @@ -421,5 +34,3 @@ int main(int argc, char **argv) { return 0; } - -