diff --git a/configure.ac b/configure.ac index a14f46f2a..8afe71120 100644 --- a/configure.ac +++ b/configure.ac @@ -701,14 +701,12 @@ else fi if test $build_usb_blaster_libftdi = yes; then - build_bitbang=yes AC_DEFINE([BUILD_USB_BLASTER_LIBFTDI], [1], [1 if you want libftdi usb_blaster.]) else AC_DEFINE([BUILD_USB_BLASTER_LIBFTDI], [0], [0 if you don't want libftdi usb_blaster.]) fi if test $build_usb_blaster_ftd2xx = yes; then - build_bitbang=yes AC_DEFINE([BUILD_USB_BLASTER_FTD2XX], [1], [1 if you want ftd2xx usb_blaster.]) else AC_DEFINE([BUILD_USB_BLASTER_FTD2XX], [0], [0 if you don't want ftd2xx usb_blaster.]) @@ -1058,7 +1056,7 @@ LDFLAGS=$LDFLAGS_SAVE CFLAGS=$CFLAGS_SAVE fi -if test $build_ft2232_libftdi = yes ; then +if test $build_ft2232_libftdi = yes -o $build_usb_blaster_libftdi = yes; then # We assume: the package is preinstalled in the proper place # these present as 2 libraries.. LIBS="$LIBS -lftdi -lusb" @@ -1182,6 +1180,7 @@ AM_CONDITIONAL([FT2232_LIBFTDI], [test $build_ft2232_libftdi = yes]) AM_CONDITIONAL([FT2232_DRIVER], [test $build_ft2232_ftd2xx = yes -o $build_ft2232_libftdi = yes]) 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_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]) @@ -1312,6 +1311,7 @@ AC_CONFIG_FILES([ src/helper/Makefile src/jtag/Makefile src/jtag/drivers/Makefile + src/jtag/drivers/usb_blaster/Makefile src/jtag/hla/Makefile src/transport/Makefile src/xsvf/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index c78e81c80..badc80dc1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -66,16 +66,12 @@ endif if FT2232_LIBFTDI FTDI2232LIB = -lftdi -lusb else -if USB_BLASTER_LIBFTDI -FTDI2232LIB = -lftdi -lusb -else if PRESTO_LIBFTDI FTDI2232LIB = -lftdi -lusb else FTDI2232LIB = endif endif -endif LIBUSB = if USE_LIBUSB1 diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index e064399b5..543615662 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -1,6 +1,7 @@ include $(top_srcdir)/common.mk noinst_LTLIBRARIES = libocdjtagdrivers.la +libocdjtagdrivers_la_LIBADD = libocdjtagdrivers_la_SOURCES = \ $(DRIVERFILES) @@ -13,6 +14,7 @@ ULINK_FIRMWARE = $(srcdir)/OpenULINK EXTRA_DIST = $(ULINK_FIRMWARE) DRIVERFILES = +SUBDIRS= # Standard Driver: common files DRIVERFILES += driver.c @@ -47,7 +49,8 @@ if FTDI_DRIVER DRIVERFILES += ftdi.c mpsse.c endif if USB_BLASTER_DRIVER -DRIVERFILES += usb_blaster.c +SUBDIRS += usb_blaster +libocdjtagdrivers_la_LIBADD += $(top_builddir)/src/jtag/drivers/usb_blaster/libocdusbblaster.la endif if AMTJTAGACCEL DRIVERFILES += amt_jtagaccel.c diff --git a/src/jtag/drivers/usb_blaster.c b/src/jtag/drivers/usb_blaster.c deleted file mode 100644 index 2ef800dbe..000000000 --- a/src/jtag/drivers/usb_blaster.c +++ /dev/null @@ -1,577 +0,0 @@ -/*************************************************************************** - * Driver for USB-JTAG, Altera USB-Blaster and compatibles * - * Original code from Kolja Waschk's USB-JTAG project * - * (http://www.ixo.de/info/usb_jtag/). * - * Some updates by Anthony Liu (2006). * - * Minor updates and cleanup by Catalin Patulea (2009). * - * Speed updates by Ali Lown (2011). * - * * - * Copyright (C) 2011 Ali Lown * - * ali@lown.me.uk * - * * - * Copyright (C) 2009 Catalin Patulea * - * cat@vv.carleton.ca * - * * - * Copyright (C) 2006 Kolja Waschk * - * usbjtag@ixo.de * - * * - * Based on ft2232.c and bitbang.c, * - * Copyright (C) 2004,2006 by Dominic Rath * - * * - * 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. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ - -/* - * The following information is originally from Kolja Waschk's USB-JTAG, - * where it was obtained by reverse engineering an Altera USB-Blaster. - * See http://www.ixo.de/info/usb_jtag/ for USB-Blaster block diagram and - * usb_jtag-20080705-1200.zip#usb_jtag/host/openocd for protocol. - * - * The same information is also on the UrJTAG mediawiki, with some additional - * notes on bits marked as "unknown" by usb_jtag. - * (http://sourceforge.net/apps/mediawiki/urjtag/index.php? - * title=Cable_Altera_USB-Blaster) - * - * USB-JTAG, Altera USB-Blaster and compatibles are typically implemented as - * an FTDIChip FT245 followed by a CPLD which handles a two-mode protocol: - * - * _________ - * | | - * | AT93C46 | - * |_________| - * __|__________ _________ - * | | | | - * USB__| FTDI 245BM |__| EPM7064 |__JTAG (B_TDO,B_TDI,B_TMS,B_TCK) - * |_____________| |_________| - * __|__________ _|___________ - * | | | | - * | 6 MHz XTAL | | 24 MHz Osc. | - * |_____________| |_____________| - * - * Protocol details are given in the code below. - * - * It is also possible to emulate this configuration using a single-chip USB - * controller like the Cypress FX2 (again, see usb_jtag for details). - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#if IS_CYGWIN == 1 -#include "windows.h" -#undef LOG_ERROR -#endif - -/* project specific includes */ -#include -#include -#include - -/* system includes */ -#include -#include -#include - -#include "bitbang.h" - -#if (BUILD_USB_BLASTER_FTD2XX == 1 && BUILD_USB_BLASTER_LIBFTDI == 1) -#error "BUILD_USB_BLASTER_FTD2XX && BUILD_USB_BLASTER_LIBFTDI " -"are mutually exclusive" -#elif (BUILD_USB_BLASTER_FTD2XX != 1 && BUILD_USB_BLASTER_LIBFTDI != 1) -#error "BUILD_USB_BLASTER_FTD2XX || BUILD_USB_BLASTER_LIBFTDI must be chosen" -#endif - -/* USB_BLASTER access library includes */ -#if BUILD_USB_BLASTER_FTD2XX == 1 -#include -#include "ftd2xx_common.h" -#elif BUILD_USB_BLASTER_LIBFTDI == 1 -#include -#endif - -#include -#include - -static char *usb_blaster_device_desc; -static uint16_t usb_blaster_vid = 0x09fb; /* Altera */ -static uint16_t usb_blaster_pid = 0x6001; /* USB-Blaster */ - -/* last output byte in simple bit banging (legacy) mode */ -static uint8_t out_value; -/* global output buffer for bit banging */ -#define BUF_LEN 64 /* Size of EP1 */ -static uint8_t out_buffer[BUF_LEN]; -static uint16_t out_count; - -#if BUILD_USB_BLASTER_FTD2XX == 1 -static FT_HANDLE ftdih; -#elif BUILD_USB_BLASTER_LIBFTDI == 1 -static struct ftdi_context ftdic; -#endif - -static int usb_blaster_buf_write( - uint8_t *buf, int size, uint32_t *bytes_written) -{ -#if BUILD_USB_BLASTER_FTD2XX == 1 - FT_STATUS status; - DWORD dw_bytes_written; - -#ifdef _DEBUG_JTAG_IO_ - LOG_DEBUG("usb_blaster_buf_write %02X (%d)", buf[0], size); -#endif - 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; -#elif BUILD_USB_BLASTER_LIBFTDI == 1 - int retval; -#ifdef _DEBUG_JTAG_IO_ - LOG_DEBUG("usb_blaster_buf_write %02X (%d)", buf[0], size); -#endif - retval = ftdi_write_data(&ftdic, buf, size); - if (retval < 0) { - *bytes_written = 0; - LOG_ERROR("ftdi_write_data: %s", ftdi_get_error_string(&ftdic)); - return ERROR_JTAG_DEVICE_ERROR; - } - *bytes_written = retval; - return ERROR_OK; -#endif -} - -static int usb_blaster_buf_read(uint8_t *buf, unsigned size, uint32_t *bytes_read) -{ -#if BUILD_USB_BLASTER_FTD2XX == 1 - DWORD dw_bytes_read; - FT_STATUS status; - - 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; - } -#ifdef _DEBUG_JTAG_IO_ - LOG_DEBUG("usb_blaster_buf_read %02X (%" PRIu32 ")", buf[0], dw_bytes_read); -#endif - *bytes_read = dw_bytes_read; - return ERROR_OK; - -#elif BUILD_USB_BLASTER_LIBFTDI == 1 - int retval; - int timeout = 100; - - *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; - LOG_ERROR("ftdi_read_data: %s", - ftdi_get_error_string(&ftdic)); - return ERROR_JTAG_DEVICE_ERROR; - } - *bytes_read += retval; - } -#ifdef _DEBUG_JTAG_IO_ - LOG_DEBUG("usb_blaster_buf_read %02X (%d)", buf[0], *bytes_read); -#endif - return ERROR_OK; -#endif -} - -/* The following code doesn't fully utilize the possibilities of the - * USB-Blaster. It only buffers data up to the maximum packet size of 64 bytes. - * - * Actually, the USB-Blaster offers a byte-shift mode to transmit up to 504 data - * bits (bidirectional) in a single USB packet. A header byte has to be sent as - * the first byte in a packet with the following meaning: - * - * Bit 7 (0x80): Must be set to indicate byte-shift mode. - * Bit 6 (0x40): If set, the USB-Blaster will also read data, not just write. - * Bit 5..0: Define the number N of following bytes - * - * All N following bytes will then be clocked out serially on TDI. If Bit 6 was - * set, it will afterwards return N bytes with TDO data read while clocking out - * the TDI data. LSB of the first byte after the header byte will appear first - * on TDI. - */ - -/* Simple bit banging mode: - * - * Bit 7 (0x80): Must be zero (see byte-shift mode above) - * Bit 6 (0x40): If set, you will receive a byte indicating the state of TDO - * in return. - * Bit 5 (0x20): Output Enable/LED. - * Bit 4 (0x10): TDI Output. - * Bit 3 (0x08): nCS Output (not used in JTAG mode). - * Bit 2 (0x04): nCE Output (not used in JTAG mode). - * Bit 1 (0x02): TMS Output. - * Bit 0 (0x01): TCK Output. - * - * For transmitting a single data bit, you need to write two bytes. Up to 64 - * bytes can be combined in a single USB packet. - * It isn't possible to read a data without transmitting data. - */ - -#define TCK (1 << 0) -#define TMS (1 << 1) -#define NCE (1 << 2) -#define NCS (1 << 3) -#define TDI (1 << 4) -#define LED (1 << 5) -#define READ (1 << 6) -#define SHMODE (1 << 7) -#define OTHERS ((1 << 2) | (1 << 3) | (1 << 5)) - -#define READ_TDO (1 << 0) - -static void usb_blaster_write_databuffer(uint8_t *buf, uint16_t len) -{ - uint32_t bytes_written; - usb_blaster_buf_write(buf, len, &bytes_written); - out_count = 0; -#ifdef _DEBUG_JTAG_IO_ - LOG_DEBUG("---- WROTE %d", bytes_written); -#endif -} - -static void usb_blaster_addtowritebuffer(uint8_t value, bool forcewrite) -{ - out_buffer[out_count] = value; - out_count += 1; - if (out_count == BUF_LEN || forcewrite) - usb_blaster_write_databuffer(out_buffer, out_count); -} - -static int usb_blaster_read_data(void) -{ - int status; - uint8_t buf[1]; - uint32_t bytes_read; - - if (out_count > 0) - usb_blaster_write_databuffer(out_buffer, out_count); - - out_value |= READ; - usb_blaster_addtowritebuffer(out_value, true); - out_value &= ~READ; - - status = usb_blaster_buf_read(buf, 1, &bytes_read); - if (status < 0) - return 0; - - return !!(buf[0] & READ_TDO); -} - -static void usb_blaster_write(int tck, int tms, int tdi) -{ -#ifdef _DEBUG_JTAG_IO_ - LOG_DEBUG("---- usb_blaster_write(%d,%d,%d)", tck, tms, tdi); -#endif - out_value &= ~(TCK | TMS | TDI); - if (tck) - out_value |= TCK; - if (tms) - out_value |= TMS; - if (tdi) - out_value |= TDI; - - usb_blaster_addtowritebuffer(out_value, false); -} - -static void usb_blaster_reset(int trst, int srst) -{ - LOG_DEBUG("TODO: usb_blaster_reset(%d,%d) isn't implemented!", - trst, srst); -} - -static void usb_blaster_blink(int state) -{ - out_value = 0x00; - if (state) - out_value |= LED; - - usb_blaster_addtowritebuffer(out_value, true); -} - -static struct bitbang_interface usb_blaster_bitbang = { - .read = usb_blaster_read_data, - .write = usb_blaster_write, - .reset = usb_blaster_reset, - .blink = usb_blaster_blink, -}; - -static int usb_blaster_init(void) -{ - uint8_t latency_timer; - -#if BUILD_USB_BLASTER_FTD2XX == 1 - FT_STATUS status; -#endif - -#if BUILD_USB_BLASTER_FTD2XX == 1 - LOG_DEBUG("'usb_blaster' interface using FTD2XX"); -#elif BUILD_USB_BLASTER_LIBFTDI == 1 - LOG_DEBUG("'usb_blaster' interface using libftdi"); -#endif - -#if BUILD_USB_BLASTER_FTD2XX == 1 - /* Open by device description */ - if (usb_blaster_device_desc == NULL) { - LOG_WARNING("no usb_blaster device description specified, " - "using default 'USB-Blaster'"); - usb_blaster_device_desc = strdup("USB-Blaster"); - } - -#if IS_WIN32 == 0 - /* Add non-standard Vid/Pid to the linux driver */ - status = FT_SetVIDPID(usb_blaster_vid, usb_blaster_pid); - if (status != FT_OK) { - LOG_WARNING("couldn't add %4.4x:%4.4x", - usb_blaster_vid, usb_blaster_pid); - } -#endif - - status = FT_OpenEx(usb_blaster_device_desc, FT_OPEN_BY_DESCRIPTION, - &ftdih); - if (status != FT_OK) { - DWORD num_devices; - - LOG_ERROR("unable to open ftdi device: %s", - ftd2xx_status_string(status)); - status = FT_ListDevices(&num_devices, NULL, - FT_LIST_NUMBER_ONLY); - if (status == FT_OK) { - char **desc_array = malloc(sizeof(char *) - * (num_devices + 1)); - unsigned int i; - - for (i = 0; i < num_devices; i++) - desc_array[i] = malloc(64); - desc_array[num_devices] = NULL; - - status = FT_ListDevices(desc_array, &num_devices, - FT_LIST_ALL | FT_OPEN_BY_DESCRIPTION); - - if (status == FT_OK) { - LOG_ERROR("ListDevices: %" PRIu32, (uint32_t)num_devices); - for (i = 0; i < num_devices; i++) - LOG_ERROR("%i: %s", i, desc_array[i]); - } - - for (i = 0; i < num_devices; i++) - free(desc_array[i]); - free(desc_array); - } else - printf("ListDevices: NONE\n"); - return ERROR_JTAG_INIT_FAILED; - } - - status = FT_SetLatencyTimer(ftdih, 2); - if (status != FT_OK) { - LOG_ERROR("unable to set latency timer: %s", - ftd2xx_status_string(status)); - return ERROR_JTAG_INIT_FAILED; - } - - status = FT_GetLatencyTimer(ftdih, &latency_timer); - if (status != FT_OK) { - LOG_ERROR("unable to get latency timer: %s", - ftd2xx_status_string(status)); - return ERROR_JTAG_INIT_FAILED; - } - LOG_DEBUG("current latency timer: %i", latency_timer); - - status = FT_SetBitMode(ftdih, 0x00, 0); - if (status != FT_OK) { - LOG_ERROR("unable to disable bit i/o mode: %s", - ftd2xx_status_string(status)); - return ERROR_JTAG_INIT_FAILED; - } -#elif BUILD_USB_BLASTER_LIBFTDI == 1 - if (ftdi_init(&ftdic) < 0) - return ERROR_JTAG_INIT_FAILED; - - /* context, vendor id, product id */ - if (ftdi_usb_open(&ftdic, usb_blaster_vid, usb_blaster_pid) < 0) { - LOG_ERROR("unable to open ftdi device: %s", ftdic.error_str); - return ERROR_JTAG_INIT_FAILED; - } - - if (ftdi_usb_reset(&ftdic) < 0) { - LOG_ERROR("unable to reset ftdi device"); - return ERROR_JTAG_INIT_FAILED; - } - - if (ftdi_set_latency_timer(&ftdic, 2) < 0) { - LOG_ERROR("unable to set latency timer"); - return ERROR_JTAG_INIT_FAILED; - } - - if (ftdi_get_latency_timer(&ftdic, &latency_timer) < 0) { - LOG_ERROR("unable to get latency timer"); - return ERROR_JTAG_INIT_FAILED; - } - LOG_DEBUG("current latency timer: %u", latency_timer); - - ftdi_disable_bitbang(&ftdic); -#endif - - bitbang_interface = &usb_blaster_bitbang; - -#if 0 -#if BUILD_USB_BLASTER_FTD2XX == 1 - status = FT_Purge(ftdih, FT_PURGE_RX | FT_PURGE_TX); - if (status != FT_OK) { - LOG_ERROR("error purging ftd2xx device: %i", status); - return ERROR_JTAG_INIT_FAILED; - } -#elif BUILD_USB_BLASTER_LIBFTDI == 1 - if (ftdi_usb_purge_buffers(&ftdic) < 0) { - LOG_ERROR("ftdi_purge_buffers: %s", ftdic.error_str); - return ERROR_JTAG_INIT_FAILED; - } -#endif -#endif - - return ERROR_OK; -} - -static int usb_blaster_quit(void) -{ - if (out_count > 0) - usb_blaster_write_databuffer(out_buffer, out_count); - -#if BUILD_USB_BLASTER_FTD2XX == 1 - FT_STATUS status; - - status = FT_Close(ftdih); -#elif BUILD_USB_BLASTER_LIBFTDI == 1 - ftdi_usb_close(&ftdic); - ftdi_deinit(&ftdic); -#endif - - if (usb_blaster_device_desc) { - free(usb_blaster_device_desc); - usb_blaster_device_desc = NULL; - } - - return ERROR_OK; -} - -COMMAND_HANDLER(usb_blaster_handle_device_desc_command) -{ - if (CMD_ARGC == 1) - usb_blaster_device_desc = strdup(CMD_ARGV[0]); - else - LOG_ERROR("require exactly one argument to " - "usb_blaster_device_desc "); - - return ERROR_OK; -} - -COMMAND_HANDLER(usb_blaster_handle_vid_pid_command) -{ - if (CMD_ARGC > 2) { - LOG_WARNING("ignoring extra IDs in usb_blaster_vid_pid " - "(maximum is 1 pair)"); - CMD_ARGC = 2; - } - if (CMD_ARGC == 2) { - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], usb_blaster_vid); - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], usb_blaster_pid); - } else - LOG_WARNING("incomplete usb_blaster_vid_pid configuration"); - - return ERROR_OK; -} - -COMMAND_HANDLER(usb_blaster_handle_pin_command) -{ - if (CMD_ARGC == 2) { - const char *const pin_name = CMD_ARGV[0]; - uint8_t mask; - unsigned int state; - - if (!strcmp(pin_name, "pin6")) - mask = NCE; - else if (!strcmp(pin_name, "pin8")) - mask = NCS; - else { - LOG_ERROR("%s: pin name must be \"pin6\" or \"pin8\"", - CMD_NAME); - return ERROR_COMMAND_SYNTAX_ERROR; - } - - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], state); - if (state == 0) { - out_value &= ~mask; - usb_blaster_addtowritebuffer(out_value, true); - } else if (state == 1) { - out_value |= mask; - usb_blaster_addtowritebuffer(out_value, true); - } else { - LOG_ERROR("%s: pin state must be 0 or 1", CMD_NAME); - return ERROR_COMMAND_SYNTAX_ERROR; - } - - return ERROR_OK; - } else { - LOG_ERROR("%s takes exactly two arguments", CMD_NAME); - return ERROR_COMMAND_SYNTAX_ERROR; - } -} - -static const struct command_registration usb_blaster_command_handlers[] = { - { - .name = "usb_blaster_device_desc", - .handler = usb_blaster_handle_device_desc_command, - .mode = COMMAND_CONFIG, - .help = "set the USB device description of the USB-Blaster", - .usage = "description-string", - }, - { - .name = "usb_blaster_vid_pid", - .handler = usb_blaster_handle_vid_pid_command, - .mode = COMMAND_CONFIG, - .help = "the vendor ID and product ID of the USB-Blaster", - .usage = "vid pid", - }, - { - .name = "usb_blaster", - .handler = usb_blaster_handle_pin_command, - .mode = COMMAND_ANY, - .help = "set pin state for the unused GPIO pins", - .usage = "(pin6|pin8) (0|1)", - }, - COMMAND_REGISTRATION_DONE -}; - -struct jtag_interface usb_blaster_interface = { - .name = "usb_blaster", - .commands = usb_blaster_command_handlers, - .supported = DEBUG_CAP_TMS_SEQ, - - .execute_queue = bitbang_execute_queue, - - .init = usb_blaster_init, - .quit = usb_blaster_quit, -}; diff --git a/src/jtag/drivers/usb_blaster/Makefile.am b/src/jtag/drivers/usb_blaster/Makefile.am new file mode 100644 index 000000000..8beadd436 --- /dev/null +++ b/src/jtag/drivers/usb_blaster/Makefile.am @@ -0,0 +1,16 @@ +include $(top_srcdir)/common.mk + +noinst_LTLIBRARIES = libocdusbblaster.la +libocdusbblaster_la_SOURCES = $(USB_BLASTER_SRC) + +USB_BLASTER_SRC = usb_blaster.c + +if USB_BLASTER_LIBFTDI +USB_BLASTER_SRC += ublast_access_ftdi.c +endif + +if USB_BLASTER_FTD2XX +USB_BLASTER_SRC += ublast_access_ftd2xx.c +endif + +noinst_HEADERS = ublast_access.h diff --git a/src/jtag/drivers/usb_blaster/ublast_access.h b/src/jtag/drivers/usb_blaster/ublast_access.h new file mode 100644 index 000000000..e0eb059e2 --- /dev/null +++ b/src/jtag/drivers/usb_blaster/ublast_access.h @@ -0,0 +1,52 @@ +/* + * Driver for USB-JTAG, Altera USB-Blaster and compatibles + * + * Inspired from original code from Kolja Waschk's USB-JTAG project + * (http://www.ixo.de/info/usb_jtag/), and from openocd project. + * + * Copyright (C) 2012 Robert Jarzmik robert.jarzmik@free.fr + * Copyright (C) 2011 Ali Lown ali@lown.me.uk + * Copyright (C) 2009 Catalin Patulea cat@vv.carleton.ca + * Copyright (C) 2006 Kolja Waschk usbjtag@ixo.de + * + * 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 ublast_lowlevel { + uint16_t ublast_vid; + 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 (*open)(struct ublast_lowlevel *low); + int (*close)(struct ublast_lowlevel *low); + int (*speed)(struct ublast_lowlevel *low, int speed); + + void *priv; +}; + +/** + * ublast_register_ftdi - get a lowlevel USB Blaster driver + * ublast_register_ftd2xx - get a lowlevel USB Blaster driver + * + * Get a lowlevel USB-Blaster driver. In the current implementation, there are 2 + * possible lowlevel drivers : + * - one based on libftdi from ftdichip.com + * - one based on libftdxx, the free alternative + * + * Returns the lowlevel driver structure. + */ +extern struct ublast_lowlevel *ublast_register_ftdi(void); +extern struct ublast_lowlevel *ublast_register_ftd2xx(void); diff --git a/src/jtag/drivers/usb_blaster/ublast_access_ftd2xx.c b/src/jtag/drivers/usb_blaster/ublast_access_ftd2xx.c new file mode 100644 index 000000000..e350650d3 --- /dev/null +++ b/src/jtag/drivers/usb_blaster/ublast_access_ftd2xx.c @@ -0,0 +1,178 @@ +/* + * Driver for USB-JTAG, Altera USB-Blaster and compatibles + * + * Inspired from original code from Kolja Waschk's USB-JTAG project + * (http://www.ixo.de/info/usb_jtag/), and from openocd project. + * + * Copyright (C) 2012 Robert Jarzmik robert.jarzmik@free.fr + * Copyright (C) 2011 Ali Lown ali@lown.me.uk + * Copyright (C) 2009 Catalin Patulea cat@vv.carleton.ca + * Copyright (C) 2006 Kolja Waschk usbjtag@ixo.de + * + * 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. + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include + +#include "ublast_access.h" + +#include +#include "jtag/drivers/ftd2xx_common.h" + +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) +{ + FT_STATUS status; + DWORD dw_bytes_written; + FT_HANDLE *ftdih = ublast_getftdih(low); + + 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; +} + +static int ublast_ftd2xx_read(struct ublast_lowlevel *low, uint8_t *buf, + unsigned size, uint32_t *bytes_read) +{ + DWORD dw_bytes_read; + FT_STATUS status; + FT_HANDLE *ftdih = ublast_getftdih(low); + + 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; +} + +static int ublast_ftd2xx_init(struct ublast_lowlevel *low) +{ + FT_STATUS status; + FT_HANDLE *ftdih = ublast_getftdih(low); + uint8_t latency_timer; + + LOG_INFO("usb blaster interface using FTD2XX"); + /* Open by device description */ + if (low->ublast_device_desc == NULL) { + LOG_WARNING("no usb blaster device description specified, " + "using default 'USB-Blaster'"); + low->ublast_device_desc = "USB-Blaster"; + } + +#if IS_WIN32 == 0 + /* Add non-standard Vid/Pid to the linux driver */ + status = FT_SetVIDPID(low->ublast_vid, low->ublast_pid); + if (status != FT_OK) { + LOG_WARNING("couldn't add %4.4x:%4.4x", + low->ublast_vid, low->ublast_pid); + } +#endif + status = FT_OpenEx(low->ublast_device_desc, FT_OPEN_BY_DESCRIPTION, + ftdih); + if (status != FT_OK) { + DWORD num_devices; + + LOG_ERROR("unable to open ftdi device: %s", + ftd2xx_status_string(status)); + status = FT_ListDevices(&num_devices, NULL, FT_LIST_NUMBER_ONLY); + if (status == FT_OK) { + char **desc_array = + malloc(sizeof(char *) * (num_devices + 1)); + unsigned int i; + + for (i = 0; i < num_devices; i++) + desc_array[i] = malloc(64); + desc_array[num_devices] = NULL; + + status = FT_ListDevices(desc_array, &num_devices, + FT_LIST_ALL | FT_OPEN_BY_DESCRIPTION); + + if (status == FT_OK) { + LOG_ERROR("ListDevices: %" PRIu32, (uint32_t)num_devices); + for (i = 0; i < num_devices; i++) + LOG_ERROR("%i: %s", i, desc_array[i]); + } + + for (i = 0; i < num_devices; i++) + free(desc_array[i]); + free(desc_array); + } else { + printf("ListDevices: NONE\n"); + } + return ERROR_JTAG_INIT_FAILED; + } + + status = FT_SetLatencyTimer(*ftdih, 2); + if (status != FT_OK) { + LOG_ERROR("unable to set latency timer: %s", + ftd2xx_status_string(status)); + return ERROR_JTAG_INIT_FAILED; + } + + status = FT_GetLatencyTimer(*ftdih, &latency_timer); + if (status != FT_OK) { + LOG_ERROR("unable to get latency timer: %s", + ftd2xx_status_string(status)); + return ERROR_JTAG_INIT_FAILED; + } + LOG_DEBUG("current latency timer: %i", latency_timer); + + status = FT_SetBitMode(*ftdih, 0x00, 0); + if (status != FT_OK) { + LOG_ERROR("unable to disable bit i/o mode: %s", + ftd2xx_status_string(status)); + return ERROR_JTAG_INIT_FAILED; + } + return ERROR_OK; +} + +static int ublast_ftd2xx_quit(struct ublast_lowlevel *low) +{ + FT_HANDLE *ftdih = ublast_getftdih(low); + + FT_Close(*ftdih); + return ERROR_OK; +} + +static struct ublast_lowlevel_priv { + FT_HANDLE ftdih; +} info; + +static struct ublast_lowlevel low = { + .open = ublast_ftd2xx_init, + .close = ublast_ftd2xx_quit, + .read = ublast_ftd2xx_read, + .write = ublast_ftd2xx_write, + .priv = &info, +}; + +struct ublast_lowlevel *ublast_register_ftd2xx(void) +{ + return &low; +} diff --git a/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c b/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c new file mode 100644 index 000000000..23893e14d --- /dev/null +++ b/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c @@ -0,0 +1,136 @@ +/* + * Driver for USB-JTAG, Altera USB-Blaster and compatibles + * + * Inspired from original code from Kolja Waschk's USB-JTAG project + * (http://www.ixo.de/info/usb_jtag/), and from openocd project. + * + * Copyright (C) 2012 Robert Jarzmik robert.jarzmik@free.fr + * Copyright (C) 2011 Ali Lown ali@lown.me.uk + * Copyright (C) 2009 Catalin Patulea cat@vv.carleton.ca + * Copyright (C) 2006 Kolja Waschk usbjtag@ixo.de + * + * 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. + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include + +#include "ublast_access.h" +#include + +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) +{ + int retval; + int timeout = 100; + struct ftdi_context *ftdic = ublast_getftdic(low); + + *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; + LOG_ERROR("ftdi_read_data: %s", + ftdi_get_error_string(ftdic)); + return ERROR_JTAG_DEVICE_ERROR; + } + *bytes_read += retval; + } + return ERROR_OK; +} + +static int ublast_ftdi_write(struct ublast_lowlevel *low, uint8_t *buf, int size, + uint32_t *bytes_written) +{ + 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", + 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) +{ + uint8_t latency_timer; + struct ftdi_context *ftdic = ublast_getftdic(low); + + LOG_INFO("usb blaster interface using libftdi"); + if (ftdi_init(ftdic) < 0) + return ERROR_JTAG_INIT_FAILED; + + /* context, vendor id, product id */ + if (ftdi_usb_open(ftdic, low->ublast_vid, low->ublast_pid) < 0) { + LOG_ERROR("unable to open ftdi device: %s", ftdic->error_str); + return ERROR_JTAG_INIT_FAILED; + } + + if (ftdi_usb_reset(ftdic) < 0) { + LOG_ERROR("unable to reset ftdi device"); + return ERROR_JTAG_INIT_FAILED; + } + + if (ftdi_set_latency_timer(ftdic, 2) < 0) { + LOG_ERROR("unable to set latency timer"); + return ERROR_JTAG_INIT_FAILED; + } + + if (ftdi_get_latency_timer(ftdic, &latency_timer) < 0) { + LOG_ERROR("unable to get latency timer"); + return ERROR_JTAG_INIT_FAILED; + } + LOG_DEBUG("current latency timer: %u", latency_timer); + + ftdi_disable_bitbang(ftdic); + return ERROR_OK; +} + +static int ublast_ftdi_quit(struct ublast_lowlevel *low) +{ + struct ftdi_context *ftdic = ublast_getftdic(low); + + ftdi_usb_close(ftdic); + ftdi_deinit(ftdic); + return ERROR_OK; +}; + +static struct ublast_lowlevel_priv { + struct ftdi_context ftdic; +} info; + +static struct ublast_lowlevel low = { + .open = ublast_ftdi_init, + .close = ublast_ftdi_quit, + .read = ublast_ftdi_read, + .write = ublast_ftdi_write, + .priv = &info, +}; + +struct ublast_lowlevel *ublast_register_ftdi(void) +{ + return &low; +} diff --git a/src/jtag/drivers/usb_blaster/usb_blaster.c b/src/jtag/drivers/usb_blaster/usb_blaster.c new file mode 100644 index 000000000..3400ca58a --- /dev/null +++ b/src/jtag/drivers/usb_blaster/usb_blaster.c @@ -0,0 +1,927 @@ +/* + * Driver for USB-JTAG, Altera USB-Blaster and compatibles + * + * Inspired from original code from Kolja Waschk's USB-JTAG project + * (http://www.ixo.de/info/usb_jtag/), and from openocd project. + * + * Copyright (C) 2012 Robert Jarzmik robert.jarzmik@free.fr + * Copyright (C) 2011 Ali Lown ali@lown.me.uk + * Copyright (C) 2009 Catalin Patulea cat@vv.carleton.ca + * Copyright (C) 2006 Kolja Waschk usbjtag@ixo.de + * + * 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. + * + */ + +/* + * The following information is originally from Kolja Waschk's USB-JTAG, + * where it was obtained by reverse engineering an Altera USB-Blaster. + * See http://www.ixo.de/info/usb_jtag/ for USB-Blaster block diagram and + * usb_jtag-20080705-1200.zip#usb_jtag/host/openocd for protocol. + * + * The same information is also on the UrJTAG mediawiki, with some additional + * notes on bits marked as "unknown" by usb_jtag. + * (http://sourceforge.net/apps/mediawiki/urjtag/index.php? + * title=Cable_Altera_USB-Blaster) + * + * USB-JTAG, Altera USB-Blaster and compatibles are typically implemented as + * an FTDIChip FT245 followed by a CPLD which handles a two-mode protocol: + * + * _________ + * | | + * | AT93C46 | + * |_________| + * __|__________ _________ + * | | | | + * USB__| FTDI 245BM |__| EPM7064 |__JTAG (B_TDO,B_TDI,B_TMS,B_TCK) + * |_____________| |_________| + * __|__________ _|___________ + * | | | | + * | 6 MHz XTAL | | 24 MHz Osc. | + * |_____________| |_____________| + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if IS_CYGWIN == 1 +#include "windows.h" +#undef LOG_ERROR +#endif + +/* project specific includes */ +#include +#include +#include +#include "ublast_access.h" + +/* system includes */ +#include +#include +#include +#include +#include + +/* Size of USB endpoint max packet size, ie. 64 bytes */ +#define MAX_PACKET_SIZE 64 +/* + * Size of data buffer that holds bytes in byte-shift mode. + * This buffer can hold multiple USB packets aligned to + * MAX_PACKET_SIZE bytes boundaries. + * BUF_LEN must be grater than or equal MAX_PACKET_SIZE. + */ +#define BUF_LEN 4096 + +struct ublast_info { + int pin6; + int pin8; + int tms; + int tdi; + uint8_t buf[BUF_LEN]; + int bufidx; + + char *lowlevel_name; + struct ublast_lowlevel *drv; + char *ublast_device_desc; + uint16_t ublast_vid, ublast_pid; +}; + +/* + * Global device control + */ +static struct ublast_info info = { + .ublast_vid = 0x09fb, /* Altera */ + .ublast_pid = 0x6001, /* USB-Blaster */ + .lowlevel_name = NULL, +}; + +/* + * Available lowlevel drivers (FTDI, FTD2xx, ...) + */ +struct drvs_map { + char *name; + struct ublast_lowlevel *(*drv_register)(void); +}; + +static struct drvs_map lowlevel_drivers_map[] = { +#if BUILD_USB_BLASTER_LIBFTDI + { .name = "ftdi", .drv_register = ublast_register_ftdi }, +#endif +#if BUILD_USB_BLASTER_FTD2XX + { .name = "ftd2xx", .drv_register = ublast_register_ftd2xx }, +#endif + { NULL, NULL }, +}; + +/* + * Access functions to lowlevel driver, agnostic of libftdi/libftdxx + */ +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_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); + + 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); + char *str = hexdump(buf, *bytes_written); + + DEBUG_JTAG_IO("(size=%d, buf=[%s]) -> %u", size, str, + *bytes_written); + free(str); + return ret; +} + +static int nb_buf_remaining(void) +{ + return BUF_LEN - info.bufidx; +} + +static void 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; +} + +/* + * Actually, the USB-Blaster offers a byte-shift mode to transmit up to 504 data + * bits (bidirectional) in a single USB packet. A header byte has to be sent as + * the first byte in a packet with the following meaning: + * + * Bit 7 (0x80): Must be set to indicate byte-shift mode. + * Bit 6 (0x40): If set, the USB-Blaster will also read data, not just write. + * Bit 5..0: Define the number N of following bytes + * + * All N following bytes will then be clocked out serially on TDI. If Bit 6 was + * set, it will afterwards return N bytes with TDO data read while clocking out + * the TDI data. LSB of the first byte after the header byte will appear first + * on TDI. + */ + +/* Simple bit banging mode: + * + * Bit 7 (0x80): Must be zero (see byte-shift mode above) + * Bit 6 (0x40): If set, you will receive a byte indicating the state of TDO + * in return. + * Bit 5 (0x20): Output Enable/LED. + * Bit 4 (0x10): TDI Output. + * Bit 3 (0x08): nCS Output (not used in JTAG mode). + * Bit 2 (0x04): nCE Output (not used in JTAG mode). + * Bit 1 (0x02): TMS Output. + * Bit 0 (0x01): TCK Output. + * + * For transmitting a single data bit, you need to write two bytes (one for + * setting up TDI/TMS/TCK=0, and one to trigger TCK high with same TDI/TMS + * held). Up to 64 bytes can be combined in a single USB packet. + * It isn't possible to read a data without transmitting data. + */ + +#define TCK (1 << 0) +#define TMS (1 << 1) +#define NCE (1 << 2) +#define NCS (1 << 3) +#define TDI (1 << 4) +#define LED (1 << 5) +#define READ (1 << 6) +#define SHMODE (1 << 7) +#define READ_TDO (1 << 0) + +/** + * ublast_reset - reset the JTAG device is possible + * @trst: 1 if TRST is to be asserted + * @srst: 1 if SRST is to be asserted + * + * This is not implemented yet. If pin6 or pin8 controlls the TRST/SRST, code + * should be added so that this function makes use of it. + */ +static void ublast_reset(int trst, int srst) +{ + DEBUG_JTAG_IO("TODO: ublast_reset(%d,%d) isn't implemented!", + trst, srst); +} + +/** + * ublast_queue_byte - queue one 'bitbang mode' byte for USB Blaster + * @abyte: the byte to queue + * + * Queues one byte in 'bitbang mode' to the USB Blaster. The byte is 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. + */ +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); +} + +/** + * ublast_build_out - build bitbang mode output byte + * @type: says if reading back TDO is required + * + * Returns the compute bitbang mode byte + */ +static uint8_t ublast_build_out(enum scan_type type) +{ + uint8_t abyte = 0; + + abyte |= info.tms ? TMS : 0; + abyte |= info.pin6 ? NCE : 0; + abyte |= info.pin8 ? NCS : 0; + abyte |= info.tdi ? TDI : 0; + abyte |= LED; + if (type == SCAN_IN || type == SCAN_IO) + abyte |= READ; + return abyte; +} + +/** + * ublast_clock_tms - clock a TMS transition + * @tms: the TMS to be sent + * + * Triggers a TMS transition (ie. one JTAG TAP state move). + */ +static void ublast_clock_tms(int tms) +{ + uint8_t out; + + DEBUG_JTAG_IO("(tms=%d)", !!tms); + info.tms = !!tms; + info.tdi = 0; + out = ublast_build_out(SCAN_OUT); + ublast_queue_byte(out); + ublast_queue_byte(out | TCK); +} + +/** + * ublast_idle_clock - put back TCK to low level + * + * See ublast_queue_tdi() comment for the usage of this function. + */ +static void ublast_idle_clock(void) +{ + uint8_t out = ublast_build_out(SCAN_OUT); + + DEBUG_JTAG_IO("."); + ublast_queue_byte(out); +} + +/** + * ublast_clock_tdi - Output a TDI with bitbang mode + * @tdi: the TDI bit to be shifted out + * @type: scan type (ie. does a readback of TDO is required) + * + * Output a TDI bit and assert clock to push it into the JTAG device : + * - writing out TCK=0, TMS==0, TDI= + * - writing out TCK=1, TMS=, TDI= which triggers the JTAG + * device aquiring the data. + * + * If a TDO is to be read back, the required read is requested (bitbang mode), + * and the USB Blaster will send back a byte with bit0 reprensenting the TDO. + */ +static void ublast_clock_tdi(int tdi, enum scan_type type) +{ + uint8_t out; + + DEBUG_JTAG_IO("(tdi=%d)", !!tdi); + info.tdi = !!tdi; + + out = ublast_build_out(SCAN_OUT); + ublast_queue_byte(out); + + out = ublast_build_out(type); + ublast_queue_byte(out | TCK); +} + +/** + * ublast_clock_tdi_flip_tms - Output a TDI with bitbang mode, change JTAG state + * @tdi: the TDI bit to be shifted out + * @type: scan type (ie. does a readback of TDO is required) + * + * This function is the same as ublast_clock_tdi(), but it changes also the TMS + * while outputing the TDI. This should be the last TDI output of a TDI + * sequence, which will change state from : + * - IRSHIFT -> IREXIT1 + * - or DRSHIFT -> DREXIT1 + */ +static void ublast_clock_tdi_flip_tms(int tdi, enum scan_type type) +{ + uint8_t out; + + DEBUG_JTAG_IO("(tdi=%d)", !!tdi); + info.tdi = !!tdi; + info.tms = !info.tms; + + out = ublast_build_out(SCAN_OUT); + ublast_queue_byte(out); + + out = ublast_build_out(type); + ublast_queue_byte(out | TCK); + + out = ublast_build_out(SCAN_OUT); + ublast_queue_byte(out); +} + +/** + * ublast_queue_bytes - queue bytes for the USB Blaster + * @bytes: byte array + * @nb_bytes: number of bytes + * + * 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. + */ +static void 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); + } + 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_tms_seq - write a TMS sequence transition to JTAG + * @bits: TMS bits to be written (bit0, bit1 .. bitN) + * @nb_bits: number of TMS bits (between 1 and 8) + * + * Write a serie of TMS transitions, where each transition consists in : + * - writing out TCK=0, TMS=, TDI= + * - writing out TCK=1, TMS=, TDI= which triggers the transition + * The function ensures that at the end of the sequence, the clock (TCK) is put + * low. + */ +static void ublast_tms_seq(const uint8_t *bits, int nb_bits) +{ + int i; + + DEBUG_JTAG_IO("(bits=%02x..., nb_bits=%d)", bits[0], nb_bits); + for (i = 0; i < nb_bits; i++) + ublast_clock_tms((bits[i / 8] >> (i % 8)) & 0x01); + ublast_idle_clock(); +} + +/** + * ublast_tms - write a tms command + * @cmd: tms command + */ +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_path_move - write a TMS sequence transition to JTAG + * @cmd: path transition + * + * Write a serie of TMS transitions, where each transition consists in : + * - writing out TCK=0, TMS=, TDI= + * - writing out TCK=1, TMS=, TDI= which triggers the transition + * The function ensures that at the end of the sequence, the clock (TCK) is put + * low. + */ +static void ublast_path_move(struct pathmove_command *cmd) +{ + int i; + + DEBUG_JTAG_IO("(num_states=%d, last_state=%d)", + cmd->num_states, cmd->path[cmd->num_states - 1]); + for (i = 0; i < cmd->num_states; i++) { + if (tap_state_transition(tap_get_state(), false) == cmd->path[i]) + ublast_clock_tms(0); + if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) + ublast_clock_tms(1); + tap_set_state(cmd->path[i]); + } + ublast_idle_clock(); +} + +/** + * ublast_state_move - move JTAG state to the target state + * @state: the target state + * + * Input the correct TMS sequence to the JTAG TAP so that we end up in the + * target state. This assumes the current state (tap_get_state()) is correct. + */ +static void ublast_state_move(tap_state_t state) +{ + uint8_t tms_scan; + int tms_len; + + DEBUG_JTAG_IO("(from %s to %s)", tap_state_name(tap_get_state()), + tap_state_name(state)); + if (tap_get_state() == state) + return; + tms_scan = tap_get_tms_path(tap_get_state(), state); + tms_len = tap_get_tms_path_len(tap_get_state(), state); + ublast_tms_seq(&tms_scan, tms_len); + tap_set_state(state); +} + +/** + * ublast_read_byteshifted_tdos - read TDO of byteshift writes + * @buf: the buffer to store the bits + * @nb_bits: the number of bits + * + * Reads back from USB Blaster TDO bits, triggered by a 'byteshift write', ie. eight + * bits per received byte from USB interface, and store them in buffer. + * + * 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 + */ +static int ublast_read_byteshifted_tdos(uint8_t *buf, 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; +} + +/** + * ublast_read_bitbang_tdos - read TDO of bitbang writes + * @buf: the buffer to store the bits + * @nb_bits: the number of bits + * + * 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 : + * - first bit is stored in byte0, bit0 (LSB) + * - second bit is stored in byte0, bit 1 + * ... + * - eight bit is sotred in byte0, bit 7 + * - ninth bit is sotred in byte1, bit 0 + * - etc ... + * + * Returns ERROR_OK if OK, ERROR_xxx if a read error occured + */ +static int ublast_read_bitbang_tdos(uint8_t *buf, 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); + + /* + * Ensure all previous bitbang writes were issued to the dongle, so that + * it returns back the read values. + */ + ublast_flush_buffer(); + + ret = ublast_buf_read(tmp, nb1, &retlen); + for (i = 0; ret == ERROR_OK && i < nb1; i++) + if (tmp[i] & READ_TDO) + *buf |= (1 << i); + else + *buf &= ~(1 << i); + return ret; +} + +/** + * ublast_queue_tdi - short description + * @bits: bits to be queued on TDI (or NULL if 0 are to be queued) + * @nb_bits: number of bits + * @scan: scan type (ie. if TDO read back is required or not) + * + * Outputs a serie of TDI bits on TDI. + * 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 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 !!! + */ +static void 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); + static uint8_t byte0[BUF_LEN]; + + /* + * As the last TDI bit should always be output in bitbang mode in order + * to activate the TMS=1 transition to EXIT_?R state. Therefore a + * situation where nb_bits is a multiple of 8 is handled as follows: + * - the number of TDI shifted out in "byteshift mode" is 8 less than + * nb_bits + * - nb1 = 8 + * This ensures that nb1 is never 0, and allows the TMS transition. + */ + if (nb8 > 0 && nb1 == 0) { + nb8--; + nb1 = 8; + } + + read_tdos = (scan == SCAN_IN || scan == SCAN_IO); + 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); + + /* + * 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) + ublast_queue_byte(SHMODE | READ | trans); + else + ublast_queue_byte(SHMODE | trans); + if (bits) + ublast_queue_bytes(&bits[i], trans); + else + ublast_queue_bytes(byte0, trans); + if (read_tdos) + ublast_read_byteshifted_tdos(&tdos[i], trans); + } + + /* + * Queue the remaining TDI bits in bitbang mode. + */ + for (i = 0; i < nb1; i++) { + int tdi = bits ? bits[nb8 + i / 8] & (1 << i) : 0; + if (bits && i == nb1 - 1) + ublast_clock_tdi_flip_tms(tdi, 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(); +} + +static void ublast_runtest(int cycles, tap_state_t state) +{ + DEBUG_JTAG_IO("%s(cycles=%i, end_state=%d)", __func__, cycles, state); + + ublast_state_move(TAP_IDLE); + ublast_queue_tdi(NULL, cycles, SCAN_OUT); + ublast_state_move(state); +} + +static void ublast_stableclocks(int cycles) +{ + DEBUG_JTAG_IO("%s(cycles=%i)", __func__, cycles); + ublast_queue_tdi(NULL, cycles, SCAN_OUT); +} + +/** + * ublast_scan - launches a DR-scan or IR-scan + * @cmd: the command to launch + * + * Launch a JTAG IR-scan or DR-scan + * + * Returns ERROR_OK if OK, ERROR_xxx if a read/write error occured. + */ +static int ublast_scan(struct scan_command *cmd) +{ + int scan_bits; + uint8_t *buf = NULL; + enum scan_type type; + int ret = ERROR_OK; + static const char * const type2str[] = { "", "SCAN_IN", "SCAN_OUT", "SCAN_IO" }; + char *log_buf = NULL; + + type = jtag_scan_type(cmd); + scan_bits = jtag_build_buffer(cmd, &buf); + + if (cmd->ir_scan) + ublast_state_move(TAP_IRSHIFT); + else + ublast_state_move(TAP_DRSHIFT); + + log_buf = hexdump(buf, DIV_ROUND_UP(scan_bits, 8)); + DEBUG_JTAG_IO("%s(scan=%s, type=%s, bits=%d, buf=[%s], end_state=%d)", __func__, + cmd->ir_scan ? "IRSCAN" : "DRSCAN", + type2str[type], + scan_bits, log_buf, cmd->end_state); + free(log_buf); + + ublast_queue_tdi(buf, scan_bits, type); + + /* + * As our JTAG is in an unstable state (IREXIT1 or DREXIT1), move it + * forward to a stable IRPAUSE or DRPAUSE. + */ + ublast_clock_tms(0); + if (cmd->ir_scan) + tap_set_state(TAP_IRPAUSE); + 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) +{ + DEBUG_JTAG_IO("%s(ms=%d)", __func__, ms); + jtag_sleep(ms); +} + +static int ublast_execute_queue(void) +{ + struct jtag_command *cmd; + int ret = ERROR_OK; + + for (cmd = jtag_command_queue; ret == ERROR_OK && cmd != NULL; + cmd = cmd->next) { + switch (cmd->type) { + case JTAG_RESET: + ublast_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; + case JTAG_RUNTEST: + ublast_runtest(cmd->cmd.runtest->num_cycles, + cmd->cmd.runtest->end_state); + break; + case JTAG_STABLECLOCKS: + ublast_stableclocks(cmd->cmd.stableclocks->num_cycles); + break; + case JTAG_TLR_RESET: + ublast_state_move(cmd->cmd.statemove->end_state); + break; + case JTAG_PATHMOVE: + ublast_path_move(cmd->cmd.pathmove); + break; + case JTAG_TMS: + ublast_tms(cmd->cmd.tms); + break; + case JTAG_SLEEP: + ublast_msleep(cmd->cmd.sleep->us); + break; + case JTAG_SCAN: + ret = ublast_scan(cmd->cmd.scan); + break; + } + } + + ublast_flush_buffer(); + return ret; +} + +/** + * ublast_init - Initialize the Altera device + * + * Initialize the device : + * - open the USB device + * - empty the write FIFO (128 bytes) + * - empty the read FIFO (384 bytes) + * + * Returns ERROR_OK if USB device found, error if not. + */ +static int ublast_init(void) +{ + static uint8_t tms_reset = 0xff; + int ret, i; + + if (info.lowlevel_name) { + for (i = 0; lowlevel_drivers_map[i].name; i++) + if (!strcmp(lowlevel_drivers_map[i].name, info.lowlevel_name)) + break; + if (lowlevel_drivers_map[i].name) + info.drv = lowlevel_drivers_map[i].drv_register(); + if (!info.drv) { + LOG_ERROR("no lowlevel driver found for %s or lowlevel driver opening error", + info.lowlevel_name); + return ERROR_JTAG_DEVICE_ERROR; + } + } else { + LOG_INFO("No lowlevel driver configured, will try them all"); + for (i = 0; !info.drv && lowlevel_drivers_map[i].name; i++) + info.drv = lowlevel_drivers_map[i].drv_register(); + if (!info.drv) { + LOG_ERROR("no lowlevel driver found"); + return ERROR_JTAG_DEVICE_ERROR; + } + } + + /* + * Register the lowlevel driver + */ + info.drv->ublast_vid = info.ublast_vid; + info.drv->ublast_pid = info.ublast_pid; + info.drv->ublast_device_desc = info.ublast_device_desc; + + ret = info.drv->open(info.drv); + if (ret == ERROR_OK) { + /* + * Flush USB-Blaster queue fifos + */ + uint32_t retlen; + ublast_buf_write(info.buf, BUF_LEN, &retlen); + /* + * Put JTAG in RESET state (five 1 on TMS) + */ + ublast_tms_seq(&tms_reset, 5); + tap_set_state(TAP_RESET); + } + return ret; +} + +/** + * ublast_quit - Release the Altera device + * + * Releases the device : + * - put the device pins in 'high impedance' mode + * - close the USB device + * + * Returns always ERROR_OK + */ +static int ublast_quit(void) +{ + uint8_t byte0 = 0; + unsigned int retlen; + + ublast_buf_write(&byte0, 1, &retlen); + return info.drv->close(info.drv); +} + +COMMAND_HANDLER(ublast_handle_device_desc_command) +{ + if (CMD_ARGC == 1) + info.ublast_device_desc = strdup(CMD_ARGV[0]); + else + LOG_ERROR("require exactly one argument to " + "ublast_device_desc "); + + return ERROR_OK; +} + +COMMAND_HANDLER(ublast_handle_vid_pid_command) +{ + if (CMD_ARGC > 2) { + LOG_WARNING("ignoring extra IDs in ublast_vid_pid " + "(maximum is 1 pair)"); + CMD_ARGC = 2; + } + if (CMD_ARGC == 2) { + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], info.ublast_vid); + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], info.ublast_pid); + } else { + LOG_WARNING("incomplete ublast_vid_pid configuration"); + } + + return ERROR_OK; +} + +COMMAND_HANDLER(ublast_handle_pin_command) +{ + uint8_t out_value; + + if (CMD_ARGC == 2) { + const char * const pin_name = CMD_ARGV[0]; + unsigned int state; + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], state); + if ((state != 0) && (state != 1)) { + LOG_ERROR("%s: pin state must be 0 or 1", CMD_NAME); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (!strcmp(pin_name, "pin6")) { + info.pin6 = state; + } else if (!strcmp(pin_name, "pin8")) { + info.pin8 = state; + } else { + LOG_ERROR("%s: pin name must be \"pin6\" or \"pin8\"", + CMD_NAME); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (info.drv) { + out_value = ublast_build_out(SCAN_OUT); + ublast_queue_byte(out_value); + ublast_flush_buffer(); + } + return ERROR_OK; + } else { + LOG_ERROR("%s takes exactly two arguments", CMD_NAME); + return ERROR_COMMAND_SYNTAX_ERROR; + } +} + +COMMAND_HANDLER(ublast_handle_lowlevel_drv_command) +{ + if (CMD_ARGC == 1) + info.lowlevel_name = strdup(CMD_ARGV[0]); + else + LOG_ERROR("require exactly one argument to " + "usb_blaster_lowlevel_driver (ftdi|ftd2xx)"); + return ERROR_OK; +} + +static const struct command_registration ublast_command_handlers[] = { + { + .name = "usb_blaster_device_desc", + .handler = ublast_handle_device_desc_command, + .mode = COMMAND_CONFIG, + .help = "set the USB device description of the USB-Blaster", + .usage = "description-string", + }, + { + .name = "usb_blaster_vid_pid", + .handler = ublast_handle_vid_pid_command, + .mode = COMMAND_CONFIG, + .help = "the vendor ID and product ID of the USB-Blaster", + .usage = "vid pid", + }, + { + .name = "usb_blaster_lowlevel_driver", + .handler = ublast_handle_lowlevel_drv_command, + .mode = COMMAND_CONFIG, + .help = "set the lowlevel access for the USB Blaster (ftdi, ftd2xx)", + .usage = "(ftdi|ftd2xx)", + }, + { + .name = "usb_blaster", + .handler = ublast_handle_pin_command, + .mode = COMMAND_ANY, + .help = "set pin state for the unused GPIO pins", + .usage = "(pin6|pin8) (0|1)", + }, + COMMAND_REGISTRATION_DONE +}; + +struct jtag_interface usb_blaster_interface = { + .name = "usb_blaster", + .commands = ublast_command_handlers, + .supported = DEBUG_CAP_TMS_SEQ, + + .execute_queue = ublast_execute_queue, + .init = ublast_init, + .quit = ublast_quit, +};