From 05534e9b4956ba3b8aeed1f4adc9154e224366cb Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Fri, 1 Jun 2018 13:53:27 +0200 Subject: [PATCH] libftdi/swdptap: Provide SWD using generic MPSSE if hardware allows. --- src/platforms/hosted/ftdi_bmp.c | 139 ++++++++-- src/platforms/hosted/ftdi_bmp.h | 66 ++++- src/platforms/hosted/libftdi_jtagtap.c | 76 +----- src/platforms/hosted/libftdi_swdptap.c | 357 ++++++++++++++++++------- 4 files changed, 435 insertions(+), 203 deletions(-) diff --git a/src/platforms/hosted/ftdi_bmp.c b/src/platforms/hosted/ftdi_bmp.c index 2d2cc635..457f9fa0 100644 --- a/src/platforms/hosted/ftdi_bmp.c +++ b/src/platforms/hosted/ftdi_bmp.c @@ -40,21 +40,39 @@ cable_desc_t *active_cable; cable_desc_t cable_desc[] = { { - /* Direct connection from FTDI to Jtag/Swd.*/ + /* Direct connection from FTDI to Jtag/Swd. + Pin 6 direct connected to RST.*/ .vendor = 0x0403, .product = 0x6010, .interface = INTERFACE_A, - .dbus_data = 0x08, - .dbus_ddr = 0x1B, + .dbus_data = PIN6 | MPSSE_CS | MPSSE_DO | MPSSE_DI, + .dbus_ddr = MPSSE_CS | MPSSE_DO | MPSSE_SK, .bitbang_tms_in_port_cmd = GET_BITS_LOW, - .bitbang_tms_in_pin = MPSSE_TMS, - .assert_srst.data_low = ~0x40, - .assert_srst.ddr_low = 0x40, - .deassert_srst.data_low = 0x40, - .deassert_srst.ddr_low = ~0x40, + .bitbang_tms_in_pin = MPSSE_CS, + .assert_srst.data_low = ~PIN6, + .assert_srst.ddr_low = PIN6, + .deassert_srst.data_low = PIN6, + .deassert_srst.ddr_low = ~PIN6, .description = "FLOSS-JTAG", .name = "flossjtag" }, + { + /* MPSSE_SK (DB0) ----------- SWDCK/JTCK + * MPSSE-DO (DB1) -- 470 R -- SWDIO/JTMS + * MPSSE-DI (DB2) ----------- SWDIO/JTMS + * DO is tristated with SWD read, so + * resistor is not necessary, but protects + * from contentions in case of errors. + * JTAG not possible.*/ + .vendor = 0x0403, + .product = 0x6014,/*FT232H*/ + .interface = INTERFACE_A, + .dbus_data = MPSSE_DO | MPSSE_DI | MPSSE_CS, + .dbus_ddr = MPSSE_SK, + .swd_read.set_data_low = MPSSE_DO, + .swd_write.set_data_low = MPSSE_DO, + .name = "ft232h_resistor_swd" + }, { /* Buffered connection from FTDI to Jtag/Swd. * TCK and TMS not independant switchable! @@ -66,27 +84,27 @@ cable_desc_t cable_desc[] = { .vendor = 0x0403, .product = 0x6010, .interface = INTERFACE_A, - .dbus_data = 0x08, - .dbus_ddr = 0x1B, - .cbus_data = 0x1c, - .cbus_ddr = 0x1f, - .assert_srst.data_high = ~0x08, - .deassert_srst.data_high = 0x08, + .dbus_data = PIN4 | MPSSE_CS | MPSSE_DI | MPSSE_DO, + .dbus_ddr = MPSSE_CS | MPSSE_DO | MPSSE_SK, + .cbus_data = PIN4 | PIN3 | PIN2, + .cbus_ddr = PIN4 | PIN3 |PIN2 | PIN1 | PIN0, + .assert_srst.data_high = ~PIN3, + .deassert_srst.data_high = PIN3, .srst_get_port_cmd = GET_BITS_LOW, - .srst_get_pin = 0x40, + .srst_get_pin = ~PIN6, .description = "FTDIJTAG", .name = "ftdijtag" }, { /* UART/SWO on Interface A * JTAG and control on INTERFACE_B - * Bit 5 high selects SWD-READ (TMS routed to TDO) + * Bit 5 high selects SWD-WRITE (TMS routed to TDO) * Bit 6 high selects JTAG vs SWD (TMS routed to TDI/TDO) * BCBUS 1 (Output) N_SRST * BCBUS 2 (Input) V_ISO available * * For bitbanged SWD, set Bit 5 low and select SWD read with - * Bit 6 low. Read Connector TMS as FTDI TDO. + * Bit 6 low. Read Connector TMS as MPSSE_DI. * * TDO is routed to Interface 0 RXD as SWO or with Uart * Connector pin 10 pulled to ground will connect Interface 0 RXD @@ -95,17 +113,19 @@ cable_desc_t cable_desc[] = { .vendor = 0x0403, .product = 0x6010, .interface = INTERFACE_B, - .dbus_data = 0x6A, - .dbus_ddr = 0x6B, - .cbus_data = 0x02, - .cbus_ddr = 0x02, + .dbus_data = PIN6 | PIN5 | MPSSE_CS | MPSSE_DO | MPSSE_DI, + .dbus_ddr = PIN6 | PIN5 | MPSSE_CS | MPSSE_DO | MPSSE_SK, + .cbus_data = PIN1 | PIN2, .bitbang_tms_in_port_cmd = GET_BITS_LOW, - .bitbang_tms_in_pin = MPSSE_TDO, /* keep bit 5 low*/ - .bitbang_swd_dbus_read_data = 0x02, + .bitbang_tms_in_pin = MPSSE_DI, /* keep bit 5 low*/ + .bitbang_swd_dbus_read_data = MPSSE_DO, .assert_srst.data_high = ~PIN1, .assert_srst.ddr_high = PIN1, .deassert_srst.data_high = PIN1, .deassert_srst.ddr_high = ~PIN1, + .swd_read.clr_data_low = PIN5 | PIN6, + .swd_write.set_data_low = PIN5, + .swd_write.clr_data_low = PIN6, .name = "ftdiswd" }, { @@ -152,7 +172,7 @@ cable_desc_t cable_desc[] = { .dbus_data = 0xA8, .dbus_ddr = 0xAB, .bitbang_tms_in_port_cmd = GET_BITS_LOW, - .bitbang_tms_in_pin = MPSSE_TMS, + .bitbang_tms_in_pin = MPSSE_CS, .name = "ftdi" }, { @@ -174,7 +194,7 @@ cable_desc_t cable_desc[] = { .dbus_data = 0x08, .dbus_ddr = 0x0B, .bitbang_tms_in_port_cmd = GET_BITS_LOW, - .bitbang_tms_in_pin = MPSSE_TMS, + .bitbang_tms_in_pin = MPSSE_CS, .name = "ft232h" }, { @@ -185,7 +205,7 @@ cable_desc_t cable_desc[] = { .dbus_data = 0x08, .dbus_ddr = 0x0B, .bitbang_tms_in_port_cmd = GET_BITS_LOW, - .bitbang_tms_in_pin = MPSSE_TMS, + .bitbang_tms_in_pin = MPSSE_CS, .name = "ft4232h" }, { @@ -380,6 +400,73 @@ int libftdi_buffer_read(uint8_t *data, int size) return size; } +void libftdi_jtagtap_tdi_tdo_seq( + uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks) +{ + int rsize, rticks; + + if(!ticks) return; + if (!DI && !DO) return; + +// printf("ticks: %d\n", ticks); + if(final_tms) ticks--; + rticks = ticks & 7; + ticks >>= 3; + uint8_t data[3]; + uint8_t cmd = ((DO)? MPSSE_DO_READ : 0) | + ((DI)? (MPSSE_DO_WRITE | MPSSE_WRITE_NEG) : 0) | MPSSE_LSB; + rsize = ticks; + if(ticks) { + data[0] = cmd; + data[1] = ticks - 1; + data[2] = 0; + libftdi_buffer_write(data, 3); + if (DI) + libftdi_buffer_write(DI, ticks); + } + if(rticks) { + int index = 0; + rsize++; + data[index++] = cmd | MPSSE_BITMODE; + data[index++] = rticks - 1; + if (DI) + data[index++] = DI[ticks]; + libftdi_buffer_write(data, index); + } + if(final_tms) { + int index = 0; + rsize++; + data[index++] = MPSSE_WRITE_TMS | ((DO)? MPSSE_DO_READ : 0) | + MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG; + data[index++] = 0; + if (DI) + data[index++] = (DI[ticks]) >> rticks?0x81 : 0x01; + libftdi_buffer_write(data, index); + } + if (DO) { + int index = 0; + uint8_t *tmp = alloca(ticks); + libftdi_buffer_read(tmp, rsize); + if(final_tms) rsize--; + + while(rsize--) { + /*if(rsize) printf("%02X ", tmp[index]);*/ + *DO++ = tmp[index++]; + } + if (rticks == 0) + *DO++ = 0; + if(final_tms) { + rticks++; + *(--DO) >>= 1; + *DO |= tmp[index] & 0x80; + } else DO--; + if(rticks) { + *DO >>= (8-rticks); + } + /*printf("%02X\n", *DO);*/ + } +} + const char *libftdi_target_voltage(void) { return "not supported"; diff --git a/src/platforms/hosted/ftdi_bmp.h b/src/platforms/hosted/ftdi_bmp.h index 35d28df6..a7037268 100644 --- a/src/platforms/hosted/ftdi_bmp.h +++ b/src/platforms/hosted/ftdi_bmp.h @@ -32,16 +32,40 @@ typedef struct data_desc_s { int16_t ddr_high; }data_desc_t; +typedef struct pin_settings_s { + uint8_t set_data_low; + uint8_t clr_data_low; + uint8_t set_data_high; + uint8_t clr_data_high; +}pin_settings_t; + typedef struct cable_desc_s { int vendor; int product; int interface; + /* Needed level on DBUS output pins to drive the JTAG signals and for + * other functionality like SRST, TRST. etc.*/ uint8_t dbus_data; + /* Write '1' for DBUS pins needed as output in JTAG mode and for + * other functionality like SRST, TRST. etc..*/ uint8_t dbus_ddr; + /* Needed level on CBUS output pins to drive the JTAG signals and for + * other functionality like SRST, TRST. etc. + * Often not needed at all.*/ uint8_t cbus_data; + /* Write '1' for CBUS pins needed as output in JTAG mode and for + * other functionality like SRST, TRST. etc. + * Often not needed at all.*/ uint8_t cbus_ddr; + /* MPSSE command to read TMS/SWDIO Port in bitbanging SWD. + * In many cases this is the TMS port of the FTDI and + * so "GET_BITS_LOW" */ uint8_t bitbang_tms_in_port_cmd; + /* Pin mask where TMS/SWDIO can be read in bitbanging SWD. + * In many cases this is the TMS port of the FTDI + * and so "MPSSE_TMS".*/ uint8_t bitbang_tms_in_pin; + /* Dbus data to allow bitbanging SWD read.*/ uint8_t bitbang_swd_dbus_read_data; uint8_t bitbang_swd_direct; /* dbus_data, dbus_ddr, cbus_data, cbus_ddr value to assert SRST. @@ -57,7 +81,23 @@ typedef struct cable_desc_s { /* PIN to read back as SRST. if 0 port from assert_srst is ised. * Use PINX if active high, use Complement (~PINX) if active low*/ uint8_t srst_get_pin; + /* dbus data for pure MPSSE SWD read. + * Use together with swd_write if by some bits on DBUS, + * SWDIO can be routed to TDI and TDO. + * If both swd_read|write and + * bitbang_swd_dbus_read_data/bitbang_tms_in_port_cmd/bitbang_tms_in_pin + * are provided, pure MPSSE SWD is choosen. + * If neither a complete set of swd_read|write or + * bitbang_swd_dbus_read_data/bitbang_tms_in_port_cmd/bitbang_tms_in_pin + * are provided, SWD can not be done. + * swd_read.set_data_low == swd_write.set_data_low == MPSSE_DO + * indicated resistor SWD and inhibits Jtag.*/ + pin_settings_t swd_read; + /* dbus data for pure MPSSE SWD write.*/ + pin_settings_t swd_write; + /* USB readable description of the device.*/ char *description; + /* Command line argument to -c option to select this device.*/ char * name; }cable_desc_t; @@ -72,17 +112,19 @@ void libftdi_buffer_flush(void); int libftdi_buffer_write(const uint8_t *data, int size); int libftdi_buffer_read(uint8_t *data, int size); const char *libftdi_target_voltage(void); +void libftdi_jtagtap_tdi_tdo_seq( + uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks); -#define MPSSE_TCK 1 -#define PIN0 1 -#define MPSSE_TDI 2 -#define PIN1 2 -#define MPSSE_TDO 4 -#define PIN2 4 -#define MPSSE_TMS 8 -#define PIN3 8 -#define PIN4 0x10 -#define PIN5 0x20 -#define PIN6 0x40 -#define PIN7 0x80 +#define MPSSE_SK 1 +#define PIN0 1 +#define MPSSE_DO 2 +#define PIN1 2 +#define MPSSE_DI 4 +#define PIN2 4 +#define MPSSE_CS 8 +#define PIN3 8 +#define PIN4 0x10 +#define PIN5 0x20 +#define PIN6 0x40 +#define PIN7 0x80 #endif diff --git a/src/platforms/hosted/libftdi_jtagtap.c b/src/platforms/hosted/libftdi_jtagtap.c index 26bcc30f..b7795472 100644 --- a/src/platforms/hosted/libftdi_jtagtap.c +++ b/src/platforms/hosted/libftdi_jtagtap.c @@ -38,14 +38,17 @@ extern struct ftdi_context *ftdic; static void jtagtap_reset(void); static void jtagtap_tms_seq(uint32_t MS, int ticks); -static void jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms, - const uint8_t *DI, int ticks); static void jtagtap_tdi_seq( const uint8_t final_tms, const uint8_t *DI, int ticks); static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI); int libftdi_jtagtap_init(jtag_proc_t *jtag_proc) { + if ((active_cable->swd_read.set_data_low == MPSSE_DO) && + (active_cable->swd_write.set_data_low == MPSSE_DO)) { + printf("Jtag not possible with resistor SWD!\n"); + return -1; + } assert(ftdic != NULL); /* select new buffer flush function if libftdi 1.5 */ #ifdef _Ftdi_Pragma @@ -84,7 +87,7 @@ int libftdi_jtagtap_init(jtag_proc_t *jtag_proc) jtag_proc->jtagtap_reset = jtagtap_reset; jtag_proc->jtagtap_next =jtagtap_next; jtag_proc->jtagtap_tms_seq = jtagtap_tms_seq; - jtag_proc->jtagtap_tdi_tdo_seq = jtagtap_tdi_tdo_seq; + jtag_proc->jtagtap_tdi_tdo_seq = libftdi_jtagtap_tdi_tdo_seq; jtag_proc->jtagtap_tdi_seq = jtagtap_tdi_seq; return 0; @@ -108,75 +111,10 @@ static void jtagtap_tms_seq(uint32_t MS, int ticks) } } -static void jtagtap_tdi_tdo_seq( - uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks) -{ - int rsize, rticks; - - if(!ticks) return; - if (!DI && !DO) return; - -// DEBUG_PROBE("ticks: %d\n", ticks); - if(final_tms) ticks--; - rticks = ticks & 7; - ticks >>= 3; - uint8_t data[3]; - uint8_t cmd = ((DO)? MPSSE_DO_READ : 0) | - ((DI)? (MPSSE_DO_WRITE | MPSSE_WRITE_NEG) : 0) | MPSSE_LSB; - rsize = ticks; - if(ticks) { - data[0] = cmd; - data[1] = ticks - 1; - data[2] = 0; - libftdi_buffer_write(data, 3); - if (DI) - libftdi_buffer_write(DI, ticks); - } - if(rticks) { - int index = 0; - rsize++; - data[index++] = cmd | MPSSE_BITMODE; - data[index++] = rticks - 1; - if (DI) - data[index++] = DI[ticks]; - libftdi_buffer_write(data, index); - } - if(final_tms) { - int index = 0; - rsize++; - data[index++] = MPSSE_WRITE_TMS | ((DO)? MPSSE_DO_READ : 0) | - MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG; - data[index++] = 0; - if (DI) - data[index++] = (DI[ticks]) >> rticks?0x81 : 0x01; - libftdi_buffer_write(data, index); - } - if (DO) { - int index = 0; - uint8_t *tmp = alloca(ticks); - libftdi_buffer_read(tmp, rsize); - if(final_tms) rsize--; - - while(rsize--) { - if(rsize) DEBUG_WIRE("%02X ", tmp[index]); - *DO++ = tmp[index++]; - } - if(final_tms) { - rticks++; - *(--DO) >>= 1; - *DO |= tmp[index] & 0x80; - } else DO--; - if(rticks) { - *DO >>= (8-rticks); - } - DEBUG_WIRE("%02X\n", *DO); - } -} - static void jtagtap_tdi_seq( const uint8_t final_tms, const uint8_t *DI, int ticks) { - return jtagtap_tdi_tdo_seq(NULL, final_tms, DI, ticks); + return libftdi_jtagtap_tdi_tdo_seq(NULL, final_tms, DI, ticks); } static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI) diff --git a/src/platforms/hosted/libftdi_swdptap.c b/src/platforms/hosted/libftdi_swdptap.c index c7491803..b38705da 100644 --- a/src/platforms/hosted/libftdi_swdptap.c +++ b/src/platforms/hosted/libftdi_swdptap.c @@ -28,12 +28,76 @@ #include "general.h" #include "ftdi_bmp.h" -static uint8_t olddir = 0; +enum swdio_status{ + SWDIO_STATUS_DRIVE = 0, + SWDIO_STATUS_FLOAT, +}; -#define MPSSE_MASK (MPSSE_TDI | MPSSE_TDO | MPSSE_TMS) -#define MPSSE_TD_MASK (MPSSE_TDI | MPSSE_TDO) +static enum swdio_status olddir; +static bool do_mpsse; + +#define MPSSE_MASK (MPSSE_DO | MPSSE_DI | MPSSE_CS) +#define MPSSE_TD_MASK (MPSSE_DO | MPSSE_DI) #define MPSSE_TMS_SHIFT (MPSSE_WRITE_TMS | MPSSE_LSB |\ MPSSE_BITMODE | MPSSE_WRITE_NEG) +#define MPSSE_TDO_SHIFT (MPSSE_DO_WRITE | MPSSE_LSB |\ + MPSSE_BITMODE | MPSSE_WRITE_NEG) + +static void swdptap_turnaround(enum swdio_status dir) +{ + if (dir == olddir) + return; + olddir = dir; + if (do_mpsse) { + if (dir == SWDIO_STATUS_FLOAT) /* SWDIO goes to input */ { + active_cable->dbus_data |= active_cable->swd_read.set_data_low; + active_cable->dbus_data &= ~active_cable->swd_read.clr_data_low; + active_cable->cbus_data |= active_cable->swd_read.set_data_high; + active_cable->cbus_data &= ~active_cable->swd_read.clr_data_high; + uint8_t cmd_read[6] = { + SET_BITS_LOW, active_cable->dbus_data, + active_cable->dbus_ddr & ~MPSSE_DO, + SET_BITS_HIGH, active_cable->cbus_data, active_cable->cbus_ddr}; + libftdi_buffer_write(cmd_read, 6); + } + uint8_t cmd[] = {MPSSE_TDO_SHIFT, 0, 0}; /* One clock cycle */ + libftdi_buffer_write(cmd, sizeof(cmd)); + if (dir == SWDIO_STATUS_DRIVE) /* SWDIO goes to output */ { + active_cable->dbus_data |= active_cable->swd_write.set_data_low; + active_cable->dbus_data &= ~active_cable->swd_write.clr_data_low; + active_cable->cbus_data |= active_cable->swd_write.set_data_high; + active_cable->cbus_data &= ~active_cable->swd_write.clr_data_high; + uint8_t cmd_write[6] = { + SET_BITS_LOW, active_cable->dbus_data, + active_cable->dbus_ddr | MPSSE_DO, + SET_BITS_HIGH, active_cable->cbus_data, active_cable->cbus_ddr}; + libftdi_buffer_write(cmd_write, 6); + } + } else { + uint8_t cmd[6]; + int index = 0; + + if(dir == SWDIO_STATUS_FLOAT) { /* SWDIO goes to input */ + cmd[index++] = SET_BITS_LOW; + if (active_cable->bitbang_swd_dbus_read_data) + cmd[index] = active_cable->bitbang_swd_dbus_read_data; + else + cmd[index] = active_cable->dbus_data; + index++; + cmd[index++] = active_cable->dbus_ddr & ~MPSSE_MASK; + } + /* One clock cycle */ + cmd[index++] = MPSSE_TMS_SHIFT; + cmd[index++] = 0; + cmd[index++] = 0; + if (dir == SWDIO_STATUS_DRIVE) { + cmd[index++] = SET_BITS_LOW; + cmd[index++] = active_cable->dbus_data | MPSSE_MASK; + cmd[index++] = active_cable->dbus_ddr & ~MPSSE_TD_MASK; + } + libftdi_buffer_write(cmd, index); + } +} static bool swdptap_seq_in_parity(uint32_t *res, int ticks); static uint32_t swdptap_seq_in(int ticks); @@ -46,6 +110,25 @@ int libftdi_swdptap_init(swd_proc_t *swd_proc) DEBUG_WARN("SWD not possible or missing item in cable description.\n"); return -1; } + bool swd_read = + active_cable->swd_read.set_data_low || + active_cable->swd_read.clr_data_low || + active_cable->swd_read.set_data_high || + active_cable->swd_read.clr_data_high; + bool swd_write = + active_cable->swd_write.set_data_low || + active_cable->swd_write.clr_data_low || + active_cable->swd_write.set_data_high || + active_cable->swd_write.clr_data_high; + do_mpsse = swd_read && swd_write; + if (!do_mpsse) { + if (!(active_cable->bitbang_tms_in_port_cmd && + active_cable->bitbang_tms_in_pin && + active_cable->bitbang_swd_dbus_read_data)) { + DEBUG_WARN("SWD not possible or missing item in cable description.\n"); + return -1; + } + } /* select new buffer flush function if libftdi 1.5 */ #ifdef _Ftdi_Pragma int err = ftdi_tcioflush(ftdic); @@ -73,11 +156,24 @@ int libftdi_swdptap_init(swd_proc_t *swd_proc) } uint8_t ftdi_init[9] = {TCK_DIVISOR, 0x01, 0x00, SET_BITS_LOW, 0,0, SET_BITS_HIGH, 0,0}; - ftdi_init[4]= active_cable->dbus_data | MPSSE_MASK; - ftdi_init[5]= active_cable->dbus_ddr & ~MPSSE_TD_MASK; + if (do_mpsse) { + DEBUG_INFO("Using genuine MPSSE for SWD.\n"); + ftdi_init[4]= active_cable->dbus_data; + active_cable->dbus_ddr &= ~MPSSE_CS; /* Do not touch SWDIO.*/ + ftdi_init[5]= active_cable->dbus_ddr; + } else { + DEBUG_INFO("Using bitbang MPSSE for SWD.\n"); + ftdi_init[4]= active_cable->dbus_data | MPSSE_MASK; + ftdi_init[5]= active_cable->dbus_ddr & ~MPSSE_TD_MASK; + } ftdi_init[7]= active_cable->cbus_data; ftdi_init[8]= active_cable->cbus_ddr; - libftdi_buffer_write(ftdi_init, 9); + libftdi_buffer_write(ftdi_init, sizeof(ftdi_init)); + if (do_mpsse) { + olddir = SWDIO_STATUS_FLOAT; + swdptap_turnaround(SWDIO_STATUS_DRIVE); + } else + olddir = SWDIO_STATUS_DRIVE; libftdi_buffer_flush(); swd_proc->swdptap_seq_in = swdptap_seq_in; @@ -88,129 +184,198 @@ int libftdi_swdptap_init(swd_proc_t *swd_proc) return 0; } -static void swdptap_turnaround(uint8_t dir) +bool swdptap_bit_in(void) { - if (dir == olddir) - return; - olddir = dir; - uint8_t cmd[6]; + swdptap_turnaround(SWDIO_STATUS_FLOAT); + uint8_t cmd[4]; int index = 0; + bool result = false; - if(dir) { /* SWDIO goes to input */ - cmd[index++] = SET_BITS_LOW; - if (active_cable->bitbang_swd_dbus_read_data) - cmd[index] = active_cable->bitbang_swd_dbus_read_data; - else - cmd[index] = active_cable->dbus_data; - index++; - cmd[index++] = active_cable->dbus_ddr & ~MPSSE_MASK; + if (do_mpsse) { + uint8_t cmd[2] = {MPSSE_DO_READ | MPSSE_LSB | MPSSE_BITMODE, 0}; + libftdi_buffer_write(cmd, sizeof(cmd)); + uint8_t data[1]; + libftdi_buffer_read(data, sizeof(data)); + result = (data[0] & 0x80); + } else { + cmd[index++] = active_cable->bitbang_tms_in_port_cmd; + cmd[index++] = MPSSE_TMS_SHIFT; + cmd[index++] = 0; + cmd[index++] = 0; + libftdi_buffer_write(cmd, index); + uint8_t data[1]; + libftdi_buffer_read(data, sizeof(data)); + result = (data[0] &= active_cable->bitbang_tms_in_pin); } - /* One clock cycle */ - cmd[index++] = MPSSE_TMS_SHIFT; - cmd[index++] = 0; - cmd[index++] = 0; - if (!dir) { - cmd[index++] = SET_BITS_LOW; - cmd[index++] = active_cable->dbus_data | MPSSE_MASK; - cmd[index++] = active_cable->dbus_ddr & ~MPSSE_TD_MASK; - } - libftdi_buffer_write(cmd, index); + return result; } -static bool swdptap_seq_in_parity(uint32_t *res, int ticks) +void swdptap_bit_out(bool val) { - int index = ticks + 1; - uint8_t cmd[4]; - unsigned int parity = 0; - - cmd[0] = active_cable->bitbang_tms_in_port_cmd; - cmd[1] = MPSSE_TMS_SHIFT; - cmd[2] = 0; - cmd[3] = 0; - swdptap_turnaround(1); - while (index--) { - libftdi_buffer_write(cmd, 4); + swdptap_turnaround(SWDIO_STATUS_DRIVE); + if (do_mpsse) { + uint8_t cmd[3] = {MPSSE_TDO_SHIFT, 0, (val)? 1:0}; + libftdi_buffer_write(cmd, sizeof(cmd)); + } else { + uint8_t cmd[3]; + cmd[0] = MPSSE_TMS_SHIFT; + cmd[1] = 0; + cmd[2] = (val)? 1 : 0; + libftdi_buffer_write(cmd, sizeof(cmd)); } - uint8_t data[33]; - unsigned int ret = 0; - libftdi_buffer_read(data, ticks + 1); - if (data[ticks] & active_cable->bitbang_tms_in_pin) - parity ^= 1; - while (ticks--) { - if (data[ticks] & active_cable->bitbang_tms_in_pin) { +} + +bool swdptap_seq_in_parity(uint32_t *res, int ticks) +{ + assert(ticks == 32); + swdptap_turnaround(SWDIO_STATUS_FLOAT); + unsigned int parity = 0; + unsigned int result = 0; + if (do_mpsse) { + uint8_t DO[5]; + libftdi_jtagtap_tdi_tdo_seq(DO, 0, NULL, ticks + 1); + result = DO[0] + (DO[1] << 8) + (DO[2] << 16) + (DO[3] << 24); + for (int i = 0; i < 32; i++) { + parity ^= (result >> i) & 1; + } + parity ^= DO[4] & 1; + } else { + int index = ticks + 1; + uint8_t cmd[4]; + + cmd[0] = active_cable->bitbang_tms_in_port_cmd; + cmd[1] = MPSSE_TMS_SHIFT; + cmd[2] = 0; + cmd[3] = 0; + while (index--) { + libftdi_buffer_write(cmd, sizeof(cmd)); + } + uint8_t data[33]; + libftdi_buffer_read(data, ticks + 1); + if (data[ticks] & active_cable->bitbang_tms_in_pin) parity ^= 1; - ret |= (1 << ticks); + index = ticks; + while (index--) { + if (data[index] & active_cable->bitbang_tms_in_pin) { + parity ^= 1; + result |= (1 << index); + } } } - *res = ret; + *res = result; return parity; } static uint32_t swdptap_seq_in(int ticks) { - int index = ticks; - uint8_t cmd[4]; + if (!ticks) + return 0; + uint32_t result = 0; + swdptap_turnaround(SWDIO_STATUS_FLOAT); + if (do_mpsse) { + uint8_t DO[4]; + libftdi_jtagtap_tdi_tdo_seq(DO, 0, NULL, ticks); + for (int i = 0; i < (ticks >> 3) + (ticks & 7)? 1: 0; i++) { + result |= DO[i] << (8 * i); + } + } else { + int index = ticks; + uint8_t cmd[4]; - cmd[0] = active_cable->bitbang_tms_in_port_cmd; - cmd[1] = MPSSE_TMS_SHIFT; - cmd[2] = 0; - cmd[3] = 0; + cmd[0] = active_cable->bitbang_tms_in_port_cmd; + cmd[1] = MPSSE_TMS_SHIFT; + cmd[2] = 0; + cmd[3] = 0; - swdptap_turnaround(1); - while (index--) { - libftdi_buffer_write(cmd, 4); + while (index--) { + libftdi_buffer_write(cmd, sizeof(cmd)); + } + uint8_t data[32]; + libftdi_buffer_read(data, ticks); + index = ticks; + while (index--) { + if (data[index] & active_cable->bitbang_tms_in_pin) + result |= (1 << index); + } } - uint8_t data[32]; - uint32_t ret = 0; - libftdi_buffer_read(data, ticks); - while (ticks--) { - if (data[ticks] & active_cable->bitbang_tms_in_pin) - ret |= (1 << ticks); - } - return ret; + return result; } static void swdptap_seq_out(uint32_t MS, int ticks) { - uint8_t cmd[15]; - unsigned int index = 0; - swdptap_turnaround(0); - while (ticks) { - cmd[index++] = MPSSE_TMS_SHIFT; - if (ticks >= 7) { - cmd[index++] = 6; - cmd[index++] = MS & 0x7f; - MS >>= 7; - ticks -= 7; - } else { - cmd[index++] = ticks - 1; - cmd[index++] = MS & 0x7f; - ticks = 0; + if (!ticks) + return; + swdptap_turnaround(SWDIO_STATUS_DRIVE); + if (do_mpsse) { + uint8_t DI[4]; + swdptap_turnaround(0); + DI[0] = (MS >> 0) & 0xff; + DI[1] = (MS >> 8) & 0xff; + DI[2] = (MS >> 16) & 0xff; + DI[3] = (MS >> 24) & 0xff; + libftdi_jtagtap_tdi_tdo_seq(NULL, 0, DI, ticks); + } else { + uint8_t cmd[15]; + unsigned int index = 0; + while (ticks) { + cmd[index++] = MPSSE_TMS_SHIFT; + if (ticks >= 7) { + cmd[index++] = 6; + cmd[index++] = MS & 0x7f; + MS >>= 7; + ticks -= 7; + } else { + cmd[index++] = ticks - 1; + cmd[index++] = MS & 0x7f; + ticks = 0; + } } + libftdi_buffer_write(cmd, index); } - libftdi_buffer_write(cmd, index); } static void swdptap_seq_out_parity(uint32_t MS, int ticks) { - uint8_t parity = 0; - int steps = ticks; + unsigned int parity = 0; uint8_t cmd[18]; unsigned int index = 0; - uint32_t data = MS; swdptap_turnaround(0); - while (steps) { - cmd[index++] = MPSSE_TMS_SHIFT; - if (steps >= 7) { - cmd[index++] = 6; - cmd[index++] = data & 0x7f; - data >>= 7; - steps -= 7; - } else { - cmd[index++] = steps - 1; - cmd[index++] = data & 0x7f; - steps = 0; + if (do_mpsse) { + uint8_t DI[5]; + DI[0] = (MS >> 0) & 0xff; + DI[1] = (MS >> 8) & 0xff; + DI[2] = (MS >> 16) & 0xff; + DI[3] = (MS >> 24) & 0xff; + while(MS) { + parity ^= (MS & 1); + MS >>= 1; } + DI[4] = parity; + libftdi_jtagtap_tdi_tdo_seq(NULL, 0, DI, ticks + 1); + } else { + int steps = ticks; + unsigned int data = MS; + while (steps) { + cmd[index++] = MPSSE_TMS_SHIFT; + if (steps >= 7) { + cmd[index++] = 6; + cmd[index++] = data & 0x7f; + data >>= 7; + steps -= 7; + } else { + cmd[index++] = steps - 1; + cmd[index++] = data & 0x7f; + steps = 0; + } + } + while (ticks--) { + parity ^= MS; + MS >>= 1; + } + cmd[index++] = MPSSE_TMS_SHIFT; + cmd[index++] = 0; + cmd[index++] = parity; + libftdi_buffer_write(cmd, index); } while (ticks--) { parity ^= MS;