/* * 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-21 Uwe Bonnes bon@elektron.ikp.physik.tu-darmstadt.de */ /*- Includes ----------------------------------------------------------------*/ #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, ID_DAP_SWD_SEQUENCE = 0x1D, }; 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); } static uint32_t swj_clock; /* Set/Get JTAG/SWD clock frequency * * With clock == 0, return last set value. */ uint32_t dap_swj_clock(uint32_t clock) { if (clock == 0) return swj_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); if (buf[0]) DEBUG_WARN("dap_swj_clock failed\n"); else swj_clock = clock; return swj_clock; } //----------------------------------------------------------------------------- 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]) DEBUG_WARN("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) { // DEBUG_WARN("dap_read_reg fault\n"); *dp_fault = 1; } if (buf[1] == DAP_TRANSFER_ERROR) { DEBUG_WARN("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; dap_index = dp->dp_jd_index; 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); DEBUG_WIRE("\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]; DEBUG_PROBE("\tdap_write_reg %02x %08x\n", reg, data); buf[0] = ID_DAP_TRANSFER; uint8_t dap_index = 0; dap_index = dp->dp_jd_index; 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) { DEBUG_WARN("dap_write_reg %02x data %08x:fault\n", reg, data); dp->fault = 1; } if (buf[1] == DAP_TRANSFER_ERROR) { DEBUG_WARN("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; dap_index = ap->dp->dp_jd_index; 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); unsigned int transferred = buf[0] + (buf[1] << 8); if (buf[2] >= DAP_TRANSFER_FAULT) { DEBUG_WARN("dap_read_block @ %08" PRIx32 " fault -> line reset\n", src); 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); 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; dap_index = ap->dp->dp_jd_index; 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; dap_index = ap->dp->dp_jd_index; *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) { DEBUG_PROBE("dap_ap_read_start\n"); uint8_t buf[63], *p = buf; buf[0] = ID_DAP_TRANSFER; uint8_t dap_index = 0; dap_index = ap->dp->dp_jd_index; *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) { DEBUG_PROBE("dap_ap_write addr %04x value %08x\n", addr, value); uint8_t buf[63], *p = buf; uint8_t dap_index = 0; dap_index = ap->dp->dp_jd_index; *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); } 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) DEBUG_WARN("dap_jtagtap_tdi_tdo_seq 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) DEBUG_WARN("dap_jtagtap_tdi_tdo_seq 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) DEBUG_WARN("dap_jtagtap_tdi_tdo_seq 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; DEBUG_PROBE("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) DEBUG_WARN("dap_jtag_configure Failed %02x\n", buf[0]); return 0; } void dap_swdptap_seq_out(uint32_t MS, int ticks) { uint8_t buf[] = { ID_DAP_SWJ_SEQUENCE, ticks, (MS >> 0) & 0xff, (MS >> 8) & 0xff, (MS >> 16) & 0xff, (MS >> 24) & 0xff }; dbg_dap_cmd(buf, 1, sizeof(buf)); if (buf[0]) DEBUG_WARN("dap_swdptap_seq_out error\n"); } void dap_swdptap_seq_out_parity(uint32_t MS, int ticks) { uint8_t buf[] = { ID_DAP_SWJ_SEQUENCE, ticks + 1, (MS >> 0) & 0xff, (MS >> 8) & 0xff, (MS >> 16) & 0xff, (MS >> 24) & 0xff, __builtin_parity(MS) & 1 }; dbg_dap_cmd(buf, 1, sizeof(buf)); if (buf[0]) DEBUG_WARN("dap_swdptap_seq_out error\n"); } #define SWD_SEQUENCE_IN 0x80 uint32_t dap_swdptap_seq_in(int ticks) { uint8_t buf[5] = { ID_DAP_SWD_SEQUENCE, 1, ticks + SWD_SEQUENCE_IN }; dbg_dap_cmd(buf, 2 + ((ticks + 7) >> 3), 3); uint32_t res = 0; int len = (ticks + 7) >> 3; while (len--) { res <<= 8; res += buf[len + 1]; } return res; } bool dap_swdptap_seq_in_parity(uint32_t *ret, int ticks) { (void)ticks; uint8_t buf[8] = { ID_DAP_SWD_SEQUENCE, 1, 33 + SWD_SEQUENCE_IN, }; dbg_dap_cmd(buf, 7, 4); uint32_t res = 0; int len = 4; while (len--) { res <<= 8; res += buf[len + 1]; } *ret = res; unsigned int parity = __builtin_parity(res) & 1; parity ^= (buf[5] % 1); DEBUG_WARN("Res %08" PRIx32" %d\n", *ret, parity & 1); return (!(parity & 1)); }