This is an automated email from Gerrit. Robert Jarzmik ([email protected]) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/1502
-- gerrit commit d27ba65fa3db2bcb0e6892b701e5c0a35ae27290 Author: Robert Jarzmik <[email protected]> Date: Sat Jul 13 11:56:08 2013 +0200 jtag/drivers: [UGLY] [WIP] usb_blaster exploratory commit for performance This is an exploration commit to assess possible performance of usb_blaster. It relies on : - an asynchronous usb read/write (inspired by MPSEE driver) - folding of jtag SCAN and PATHMOVES before issuing USB commands to the usb blaster The performance is not significant on dump_image (from 10kBi/s to 10kBi/s with an XScale PX270), and from 2kBi/s to 12kBi/s on load_image. The most relevant test is : - ./configure --enable-maintainer-mode --enable-verbose --enable-usb_blaster_libftdi --enable-usb_blaster - make - in openocd.cfg, don't forget "usb_blaster_lowlevel_driver libusb" - make the benchmarking Change-Id: I06e08afb4376a8450774657f7ec93bbee1965fe2 Signed-off-by: Robert Jarzmik <[email protected]> diff --git a/configure.ac b/configure.ac index 87f95d5..eba4d4d 100644 --- a/configure.ac +++ b/configure.ac @@ -397,6 +397,10 @@ AC_ARG_ENABLE([usb_blaster_ftd2xx], AS_HELP_STRING([--enable-usb_blaster_ftd2xx], [Enable building support for the Altera USB-Blaster using the FTD2XX driver from ftdichip.com]), [build_usb_blaster_ftd2xx=$enableval], [build_usb_blaster_ftd2xx=no]) +AC_ARG_ENABLE([usb_blaster_libusb], + AS_HELP_STRING([--enable-usb_blaster_libusb], [Enable building support for the Alterra USB-Blaster using libusb-1.0 in asynchronous mode]), + [build_usb_blaster_libusb=$enableval], [build_usb_blaster_libusb=no]) + AC_ARG_ENABLE([amtjtagaccel], AS_HELP_STRING([--enable-amtjtagaccel], [Enable building the Amontec JTAG-Accelerator driver]), [build_amtjtagaccel=$enableval], [build_amtjtagaccel=no]) @@ -732,6 +736,12 @@ else AC_DEFINE([BUILD_USB_BLASTER_FTD2XX], [0], [0 if you don't want ftd2xx usb_blaster.]) fi +if test $build_usb_blaster_libusb = yes; then + AC_DEFINE([BUILD_USB_BLASTER_LIBUSB], [1], [1 if you want libusb usb_blaster.]) +else + AC_DEFINE([BUILD_USB_BLASTER_LIBUSB], [0], [0 if you don't want libusb usb_blaster.]) +fi + if test $build_amtjtagaccel = yes; then AC_DEFINE([BUILD_AMTJTAGACCEL], [1], [1 if you want the Amontec JTAG-Accelerator driver.]) else @@ -1192,7 +1202,7 @@ fi # check if some driver requires libusb-1.x need_usb_ng=no if test $build_ftdi = yes -o $build_hladapter_icdi = yes -o \ - $build_hladapter_stlink = yes; then + $build_hladapter_stlink = yes -o $build_usb_blaster_libusb = yes; then need_usb_ng=yes fi @@ -1240,6 +1250,7 @@ AM_CONDITIONAL([FT2232_DRIVER], [test $build_ft2232_ftd2xx = yes -o $build_ft223 AM_CONDITIONAL([FTDI_DRIVER], [test $build_ftdi = yes]) AM_CONDITIONAL([USB_BLASTER_LIBFTDI], [test $build_usb_blaster_libftdi = yes]) AM_CONDITIONAL([USB_BLASTER_FTD2XX], [test $build_usb_blaster_ftd2xx = yes]) +AM_CONDITIONAL([USB_BLASTER_LIBUSB], [test $build_usb_blaster_libusb = yes]) AM_CONDITIONAL([USB_BLASTER_DRIVER], [test $build_usb_blaster_ftd2xx = yes -o $build_usb_blaster_libftdi = yes]) AM_CONDITIONAL([AMTJTAGACCEL], [test $build_amtjtagaccel = yes]) AM_CONDITIONAL([GW16012], [test $build_gw16012 = yes]) diff --git a/src/jtag/drivers/usb_blaster/Makefile.am b/src/jtag/drivers/usb_blaster/Makefile.am index 1cf7ba9..f450056 100644 --- a/src/jtag/drivers/usb_blaster/Makefile.am +++ b/src/jtag/drivers/usb_blaster/Makefile.am @@ -3,7 +3,7 @@ include $(top_srcdir)/common.mk noinst_LTLIBRARIES = libocdusbblaster.la libocdusbblaster_la_SOURCES = $(USB_BLASTER_SRC) -USB_BLASTER_SRC = usb_blaster.c +USB_BLASTER_SRC = usb_blaster.c ublast_access_common.c if USB_BLASTER_LIBFTDI USB_BLASTER_SRC += ublast_access_ftdi.c @@ -13,6 +13,10 @@ if USB_BLASTER_FTD2XX USB_BLASTER_SRC += ublast_access_ftd2xx.c endif +if USB_BLASTER_LIBUSB +USB_BLASTER_SRC += ublast_access_libusb.c +endif + noinst_HEADERS = ublast_access.h MAINTAINERCLEANFILES = $(srcdir)/Makefile.in diff --git a/src/jtag/drivers/usb_blaster/ublast_access.h b/src/jtag/drivers/usb_blaster/ublast_access.h index e0eb059..4e38567 100644 --- a/src/jtag/drivers/usb_blaster/ublast_access.h +++ b/src/jtag/drivers/usb_blaster/ublast_access.h @@ -26,10 +26,11 @@ struct ublast_lowlevel { uint16_t ublast_pid; char *ublast_device_desc; - int (*write)(struct ublast_lowlevel *low, uint8_t *buf, int size, - uint32_t *bytes_written); - int (*read)(struct ublast_lowlevel *low, uint8_t *buf, unsigned size, - uint32_t *bytes_read); + int (*queue_write)(struct ublast_lowlevel *low, uint8_t *buf, + int size, uint32_t *bytes_written); + int (*queue_read)(struct ublast_lowlevel *low, uint8_t *buf, + unsigned size, uint32_t *bytes_read); + void (*flush)(struct ublast_lowlevel *low); int (*open)(struct ublast_lowlevel *low); int (*close)(struct ublast_lowlevel *low); int (*speed)(struct ublast_lowlevel *low, int speed); @@ -50,3 +51,4 @@ struct ublast_lowlevel { */ extern struct ublast_lowlevel *ublast_register_ftdi(void); extern struct ublast_lowlevel *ublast_register_ftd2xx(void); +extern struct ublast_lowlevel *ublast_register_libusb(void); diff --git a/src/jtag/drivers/usb_blaster/ublast_access_common.c b/src/jtag/drivers/usb_blaster/ublast_access_common.c new file mode 100644 index 0000000..5b9c52e --- /dev/null +++ b/src/jtag/drivers/usb_blaster/ublast_access_common.c @@ -0,0 +1,114 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <jtag/interface.h> + +#include "ublast_access.h" +#include "ublast_access_common.h" + +static int get_bytes_of_reqs(struct list_head *reqs) +{ + struct rw_req *req; + int nb = 0; + + list_for_each_entry(req, reqs, list) + nb += req->nb; + return nb; +} + +static void xfer_reqs_to_buf(unsigned char *buf, struct list_head *reqs) +{ + struct rw_req *req; + + list_for_each_entry(req, reqs, list) { + memmove(buf, req->buf, req->nb); + buf += req->nb; + } +} + +static void xfer_buf_to_reqs(unsigned char *buf, struct list_head *reqs) +{ + struct rw_req *req; + + list_for_each_entry(req, reqs, list) { + memmove(req->buf, buf, req->nb); + buf += req->nb; + } +} + +int ublast_common_flush(struct ublast_lowlevel *low, + struct list_head *read_reqs, + struct list_head *write_reqs, + int(*read)(struct ublast_lowlevel*, uint8_t*, unsigned), + int(*write)(struct ublast_lowlevel*, uint8_t*, int)) +{ + int retval = 0, nb_read, nb_write; + struct rw_req *req, *tmp; + unsigned char *buf_read = NULL, *buf_write = NULL; + + nb_read = get_bytes_of_reqs(read_reqs); + nb_write = get_bytes_of_reqs(write_reqs); + buf_read = malloc(nb_read); + buf_write = malloc(nb_write); + if (!buf_read || !buf_write) { + retval = -ENOMEM; + goto out; + } + + xfer_reqs_to_buf(buf_read, read_reqs); + xfer_reqs_to_buf(buf_write, write_reqs); + + retval = write(low, buf_write, nb_write); + if (retval < 0) { + LOG_ERROR("error_write_data: %d", retval); + goto out; + } + retval = read(low, buf_read, nb_read); + if (retval < 0) { + LOG_ERROR("error read data: %d", retval); + goto out; + } +out: + xfer_buf_to_reqs(buf_read, read_reqs); + list_for_each_entry_safe(req, tmp, write_reqs, list) { + list_del(&req->list); + free(req->buf); + free(req); + } + list_for_each_entry_safe(req, tmp, read_reqs, list) { + list_del(&req->list); + free(req); + } + return retval; +} + +int ublast_common_queue_read(struct list_head *read_reqs, + uint8_t *buf, unsigned int size) +{ + struct rw_req *req = malloc(sizeof(*req)); + + if (!req) + return -ENOMEM; + req->buf = buf; + req->nb = size; + list_add_tail(&req->list, read_reqs); + return size; +} + +int ublast_common_queue_write(struct list_head *write_reqs, + uint8_t *buf, unsigned int size) +{ + struct rw_req *req = malloc(sizeof(*req)); + + if (!req) + return -ENOMEM; + req->buf = malloc(size); + if (!req->buf) { + free(req); + return -ENOMEM; + } + memcpy(req->buf, buf, size); + req->nb = size; + list_add_tail(&req->list, write_reqs); + return size; +} diff --git a/src/jtag/drivers/usb_blaster/ublast_access_common.h b/src/jtag/drivers/usb_blaster/ublast_access_common.h new file mode 100644 index 0000000..f183180 --- /dev/null +++ b/src/jtag/drivers/usb_blaster/ublast_access_common.h @@ -0,0 +1,34 @@ +/* + * Driver for USB-JTAG, Altera USB-Blaster and compatibles + * + * + * Copyright (C) 2012 Robert Jarzmik [email protected] + * + * 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 2 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. + * + */ + +struct rw_req { + void *buf; + int nb; + struct list_head list; +}; + +extern int ublast_common_flush(struct ublast_lowlevel *low, + struct list_head *read_reqs, + struct list_head *write_reqs, + int(*read)(struct ublast_lowlevel*, uint8_t*, unsigned), + int(*write)(struct ublast_lowlevel*, uint8_t*, int)); +extern int ublast_common_queue_read(struct list_head *read_reqs, + uint8_t *buf, unsigned int size); +extern int ublast_common_queue_write(struct list_head *write_reqs, + uint8_t *buf, unsigned int size); + diff --git a/src/jtag/drivers/usb_blaster/ublast_access_ftd2xx.c b/src/jtag/drivers/usb_blaster/ublast_access_ftd2xx.c index e350650..998c741 100644 --- a/src/jtag/drivers/usb_blaster/ublast_access_ftd2xx.c +++ b/src/jtag/drivers/usb_blaster/ublast_access_ftd2xx.c @@ -28,17 +28,34 @@ #include <jtag/commands.h> #include "ublast_access.h" +#include "ublast_access_common.h" #include <ftd2xx.h> #include "jtag/drivers/ftd2xx_common.h" +static LIST_HEAD(read_reqs); +static LIST_HEAD(write_reqs); + static FT_HANDLE *ublast_getftdih(struct ublast_lowlevel *low) { return low->priv; } -static int ublast_ftd2xx_write(struct ublast_lowlevel *low, uint8_t *buf, int size, - uint32_t *bytes_written) +static int ublast_ftd2xx_queue_read(struct ublast_lowlevel *low, uint8_t *buf, + unsigned size, uint32_t *bytes_read) +{ + *bytes_read = size; + return ublast_common_queue_read(&read_reqs, buf, size); +} + +static int ublast_ftd2xx_queue_write(struct ublast_lowlevel *low, uint8_t *buf, + int size, uint32_t *bytes_written) +{ + *bytes_written = size; + return ublast_common_queue_write(&write_reqs, buf, (unsigned int)size); +} + +static int ublast_ftd2xx_do_write(struct ublast_lowlevel *low, uint8_t *buf, int size) { FT_STATUS status; DWORD dw_bytes_written; @@ -46,16 +63,14 @@ static int ublast_ftd2xx_write(struct ublast_lowlevel *low, uint8_t *buf, int si status = FT_Write(*ftdih, buf, size, &dw_bytes_written); if (status != FT_OK) { - *bytes_written = dw_bytes_written; LOG_ERROR("FT_Write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } - *bytes_written = dw_bytes_written; - return ERROR_OK; + return dw_bytes_written; } -static int ublast_ftd2xx_read(struct ublast_lowlevel *low, uint8_t *buf, - unsigned size, uint32_t *bytes_read) +static int ublast_ftd2xx_do_read(struct ublast_lowlevel *low, uint8_t *buf, + unsigned size) { DWORD dw_bytes_read; FT_STATUS status; @@ -63,12 +78,21 @@ static int ublast_ftd2xx_read(struct ublast_lowlevel *low, uint8_t *buf, status = FT_Read(*ftdih, buf, size, &dw_bytes_read); if (status != FT_OK) { - *bytes_read = dw_bytes_read; LOG_ERROR("FT_Read returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } - *bytes_read = dw_bytes_read; - return ERROR_OK; + return dw_bytes_read; +} + +static void ublast_ftd2xx_flush(struct ublast_lowlevel *low) +{ + int retval; + + retval = ublast_common_flush(low, &read_reqs, &write_reqs, + ublast_ftd2xx_do_read, + ublast_ftd2xx_do_write); + if (retval < 0) + LOG_ERROR("FT returned: %s", ftd2xx_status_string(retval)); } static int ublast_ftd2xx_init(struct ublast_lowlevel *low) @@ -167,8 +191,9 @@ static struct ublast_lowlevel_priv { static struct ublast_lowlevel low = { .open = ublast_ftd2xx_init, .close = ublast_ftd2xx_quit, - .read = ublast_ftd2xx_read, - .write = ublast_ftd2xx_write, + .queue_read = ublast_ftd2xx_queue_read, + .queue_write = ublast_ftd2xx_queue_write, + .flush = ublast_ftd2xx_flush, .priv = &info, }; diff --git a/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c b/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c index 23893e1..e958699 100644 --- a/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c +++ b/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c @@ -28,50 +28,89 @@ #include <jtag/commands.h> #include "ublast_access.h" +#include "ublast_access_common.h" #include <ftdi.h> +static LIST_HEAD(read_reqs); +static LIST_HEAD(write_reqs); + static struct ftdi_context *ublast_getftdic(struct ublast_lowlevel *low) { return low->priv; } -static int ublast_ftdi_read(struct ublast_lowlevel *low, uint8_t *buf, - unsigned size, uint32_t *bytes_read) +static char *hexdump(uint8_t *buf, unsigned int size) +{ + unsigned int i; + char *str = calloc(size * 2 + 1, 1); + + for (i = 0; i < size; i++) + sprintf(str + 2*i, "%02x", buf[i]); + return str; +} + +static int ublast_ftdi_queue_read(struct ublast_lowlevel *low, uint8_t *buf, + unsigned size, uint32_t *bytes_read) +{ + *bytes_read = size; + return ublast_common_queue_read(&read_reqs, buf, size); +} + +static int ublast_ftdi_queue_write(struct ublast_lowlevel *low, uint8_t *buf, + int size, uint32_t *bytes_written) +{ + *bytes_written = size; + return ublast_common_queue_write(&write_reqs, buf, (unsigned int)size); +} + +static int ublast_ftdi_do_read(struct ublast_lowlevel *low, uint8_t *buf, + unsigned size) { int retval; + uint32_t bytes_read; int timeout = 100; struct ftdi_context *ftdic = ublast_getftdic(low); + char *str; - *bytes_read = 0; - while ((*bytes_read < size) && timeout--) { - retval = ftdi_read_data(ftdic, buf + *bytes_read, - size - *bytes_read); + bytes_read = 0; + while ((bytes_read < size) && timeout--) { + retval = ftdi_read_data(ftdic, buf + bytes_read, + size - bytes_read); if (retval < 0) { - *bytes_read = 0; + bytes_read = 0; LOG_ERROR("ftdi_read_data: %s", ftdi_get_error_string(ftdic)); return ERROR_JTAG_DEVICE_ERROR; } - *bytes_read += retval; + bytes_read += retval; + str = retval < 0 ? NULL : hexdump(buf + bytes_read, retval); + DEBUG_JTAG_IO("USB actual read %d bytes : [%s]", retval, str); + free(str); } - return ERROR_OK; + return bytes_read; } -static int ublast_ftdi_write(struct ublast_lowlevel *low, uint8_t *buf, int size, - uint32_t *bytes_written) +static int ublast_ftdi_do_write(struct ublast_lowlevel *low, uint8_t *buf, int size) +{ + struct ftdi_context *ftdic = ublast_getftdic(low); + char *str; + + str = hexdump(buf, size); + DEBUG_JTAG_IO("USB actual write %d bytes : [%s]", size, str); + free(str); + return ftdi_write_data(ftdic, buf, size); +} + +static void ublast_ftdi_flush(struct ublast_lowlevel *low) { int retval; struct ftdi_context *ftdic = ublast_getftdic(low); - retval = ftdi_write_data(ftdic, buf, size); - if (retval < 0) { - *bytes_written = 0; - LOG_ERROR("ftdi_write_data: %s", + retval = ublast_common_flush(low, &read_reqs, &write_reqs, + ublast_ftdi_do_read, ublast_ftdi_do_write); + if (retval < 0) + LOG_ERROR("ftdi flush: %s", ftdi_get_error_string(ftdic)); - return ERROR_JTAG_DEVICE_ERROR; - } - *bytes_written = retval; - return ERROR_OK; } static int ublast_ftdi_init(struct ublast_lowlevel *low) @@ -125,8 +164,9 @@ static struct ublast_lowlevel_priv { static struct ublast_lowlevel low = { .open = ublast_ftdi_init, .close = ublast_ftdi_quit, - .read = ublast_ftdi_read, - .write = ublast_ftdi_write, + .queue_read = ublast_ftdi_queue_read, + .queue_write = ublast_ftdi_queue_write, + .flush = ublast_ftdi_flush, .priv = &info, }; diff --git a/src/jtag/drivers/usb_blaster/ublast_access_libusb.c b/src/jtag/drivers/usb_blaster/ublast_access_libusb.c new file mode 100644 index 0000000..de82f3e --- /dev/null +++ b/src/jtag/drivers/usb_blaster/ublast_access_libusb.c @@ -0,0 +1,422 @@ +/* + * Driver for simple USB buffering access layer + * + * Copyright (C) 2012 Robert Jarzmik [email protected] + * + * 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 2 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. + * + * This simple access layer does : + * - buffering : nothing is actually send over USB before an explicit flush() + * - streaming : all read/writes are supposed to be a stream, the USB packet + * semantics are lost + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <jtag/interface.h> +#include <jtag/commands.h> + +#include "ublast_access.h" +#include "helper/log.h" +#include <libusb-1.0/libusb.h> + +#define FTDI_DEVICE_OUT_REQTYPE (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE) +#define FTDI_DEVICE_IN_REQTYPE (0x80 | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE +#define SIO_RESET_REQUEST 0x00 +#define SIO_RESET_SIO 0 +#define SIO_RESET_PURGE_RX 1 +#define SIO_RESET_PURGE_TX 2 + +struct usb_ctx { + libusb_context *usb_ctx; + libusb_device_handle *dev; + int interface; + uint8_t ep_in; + uint8_t ep_out; + int timeout; + struct list_head read_reqs; + struct list_head write_reqs; +}; + +struct rw_req { + void *buf; + int nb; + struct list_head list; +}; + +struct transfer_result { + int nb_sumitted; + int nb_finished; +}; + +/** Port interface for chips with multiple interfaces */ +enum ftdi_interface +{ + INTERFACE_ANY = 0, + INTERFACE_A = 1, + INTERFACE_B = 2, + INTERFACE_C = 3, + INTERFACE_D = 4 +}; + +static void usb_reset(struct usb_ctx *ctx) +{ + int rc; + + rc = libusb_control_transfer(ctx->dev, FTDI_DEVICE_OUT_REQTYPE, + SIO_RESET_REQUEST, SIO_RESET_SIO, + INTERFACE_A, NULL, 0, ctx->timeout); + if (rc) + LOG_INFO("control transfer failed : %d\n", rc); +} + + +static struct usb_ctx* usb_open(const uint16_t vid, const uint16_t pid, + const int usb_interface, const uint8_t ep_in, + const uint8_t ep_out) +{ + int rc; + struct usb_ctx *ctx; + + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) + goto err_mem; + rc = libusb_init(&ctx->usb_ctx); + if (rc < 0) + goto err_init; + ctx->dev = libusb_open_device_with_vid_pid(ctx->usb_ctx, vid, pid); + if (!ctx->dev) + goto err_open; + ctx->interface = usb_interface; + rc = libusb_claim_interface(ctx->dev, ctx->interface); + if (rc != LIBUSB_SUCCESS) { + LOG_ERROR("libusb_claim_interface() failed with %d", rc); + goto err_interface; + } + usb_reset(ctx); + ctx->ep_in = ep_in; + ctx->ep_out = ep_out; + INIT_LIST_HEAD(&ctx->read_reqs); + INIT_LIST_HEAD(&ctx->write_reqs); + + ctx->timeout = 0; + return ctx; + +err_interface: + libusb_close(ctx->dev); +err_open: + libusb_exit(ctx->usb_ctx); +err_init: + free(ctx); +err_mem: + return NULL; +} + +static void usb_close(struct usb_ctx *ctx) +{ + libusb_close(ctx->dev); + libusb_exit(ctx->usb_ctx); + free(ctx); +} + +static int usb_queue_read(struct usb_ctx *ctx, void *buf, int nb) +{ + struct rw_req *req = malloc(sizeof(*req)); + + if (!req) + return -ENOMEM; + req->buf = buf; + req->nb = nb; + list_add_tail(&req->list, &ctx->read_reqs); + return nb; +} + +static int usb_queue_write(struct usb_ctx *ctx, void *buf, int nb, bool copy) +{ + struct rw_req *req = malloc(sizeof(*req)); + + if (!req) + return -ENOMEM; + if (copy) + req->buf = malloc(nb); + else + req->buf = buf; + if (!req->buf) { + free(req); + return -ENOMEM; + } + req->nb = nb; + memcpy(req->buf, buf, nb); + list_add_tail(&req->list, &ctx->write_reqs); + return nb; +} + +static void read_cb(struct libusb_transfer *transfer) +{ + struct transfer_result *result = transfer->user_data; + + DEBUG_JTAG_IO("status=%d, transferred %d+%d=%d", + transfer->status, + result->nb_finished, + transfer->actual_length, + result->nb_finished + transfer->actual_length); + if (transfer->actual_length >= 2) { + memmove(transfer->buffer, transfer->buffer + 2, + transfer->actual_length - 2); + result->nb_finished += transfer->actual_length - 2; + + if (result->nb_finished < result->nb_sumitted) { + transfer->length -= (transfer->actual_length - 2); + transfer->buffer += (transfer->actual_length - 2); + if (libusb_submit_transfer(transfer)) + result->nb_finished = result->nb_sumitted; + } + } +} + +static void write_cb(struct libusb_transfer *transfer) +{ + struct transfer_result *result = transfer->user_data; + + DEBUG_JTAG_IO("status=%d, transferred %d+%d=%d", + transfer->status, + result->nb_finished, + transfer->actual_length, + result->nb_finished + transfer->actual_length); + result->nb_finished += transfer->actual_length; + + if (result->nb_finished < result->nb_sumitted) { + transfer->length -= transfer->actual_length; + transfer->buffer += transfer->actual_length; + if (libusb_submit_transfer(transfer)) + result->nb_finished = result->nb_sumitted; + } +} + +static int get_bytes_of_reqs(struct list_head *reqs) +{ + struct rw_req *req; + int nb = 0; + + list_for_each_entry(req, reqs, list) + nb += req->nb; + return nb; +} + +static void xfer_reqs_to_buf(unsigned char *buf, struct list_head *reqs) +{ + struct rw_req *req; + + list_for_each_entry(req, reqs, list) { + memmove(buf, req->buf, req->nb); + buf += req->nb; + } +} + +static char *hexdump(uint8_t *buf, unsigned int size) +{ + unsigned int i; + char *str = calloc(size * 2 + 1, 1); + + for (i = 0; i < size; i++) + sprintf(str + 2*i, "%02x", buf[i]); + return str; +} + +static void xfer_buf_to_reqs(unsigned char *buf, struct list_head *reqs) +{ + struct rw_req *req; + char *str; + + list_for_each_entry(req, reqs, list) { + str = hexdump(buf, req->nb); + free(str); + + memmove(req->buf, buf, req->nb); + buf += req->nb; + } +} + +static int usb_flush(struct usb_ctx *ctx) +{ + int nb_read, nb_read_align, nb_write, rc = 0; + unsigned char *buf_read = NULL, *buf_write = NULL; + struct libusb_transfer *read_transfer, *write_transfer; + struct transfer_result read_result = { .nb_finished = 0 }; + struct transfer_result write_result = { .nb_finished = 0 }; + + nb_read = get_bytes_of_reqs(&ctx->read_reqs); + nb_read_align = (((nb_read + 2)/ 64) + 1) * 64; + nb_write = get_bytes_of_reqs(&ctx->write_reqs); + DEBUG_JTAG_IO("write %d, read %d", nb_write, nb_read); + + if (nb_read == 0 && nb_write == 0) + return 0; + read_result.nb_sumitted = nb_read; + write_result.nb_sumitted = nb_write; + + buf_read = malloc(nb_read_align); + buf_write = malloc(nb_write); + if (!buf_read || !buf_write) { + rc = -ENOMEM; + goto out; + } + + xfer_reqs_to_buf(buf_read, &ctx->read_reqs); + xfer_reqs_to_buf(buf_write, &ctx->write_reqs); + + char *str = hexdump(buf_write, nb_write); + DEBUG_JTAG_IO("actual write %d bytes [%s]", nb_write, str); + free(str); + + read_transfer = libusb_alloc_transfer(0); + write_transfer = libusb_alloc_transfer(0); + libusb_fill_bulk_transfer(read_transfer, ctx->dev, ctx->ep_in, + buf_read, nb_read_align, + read_cb, &read_result, ctx->timeout); + libusb_fill_bulk_transfer(write_transfer, ctx->dev, ctx->ep_out, + buf_write, nb_write, + write_cb, &write_result, ctx->timeout); + if (nb_write) + rc = libusb_submit_transfer(write_transfer); + if (!rc && nb_read) + rc = libusb_submit_transfer(read_transfer); + + /* Polling loop, more or less taken from libftdi */ + while ((read_result.nb_finished < nb_read || + write_result.nb_finished < nb_write) && !rc) { + rc = libusb_handle_events(ctx->usb_ctx); + + keep_alive(); + if (!rc) + continue; + if (nb_write) + libusb_cancel_transfer(write_transfer); + if (nb_read) + libusb_cancel_transfer(read_transfer); + rc = 0; + while (!rc && nb_write && + write_transfer->status != LIBUSB_TRANSFER_CANCELLED) + rc = libusb_handle_events(ctx->usb_ctx); + while (!rc && nb_read && + read_transfer->status != LIBUSB_TRANSFER_CANCELLED) + rc = libusb_handle_events(ctx->usb_ctx); + } + + if (rc) { + LOG_ERROR("libusb_handle_events() failed with %d", rc); + rc = -EIO; + } else if (nb_write && write_result.nb_finished < nb_write) { + LOG_ERROR("usb device did not accept all data: %d, tried %d", + write_result.nb_finished, nb_write); + rc = -EIO; + } else if (nb_read && read_result.nb_finished < nb_read) { + LOG_ERROR("usb device did not return all data: %d, expected %d", + read_result.nb_finished, nb_read); + rc = -EIO;; + } else { + rc = 0; + xfer_buf_to_reqs(buf_read, &ctx->read_reqs); + xfer_buf_to_reqs(buf_write, &ctx->write_reqs); + str = hexdump(buf_read, nb_read); + DEBUG_JTAG_IO("actual read %d bytes [%s]", nb_read, str); + free(str); + } + INIT_LIST_HEAD(&ctx->read_reqs); + INIT_LIST_HEAD(&ctx->write_reqs); + + if (nb_write) + libusb_free_transfer(write_transfer); + if (nb_read) + libusb_free_transfer(read_transfer); + /* if (rc) */ + /* usb_purge(ctx); */ + +out: + if (buf_read) + free(buf_read); + if (buf_write) + free(buf_write); + return rc; +} + +/* + * This is the ublast_access specific part + */ +static struct usb_ctx *ublast_getctx(struct ublast_lowlevel *low) +{ + return low->priv; +} + +static int ublast_libusb_read(struct ublast_lowlevel *low, uint8_t *buf, + unsigned size, uint32_t *bytes_read) +{ + struct usb_ctx *ctx = ublast_getctx(low); + int rc; + + rc = usb_queue_read(ctx, buf, size); + *bytes_read = size; + return rc < 0 ? ERROR_JTAG_DEVICE_ERROR : ERROR_OK; +} + +static int ublast_libusb_write(struct ublast_lowlevel *low, uint8_t *buf, int size, + uint32_t *bytes_written) +{ + struct usb_ctx *ctx = ublast_getctx(low); + int rc; + + rc = usb_queue_write(ctx, buf, size, true); + *bytes_written = size; + return rc < 0 ? ERROR_JTAG_DEVICE_ERROR : ERROR_OK; +} + +static void ublast_libusb_flush(struct ublast_lowlevel *low) +{ + struct usb_ctx *ctx = ublast_getctx(low); + + usb_flush(ctx); +} + +static int ublast_libusb_init(struct ublast_lowlevel *low) +{ + struct usb_ctx *ctx; + + LOG_INFO("usb blaster interface using libusb"); + ctx = usb_open(low->ublast_vid, low->ublast_pid, 0, 0x81, 0x02); + if (!ctx) + return ERROR_JTAG_INIT_FAILED; + low->priv = ctx; + + return ERROR_OK; +} + +static int ublast_libusb_quit(struct ublast_lowlevel *low) +{ + struct usb_ctx *ctx = ublast_getctx(low); + + usb_close(ctx); + return ERROR_OK; +}; + +static struct ublast_lowlevel low = { + .open = ublast_libusb_init, + .close = ublast_libusb_quit, + .queue_read = ublast_libusb_read, + .queue_write = ublast_libusb_write, + .flush = ublast_libusb_flush, + .priv = NULL, +}; + +struct ublast_lowlevel *ublast_register_libusb(void) +{ + return &low; +} diff --git a/src/jtag/drivers/usb_blaster/usb_blaster.c b/src/jtag/drivers/usb_blaster/usb_blaster.c index ccbed0e..af33490 100644 --- a/src/jtag/drivers/usb_blaster/usb_blaster.c +++ b/src/jtag/drivers/usb_blaster/usb_blaster.c @@ -71,6 +71,7 @@ #include <unistd.h> #include <sys/time.h> #include <time.h> +#include <list.h> /* Size of USB endpoint max packet size, ie. 64 bytes */ #define MAX_PACKET_SIZE 64 @@ -82,6 +83,15 @@ */ #define BUF_LEN 4096 +struct ublast_readback_request { + int nb_byteshift; + int nb_bitbang; + unsigned char *tdos; + struct list_head list; + struct scan_command *scan_cmd; +}; +LIST_HEAD(readback_reqs); + enum gpio_steer { FIXED_0 = 0, FIXED_1, @@ -96,8 +106,6 @@ struct ublast_info { int tdi; bool trst_asserted; bool srst_asserted; - uint8_t buf[BUF_LEN]; - int bufidx; char *lowlevel_name; struct ublast_lowlevel *drv; @@ -133,9 +141,14 @@ static struct drvs_map lowlevel_drivers_map[] = { #if BUILD_USB_BLASTER_FTD2XX { .name = "ftd2xx", .drv_register = ublast_register_ftd2xx }, #endif +#if BUILD_USB_BLASTER_LIBUSB + { .name = "libusb", .drv_register = ublast_register_libusb }, +#endif { NULL, NULL }, }; +static int ublast_handle_readbacks(void); + /* * Access functions to lowlevel driver, agnostic of libftdi/libftdxx */ @@ -151,18 +164,14 @@ static char *hexdump(uint8_t *buf, unsigned int size) static int ublast_buf_read(uint8_t *buf, unsigned size, uint32_t *bytes_read) { - int ret = info.drv->read(info.drv, buf, size, bytes_read); - char *str = hexdump(buf, *bytes_read); + int ret = info.drv->queue_read(info.drv, buf, size, bytes_read); - DEBUG_JTAG_IO("(size=%d, buf=[%s]) -> %u", size, str, - *bytes_read); - free(str); return ret; } static int ublast_buf_write(uint8_t *buf, int size, uint32_t *bytes_written) { - int ret = info.drv->write(info.drv, buf, size, bytes_written); + int ret = info.drv->queue_write(info.drv, buf, size, bytes_written); char *str = hexdump(buf, *bytes_written); DEBUG_JTAG_IO("(size=%d, buf=[%s]) -> %u", size, str, @@ -171,22 +180,26 @@ static int ublast_buf_write(uint8_t *buf, int size, uint32_t *bytes_written) return ret; } -static int nb_buf_remaining(void) +static void ublast_flush(void) { - return BUF_LEN - info.bufidx; + DEBUG_JTAG_IO("underway"); + info.drv->flush(info.drv); + ublast_handle_readbacks(); } -static void ublast_flush_buffer(void) -{ - unsigned int retlen; - int nb = info.bufidx, ret = ERROR_OK; +/* static int ublast_flush_buffer(void) */ +/* { */ +/* unsigned int retlen; */ +/* int nb = info.bufidx, ret = ERROR_OK; */ - while (ret == ERROR_OK && nb > 0) { - ret = ublast_buf_write(info.buf, nb, &retlen); - nb -= retlen; - } - info.bufidx = 0; -} +/* while (ret == ERROR_OK && nb > 0) { */ +/* ret = ublast_buf_write(info.buf, nb, &retlen); */ +/* nb -= retlen; */ +/* } */ +/* ret = info.bufidx; */ +/* info.bufidx = 0; */ +/* return ret; */ +/* } */ /* * Actually, the USB-Blaster offers a byte-shift mode to transmit up to 504 data @@ -231,6 +244,8 @@ static void ublast_flush_buffer(void) #define SHMODE (1 << 7) #define READ_TDO (1 << 0) +#define MAX_BYTESHIFT_NB (63) /* bit7 and bit6 busy, others free*/ + /** * ublast_queue_byte - queue one 'bitbang mode' byte for USB Blaster * @abyte: the byte to queue @@ -241,12 +256,17 @@ static void ublast_flush_buffer(void) */ static void ublast_queue_byte(uint8_t abyte) { - if (nb_buf_remaining() < 1) - ublast_flush_buffer(); - info.buf[info.bufidx++] = abyte; - if (nb_buf_remaining() == 0) - ublast_flush_buffer(); - DEBUG_JTAG_IO("(byte=0x%02x)", abyte); + unsigned int retlen; + + if (abyte & SHMODE) + DEBUG_JTAG_IO("(byte=0x%02x: shiftmode=%d, readback=%d)", + abyte, !!(abyte & SHMODE), !!(abyte & READ_TDO)); + else + DEBUG_JTAG_IO("(byte=0x%02x: shiftmode=%d, readback=%d, pin6=%d, pin8=%d, tms=%d, tdi=%d, tck=%d)", + abyte, !!(abyte & SHMODE), !!(abyte & READ_TDO), + !!(abyte & NCE), !!(abyte & NCS), !!(abyte & TMS), + !!(abyte & TDI), !!(abyte & TCK)); + ublast_buf_write(&abyte, 1, &retlen); } /** @@ -304,7 +324,6 @@ static void ublast_reset(int trst, int srst) info.srst_asserted = srst; out_value = ublast_build_out(SCAN_OUT); ublast_queue_byte(out_value); - ublast_flush_buffer(); } /** @@ -332,6 +351,7 @@ static void ublast_clock_tms(int tms) */ static void ublast_idle_clock(void) { + info.tms = 0; uint8_t out = ublast_build_out(SCAN_OUT); DEBUG_JTAG_IO("."); @@ -402,23 +422,20 @@ static void ublast_clock_tdi_flip_tms(int tdi, enum scan_type type) * Queues bytes to be sent to the USB Blaster. The bytes are not * actually sent, but stored in a buffer. The write is performed once * the buffer is filled, or if an explicit ublast_flush_buffer() is called. + * + * Returns the number of bytes actually send to lowlevel driver (ie. a non-zero + * value implies that a flush happened). + * */ -static void ublast_queue_bytes(uint8_t *bytes, int nb_bytes) +static int ublast_queue_bytes(uint8_t *bytes, int nb_bytes) { - if (info.bufidx + nb_bytes > BUF_LEN) { - LOG_ERROR("buggy code, should never queue more that %d bytes", - info.bufidx + nb_bytes); - exit(-1); - } + int ret = 0; + unsigned int bytes_written; + DEBUG_JTAG_IO("(nb_bytes=%d, bytes=[0x%02x, ...])", nb_bytes, bytes ? bytes[0] : 0); - if (bytes) - memcpy(&info.buf[info.bufidx], bytes, nb_bytes); - else - memset(&info.buf[info.bufidx], 0, nb_bytes); - info.bufidx += nb_bytes; - if (nb_buf_remaining() == 0) - ublast_flush_buffer(); + ublast_buf_write(bytes, nb_bytes, &bytes_written); + return ret; } /** @@ -450,6 +467,7 @@ static void ublast_tms(struct tms_command *cmd) { DEBUG_JTAG_IO("(num_bits=%d)", cmd->num_bits); ublast_tms_seq(cmd->bits, cmd->num_bits); + ublast_flush(); } /** @@ -502,7 +520,8 @@ static void ublast_state_move(tap_state_t state) /** * ublast_read_byteshifted_tdos - read TDO of byteshift writes - * @buf: the buffer to store the bits + * @dst: the buffer to store the bits + * @src: the raw byte stream * @nb_bits: the number of bits * * Reads back from USB Blaster TDO bits, triggered by a 'byteshift write', ie. eight @@ -510,28 +529,19 @@ static void ublast_state_move(tap_state_t state) * * As the USB blaster stores the TDO bits in LSB (ie. first bit in (byte0, * bit0), second bit in (byte0, bit1), ...), which is what we want to return, - * simply read bytes from USB interface and store them. - * - * Returns ERROR_OK if OK, ERROR_xxx if a read error occured + * do nothing ... */ -static int ublast_read_byteshifted_tdos(uint8_t *buf, int nb_bytes) +static void ublast_read_byteshifted_tdos(uint8_t *dst, uint8_t *src, int nb_bytes) { - unsigned int retlen; - int ret = ERROR_OK; - - DEBUG_JTAG_IO("%s(buf=%p, num_bits=%d)", __func__, buf, nb_bytes * 8); - ublast_flush_buffer(); - while (ret == ERROR_OK && nb_bytes > 0) { - ret = ublast_buf_read(buf, nb_bytes, &retlen); - nb_bytes -= retlen; - } - return ret; + DEBUG_JTAG_IO("buf=%p, num_bits=%d", src, nb_bytes * 8); + return; } /** * ublast_read_bitbang_tdos - read TDO of bitbang writes - * @buf: the buffer to store the bits - * @nb_bits: the number of bits + * @dst: the buffer to store the bits + * @src: the raw byte stream + * @nb_bits: the number of bits (between 1 and 9 included) * * Reads back from USB Blaster TDO bits, triggered by a 'bitbang write', ie. one * bit per received byte from USB interface, and store them in buffer, where : @@ -544,27 +554,20 @@ static int ublast_read_byteshifted_tdos(uint8_t *buf, int nb_bytes) * * Returns ERROR_OK if OK, ERROR_xxx if a read error occured */ -static int ublast_read_bitbang_tdos(uint8_t *buf, int nb_bits) +static int ublast_read_bitbang_tdos(uint8_t *dst, uint8_t *src, int nb_bits) { int nb1 = nb_bits; int i, ret = ERROR_OK; - unsigned int retlen; - uint8_t tmp[8]; - - DEBUG_JTAG_IO("%s(buf=%p, num_bits=%d)", __func__, buf, nb_bits); + uint8_t tmp[9]; - /* - * Ensure all previous bitbang writes were issued to the dongle, so that - * it returns back the read values. - */ - ublast_flush_buffer(); + DEBUG_JTAG_IO("%s(buf=%p, num_bits=%d)", __func__, src, nb_bits); - ret = ublast_buf_read(tmp, nb1, &retlen); + memcpy(tmp, src, nb1); for (i = 0; ret == ERROR_OK && i < nb1; i++) if (tmp[i] & READ_TDO) - *buf |= (1 << i); + dst[i /8] |= (1 << i); else - *buf &= ~(1 << i); + dst[i / 8] &= ~(1 << i); return ret; } @@ -578,22 +581,28 @@ static int ublast_read_bitbang_tdos(uint8_t *buf, int nb_bits) * As a side effect, the last TDI bit is sent along a TMS=1, and triggers a JTAG * TAP state shift if input bits were non NULL. * - * In order to not saturate the USB Blaster queues, this method reads back TDO - * if the scan type requests it, and stores them back in bits. + * As the write is not actually done but just queued, the readback request queue + * should be added an item after calling this function. In order to not saturate + * the USB Blaster queues, this method queues the readback data on readback + * queue, so that ublast_flush() can rework the tdos into a bitstream * * As a side note, the state of TCK when entering this function *must* be * low. This is because byteshift mode outputs TDI on rising TCK and reads TDO * on falling TCK if and only if TCK is low before queuing byteshift mode bytes. * If TCK was high, the USB blaster will queue TDI on falling edge, and read TDO * on rising edge !!! + * + * Return the allocated structure controlling the request */ -static void ublast_queue_tdi(uint8_t *bits, int nb_bits, enum scan_type scan) +static struct ublast_readback_request * +ublast_queue_tdi(uint8_t *bits, int nb_bits, enum scan_type scan) { int nb8 = nb_bits / 8; int nb1 = nb_bits % 8; - int nbfree_in_packet, i, trans = 0, read_tdos; - uint8_t *tdos = calloc(1, nb_bits / 8 + 1); + int i, trans = 0, read_tdos; + uint32_t retlen; static uint8_t byte0[BUF_LEN]; + struct ublast_readback_request *req = NULL; /* * As the last TDI bit should always be output in bitbang mode in order @@ -610,17 +619,24 @@ static void ublast_queue_tdi(uint8_t *bits, int nb_bits, enum scan_type scan) } read_tdos = (scan == SCAN_IN || scan == SCAN_IO); + if (read_tdos) { + req = calloc(1, sizeof(*req)); + if (!req) + return NULL; + req->tdos = calloc(1, nb8 + nb1); + if (!req->tdos) + return NULL; + req->nb_byteshift = nb8; + req->nb_bitbang = nb1; + ublast_buf_read(req->tdos, nb8 + nb1, &retlen); + } + for (i = 0; i < nb8; i += trans) { - /* - * Calculate number of bytes to fill USB packet of size MAX_PACKET_SIZE - */ - nbfree_in_packet = (MAX_PACKET_SIZE - (info.bufidx%MAX_PACKET_SIZE)); - trans = MIN(nbfree_in_packet - 1, nb8 - i); + trans = MIN(MAX_BYTESHIFT_NB, nb8 - i); /* * Queue a byte-shift mode transmission, with as many bytes as * is possible with regard to : - * - current filling level of write buffer * - remaining bytes to write in byte-shift mode */ if (read_tdos) @@ -631,8 +647,6 @@ static void ublast_queue_tdi(uint8_t *bits, int nb_bits, enum scan_type scan) ublast_queue_bytes(&bits[i], trans); else ublast_queue_bytes(byte0, trans); - if (read_tdos) - ublast_read_byteshifted_tdos(&tdos[i], trans); } /* @@ -645,17 +659,40 @@ static void ublast_queue_tdi(uint8_t *bits, int nb_bits, enum scan_type scan) else ublast_clock_tdi(tdi, scan); } - if (nb1 && read_tdos) - ublast_read_bitbang_tdos(&tdos[nb8], nb1); - - if (bits) - memcpy(bits, tdos, DIV_ROUND_UP(nb_bits, 8)); - free(tdos); /* * Ensure clock is in lower state */ ublast_idle_clock(); + + return req; +} + +static int ublast_handle_readbacks(void) +{ + struct ublast_readback_request *req, *tmp; + int ret = 0, nb_bytes; + char *str; + + list_for_each_entry_safe(req, tmp, &readback_reqs, list) { + nb_bytes = req->nb_byteshift + req->nb_bitbang; + str = hexdump(req->tdos, nb_bytes); + DEBUG_JTAG_IO("read back on TDO: (size=%d(%d+%d), buf=[%s])", + nb_bytes, req->nb_byteshift, req->nb_bitbang, str); + free(str); + + ublast_read_byteshifted_tdos(req->tdos, req->tdos, + req->nb_byteshift); + ublast_read_bitbang_tdos(req->tdos + req->nb_byteshift, + req->tdos + req->nb_byteshift, + req->nb_bitbang); + + ret |= jtag_read_buffer(req->tdos, req->scan_cmd); + free(req->tdos); + list_del(&req->list); + free(req); + } + return ret; } static void ublast_runtest(int cycles, tap_state_t state) @@ -689,6 +726,7 @@ static int ublast_scan(struct scan_command *cmd) int ret = ERROR_OK; static const char * const type2str[] = { "", "SCAN_IN", "SCAN_OUT", "SCAN_IO" }; char *log_buf = NULL; + struct ublast_readback_request *req = NULL; type = jtag_scan_type(cmd); scan_bits = jtag_build_buffer(cmd, &buf); @@ -705,7 +743,11 @@ static int ublast_scan(struct scan_command *cmd) scan_bits, log_buf, cmd->end_state); free(log_buf); - ublast_queue_tdi(buf, scan_bits, type); + req = ublast_queue_tdi(buf, scan_bits, type); + if (req) { + req->scan_cmd = cmd; + list_add_tail(&req->list, &readback_reqs); + } /* * As our JTAG is in an unstable state (IREXIT1 or DREXIT1), move it @@ -717,17 +759,15 @@ static int ublast_scan(struct scan_command *cmd) else tap_set_state(TAP_DRPAUSE); - ret = jtag_read_buffer(buf, cmd); - if (buf) - free(buf); ublast_state_move(cmd->end_state); return ret; } -static void ublast_msleep(int ms) +static void ublast_msleep(int us) { - DEBUG_JTAG_IO("%s(ms=%d)", __func__, ms); - jtag_sleep(ms); + DEBUG_JTAG_IO("%s(us=%d)", __func__, us); + jtag_sleep(us); + ublast_flush(); } static int ublast_execute_queue(void) @@ -739,17 +779,21 @@ static int ublast_execute_queue(void) cmd = cmd->next) { switch (cmd->type) { case JTAG_RESET: + ublast_flush(); ublast_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + ublast_flush(); break; case JTAG_RUNTEST: ublast_runtest(cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); + ublast_flush(); break; case JTAG_STABLECLOCKS: ublast_stableclocks(cmd->cmd.stableclocks->num_cycles); break; case JTAG_TLR_RESET: ublast_state_move(cmd->cmd.statemove->end_state); + ublast_flush(); break; case JTAG_PATHMOVE: ublast_path_move(cmd->cmd.pathmove); @@ -765,8 +809,8 @@ static int ublast_execute_queue(void) break; } } + ublast_flush(); - ublast_flush_buffer(); return ret; } @@ -783,6 +827,7 @@ static int ublast_execute_queue(void) static int ublast_init(void) { static uint8_t tms_reset = 0xff; + static unsigned char buf0[BUF_LEN]; int ret, i; if (info.lowlevel_name) { @@ -819,11 +864,16 @@ static int ublast_init(void) * Flush USB-Blaster queue fifos */ uint32_t retlen; - ublast_buf_write(info.buf, BUF_LEN, &retlen); + buf0[0] = ublast_build_out(SCAN_OUT); + memset(buf0, buf0[0], sizeof(buf0)); + ublast_buf_write(buf0, BUF_LEN, &retlen); + ublast_flush(); + /* * Put JTAG in RESET state (five 1 on TMS) */ ublast_tms_seq(&tms_reset, 5); + ublast_flush(); tap_set_state(TAP_RESET); } return ret; @@ -935,7 +985,7 @@ COMMAND_HANDLER(ublast_handle_pin_command) if (info.drv) { out_value = ublast_build_out(SCAN_OUT); ublast_queue_byte(out_value); - ublast_flush_buffer(); + ublast_flush(); } } return ERROR_OK; -- ------------------------------------------------------------------------------ See everything from the browser to the database with AppDynamics Get end-to-end visibility with application monitoring from AppDynamics Isolate bottlenecks and diagnose root cause in seconds. Start your free trial of AppDynamics Pro today! http://pubads.g.doubleclick.net/gampad/clk?id=48808831&iu=/4140/ostg.clktrk _______________________________________________ OpenOCD-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openocd-devel
