From ef558eebb8e7c4648c95c3d1c16c3e40c4dde246 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Sat, 25 Apr 2020 14:55:48 +0200 Subject: [PATCH] CMSIS-DAP support. Thanks to edbg, pyocd and openocd for code and ideas. --- .travis.yml | 2 +- src/platforms/hosted/Makefile.inc | 13 +- src/platforms/hosted/cmsis_dap.c | 372 +++++++++++++++ src/platforms/hosted/cmsis_dap.h | 50 ++ src/platforms/hosted/dap.c | 753 ++++++++++++++++++++++++++++++ src/platforms/hosted/dap.h | 94 ++++ src/platforms/hosted/platform.c | 30 ++ src/platforms/pc/cl_utils.c | 2 +- src/platforms/pc/cl_utils.h | 7 + 9 files changed, 1318 insertions(+), 5 deletions(-) create mode 100644 src/platforms/hosted/cmsis_dap.c create mode 100644 src/platforms/hosted/cmsis_dap.h create mode 100644 src/platforms/hosted/dap.c create mode 100644 src/platforms/hosted/dap.h diff --git a/.travis.yml b/.travis.yml index 5806aef4..c7dc4247 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - wget http://www.intra2net.com/en/developer/libftdi/download/libftdi1-1.2.tar.bz2.sig - gpg --trust-model always --verify libftdi1-1.2.tar.bz2.sig - tar -xjf libftdi1-1.2.tar.bz2 - - sudo apt-get install -y build-essential libboost-all-dev gcc-arm-embedded libusb-1.0-0-dev + - sudo apt-get install -y build-essential libboost-all-dev gcc-arm-embedded libusb-1.0-0-dev libhidapi-dev install: - cd libftdi1-1.2 diff --git a/src/platforms/hosted/Makefile.inc b/src/platforms/hosted/Makefile.inc index 656f450b..dd1dfc44 100644 --- a/src/platforms/hosted/Makefile.inc +++ b/src/platforms/hosted/Makefile.inc @@ -9,14 +9,14 @@ LDFLAGS += -lasan else ifneq (, $(findstring mingw, $(SYS))) SRC += serial_win.c LDFLAGS += -lws2_32 -LDFLAGS += -lhid -lsetupapi +LDFLAGS += -lsetupapi else ifneq (, $(findstring cygwin, $(SYS))) SRC += serial_win.c LDFLAGS += -lws2_32 -LDFLAGS += -lhid -lsetupapi +LDFLAGS += -lsetupapi #https://github.com/dmlc/xgboost/issues/1945 indicates macosx as indicator else ifneq (filter, macosx darwin, $(SYS))) -LDFLAGS += -lhid -lsetupapi +LDFLAGS += -lsetupapi LDFLAGS += hidapi/mac/.libs/libhidapi.a -framework IOKit LDFLAGS += -framework CoreFoundation hidapi/mac/.libs/libhidapi.a CFLAGS += -Ihidapi/hidapi @@ -26,6 +26,13 @@ LDFLAGS += -lusb-1.0 CFLAGS += $(shell pkg-config --cflags libftdi1) LDFLAGS += $(shell pkg-config --libs libftdi1) +ifeq ($(shell pkg-config --exists hidapi-libusb && echo 0), 0) +CFLAGS += $(shell pkg-config --cflags hidapi-libusb) +LDFLAGS += $(shell pkg-config --libs hidapi-libusb) +CFLAGS += -DCMSIS_DAP +SRC += cmsis_dap.c dap.c +endif + VPATH += platforms/pc SRC += timing.c cl_utils.c utils.c libusb_utils.c SRC += stlinkv2.c diff --git a/src/platforms/hosted/cmsis_dap.c b/src/platforms/hosted/cmsis_dap.c new file mode 100644 index 00000000..04c39059 --- /dev/null +++ b/src/platforms/hosted/cmsis_dap.c @@ -0,0 +1,372 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2019-20 Uwe Bonnes + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/* Modified from edbg.c + * Links between bmp and edbg + * + * https://arm-software.github.io/CMSIS_5/DAP/html/index.html +*/ + +#include "general.h" +#include "gdb_if.h" +#include "adiv5.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "dap.h" +#include "cmsis_dap.h" + +#include "cl_utils.h" +#include "target.h" +#include "target_internal.h" + +#define MAX_DEBUGGERS 20 + +uint8_t dap_caps; +uint8_t mode; + +/*- Variables ---------------------------------------------------------------*/ +static hid_device *handle = NULL; +static uint8_t hid_buffer[1024 + 1]; +static int report_size = 512 + 1; // TODO: read actual report size +/* LPC845 Breakout Board Rev. 0 report invalid response with > 65 bytes */ +int dap_init(bmp_info_t *info) +{ + if (hid_init()) + return -1; + int size = strlen(info->serial); + wchar_t serial[size + 1], *wc = serial; + for (int i = 0; i < size; i++) + *wc++ = info->serial[i]; + *wc = 0; + /* Blacklist devices that do not wirk with 513 byte report length + * FIXME: Find a solution to decipher from the device. + */ + if ((info->vid == 0x1fc9) && (info->pid == 0x0132)) { + printf("Blacklist\n"); + report_size = 64 + 1; + } + handle = hid_open(info->vid, info->pid, serial); + if (!handle) + return -1; + dap_disconnect(); + size = dap_info(DAP_INFO_CAPABILITIES, hid_buffer, sizeof(hid_buffer)); + dap_caps = hid_buffer[0]; + printf(" Cap (0x%2x): %s%s%s", hid_buffer[0], + (hid_buffer[0] & 1)? "SWD" : "", + ((hid_buffer[0] & 3) == 3) ? "/" : "", + (hid_buffer[0] & 2)? "JTAG" : ""); + if (hid_buffer[0] & 4) + printf(", SWO_UART"); + if (hid_buffer[0] & 8) + printf(", SWO_MANCHESTER"); + if (hid_buffer[0] & 0x10) + printf(", Atomic Cmds"); + printf("\n"); + return 0; +} + +static void dap_dp_abort(ADIv5_DP_t *dp, uint32_t abort) +{ + /* DP Write to Reg 0.*/ + dap_write_reg(dp, ADIV5_DP_ABORT, abort); +} + +static uint32_t dap_dp_error(ADIv5_DP_t *dp) +{ + uint32_t ctrlstat = dap_read_reg(dp, ADIV5_DP_CTRLSTAT); + uint32_t err = ctrlstat & + (ADIV5_DP_CTRLSTAT_STICKYORUN | ADIV5_DP_CTRLSTAT_STICKYCMP | + ADIV5_DP_CTRLSTAT_STICKYERR | ADIV5_DP_CTRLSTAT_WDATAERR); + uint32_t clr = 0; + if(err & ADIV5_DP_CTRLSTAT_STICKYORUN) + clr |= ADIV5_DP_ABORT_ORUNERRCLR; + if(err & ADIV5_DP_CTRLSTAT_STICKYCMP) + clr |= ADIV5_DP_ABORT_STKCMPCLR; + if(err & ADIV5_DP_CTRLSTAT_STICKYERR) + clr |= ADIV5_DP_ABORT_STKERRCLR; + if(err & ADIV5_DP_CTRLSTAT_WDATAERR) + clr |= ADIV5_DP_ABORT_WDERRCLR; + dap_write_reg(dp, ADIV5_DP_ABORT, clr); + dp->fault = 0; + return err; +} + +static uint32_t dap_dp_low_access(struct ADIv5_DP_s *dp, uint8_t RnW, + uint16_t addr, uint32_t value) +{ + bool APnDP = addr & ADIV5_APnDP; + uint32_t res = 0; + uint8_t reg = (addr & 0xc) | ((APnDP)? 1 : 0); + if (RnW) { + res = dap_read_reg(dp, reg); + } + else { + dap_write_reg(dp, reg, value); + } + return res; +} + +static uint32_t dap_dp_read_reg(ADIv5_DP_t *dp, uint16_t addr) +{ + return dap_read_reg(dp, addr); +} + +void dap_exit_function(void) +{ + if (handle) { + dap_disconnect(); + hid_close(handle); + } +} + +int dbg_get_report_size(void) +{ + return report_size; +} + +int dbg_dap_cmd(uint8_t *data, int size, int rsize) + +{ + char cmd = data[0]; + int res; + + memset(hid_buffer, 0xff, report_size + 1); + + hid_buffer[0] = 0x00; // Report ID?? + memcpy(&hid_buffer[1], data, rsize); + + if (cl_debuglevel & BMP_DEBUG_WIRE) { + printf("cmd : "); + for(int i = 0; (i < 16) && (i < rsize + 1); i++) + printf("%02x.", hid_buffer[i]); + printf("\n"); + } + res = hid_write(handle, hid_buffer, rsize + 1); + if (res < 0) { + fprintf(stderr, "Error: %ls\n", hid_error(handle)); + exit(-1); + } + if (size) { + res = hid_read(handle, hid_buffer, report_size + 1); + if (res < 0) { + fprintf(stderr, "debugger read(): %ls\n", hid_error(handle)); + exit(-1); + } + if (size && hid_buffer[0] != cmd) { + printf("cmd %02x invalid response received %02x\n", + cmd, hid_buffer[0]); + } + res--; + memcpy(data, &hid_buffer[1], (size < res) ? size : res); + if (cl_debuglevel & BMP_DEBUG_WIRE) { + printf("cmd res:"); + for(int i = 0; (i < 16) && (i < size + 4); i++) + printf("%02x.", hid_buffer[i]); + printf("\n"); + } + } + + return res; +} +#define ALIGNOF(x) (((x) & 3) == 0 ? ALIGN_WORD : \ + (((x) & 1) == 0 ? ALIGN_HALFWORD : ALIGN_BYTE)) + +static void dap_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len) +{ + if (len == 0) + return; + enum align align = MIN(ALIGNOF(src), ALIGNOF(len)); +#if 0 + printf("memread @ %" PRIx32 " len %ld, align %d , start: \n", + src, len, align); +#endif + if (((unsigned)(1 << align)) == len) + return dap_read_single(ap, dest, src, align); + /* One word transfer for every byte/halfword/word + * Total number of bytes in transfer*/ + unsigned int max_size = (dbg_get_report_size() - 5) >> (2 - align); + while (len) { + dap_ap_mem_access_setup(ap, src, align); + /* Calculate length until next access setup is needed */ + unsigned int blocksize = (src | 0x3ff) - src + 1; + if (blocksize > len) + blocksize = len; + while (blocksize) { + unsigned int transfersize = blocksize; + if (transfersize > max_size) + transfersize = max_size; + unsigned int res = dap_read_block(ap, dest, src, transfersize, + align); + if (res) { +// printf("mem_read failed %02x\n", res); + ap->dp->fault = 1; + return; + } + blocksize -= transfersize; + len -= transfersize; + dest += transfersize; + src += transfersize; + } + } +// printf("memread res last data %08" PRIx32 "\n", ((uint32_t*)dest)[-1]); +} + +static void dap_mem_write_sized( + ADIv5_AP_t *ap, uint32_t dest, const void *src, + size_t len, enum align align) +{ + if (len == 0) + return; +#if 0 + printf("memwrite @ %" PRIx32 " len %ld, align %d , %08x start: \n", + dest, len, align, *(uint32_t *)src); +#endif + if (((unsigned)(1 << align)) == len) + return dap_write_single(ap, dest, src, align); + unsigned int max_size = (dbg_get_report_size() - 5) >> (2 - align); + while (len) { + dap_ap_mem_access_setup(ap, dest, align); + unsigned int blocksize = (dest | 0x3ff) - dest + 1; + if (blocksize > len) + blocksize = len; + while (blocksize) { + unsigned int transfersize = blocksize; + if (transfersize > max_size) + transfersize = max_size; + unsigned int res = dap_write_block(ap, dest, src, transfersize, + align); + if (res) { + printf("mem_write failed %02x\n", res); + ap->dp->fault = 1; + return; + } + blocksize -= transfersize; + len -= transfersize; + dest += transfersize; + src += transfersize; + } + } +// printf("memwrite done\n"); +} + +int dap_enter_debug_swd(ADIv5_DP_t *dp) +{ + target_list_free(); + if (!(dap_caps & DAP_CAP_SWD)) + return -1; + mode = DAP_CAP_SWD; + dap_swj_clock(2000000); + dap_transfer_configure(2, 128, 128); + dap_swd_configure(0); + dap_connect(false); + dap_led(0, 1); + dap_reset_link(false); + + dp->idcode = dap_read_idcode(dp); + dp->dp_read = dap_dp_read_reg; + dp->error = dap_dp_error; + dp->low_access = dap_dp_low_access; + dp->abort = dap_dp_abort; /* DP Write to Reg 0.*/ + return 0; +} + +void dap_adiv5_dp_defaults(ADIv5_DP_t *dp) +{ + if ((mode == DAP_CAP_JTAG) && dap_jtag_configure()) + return; + dp->ap_read = dap_ap_read; + dp->ap_write = dap_ap_write; + dp->mem_read = dap_mem_read; + dp->mem_write_sized = dap_mem_write_sized; +} + +static void cmsis_dap_jtagtap_reset(void) +{ + jtagtap_soft_reset(); + /* Is there a way to know if TRST is available?*/ +} + +static void cmsis_dap_jtagtap_tms_seq(uint32_t MS, int ticks) +{ + uint8_t TMS[4] = {MS & 0xff, (MS >> 8) & 0xff, (MS >> 16) & 0xff, + (MS >> 24) & 0xff}; + dap_jtagtap_tdi_tdo_seq(NULL, false, TMS, NULL, ticks); + if (cl_debuglevel & BMP_DEBUG_PLATFORM) + printf("tms_seq DI %08x %d\n", MS, ticks); +} + +static void cmsis_dap_jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms, + const uint8_t *DI, int ticks) +{ + dap_jtagtap_tdi_tdo_seq(DO, (final_tms), NULL, DI, ticks); + if (cl_debuglevel & BMP_DEBUG_PLATFORM) + printf("jtagtap_tdi_tdo_seq %d, %02x-> %02x\n", ticks, DI[0], DO[0]); +} + +static void cmsis_dap_jtagtap_tdi_seq(const uint8_t final_tms, + const uint8_t *DI, int ticks) +{ + dap_jtagtap_tdi_tdo_seq(NULL, (final_tms), NULL, DI, ticks); + if (cl_debuglevel & BMP_DEBUG_PLATFORM) + printf("jtagtap_tdi_seq %d, %02x\n", ticks, DI[0]); +} + +static uint8_t cmsis_dap_jtagtap_next(uint8_t dTMS, uint8_t dTDI) +{ + uint8_t tdo[1]; + dap_jtagtap_tdi_tdo_seq(tdo, false, &dTMS, &dTDI, 1); + if (cl_debuglevel & BMP_DEBUG_PLATFORM) + printf("next tms %02x tdi %02x tdo %02x\n", dTMS, dTDI, tdo[0]); + return (tdo[0] & 1); +} + +int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc) +{ + if (cl_debuglevel) + printf("jtap_init\n"); + if (!(dap_caps & DAP_CAP_JTAG)) + return -1; + mode = DAP_CAP_JTAG; + dap_disconnect(); + dap_connect(true); + dap_swj_clock(2000000); + jtag_proc->jtagtap_reset = cmsis_dap_jtagtap_reset; + jtag_proc->jtagtap_next = cmsis_dap_jtagtap_next; + jtag_proc->jtagtap_tms_seq = cmsis_dap_jtagtap_tms_seq; + jtag_proc->jtagtap_tdi_tdo_seq = cmsis_dap_jtagtap_tdi_tdo_seq; + jtag_proc->jtagtap_tdi_seq = cmsis_dap_jtagtap_tdi_seq; + dap_reset_link(true); + return 0; +} + +int dap_jtag_dp_init(ADIv5_DP_t *dp) +{ + dp->dp_read = dap_dp_read_reg; + dp->error = dap_dp_error; + dp->low_access = dap_dp_low_access; + dp->abort = dap_dp_abort; + + return true; +} diff --git a/src/platforms/hosted/cmsis_dap.h b/src/platforms/hosted/cmsis_dap.h new file mode 100644 index 00000000..10b19697 --- /dev/null +++ b/src/platforms/hosted/cmsis_dap.h @@ -0,0 +1,50 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2019 Uwe Bonnes + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#if !defined(__CMSIS_DAP_H_) +#define __CMSIS_DAP_H_ + +#include "adiv5.h" +#include "cl_utils.h" + +#if defined(CMSIS_DAP) +int dap_init(bmp_info_t *info); +int dap_enter_debug_swd(ADIv5_DP_t *dp); +void dap_exit_function(void); +void dap_adiv5_dp_defaults(ADIv5_DP_t *dp); +int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc); +int dap_jtag_dp_init(ADIv5_DP_t *dp); +#else +int dap_init(bmp_info_t *info) {(void)info; return -1;} +int dap_enter_debug_swd(ADIv5_DP_t *dp) {(void)dp; return -1;} +void dap_exit_function(void) {return;}; +void dap_adiv5_dp_defaults(ADIv5_DP_t *dp) {(void)dp; return; } +int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc) +{ + (void)jtag_proc; + return -1; +} +int dap_jtag_dp_init(ADIv5_DP_t *dp) +{ + (void)dp; + return -1; +} + +#endif + +#endif diff --git a/src/platforms/hosted/dap.c b/src/platforms/hosted/dap.c new file mode 100644 index 00000000..5f32dc86 --- /dev/null +++ b/src/platforms/hosted/dap.c @@ -0,0 +1,753 @@ +/* + * Copyright (c) 2013-2015, Alex Taradov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* Modified for Blackmagic Probe + * Copyright (c) 2020 Uwe Bonnes bon@elektron.ikp.physik.tu-darmstadt.de + */ + +/*- Includes ----------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include "dap.h" +#include "jtag_scan.h" + +/*- Definitions -------------------------------------------------------------*/ +enum +{ + ID_DAP_INFO = 0x00, + ID_DAP_LED = 0x01, + ID_DAP_CONNECT = 0x02, + ID_DAP_DISCONNECT = 0x03, + ID_DAP_TRANSFER_CONFIGURE = 0x04, + ID_DAP_TRANSFER = 0x05, + ID_DAP_TRANSFER_BLOCK = 0x06, + ID_DAP_TRANSFER_ABORT = 0x07, + ID_DAP_WRITE_ABORT = 0x08, + ID_DAP_DELAY = 0x09, + ID_DAP_RESET_TARGET = 0x0a, + ID_DAP_SWJ_PINS = 0x10, + ID_DAP_SWJ_CLOCK = 0x11, + ID_DAP_SWJ_SEQUENCE = 0x12, + ID_DAP_SWD_CONFIGURE = 0x13, + ID_DAP_JTAG_SEQUENCE = 0x14, + ID_DAP_JTAG_CONFIGURE = 0x15, + ID_DAP_JTAG_IDCODE = 0x16, +}; + +enum +{ + DAP_TRANSFER_APnDP = 1 << 0, + DAP_TRANSFER_RnW = 1 << 1, + DAP_TRANSFER_A2 = 1 << 2, + DAP_TRANSFER_A3 = 1 << 3, + DAP_TRANSFER_MATCH_VALUE = 1 << 4, + DAP_TRANSFER_MATCH_MASK = 1 << 5, +}; + +enum +{ + DAP_TRANSFER_INVALID = 0, + DAP_TRANSFER_OK = 1 << 0, + DAP_TRANSFER_WAIT = 1 << 1, + DAP_TRANSFER_FAULT = 1 << 2, + DAP_TRANSFER_ERROR = 1 << 3, + DAP_TRANSFER_MISMATCH = 1 << 4, + DAP_TRANSFER_NO_TARGET = 7, +}; + +enum +{ + DAP_SWJ_SWCLK_TCK = 1 << 0, + DAP_SWJ_SWDIO_TMS = 1 << 1, + DAP_SWJ_TDI = 1 << 2, + DAP_SWJ_TDO = 1 << 3, + DAP_SWJ_nTRST = 1 << 5, + DAP_SWJ_nRESET = 1 << 7, +}; + +enum +{ + DAP_OK = 0x00, + DAP_ERROR = 0xff, +}; + +enum +{ + DAP_JTAG_TMS = 1 << 6, + DAP_JTAG_TDO_CAPTURE = 1 << 7, +}; + +enum +{ + SWD_DP_R_IDCODE = 0x00, + SWD_DP_W_ABORT = 0x00, + SWD_DP_R_CTRL_STAT = 0x04, + SWD_DP_W_CTRL_STAT = 0x04, // When CTRLSEL == 0 + SWD_DP_W_WCR = 0x04, // When CTRLSEL == 1 + SWD_DP_R_RESEND = 0x08, + SWD_DP_W_SELECT = 0x08, + SWD_DP_R_RDBUFF = 0x0c, +}; + +enum +{ + SWD_AP_CSW = 0x00 | DAP_TRANSFER_APnDP, + SWD_AP_TAR = 0x04 | DAP_TRANSFER_APnDP, + SWD_AP_DRW = 0x0c | DAP_TRANSFER_APnDP, + + SWD_AP_DB0 = 0x00 | DAP_TRANSFER_APnDP, // 0x10 + SWD_AP_DB1 = 0x04 | DAP_TRANSFER_APnDP, // 0x14 + SWD_AP_DB2 = 0x08 | DAP_TRANSFER_APnDP, // 0x18 + SWD_AP_DB3 = 0x0c | DAP_TRANSFER_APnDP, // 0x1c + + SWD_AP_CFG = 0x04 | DAP_TRANSFER_APnDP, // 0xf4 + SWD_AP_BASE = 0x08 | DAP_TRANSFER_APnDP, // 0xf8 + SWD_AP_IDR = 0x0c | DAP_TRANSFER_APnDP, // 0xfc +}; + +#define DP_ABORT_DAPABORT (1 << 0) +#define DP_ABORT_STKCMPCLR (1 << 1) +#define DP_ABORT_STKERRCLR (1 << 2) +#define DP_ABORT_WDERRCLR (1 << 3) +#define DP_ABORT_ORUNERRCLR (1 << 4) + +#define DP_CST_ORUNDETECT (1 << 0) +#define DP_CST_STICKYORUN (1 << 1) +#define DP_CST_TRNMODE_NORMAL (0 << 2) +#define DP_CST_TRNMODE_VERIFY (1 << 2) +#define DP_CST_TRNMODE_COMPARE (2 << 2) +#define DP_CST_STICKYCMP (1 << 4) +#define DP_CST_STICKYERR (1 << 5) +#define DP_CST_READOK (1 << 6) +#define DP_CST_WDATAERR (1 << 7) +#define DP_CST_MASKLANE(x) ((x) << 8) +#define DP_CST_TRNCNT(x) ((x) << 12) +#define DP_CST_CDBGRSTREQ (1 << 26) +#define DP_CST_CDBGRSTACK (1 << 27) +#define DP_CST_CDBGPWRUPREQ (1 << 28) +#define DP_CST_CDBGPWRUPACK (1 << 29) +#define DP_CST_CSYSPWRUPREQ (1 << 30) +#define DP_CST_CSYSPWRUPACK (1 << 31) + +#define DP_SELECT_CTRLSEL (1 << 0) +#define DP_SELECT_APBANKSEL(x) ((x) << 4) +#define DP_SELECT_APSEL(x) ((x) << 24) + +#define AP_CSW_SIZE_BYTE (0 << 0) +#define AP_CSW_SIZE_HALF (1 << 0) +#define AP_CSW_SIZE_WORD (2 << 0) +#define AP_CSW_ADDRINC_OFF (0 << 4) +#define AP_CSW_ADDRINC_SINGLE (1 << 4) +#define AP_CSW_ADDRINC_PACKED (2 << 4) +#define AP_CSW_DEVICEEN (1 << 6) +#define AP_CSW_TRINPROG (1 << 7) +#define AP_CSW_SPIDEN (1 << 23) +#define AP_CSW_PROT(x) ((x) << 24) +#define AP_CSW_DBGSWENABLE (1 << 31) + +/*- Implementations ---------------------------------------------------------*/ + +//----------------------------------------------------------------------------- +void dap_led(int index, int state) +{ + uint8_t buf[3]; + + buf[0] = ID_DAP_LED; + buf[1] = index; + buf[2] = state; + dbg_dap_cmd(buf, sizeof(buf), 3); +} + +//----------------------------------------------------------------------------- +void dap_connect(bool jtag) +{ + uint8_t buf[2]; + + buf[0] = ID_DAP_CONNECT; + buf[1] = (jtag) ? DAP_CAP_JTAG : DAP_CAP_SWD; + dbg_dap_cmd(buf, sizeof(buf), 2); + +} + +//----------------------------------------------------------------------------- +void dap_disconnect(void) +{ + uint8_t buf[1]; + + buf[0] = ID_DAP_DISCONNECT; + dbg_dap_cmd(buf, sizeof(buf), 1); +} + +//----------------------------------------------------------------------------- +void dap_swj_clock(uint32_t clock) +{ + uint8_t buf[5]; + + buf[0] = ID_DAP_SWJ_CLOCK; + buf[1] = clock & 0xff; + buf[2] = (clock >> 8) & 0xff; + buf[3] = (clock >> 16) & 0xff; + buf[4] = (clock >> 24) & 0xff; + dbg_dap_cmd(buf, sizeof(buf), 5); + +} + +//----------------------------------------------------------------------------- +void dap_transfer_configure(uint8_t idle, uint16_t count, uint16_t retry) +{ + uint8_t buf[6]; + + buf[0] = ID_DAP_TRANSFER_CONFIGURE; + buf[1] = idle; + buf[2] = count & 0xff; + buf[3] = (count >> 8) & 0xff; + buf[4] = retry & 0xff; + buf[5] = (retry >> 8) & 0xff; + dbg_dap_cmd(buf, sizeof(buf), 6); +} + +//----------------------------------------------------------------------------- +void dap_swd_configure(uint8_t cfg) +{ + uint8_t buf[2]; + + buf[0] = ID_DAP_SWD_CONFIGURE; + buf[1] = cfg; + dbg_dap_cmd(buf, sizeof(buf), 2); +} + +//----------------------------------------------------------------------------- +int dap_info(int info, uint8_t *data, int size) +{ + uint8_t buf[256]; + int rsize; + + buf[0] = ID_DAP_INFO; + buf[1] = info; + dbg_dap_cmd(buf, sizeof(buf), 2); + + rsize = (size < buf[0]) ? size : buf[0]; + memcpy(data, &buf[1], rsize); + + if (rsize < size) + data[rsize] = 0; + + return rsize; +} + +void dap_reset_pin(int state) +{ + uint8_t buf[7]; + + buf[0] = ID_DAP_SWJ_PINS; + buf[1] = state ? DAP_SWJ_nRESET : 0; // Value + buf[2] = DAP_SWJ_nRESET; // Select + buf[3] = 0; // Wait + buf[4] = 0; + buf[5] = 0; + buf[6] = 0; + dbg_dap_cmd(buf, sizeof(buf), 7); +} + +void dap_trst_reset(void) +{ + uint8_t buf[7]; + + buf[0] = ID_DAP_SWJ_PINS; + buf[1] = DAP_SWJ_nTRST; + buf[2] = 0; + buf[3] = 0; + buf[4] = 4; /* ~ 1 ms*/ + buf[5] = 0; + buf[6] = 0; + dbg_dap_cmd(buf, sizeof(buf), 7); + + buf[0] = ID_DAP_SWJ_PINS; + buf[1] = DAP_SWJ_nTRST; + buf[2] = DAP_SWJ_nTRST; + dbg_dap_cmd(buf, sizeof(buf), 7); +} + +static void dap_line_reset(void) +{ + uint8_t buf[] = { + ID_DAP_SWJ_SEQUENCE, + 64, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0 + }; + dbg_dap_cmd(buf, sizeof(buf), 10); + if (buf[0]) + printf("line reset failed\n"); +} + +static uint32_t wait_word(uint8_t *buf, int size, int len, uint8_t *dp_fault) +{ + do { + dbg_dap_cmd(buf, size, len); + if (buf[1] < DAP_TRANSFER_WAIT) + break; + } while (buf[1] == DAP_TRANSFER_WAIT); + + if (buf[1] > DAP_TRANSFER_WAIT) { +// printf("dap_read_reg fault\n"); + *dp_fault = 1; + } + if (buf[1] == DAP_TRANSFER_ERROR) { + printf("dap_read_reg, protocoll error\n"); + dap_line_reset(); + } + uint32_t res = + ((uint32_t)buf[5] << 24) | ((uint32_t)buf[4] << 16) | + ((uint32_t)buf[3] << 8) | (uint32_t)buf[2]; + return res; +} + +//----------------------------------------------------------------------------- +uint32_t dap_read_reg(ADIv5_DP_t *dp, uint8_t reg) +{ + uint8_t buf[8]; + uint8_t dap_index = 0; + if (dp->dev) + dap_index = dp->dev->dev; + buf[0] = ID_DAP_TRANSFER; + buf[1] = dap_index; + buf[2] = 0x01; // Request size + buf[3] = reg | DAP_TRANSFER_RnW; + uint32_t res = wait_word(buf, 8, 4, &dp->fault); +// printf("\tdap_read_reg %02x %08x\n", reg, res); + return res; +} + +//----------------------------------------------------------------------------- +void dap_write_reg(ADIv5_DP_t *dp, uint8_t reg, uint32_t data) +{ + uint8_t buf[8]; + // printf("\tdap_write_reg %02x %08x\n", reg, data); + + buf[0] = ID_DAP_TRANSFER; + uint8_t dap_index = 0; + if (dp->dev) + dap_index = dp->dev->dev; + buf[1] = dap_index; + buf[2] = 0x01; // Request size + buf[3] = reg & ~DAP_TRANSFER_RnW;; + buf[4] = data & 0xff; + buf[5] = (data >> 8) & 0xff; + buf[6] = (data >> 16) & 0xff; + buf[7] = (data >> 24) & 0xff; + do { + dbg_dap_cmd(buf, sizeof(buf), 8); + if (buf[1] < DAP_TRANSFER_WAIT) + break; + } while (buf[1] == DAP_TRANSFER_WAIT); + + if (buf[1] > DAP_TRANSFER_WAIT) { +// printf("dap_write_reg %02x data %08x:fault\n", reg, data); + dp->fault = 1; + } + if (buf[1] == DAP_TRANSFER_ERROR) { +// printf("dap_write_reg %02x data %08x: protocoll error\n", reg, data); + dap_line_reset(); + } +} + +unsigned int dap_read_block(ADIv5_AP_t *ap, void *dest, uint32_t src, + size_t len, enum align align) +{ + uint8_t buf[1024]; + unsigned int sz = len >> align; + uint8_t dap_index = 0; + if (ap->dp->dev) + dap_index = ap->dp->dev->dev; + buf[0] = ID_DAP_TRANSFER_BLOCK; + buf[1] = dap_index; + buf[2] = sz & 0xff; + buf[3] = (sz >> 8) & 0xff; + buf[4] = SWD_AP_DRW | DAP_TRANSFER_RnW; + dbg_dap_cmd(buf, 1023, 5 + 1); + unsigned int transferred = buf[0] + (buf[1] << 8); + if (buf[2] > DAP_TRANSFER_FAULT) { + printf("line_reset\n"); + dap_line_reset(); + } + if (sz != transferred) { + return 1; + } else if (align > ALIGN_HALFWORD) { + memcpy(dest, &buf[3], len); + } else { + uint32_t *p = (uint32_t *)&buf[3]; + while(sz) { + dest = extract(dest, src, *p, align); + p++; + src += (1 << align); + dest += (1 << align); + sz--; + } + } + return (buf[2] > DAP_TRANSFER_WAIT) ? 1 : 0; +} + +unsigned int dap_write_block(ADIv5_AP_t *ap, uint32_t dest, const void *src, + size_t len, enum align align) +{ + uint8_t buf[1024]; + unsigned int sz = len >> align; + uint8_t dap_index = 0; + if (ap->dp->dev) + dap_index = ap->dp->dev->dev; + buf[0] = ID_DAP_TRANSFER_BLOCK; + buf[1] = dap_index; + buf[2] = sz & 0xff; + buf[3] = (sz >> 8) & 0xff; + buf[4] = SWD_AP_DRW; + if (align > ALIGN_HALFWORD) { + memcpy(&buf[5], src, len); + } else { + unsigned int size = len; + uint32_t *p = (uint32_t *)&buf[5]; + while (size) { + uint32_t tmp = 0; + /* Pack data into correct data lane */ + if (align == ALIGN_BYTE) { + tmp = ((uint32_t)*(uint8_t *)src) << ((dest & 3) << 3); + } else { + tmp = ((uint32_t)*(uint16_t *)src) << ((dest & 2) << 3); + } + src = src + (1 << align); + dest += (1 << align); + size--; + *p++ = tmp; + } + } + dbg_dap_cmd(buf, 1023, 5 + (sz << 2)); + if (buf[2] > DAP_TRANSFER_FAULT) { + dap_line_reset(); + } + return (buf[2] > DAP_TRANSFER_WAIT) ? 1 : 0; +} + +//----------------------------------------------------------------------------- +void dap_reset_link(bool jtag) +{ + uint8_t buf[128], *p = buf; + + //------------- + *p++ = ID_DAP_SWJ_SEQUENCE; + p++; + *p++ = 0xff; + *p++ = 0xff; + *p++ = 0xff; + *p++ = 0xff; + *p++ = 0xff; + *p++ = 0xff; + *p++ = 0xff; + if (jtag) { + *p++ = 0x3c; + *p++ = 0xe7; + *p++ = 0x1f; + buf[1] = ((p - &buf[2]) * 8) - 2; + } else { + *p++ = 0x9e; + *p++ = 0xe7; + *p++ = 0xff; + *p++ = 0xff; + *p++ = 0xff; + *p++ = 0xff; + *p++ = 0xff; + *p++ = 0xff; + *p++ = 0xff; + *p++ = 0x00; + buf[1] = (p - &buf[2]) * 8; + } + dbg_dap_cmd(buf, sizeof(buf), p - buf); + + if (!jtag) { + //------------- + buf[0] = ID_DAP_TRANSFER; + buf[1] = 0; // DAP index + buf[2] = 1; // Request size + buf[3] = SWD_DP_R_IDCODE | DAP_TRANSFER_RnW; + dbg_dap_cmd(buf, sizeof(buf), 4); + } +} + +//----------------------------------------------------------------------------- +uint32_t dap_read_idcode(ADIv5_DP_t *dp) +{ + return dap_read_reg(dp, SWD_DP_R_IDCODE); +} + +static uint8_t *mem_access_setup(ADIv5_AP_t *ap, uint8_t *p, + uint32_t addr, enum align align) +{ + uint32_t csw = ap->csw | ADIV5_AP_CSW_ADDRINC_SINGLE; + switch (align) { + case ALIGN_BYTE: + csw |= ADIV5_AP_CSW_SIZE_BYTE; + break; + case ALIGN_HALFWORD: + csw |= ADIV5_AP_CSW_SIZE_HALFWORD; + break; + case ALIGN_DWORD: + case ALIGN_WORD: + csw |= ADIV5_AP_CSW_SIZE_WORD; + break; + } + uint8_t dap_index = 0; + if (ap->dp->dev) + dap_index = ap->dp->dev->dev; + *p++ = ID_DAP_TRANSFER; + *p++ = dap_index; + *p++ = 3; /* Nr transfers */ + *p++ = SWD_DP_W_SELECT; + *p++ = ADIV5_AP_CSW & 0xF0; + *p++ = 0; + *p++ = 0; + *p++ = ap->apsel & 0xff; + *p++ = SWD_AP_CSW; + *p++ = (csw >> 0) & 0xff; + *p++ = (csw >> 8) & 0xff; + *p++ = (csw >> 16) & 0xff; + *p++ = (csw >> 24) & 0xff; + *p++ = SWD_AP_TAR ; + *p++ = (addr >> 0) & 0xff; + *p++ = (addr >> 8) & 0xff; + *p++ = (addr >> 16) & 0xff; + *p++ = (addr >> 24) & 0xff; + return p; +} + +void dap_ap_mem_access_setup(ADIv5_AP_t *ap, uint32_t addr, enum align align) +{ + uint8_t buf[63]; + uint8_t *p = mem_access_setup(ap, buf, addr, align); + dbg_dap_cmd(buf, sizeof(buf), p - buf); +} + +uint32_t dap_ap_read(ADIv5_AP_t *ap, uint16_t addr) +{ +// printf("dap_ap_read_start\n"); + uint8_t buf[63], *p = buf; + buf[0] = ID_DAP_TRANSFER; + uint8_t dap_index = 0; + if (ap->dp->dev) + dap_index = ap->dp->dev->dev; + *p++ = ID_DAP_TRANSFER; + *p++ = dap_index; + *p++ = 2; /* Nr transfers */ + *p++ = SWD_DP_W_SELECT; + *p++ = (addr & 0xF0); + *p++ = 0; + *p++ = 0; + *p++ = ap->apsel & 0xff; + *p++ = (addr & 0x0c) | DAP_TRANSFER_RnW | + ((addr & 0x100) ? DAP_TRANSFER_APnDP : 0); + uint32_t res = wait_word(buf, 63, p - buf, &ap->dp->fault); + return res; +} + +void dap_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value) +{ +// printf("dap_ap_write addr %04x value %08x\n", addr, value); + uint8_t buf[63], *p = buf; + uint8_t dap_index = 0; + if (ap->dp->dev) + dap_index = ap->dp->dev->dev; + *p++ = ID_DAP_TRANSFER; + *p++ = dap_index; + *p++ = 2; /* Nr transfers */ + *p++ = SWD_DP_W_SELECT; + *p++ = (addr & 0xF0); + *p++ = 0; + *p++ = 0; + *p++ = ap->apsel & 0xff; + *p++ = (addr & 0x0c) | ((addr & 0x100) ? DAP_TRANSFER_APnDP : 0); + *p++ = (value >> 0) & 0xff; + *p++ = (value >> 8) & 0xff; + *p++ = (value >> 16) & 0xff; + *p++ = (value >> 24) & 0xff; + dbg_dap_cmd(buf, sizeof(buf), p - buf); +// printf("dap_ap_write done\n"); +} + +void dap_read_single(ADIv5_AP_t *ap, void *dest, uint32_t src, enum align align) +{ + uint8_t buf[63]; + uint8_t *p = mem_access_setup(ap, buf, src, align); + *p++ = SWD_AP_DRW | DAP_TRANSFER_RnW; + buf[2] = 4; + uint32_t tmp = wait_word(buf, 63, p - buf, &ap->dp->fault); + dest = extract(dest, src, tmp, align); +} + +void dap_write_single(ADIv5_AP_t *ap, uint32_t dest, const void *src, + enum align align) +{ + uint8_t buf[63]; + uint8_t *p = mem_access_setup(ap, buf, dest, align); + *p++ = SWD_AP_DRW; + uint32_t tmp = 0; + /* Pack data into correct data lane */ + switch (align) { + case ALIGN_BYTE: + tmp = ((uint32_t)*(uint8_t *)src) << ((dest & 3) << 3); + break; + case ALIGN_HALFWORD: + tmp = ((uint32_t)*(uint16_t *)src) << ((dest & 2) << 3); + break; + case ALIGN_DWORD: + case ALIGN_WORD: + tmp = *(uint32_t *)src; + break; + } + *p++ = (tmp >> 0) & 0xff; + *p++ = (tmp >> 8) & 0xff; + *p++ = (tmp >> 16) & 0xff; + *p++ = (tmp >> 24) & 0xff; + buf[2] = 4; + dbg_dap_cmd(buf, sizeof(buf), p - buf); +} + +void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS, + const uint8_t *DI, int ticks) +{ + uint8_t buf[64]; + if (!TMS) { + int last_byte = 0; + int last_bit = 0; + if (final_tms) { + last_byte = ticks >> 3; + last_bit = ticks & 7; + ticks --; + } + while (ticks) { + int transfers = ticks; + if (transfers > 64) + transfers = 64; + uint8_t *p = buf; + *p++ = ID_DAP_JTAG_SEQUENCE; + *p++ = 1; + *p++ = transfers | ((DO) ? DAP_JTAG_TDO_CAPTURE : 0); + int n_di_bytes = (transfers + 7) >> 3; + if (DI) { + p = memcpy(p, DI, n_di_bytes); + DI += n_di_bytes; + } else { + p = memset(p, 0xff, n_di_bytes); + } + p += n_di_bytes; + dbg_dap_cmd(buf, sizeof(buf), p - buf); + if (buf[0] != DAP_OK) + printf("Failed %02x\n", buf[0]); + if (DO) { + memcpy(DO, &buf[1], (transfers + 7) >> 3); + DO += (transfers + 7) >> 3; + } + ticks -= transfers; + } + if (final_tms) { + uint8_t *p = buf; + *p++ = ID_DAP_JTAG_SEQUENCE; + *p++ = 1; + *p++ = 1 | ((DO) ? DAP_JTAG_TDO_CAPTURE : 0) | DAP_JTAG_TMS; + if (DI) { + *p++ = ((DI[last_byte] & (1 << last_bit)) ? 1 : 0); + } else { + *p++ = 0; + } + dbg_dap_cmd(buf, sizeof(buf), p - buf); + if (buf[0] == DAP_ERROR) + printf("Failed %02x\n", buf[0]); + if (DO) { + if (buf[1] & 1) + DO[last_byte] |= (1 << last_bit); + else + DO[last_byte] &= ~(1 << last_bit); + } + } + } else { + while(ticks) { + uint8_t *p = buf; + int transfers = ticks; + if (transfers > 64) + transfers = 64; + p = buf; + *p++ = ID_DAP_JTAG_SEQUENCE; + *p++ = transfers; + for (int i = 0; i < transfers; i++) { + *p++ = 1 | ((DO) ? DAP_JTAG_TDO_CAPTURE : 0) | + ((TMS[i >> 8] & (1 << (i & 7))) ? DAP_JTAG_TMS : 0); + if (DI) + *p++ = (DI[i >> 8] & (1 << (i & 7))) ? 1 : 0; + else + *p++ = 0x55; + } + dbg_dap_cmd(buf, sizeof(buf), p - buf); + if (buf[0] == DAP_ERROR) + printf("Failed %02x\n", buf[0]); + if (DO) { + for (int i = 0; i < transfers; i++) { + if (buf[i + 1]) + DO[i >> 8] |= (1 << (i & 7)); + else + DO[i >> 8] &= ~(1 << (i & 7)); + } + } + ticks -= transfers; + } + } +} + +int dap_jtag_configure(void) +{ + uint8_t buf[64], *p = &buf[2]; + int i = 0; + for (; i < jtag_dev_count; i++) { + struct jtag_dev_s *jtag_dev = &jtag_devs[i]; + *p++ = jtag_dev->ir_len; + printf("irlen %d\n", jtag_dev->ir_len); + } + if ((!i || i >= JTAG_MAX_DEVS)) + return -1; + buf[0] = 0x15; + buf[1] = i; + dbg_dap_cmd(buf, sizeof(buf), p - buf); + if (buf[0] != DAP_OK) + printf("dap_jtag_configure Failed %02x\n", buf[0]); + return 0; +} diff --git a/src/platforms/hosted/dap.h b/src/platforms/hosted/dap.h new file mode 100644 index 00000000..6a6fbb52 --- /dev/null +++ b/src/platforms/hosted/dap.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2013-2015, Alex Taradov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DAP_H_ +#define _DAP_H_ + +/*- Includes ----------------------------------------------------------------*/ +#include +#include +#include "adiv5.h" + +/*- Definitions -------------------------------------------------------------*/ +enum +{ + DAP_INFO_VENDOR = 0x01, + DAP_INFO_PRODUCT = 0x02, + DAP_INFO_SER_NUM = 0x03, + DAP_INFO_FW_VER = 0x04, + DAP_INFO_DEVICE_VENDOR = 0x05, + DAP_INFO_DEVICE_NAME = 0x06, + DAP_INFO_CAPABILITIES = 0xf0, + DAP_INFO_TDT = 0xf1, + DAP_INFO_SWO_BUF_SIZE = 0xfd, + DAP_INFO_PACKET_COUNT = 0xfe, + DAP_INFO_PACKET_SIZE = 0xff, +}; + +enum +{ + DAP_CAP_SWD = (1 << 0), + DAP_CAP_JTAG = (1 << 1), + DAP_CAP_SWO_UART = (1 << 2), + DAP_CAP_SWO_MANCHESTER = (1 << 3), + DAP_CAP_ATOMIC_CMD = (1 << 4), + DAP_CAP_TDT = (1 << 5), + DAP_CAP_SWO_STREAMING = (1 << 6), +}; + +/*- Prototypes --------------------------------------------------------------*/ +void dap_led(int index, int state); +void dap_connect(bool jtag); +void dap_disconnect(void); +void dap_swj_clock(uint32_t clock); +void dap_transfer_configure(uint8_t idle, uint16_t count, uint16_t retry); +void dap_swd_configure(uint8_t cfg); +int dap_info(int info, uint8_t *data, int size); +void dap_reset_target(void); +void dap_trst_reset(void); +void dap_reset_target_hw(int state); +void dap_reset_pin(int state); +uint32_t dap_read_reg(ADIv5_DP_t *dp, uint8_t reg); +void dap_write_reg(ADIv5_DP_t *dp, uint8_t reg, uint32_t data); +void dap_reset_link(bool jtag); +uint32_t dap_read_idcode(ADIv5_DP_t *dp); +unsigned int dap_read_block(ADIv5_AP_t *ap, void *dest, uint32_t src, + size_t len, enum align align); +unsigned int dap_write_block(ADIv5_AP_t *ap, uint32_t dest, const void *src, + size_t len, enum align align); +void dap_ap_mem_access_setup(ADIv5_AP_t *ap, uint32_t addr, enum align align); +uint32_t dap_ap_read(ADIv5_AP_t *ap, uint16_t addr); +void dap_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value); +void dap_read_single(ADIv5_AP_t *ap, void *dest, uint32_t src, enum align align); +void dap_write_single(ADIv5_AP_t *ap, uint32_t dest, const void *src, + enum align align); +int dbg_dap_cmd(uint8_t *data, int size, int rsize); +void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS, + const uint8_t *DI, int ticks); +int dap_jtag_configure(void); +#endif // _DAP_H_ diff --git a/src/platforms/hosted/platform.c b/src/platforms/hosted/platform.c index 75df0555..28bfd359 100644 --- a/src/platforms/hosted/platform.c +++ b/src/platforms/hosted/platform.c @@ -36,6 +36,7 @@ #include "stlinkv2.h" #include "ftdi_bmp.h" #include "jlink.h" +#include "cmsis_dap.h" #define VENDOR_ID_BMP 0x1d50 #define PRODUCT_ID_BMP 0x6018 @@ -69,6 +70,9 @@ static void exit_function(void) } } switch (info.bmp_type) { + case BMP_TYPE_CMSIS_DAP: + dap_exit_function(); + break; default: break; } @@ -169,6 +173,8 @@ static int find_debuggers( BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info) fprintf(stderr, "INFO: STLINKV1 not supported\n"); continue; } + } else if ((strstr(manufacturer, "CMSIS")) || (strstr(product, "CMSIS"))) { + type = BMP_TYPE_CMSIS_DAP; } else if (desc.idVendor == VENDOR_ID_SEGGER) { type = BMP_TYPE_JLINK; } else{ @@ -244,6 +250,10 @@ void platform_init(int argc, char **argv) if (stlink_init( &info)) exit(-1); break; + case BMP_TYPE_CMSIS_DAP: + if (dap_init( &info)) + exit(-1); + break; case BMP_TYPE_LIBFTDI: break; case BMP_TYPE_JLINK: @@ -282,6 +292,18 @@ int platform_adiv5_swdp_scan(void) free(dp); break; } + case BMP_TYPE_CMSIS_DAP: + { + target_list_free(); + ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp)); + if (!dap_enter_debug_swd(dp)) { + adiv5_dp_init(dp); + if (target_list) + return 1; + } + free(dp); + break; + } case BMP_TYPE_JLINK: return jlink_swdp_scan(&info); default: @@ -296,6 +318,7 @@ int platform_swdptap_init(void) case BMP_TYPE_BMP: return remote_swdptap_init(&swd_proc); case BMP_TYPE_STLINKV2: + case BMP_TYPE_CMSIS_DAP: case BMP_TYPE_JLINK: return 0; case BMP_TYPE_LIBFTDI: @@ -312,6 +335,7 @@ int platform_jtag_scan(const uint8_t *lrlens) case BMP_TYPE_BMP: case BMP_TYPE_LIBFTDI: case BMP_TYPE_JLINK: + case BMP_TYPE_CMSIS_DAP: return jtag_scan(lrlens); case BMP_TYPE_STLINKV2: return jtag_scan_stlinkv2(&info, lrlens); @@ -332,6 +356,8 @@ int platform_jtagtap_init(void) return libftdi_jtagtap_init(&jtag_proc); case BMP_TYPE_JLINK: return jlink_jtagtap_init(&info, &jtag_proc); + case BMP_TYPE_CMSIS_DAP: + return cmsis_dap_jtagtap_init(&jtag_proc); default: return -1; } @@ -343,6 +369,8 @@ void platform_adiv5_dp_defaults(ADIv5_DP_t *dp) switch (info.bmp_type) { case BMP_TYPE_STLINKV2: return stlink_adiv5_dp_defaults(dp); + case BMP_TYPE_CMSIS_DAP: + return dap_adiv5_dp_defaults(dp); default: break; } @@ -357,6 +385,8 @@ int platform_jtag_dp_init(ADIv5_DP_t *dp) return 0; case BMP_TYPE_STLINKV2: return stlink_jtag_dp_init(dp); + case BMP_TYPE_CMSIS_DAP: + return dap_jtag_dp_init(dp); default: return 0; } diff --git a/src/platforms/pc/cl_utils.c b/src/platforms/pc/cl_utils.c index 8719fe32..aedd14de 100644 --- a/src/platforms/pc/cl_utils.c +++ b/src/platforms/pc/cl_utils.c @@ -165,7 +165,7 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv) if (optarg) cl_debuglevel = strtol(optarg, NULL, 0); else - cl_debuglevel = -1; + cl_debuglevel = 1; break; case 'j': opt->opt_usejtag = true; diff --git a/src/platforms/pc/cl_utils.h b/src/platforms/pc/cl_utils.h index 88bff7ed..b65d0e69 100644 --- a/src/platforms/pc/cl_utils.h +++ b/src/platforms/pc/cl_utils.h @@ -36,6 +36,13 @@ enum bmp_cl_mode { BMP_MODE_FLASH_VERIFY }; +enum BMP_DEBUG { + BMP_DEBUG_NONE = 0, + BMP_DEBUG_INFO = 1, + BMP_DEBUG_PLATFORM = 2, + BMP_DEBUG_WIRE = 4 +}; + typedef struct BMP_CL_OPTIONS_s { enum bmp_cl_mode opt_mode; bool opt_usejtag;