You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1131 lines
30 KiB
1131 lines
30 KiB
12 years ago
|
/*
|
||
|
* 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;
|
||
|
}
|
||
|
|