summaryrefslogtreecommitdiffstats
path: root/fpga/xilinx/programmer/dependencies/libxsvf/xsvftool-ft232h.c
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/xilinx/programmer/dependencies/libxsvf/xsvftool-ft232h.c')
-rw-r--r--fpga/xilinx/programmer/dependencies/libxsvf/xsvftool-ft232h.c1130
1 files changed, 1130 insertions, 0 deletions
diff --git a/fpga/xilinx/programmer/dependencies/libxsvf/xsvftool-ft232h.c b/fpga/xilinx/programmer/dependencies/libxsvf/xsvftool-ft232h.c
new file mode 100644
index 0000000..e86362d
--- /dev/null
+++ b/fpga/xilinx/programmer/dependencies/libxsvf/xsvftool-ft232h.c
@@ -0,0 +1,1130 @@
+/*
+ * Lib(X)SVF - A library for implementing SVF and XSVF JTAG players
+ *
+ * Copyright (C) 2009 RIEGL Research ForschungsGmbH
+ * Copyright (C) 2009 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * A JTAG SVF/XSVF Player based on libxsvf for the FTDI FT232H, FT2232H and
+ * FT4232H High Speed USB to Multipurpose UART/FIFO ICs.
+ *
+ * This also serves as an example program for using libxvsf with asynchonous
+ * hardware interfaces. Have a look at 'xsvftool-gpio.c' for a simple libxsvf
+ * example for synchonous interfaces (such as register mapped GPIOs).
+ *
+ * IMPORTANT NOTE: You need libftdi [1] (version 0.16 or newer) installed
+ * to build this program.
+ *
+ * To run it at full speed you need a version of libftdi that has been
+ * compiled with '--with-async-mode', and must enable all four defines
+ * BLOCK_WRITE, ASYNC_WRITE, BACKGROUND_READ and INTERLACED_READ_WRITE below.
+ *
+ * [1] http://www.intra2net.com/en/developer/libftdi/
+ */
+
+#include "libxsvf.h"
+
+#define BUFFER_SIZE (1024*16)
+
+#define BLOCK_WRITE
+// #define ASYNC_WRITE
+// #define BACKGROUND_READ
+// #define INTERLACED_READ_WRITE
+
+#include <sys/time.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ftdi.h>
+#include <math.h>
+#ifdef BACKGROUND_READ
+# include <pthread.h>
+#endif
+
+struct read_job_s;
+struct udata_s;
+struct buffer_s;
+
+typedef void job_handler_t(struct udata_s *u, struct read_job_s *job, unsigned char *data);
+
+struct read_job_s {
+ struct read_job_s *next;
+ int data_len, bits_len;
+ struct buffer_s *buffer;
+ job_handler_t *handler;
+ unsigned int command_id;
+};
+
+struct buffer_s {
+ unsigned int tms:1;
+ unsigned int tdi:1;
+ unsigned int tdi_enable:1;
+ unsigned int tdo:1;
+ unsigned int tdo_enable:1;
+ unsigned int rmask:1;
+};
+
+struct udata_s {
+ FILE *f;
+ struct ftdi_context ftdic;
+ uint16_t device_vendor;
+ uint16_t device_product;
+ int device_channel;
+ int eeprom_size;
+ int buffer_size;
+ struct buffer_s buffer[BUFFER_SIZE];
+ struct read_job_s *job_fifo_out, *job_fifo_in;
+ int last_tms;
+ int last_tdo;
+ int buffer_i;
+ int retval_i;
+ int retval[256];
+ int error_rc;
+ int verbose;
+ int syncmode;
+ int forcemode;
+ int frequency;
+#ifdef BACKGROUND_READ
+# ifdef INTERLACED_READ_WRITE
+ int total_job_bits;
+ int writer_wait_flag;
+ pthread_mutex_t writer_wait_flag_mutex;
+# endif
+ int reader_terminate;
+ pthread_mutex_t read_write_mutex;
+ pthread_cond_t read_more_cond;
+ pthread_cond_t read_done_cond;
+ pthread_t read_thread;
+#endif
+#ifdef BLOCK_WRITE
+ int ftdibuf_len;
+ unsigned char ftdibuf[4096];
+#endif
+};
+
+static FILE *dumpfile = NULL;
+
+static void write_dumpfile(int wr, unsigned char *buf, int size, unsigned int command_id)
+{
+ int i;
+ if (!dumpfile)
+ return;
+ fprintf(dumpfile, "%s[%u] %04x:", wr ? "SEND" : "RECV", command_id, size);
+ for (i = 0; i < size; i++)
+ fprintf(dumpfile, " %02x", buf[i]);
+ fprintf(dumpfile, "\n");
+}
+
+static int my_ftdi_read_data(struct ftdi_context *ftdi, unsigned char *buf, int size, unsigned int command_id)
+{
+ int pos = 0;
+ int poll_count = 0;
+ while (pos < size) {
+ int rc = ftdi_read_data(ftdi, buf+pos, size-pos);
+ if (rc < 0) {
+ fprintf(stderr, "[***] ftdi_read_data returned error `%s' (rc=%d).\n", ftdi_get_error_string(ftdi), rc);
+ break;
+ }
+ // this check should only be needed for very low JTAG clock frequencies
+ if (rc == 0) {
+ if (++poll_count > 8) {
+ fprintf(stderr, "[***] my_ftdi_read_data gives up polling <id=%u, pos=%u, size=%u>.\n", command_id, pos, size);
+ break;
+ }
+ // fprintf(stderr, "[%d/8] my_ftdi_read_data with len=%d polling at %d..\n", poll_count, size, pos);
+ usleep(4096 << poll_count);
+ }
+ pos += rc;
+ }
+ write_dumpfile(0, buf, pos, command_id);
+ return pos;
+}
+
+static int my_ftdi_write_data(struct udata_s *u, unsigned char *buf, int size, int sync)
+{
+#ifdef BLOCK_WRITE
+ int rc, total_queued = 0;
+
+ sync = 1;
+
+ while (size > 0)
+ {
+ if (u->ftdibuf_len == 4096) {
+ if (dumpfile)
+ fprintf(dumpfile, "WRITE %d BYTES (buffer full)\n", u->ftdibuf_len);
+#ifdef ASYNC_WRITE
+ rc = ftdi_write_data_async(&u->ftdic, u->ftdibuf, u->ftdibuf_len);
+#else
+ rc = ftdi_write_data(&u->ftdic, u->ftdibuf, u->ftdibuf_len);
+#endif
+ if (rc != u->ftdibuf_len)
+ return -1;
+ u->ftdibuf_len = 0;
+ }
+
+ int chunksize = 4096 - u->ftdibuf_len;
+ if (chunksize > size)
+ chunksize = size;
+
+ memcpy(u->ftdibuf + u->ftdibuf_len, buf, chunksize);
+ u->ftdibuf_len += chunksize;
+ total_queued += chunksize;
+ size -= chunksize;
+ buf += chunksize;
+ }
+
+ if (sync && u->ftdibuf_len > 0) {
+ if (dumpfile)
+ fprintf(dumpfile, "WRITE %d BYTES (sync)\n", u->ftdibuf_len);
+#ifdef ASYNC_WRITE
+ rc = ftdi_write_data_async(&u->ftdic, u->ftdibuf, u->ftdibuf_len);
+#else
+ rc = ftdi_write_data(&u->ftdic, u->ftdibuf, u->ftdibuf_len);
+#endif
+ if (rc != u->ftdibuf_len)
+ return -1;
+ u->ftdibuf_len = 0;
+ }
+
+ return total_queued;
+#else
+# ifdef ASYNC_WRITE
+ return ftdi_write_data_async(&u->ftdic, buf, size);
+# else
+ return ftdi_write_data(&u->ftdic, buf, size);
+# endif
+#endif
+}
+
+static struct read_job_s *new_read_job(struct udata_s *u, int data_len, int bits_len, struct buffer_s *buffer, job_handler_t *handler)
+{
+ struct read_job_s *job = calloc(1, sizeof(struct read_job_s));
+ static unsigned int command_count = 0;
+
+ job->data_len = data_len;
+ job->bits_len = bits_len;
+ job->buffer = calloc(bits_len, sizeof(struct buffer_s));
+ memcpy(job->buffer, buffer, bits_len*sizeof(struct buffer_s));
+ job->handler = handler;
+ job->command_id = command_count++;
+
+ if (u->job_fifo_in)
+ u->job_fifo_in->next = job;
+ if (!u->job_fifo_out)
+ u->job_fifo_out = job;
+ u->job_fifo_in = job;
+
+#ifdef BACKGROUND_READ
+# ifdef INTERLACED_READ_WRITE
+ u->total_job_bits += bits_len;
+# endif
+#endif
+
+ return job;
+}
+
+static void transfer_tms_job_handler(struct udata_s *u, struct read_job_s *job, unsigned char *data)
+{
+ int i;
+ for (i=0; i<job->bits_len; i++) {
+ // seams like output is align to the MSB in the byte and is LSB first
+ int bitpos = i + (8 - job->bits_len);
+ int line_tdo = (*data & (1 << bitpos)) != 0 ? 1 : 0;
+ if (job->buffer[i].tdo_enable && job->buffer[i].tdo != line_tdo)
+ u->error_rc = -1;
+ if (job->buffer[i].rmask && u->retval_i < 256)
+ u->retval[u->retval_i++] = line_tdo;
+ u->last_tdo = line_tdo;
+ }
+}
+
+static void transfer_tms(struct udata_s *u, struct buffer_s *d, int tdi, int len)
+{
+ int i, rc;
+
+ unsigned char data_command[] = {
+ 0x6e, len-1, tdi << 7, 0x87
+ };
+
+ for (i=0; i<len; i++)
+ data_command[2] |= d[i].tms << i;
+ data_command[2] |= d[len-1].tms << len;
+ u->last_tms = d[len-1].tms;
+
+ struct read_job_s *rj = new_read_job(u, 1, len, d, &transfer_tms_job_handler);
+
+ write_dumpfile(1, data_command, sizeof(data_command), rj->command_id);
+ rc = my_ftdi_write_data(u, data_command, sizeof(data_command), 0);
+ if (rc != sizeof(data_command)) {
+ fprintf(stderr, "IO Error: Transfer tms write failed: %s (rc=%d/%d)\n",
+ ftdi_get_error_string(&u->ftdic), rc, (int)sizeof(data_command));
+ u->error_rc = -1;
+ }
+}
+
+static void transfer_tdi_job_handler(struct udata_s *u, struct read_job_s *job, unsigned char *data)
+{
+ int i, j, k;
+ int bytes = job->bits_len / 8;
+ int bits = job->bits_len % 8;
+
+ for (i=0, j=0; j<bytes; j++) {
+ for (k=0; k<8; k++, i++) {
+ int line_tdo = (data[j] & (1 << k)) != 0 ? 1 : 0;
+ if (job->buffer[i].tdo_enable && job->buffer[i].tdo != line_tdo)
+ if (!u->forcemode)
+ u->error_rc = -1;
+ if (job->buffer[j*8+k].rmask && u->retval_i < 256)
+ u->retval[u->retval_i++] = line_tdo;
+ }
+ }
+ for (j=0; j<bits; j++, i++) {
+ int bitpos = j + (8 - bits);
+ int line_tdo = (data[bytes] & (1 << bitpos)) != 0 ? 1 : 0;
+ if (job->buffer[i].tdo_enable && job->buffer[i].tdo != line_tdo)
+ if (!u->forcemode)
+ u->error_rc = -1;
+ if (job->buffer[i].rmask && u->retval_i < 256)
+ u->retval[u->retval_i++] = line_tdo;
+ u->last_tdo = line_tdo;
+ }
+}
+
+static void transfer_tdi(struct udata_s *u, struct buffer_s *d, int len)
+{
+ int bytes = len / 8;
+ int bits = len % 8;
+
+ int command_len = 1;
+ int data_len = 0;
+ if (bytes) {
+ command_len += 3 + bytes;
+ data_len += bytes;
+ }
+ if (bits) {
+ command_len += 3;
+ data_len++;
+ }
+
+ int i, j, k, rc;
+ unsigned char command[command_len];
+
+ i = 0;
+ if (bytes) {
+ command[i++] = 0x39;
+ command[i++] = (bytes-1) & 0xff;
+ command[i++] = (bytes-1) >> 8;
+ for (j=0; j<bytes; j++, i++) {
+ command[i] = 0;
+ for (k=0; k<8; k++)
+ command[i] |= d[j*8+k].tdi << k;
+ }
+ }
+ if (bits) {
+ command[i++] = 0x3b;
+ command[i++] = bits-1;
+ command[i] = 0;
+ for (j=0; j<bits; j++)
+ command[i] |= d[bytes*8+j].tdi << j;
+ i++;
+ }
+ command[i] = 0x87;
+ assert(i+1 == command_len);
+
+ struct read_job_s *rj = new_read_job(u, data_len, len, d, &transfer_tdi_job_handler);
+
+ write_dumpfile(1, command, command_len, rj->command_id);
+ rc = my_ftdi_write_data(u, command, command_len, 0);
+ if (rc != command_len) {
+ fprintf(stderr, "IO Error: Transfer tdi write failed: %s (rc=%d/%d)\n",
+ ftdi_get_error_string(&u->ftdic), rc, command_len);
+ u->error_rc = -1;
+ }
+}
+
+static void process_next_read_job(struct udata_s *u)
+{
+ if (!u->job_fifo_out)
+ return;
+
+#ifdef ASYNC_WRITE
+ ftdi_async_complete(&u->ftdic,1);
+#endif
+
+ struct read_job_s *job = u->job_fifo_out;
+
+ u->job_fifo_out = job->next;
+ if (!u->job_fifo_out)
+ u->job_fifo_in = NULL;
+
+ unsigned char data[job->data_len];
+ if (my_ftdi_read_data(&u->ftdic, data, job->data_len, job->command_id) != job->data_len) {
+ fprintf(stderr, "IO Error: FTDI/USB read failed!\n");
+ u->error_rc = -1;
+ } else {
+ job->handler(u, job, data);
+ }
+
+#ifdef BACKGROUND_READ
+# ifdef INTERLACED_READ_WRITE
+ u->total_job_bits -= job->bits_len;
+# endif
+#endif
+
+ free(job->buffer);
+ free(job);
+}
+
+#ifdef BACKGROUND_READ
+static void *reader_main(void *arg)
+{
+ struct udata_s *u = arg;
+ pthread_mutex_lock(&u->read_write_mutex);
+ while (!u->reader_terminate) {
+ while (u->job_fifo_out) {
+ process_next_read_job(u);
+#ifdef INTERLACED_READ_WRITE
+ if (u->total_job_bits <= u->buffer_size/2) {
+ pthread_mutex_lock(&u->writer_wait_flag_mutex);
+ int writer_is_waiting = u->writer_wait_flag;
+ pthread_mutex_unlock(&u->writer_wait_flag_mutex);
+ if (writer_is_waiting)
+ break;
+ }
+#endif
+ }
+ pthread_cond_signal(&u->read_done_cond);
+ pthread_cond_wait(&u->read_more_cond, &u->read_write_mutex);
+ }
+ pthread_mutex_unlock(&u->read_write_mutex);
+ return NULL;
+}
+#endif
+
+static void buffer_flush(struct udata_s *u)
+{
+#ifdef BACKGROUND_READ
+# ifdef INTERLACED_READ_WRITE
+ pthread_mutex_lock(&u->writer_wait_flag_mutex);
+ u->writer_wait_flag = 1;
+ pthread_mutex_unlock(&u->writer_wait_flag_mutex);
+ pthread_mutex_lock(&u->read_write_mutex);
+ while (u->total_job_bits > u->buffer_size/2) {
+ pthread_cond_wait(&u->read_done_cond, &u->read_write_mutex);
+ }
+# else
+ pthread_mutex_lock(&u->read_write_mutex);
+ while (u->job_fifo_out) {
+ pthread_cond_wait(&u->read_done_cond, &u->read_write_mutex);
+ }
+# endif
+#endif
+ int pos = 0;
+ while (pos < u->buffer_i)
+ {
+ struct buffer_s b = u->buffer[pos];
+ if (u->last_tms != b.tms) {
+ int len = u->buffer_i - pos;
+ len = len > 6 ? 6 : len;
+ int tdi=-1, i;
+ for (i=0; i<len; i++) {
+ if (!u->buffer[pos+i].tdi_enable)
+ continue;
+ if (tdi < 0)
+ tdi = u->buffer[pos+i].tdi;
+ if (tdi != u->buffer[pos+i].tdi)
+ len = i;
+ }
+ // printf("transfer_tms <len=%d, tdi=%d>\n", len, tdi < 0 ? 1 : tdi);
+ transfer_tms(u, u->buffer+pos, (tdi & 1), len);
+ pos += len;
+ continue;
+ }
+ int len = u->buffer_i - pos;
+ int i;
+ for (i=0; i<len; i++) {
+ if (u->buffer[pos+i].tms != u->last_tms)
+ len = i;
+ }
+ // printf("transfer_tdi <len=%d, tms=%d>\n", len, u->last_tms);
+ transfer_tdi(u, u->buffer+pos, len);
+ pos += len;
+ }
+ u->buffer_i = 0;
+
+#ifdef BLOCK_WRITE
+ int rc = my_ftdi_write_data(u, NULL, 0, 1);
+ if (rc != 0) {
+ fprintf(stderr, "IO Error: Ftdi write failed: %s\n",
+ ftdi_get_error_string(&u->ftdic));
+ u->error_rc = -1;
+ }
+#endif
+
+#ifdef BACKGROUND_READ
+# ifdef INTERLACED_READ_WRITE
+ pthread_mutex_lock(&u->writer_wait_flag_mutex);
+ u->writer_wait_flag = 0;
+ pthread_mutex_unlock(&u->writer_wait_flag_mutex);
+# endif
+ pthread_mutex_unlock(&u->read_write_mutex);
+ pthread_cond_signal(&u->read_more_cond);
+#else
+ while (u->job_fifo_out)
+ process_next_read_job(u);
+#endif
+}
+
+static void buffer_sync(struct udata_s *u)
+{
+ buffer_flush(u);
+#ifdef BACKGROUND_READ
+ pthread_mutex_lock(&u->read_write_mutex);
+ while (u->job_fifo_out) {
+ pthread_cond_wait(&u->read_done_cond, &u->read_write_mutex);
+ }
+ pthread_mutex_unlock(&u->read_write_mutex);
+#endif
+}
+
+static void buffer_add(struct udata_s *u, int tms, int tdi, int tdo, int rmask)
+{
+ u->buffer[u->buffer_i].tms = tms;
+ u->buffer[u->buffer_i].tdi = tdi;
+ u->buffer[u->buffer_i].tdi_enable = tdi >= 0;
+ u->buffer[u->buffer_i].tdo = tdo;
+ u->buffer[u->buffer_i].tdo_enable = tdo >= 0;
+ u->buffer[u->buffer_i].rmask = rmask;
+ u->buffer_i++;
+
+ if (u->buffer_i >= u->buffer_size)
+ buffer_flush(u);
+}
+
+static int h_setup(struct libxsvf_host *h)
+{
+ int device_is_amontec_jtagkey_2p = 0;
+
+ struct udata_s *u = h->user_data;
+ u->buffer_size = BUFFER_SIZE;
+#ifdef BLOCK_WRITE
+ u->ftdibuf_len = 0;
+#endif
+
+ if (ftdi_init(&u->ftdic) < 0)
+ return -1;
+
+ if (u->eeprom_size > 0)
+ u->ftdic.eeprom_size = u->eeprom_size;
+
+ if (u->device_channel > 0) {
+ enum ftdi_interface interface =
+ u->device_channel == 1 ? INTERFACE_A :
+ u->device_channel == 2 ? INTERFACE_B :
+ u->device_channel == 3 ? INTERFACE_C :
+ u->device_channel == 4 ? INTERFACE_D : INTERFACE_ANY;
+ if (ftdi_set_interface(&u->ftdic, interface) < 0) {
+ fprintf(stderr, "IO Error: Interface setup failed (set port).\n");
+ ftdi_deinit(&u->ftdic);
+ return -1;
+ }
+ }
+
+ if (u->device_vendor > 0 || u->device_product > 0) {
+ if (ftdi_usb_open(&u->ftdic, u->device_vendor, u->device_product) == 0)
+ goto found_device;
+ goto failed_device;
+ }
+
+ // 0x0403:0xcff8 = Amontec JTAGkey2P
+ if (ftdi_usb_open(&u->ftdic, 0x0403, 0xcff8) == 0) {
+ device_is_amontec_jtagkey_2p = 1;
+ goto found_device;
+ }
+
+ // 0x0403:0x6010 = Plain FTDI 2232H
+ if (ftdi_usb_open(&u->ftdic, 0x0403, 0x6010) == 0) {
+ goto found_device;
+ }
+
+ // 0x0403:0x6011 = Plain FTDI 4232H
+ if (ftdi_usb_open(&u->ftdic, 0x0403, 0x6011) == 0) {
+ goto found_device;
+ }
+
+ // 0x0403:0x6014 = Plain FTDI 232H
+ if (ftdi_usb_open(&u->ftdic, 0x0403, 0x6014) == 0) {
+ u->buffer_size = 64;
+ goto found_device;
+ }
+
+failed_device:
+ fprintf(stderr, "IO Error: Interface setup failed (can't find or can't open device).\n");
+ ftdi_deinit(&u->ftdic);
+ return -1;
+found_device:;
+
+#if 0
+ // Older versions of libftdi don't have the TYPE_232H enum value.
+ // So we simply skip this check and let BITMODE_MPSSE below fail for non-H type chips.
+ if (u->ftdic.type != TYPE_232H && u->ftdic.type != TYPE_2232H && u->ftdic.type != TYPE_4232H) {
+ fprintf(stderr, "IO Error: Interface setup failed (wrong chip type).\n");
+ ftdi_usb_close(&u->ftdic);
+ ftdi_deinit(&u->ftdic);
+ return -1;
+ }
+#endif
+
+#if 1
+ if (ftdi_usb_reset(&u->ftdic) < 0) {
+ fprintf(stderr, "IO Error: Interface setup failed (usb reset).\n");
+ ftdi_usb_close(&u->ftdic);
+ ftdi_deinit(&u->ftdic);
+ return -1;
+ }
+
+ if (ftdi_usb_purge_buffers(&u->ftdic) < 0) {
+ fprintf(stderr, "IO Error: Interface setup failed (purge buffers).\n");
+ ftdi_usb_close(&u->ftdic);
+ ftdi_deinit(&u->ftdic);
+ return -1;
+ }
+#endif
+
+ if (ftdi_set_bitmode(&u->ftdic, 0xff, BITMODE_MPSSE) < 0) {
+ fprintf(stderr, "IO Error: Interface setup failed (MPSSE mode).\n");
+ ftdi_usb_close(&u->ftdic);
+ ftdi_deinit(&u->ftdic);
+ return -1;
+ }
+
+ unsigned char plain_init_commands[] = {
+ // 0x86, 0x6f, 0x17, // initial clk freq (1 kHz)
+ // 0x86, 0x05, 0x00, // initial clk freq (1 MHz)
+ 0x86, 0x02, 0x00, // initial clk freq (2 MHz)
+ 0x80, 0x08, 0x0b, // initial line states
+ // 0x84, // enable loopback
+ 0x85, // disable loopback
+ };
+ unsigned char amontec_init_commands[] = {
+ 0x86, 0x02, 0x00, // initial clk freq (2 MHz)
+ 0x80, 0x08, 0x1b, // initial line states
+ 0x85, // disable loopback
+ };
+ unsigned char *init_commands_p = plain_init_commands;
+ int init_commands_sz = sizeof(plain_init_commands);
+
+ if (device_is_amontec_jtagkey_2p) {
+ init_commands_p = amontec_init_commands;
+ init_commands_sz = sizeof(amontec_init_commands);
+ }
+
+ write_dumpfile(1, init_commands_p, init_commands_sz, 0);
+ if (ftdi_write_data(&u->ftdic, init_commands_p, init_commands_sz) != init_commands_sz) {
+ fprintf(stderr, "IO Error: Interface setup failed (init commands): %s\n",
+ ftdi_get_error_string(&u->ftdic));
+ ftdi_disable_bitbang(&u->ftdic);
+ ftdi_usb_close(&u->ftdic);
+ ftdi_deinit(&u->ftdic);
+ return -1;
+ }
+
+ if (u->frequency > 0)
+ h->set_frequency(h, u->frequency);
+
+ u->job_fifo_out = NULL;
+ u->job_fifo_in = NULL;
+ u->last_tms = -1;
+ u->last_tdo = -1;
+ u->buffer_i = 0;
+ u->error_rc = 0;
+
+#ifdef BACKGROUND_READ
+# ifdef INTERLACED_READ_WRITE
+ u->total_job_bits = 0;
+ u->writer_wait_flag = 0;
+ pthread_mutex_init(&u->writer_wait_flag_mutex, NULL);
+# endif
+ u->reader_terminate = 0;
+ pthread_mutex_init(&u->read_write_mutex, NULL);
+ pthread_cond_init(&u->read_more_cond, NULL);
+ pthread_cond_init(&u->read_done_cond, NULL);
+ pthread_create(&u->read_thread, NULL, &reader_main, u);
+#endif
+
+ return 0;
+}
+
+static int h_shutdown(struct libxsvf_host *h)
+{
+ struct udata_s *u = h->user_data;
+ buffer_sync(u);
+#ifdef BACKGROUND_READ
+ pthread_mutex_lock(&u->read_write_mutex);
+ u->reader_terminate = 1;
+ pthread_cond_signal(&u->read_more_cond);
+ pthread_mutex_unlock(&u->read_write_mutex);
+
+ pthread_join(u->read_thread, NULL);
+ pthread_cond_destroy(&u->read_done_cond);
+ pthread_cond_destroy(&u->read_more_cond);
+ pthread_mutex_destroy(&u->read_write_mutex);
+# ifdef INTERLACED_READ_WRITE
+ pthread_mutex_destroy(&u->writer_wait_flag_mutex);
+# endif
+#endif
+ ftdi_disable_bitbang(&u->ftdic);
+ ftdi_usb_close(&u->ftdic);
+ ftdi_deinit(&u->ftdic);
+ return u->error_rc;
+}
+
+static void h_udelay(struct libxsvf_host *h, long usecs, int tms, long num_tck)
+{
+ struct udata_s *u = h->user_data;
+ buffer_sync(u);
+ if (num_tck > 0) {
+ struct timeval tv1, tv2;
+ gettimeofday(&tv1, NULL);
+ while (num_tck > 0) {
+ buffer_add(u, tms, -1, -1, 0);
+ num_tck--;
+ }
+ buffer_sync(u);
+ gettimeofday(&tv2, NULL);
+ if (tv2.tv_sec > tv1.tv_sec) {
+ usecs -= (1000000 - tv1.tv_usec) + (tv2.tv_sec - tv1.tv_sec - 1) * 1000000;
+ tv1.tv_usec = 0;
+ }
+ usecs -= tv2.tv_usec - tv1.tv_usec;
+ }
+ if (usecs > 0) {
+ usleep(usecs);
+ }
+}
+
+static int h_getbyte(struct libxsvf_host *h)
+{
+ struct udata_s *u = h->user_data;
+ return fgetc(u->f);
+}
+
+static int h_sync(struct libxsvf_host *h)
+{
+ struct udata_s *u = h->user_data;
+ buffer_sync(u);
+ int rc = u->error_rc;
+ u->error_rc = 0;
+ return rc;
+}
+
+static int h_pulse_tck(struct libxsvf_host *h, int tms, int tdi, int tdo, int rmask, int sync)
+{
+ struct udata_s *u = h->user_data;
+ if (u->syncmode)
+ sync = 1;
+ buffer_add(u, tms, tdi, tdo, rmask);
+ if (sync) {
+ buffer_sync(u);
+ int rc = u->error_rc < 0 ? u->error_rc : u->last_tdo;
+ u->error_rc = 0;
+ return rc;
+ }
+ return u->error_rc < 0 ? u->error_rc : 1;
+}
+
+static int h_set_frequency(struct libxsvf_host *h, int v)
+{
+ struct udata_s *u = h->user_data;
+ if (u->syncmode && v > 10000)
+ v = 10000;
+ unsigned char setfreq_command[] = { 0x86, 0x02, 0x00 };
+ int div = fmax(ceil(12e6 / (2*v) - 1), 2);
+ setfreq_command[1] = div >> 0;
+ setfreq_command[2] = div >> 8;
+ write_dumpfile(1, setfreq_command, sizeof(setfreq_command), 0);
+ int rc = my_ftdi_write_data(u, setfreq_command, sizeof(setfreq_command), 1);
+ if (rc != sizeof(setfreq_command)) {
+ fprintf(stderr, "IO Error: Set frequency write failed: %s (rc=%d/%d)\n",
+ ftdi_get_error_string(&u->ftdic), rc, (int)sizeof(setfreq_command));
+ u->error_rc = -1;
+ }
+ return 0;
+}
+
+static void h_report_tapstate(struct libxsvf_host *h)
+{
+ struct udata_s *u = h->user_data;
+ if (u->verbose >= 2)
+ printf("[%s]\n", libxsvf_state2str(h->tap_state));
+}
+
+static void h_report_device(struct libxsvf_host *h, unsigned long idcode)
+{
+ printf("idcode=0x%08lx, revision=0x%01lx, part=0x%04lx, manufactor=0x%03lx\n", idcode,
+ (idcode >> 28) & 0xf, (idcode >> 12) & 0xffff, (idcode >> 1) & 0x7ff);
+}
+
+static void h_report_status(struct libxsvf_host *h, const char *message)
+{
+ struct udata_s *u = h->user_data;
+ if (u->verbose >= 1)
+ printf("[STATUS] %s\n", message);
+}
+
+static void h_report_error(struct libxsvf_host *h, const char *file, int line, const char *message)
+{
+ fprintf(stderr, "[%s:%d] %s\n", file, line, message);
+}
+
+static void *h_realloc(struct libxsvf_host *h, void *ptr, int size, enum libxsvf_mem which)
+{
+ return realloc(ptr, size);
+}
+
+static struct udata_s u = {
+};
+
+static struct libxsvf_host h = {
+ .udelay = h_udelay,
+ .setup = h_setup,
+ .shutdown = h_shutdown,
+ .getbyte = h_getbyte,
+ .sync = h_sync,
+ .pulse_tck = h_pulse_tck,
+ .set_frequency = h_set_frequency,
+ .report_tapstate = h_report_tapstate,
+ .report_device = h_report_device,
+ .report_status = h_report_status,
+ .report_error = h_report_error,
+ .realloc = h_realloc,
+ .user_data = &u
+};
+
+static uint16_t eeprom_checksum(unsigned char *data, int len)
+{
+ uint16_t checksum = 0xAAAA;
+ int i;
+
+ for (i = 0; i < len; i+=2) {
+ uint16_t value = (data[i+1] << 8) | data[i];
+ checksum = value ^ checksum;
+ checksum = (checksum << 1) | (checksum >> 15);
+ }
+
+ return checksum;
+}
+
+const char *progname;
+
+static void help()
+{
+ fprintf(stderr, "\n");
+ fprintf(stderr, "A JTAG SVF/XSVF Player based on libxsvf for the FTDI FT232H, FT2232H and\n");
+ fprintf(stderr, "FT4232H High Speed USB to Multipurpose UART/FIFO ICs.\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "xsvftool-ft2232h, part of Lib(X)SVF (http://www.clifford.at/libxsvf/).\n");
+ fprintf(stderr, "Copyright (C) 2009 RIEGL Research ForschungsGmbH\n");
+ fprintf(stderr, "Copyright (C) 2009 Clifford Wolf <clifford@clifford.at>\n");
+ fprintf(stderr, "Lib(X)SVF is free software licensed under the ISC license.\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Usage: %s [ -v[v..] ] [ -d dumpfile ] [ -L | -B ] [ -S ] [ -F ] \\\n", progname);
+ fprintf(stderr, " %*s [ -D vendor:product ] [ -C channel ] [ -f freq[k|M] ] \\\n", (int)(strlen(progname)+1), "");
+ fprintf(stderr, " %*s [ -Z eeprom-size] [ [-G] -W eeprom-filename ] [ -R eeprom-filename ] \\\n", (int)(strlen(progname)+1), "");
+ fprintf(stderr, " %*s { -s svf-file | -x xsvf-file | -c } ...\n", (int)(strlen(progname)+1), "");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " -v\n");
+ fprintf(stderr, " Enable verbose output (repeat for incrased verbosity)\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " -d dumpfile\n");
+ fprintf(stderr, " Write a logfile of all MPSSE comunication\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " -L, -B\n");
+ fprintf(stderr, " Print RMASK bits as hex value (little or big endian)\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " -S\n");
+ fprintf(stderr, " Run in synchronous mode (slow but report errors right away)\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " -F\n");
+ fprintf(stderr, " Force mode (ignore all TDO mismatches)\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " -f freq[k|M]\n");
+ fprintf(stderr, " Set maximum frequency in Hz, kHz or MHz\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " -D vendor:product\n");
+ fprintf(stderr, " Select device using USB vendor and product id\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " -C channel\n");
+ fprintf(stderr, " Select channel on target device (A, B, C or D)\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " -Z eeprom-size\n");
+ fprintf(stderr, " Set size of the FTDI EEPROM\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " -G\n");
+ fprintf(stderr, " Generate checksum before writing EEPROM data\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " -W eeprom-filename\n");
+ fprintf(stderr, " Write content of the given file to the FTDI EEPROM\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " -R eeprom-filename\n");
+ fprintf(stderr, " Write content of the FTDI EEPROM to the given file\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " -s svf-file\n");
+ fprintf(stderr, " Play the specified SVF file\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " -x xsvf-file\n");
+ fprintf(stderr, " Play the specified XSVF file\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, " -c\n");
+ fprintf(stderr, " List devices in JTAG chain\n");
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ int rc = 0;
+ int gotaction = 0;
+ int genchecksum = 0;
+ int hex_mode = 0;
+ int opt, i, j;
+
+ progname = argc >= 1 ? argv[0] : "xsvftool-ft232h";
+ while ((opt = getopt(argc, argv, "vd:LBSFD:C:Z:GW:R:f:x:s:c")) != -1)
+ {
+ switch (opt)
+ {
+ case 'v':
+ u.verbose++;
+ break;
+ case 'd':
+ if (!strcmp(optarg, "-"))
+ dumpfile = stdout;
+ else
+ dumpfile = fopen(optarg, "w");
+ if (!dumpfile) {
+ fprintf(stderr, "Can't open dumpfile `%s': %s\n", optarg, strerror(errno));
+ rc = 1;
+ }
+ break;
+ case 'f':
+ u.frequency = strtol(optarg, &optarg, 10);
+ while (*optarg != 0) {
+ if (*optarg == 'k') {
+ u.frequency *= 1000;
+ optarg++;
+ continue;
+ }
+ if (*optarg == 'M') {
+ u.frequency *= 1000000;
+ optarg++;
+ continue;
+ }
+ if (optarg[0] == 'H' && optarg[1] == 'z') {
+ optarg += 2;
+ continue;
+ }
+ help();
+ }
+ break;
+ case 'D':
+ {
+ char *endptr = NULL;
+ u.device_vendor = strtol(optarg, &endptr, 16);
+ if (!endptr || *endptr != ':')
+ help();
+ u.device_product = strtol(endptr, &endptr, 16);
+ if (!endptr || *endptr != 0)
+ help();
+ }
+ break;
+ case 'C':
+ if (!strcmp(optarg, "A"))
+ u.device_channel = 1;
+ else
+ if (!strcmp(optarg, "B"))
+ u.device_channel = 2;
+ else
+ if (!strcmp(optarg, "C"))
+ u.device_channel = 3;
+ else
+ if (!strcmp(optarg, "D"))
+ u.device_channel = 4;
+ else
+ help();
+ break;
+ case 'Z':
+ {
+ char *endptr = NULL;
+ u.eeprom_size = strtol(optarg, &endptr, 0);
+ if (!endptr || *endptr != 0)
+ help();
+ }
+ break;
+ case 'G':
+ genchecksum = 1;
+ break;
+ case 'W':
+ {
+ gotaction = 1;
+ if (h_setup(&h) < 0)
+ return 1;
+ unsigned char eeprom_data[u.ftdic.eeprom_size];
+
+ FILE *f = fopen(optarg, "r");
+ if (f == NULL) {
+ fprintf(stderr, "Can't open EEPROM file `%s' for reading: %s\n", optarg, strerror(errno));
+ h_shutdown(&h);
+ return 1;
+ }
+ if (fread(eeprom_data, u.ftdic.eeprom_size, 1, f) != 1) {
+ fprintf(stderr, "Can't read EEPROM file `%s': %s\n", optarg, strerror(errno));
+ h_shutdown(&h);
+ return 1;
+ }
+ fclose(f);
+
+ uint16_t checksum = eeprom_checksum(eeprom_data, u.ftdic.eeprom_size-2);
+ if (genchecksum) {
+ eeprom_data[u.ftdic.eeprom_size-1] = checksum >> 8;
+ eeprom_data[u.ftdic.eeprom_size-2] = checksum;
+ }
+
+ uint16_t checksum_chip = (eeprom_data[u.ftdic.eeprom_size-1] << 8) | eeprom_data[u.ftdic.eeprom_size-2];
+ if (checksum != checksum_chip) {
+ fprintf(stderr, "ERROR: Checksum from EEPROM data is invalid! (is 0x%04x instead of 0x%04x)\n",
+ checksum_chip, checksum);
+ h_shutdown(&h);
+ return 1;
+ }
+
+ if (ftdi_write_eeprom(&u.ftdic, eeprom_data) < 0) {
+ fprintf(stderr, "Writing EEPROM data failed! (size=%d)\n", u.ftdic.eeprom_size);
+ h_shutdown(&h);
+ return 1;
+ }
+ if (h_shutdown(&h) < 0)
+ return 1;
+ }
+ break;
+ case 'R':
+ {
+ gotaction = 1;
+ if (h_setup(&h) < 0)
+ return 1;
+ int eeprom_size = u.ftdic.eeprom_size;
+ unsigned char eeprom_data[eeprom_size];
+ if (ftdi_read_eeprom(&u.ftdic, eeprom_data) < 0) {
+ fprintf(stderr, "Reading EEPROM data failed! (size=%d)\n", u.ftdic.eeprom_size);
+ h_shutdown(&h);
+ return 1;
+ }
+ if (h_shutdown(&h) < 0)
+ return 1;
+
+ FILE *f = fopen(optarg, "w");
+ if (f == NULL) {
+ fprintf(stderr, "Can't open EEPROM file `%s' for writing: %s\n", optarg, strerror(errno));
+ return 1;
+ }
+ if (fwrite(eeprom_data, eeprom_size, 1, f) != 1) {
+ fprintf(stderr, "Can't write EEPROM file `%s': %s\n", optarg, strerror(errno));
+ return 1;
+ }
+ fclose(f);
+
+ uint16_t checksum = eeprom_checksum(eeprom_data, eeprom_size-2);
+ uint16_t checksum_chip = (eeprom_data[eeprom_size-1] << 8) | eeprom_data[eeprom_size-2];
+ if (checksum != checksum_chip)
+ fprintf(stderr, "WARNING: Checksum from EEPROM data is invalid! (is 0x%04x instead of 0x%04x)\n",
+ checksum_chip, checksum);
+ }
+ break;
+ case 'x':
+ case 's':
+ gotaction = 1;
+ if (!strcmp(optarg, "-"))
+ u.f = stdin;
+ else
+ u.f = fopen(optarg, "rb");
+ if (u.f == NULL) {
+ fprintf(stderr, "Can't open %s file `%s': %s\n", opt == 's' ? "SVF" : "XSVF", optarg, strerror(errno));
+ rc = 1;
+ break;
+ }
+ if (libxsvf_play(&h, opt == 's' ? LIBXSVF_MODE_SVF : LIBXSVF_MODE_XSVF) < 0) {
+ fprintf(stderr, "Error while playing %s file `%s'.\n", opt == 's' ? "SVF" : "XSVF", optarg);
+ rc = 1;
+ }
+ if (strcmp(optarg, "-"))
+ fclose(u.f);
+ break;
+ case 'c':
+ gotaction = 1;
+ int old_frequency = u.frequency;
+ if (u.frequency == 0)
+ u.frequency = 10000;
+ if (libxsvf_play(&h, LIBXSVF_MODE_SCAN) < 0) {
+ fprintf(stderr, "Error while scanning JTAG chain.\n");
+ rc = 1;
+ }
+ u.frequency = old_frequency;
+ break;
+ case 'L':
+ hex_mode = 1;
+ break;
+ case 'B':
+ hex_mode = 2;
+ break;
+ case 'S':
+ if (u.frequency == 0)
+ u.frequency = 10000;
+ u.syncmode = 1;
+ break;
+ case 'F':
+ u.forcemode = 1;
+ break;
+ default:
+ help();
+ break;
+ }
+ }
+
+ if (!gotaction)
+ help();
+
+ if (u.retval_i) {
+ if (hex_mode) {
+ printf("0x");
+ for (i=0; i < u.retval_i; i+=4) {
+ int val = 0;
+ for (j=i; j<i+4; j++)
+ val = val << 1 | u.retval[hex_mode > 1 ? j : u.retval_i - j - 1];
+ printf("%x", val);
+ }
+ } else {
+ printf("%d rmask bits:", u.retval_i);
+ for (i=0; i < u.retval_i; i++)
+ printf(" %d", u.retval[i]);
+ }
+ printf("\n");
+ }
+
+ return rc;
+}
+