merged changes from /branches/ft2232_eval@770

this is the initial stable version of the ft2232 cable driver


git-svn-id: https://urjtag.svn.sourceforge.net/svnroot/urjtag/trunk@771 b68d4a1b-bc3d-0410-92ed-d4ac073336b7
master
Arnim Läuger 17 years ago
parent 731abd1643
commit 4912ec2f2e

@ -43,7 +43,7 @@ struct cable_driver_t {
void (*cable_free)( cable_t *cable );
int (*init)( cable_t * );
void (*done)( cable_t * );
void (*clock)( cable_t *, int, int );
void (*clock)( cable_t *, int, int, int );
int (*get_tdo)( cable_t * );
int (*transfer)( cable_t *, int, char *, char * );
int (*set_trst)( cable_t *, int );
@ -60,7 +60,7 @@ struct cable_t {
void cable_free( cable_t *cable );
int cable_init( cable_t *cable );
void cable_done( cable_t *cable );
void cable_clock( cable_t *cable, int tms, int tdi );
void cable_clock( cable_t *cable, int tms, int tdi, int n );
int cable_get_tdo( cable_t *cable );
int cable_set_trst( cable_t *cable, int trst );
int cable_get_trst( cable_t *cable );

@ -45,7 +45,7 @@ struct chain_t {
chain_t *chain_alloc( void );
void chain_free( chain_t *chain );
void chain_disconnect( chain_t *chain );
void chain_clock( chain_t *chain, int tms, int tdi );
void chain_clock( chain_t *chain, int tms, int tdi, int n );
int chain_set_trst( chain_t *chain, int trst );
int chain_get_trst( chain_t *chain );
void chain_shift_instructions( chain_t *chain );

@ -87,6 +87,7 @@ cmd_cable_help( void )
"Usage: %s DEV CABLE\n"
"Usage: %s VID:PID:S/N CABLE\n"
"Usage: %s VID:PID:S/N CABLE\n"
"Usage: %s VID:PID:S/N CABLE\n"
"Select JTAG cable connected to parallel port.\n"
"\n"
"PORTADDR parallel port address (e.g. 0x378)\n"
@ -98,7 +99,7 @@ cmd_cable_help( void )
"\n"
"List of supported cables:\n"
"%-13s No cable connected\n"
), "cable parallel", "cable ppdev", "cable ftdi", "cable xpcu", "none" );
), "cable parallel", "cable ppdev", "cable ftdi", "cable ftdi-mpsse", "cable xpcu", "none" );
for (i = 0; cable_drivers[i]; i++)
printf( _("%-13s %s\n"), cable_drivers[i]->name, _(cable_drivers[i]->description) );

@ -92,9 +92,7 @@ static int issued_runtest_maxtime;
static void
svf_force_reset_state(void)
{
int i;
for (i = 1; i <= 5; i++)
chain_clock(chain, 1, 0);
chain_clock(chain, 1, 0, 5);
tap_state_reset(chain);
}
@ -128,11 +126,11 @@ svf_goto_state(int new_state)
switch (current_state) {
case Test_Logic_Reset:
chain_clock(chain, 0, 0);
chain_clock(chain, 0, 0, 1);
break;
case Run_Test_Idle:
chain_clock(chain, 1, 0);
chain_clock(chain, 1, 0, 1);
break;
case Select_DR_Scan:
@ -142,86 +140,86 @@ svf_goto_state(int new_state)
(current_state & TAPSTAT_DR && new_state & TAPSTAT_IR) ||
(current_state & TAPSTAT_IR && new_state & TAPSTAT_DR))
/* progress in select-idle/reset loop */
chain_clock(chain, 1, 0);
chain_clock(chain, 1, 0, 1);
else
/* enter DR/IR branch */
chain_clock(chain, 0, 0);
chain_clock(chain, 0, 0, 1);
break;
case Capture_DR:
if (new_state == Shift_DR)
/* enter Shift_DR state */
chain_clock(chain, 0, 0);
chain_clock(chain, 0, 0, 1);
else
/* bypass Shift_DR */
chain_clock(chain, 1, 0);
chain_clock(chain, 1, 0, 1);
break;
case Capture_IR:
if (new_state == Shift_IR)
/* enter Shift_IR state */
chain_clock(chain, 0, 0);
chain_clock(chain, 0, 0, 1);
else
/* bypass Shift_IR */
chain_clock(chain, 1, 0);
chain_clock(chain, 1, 0, 1);
break;
case Shift_DR:
case Shift_IR:
/* progress to Exit1_DR/IR */
chain_clock(chain, 1, 0);
chain_clock(chain, 1, 0, 1);
break;
case Exit1_DR:
if (new_state == Pause_DR)
/* enter Pause_DR state */
chain_clock(chain, 0, 0);
chain_clock(chain, 0, 0, 1);
else
/* bypass Pause_DR */
chain_clock(chain, 1, 0);
chain_clock(chain, 1, 0, 1);
break;
case Exit1_IR:
if (new_state == Pause_IR)
/* enter Pause_IR state */
chain_clock(chain, 0, 0);
chain_clock(chain, 0, 0, 1);
else
/* bypass Pause_IR */
chain_clock(chain, 1, 0);
chain_clock(chain, 1, 0, 1);
break;
case Pause_DR:
case Pause_IR:
/* progress to Exit2_DR/IR */
chain_clock(chain, 1, 0);
chain_clock(chain, 1, 0, 1);
break;
case Exit2_DR:
if (new_state == Shift_DR)
/* enter Shift_DR state */
chain_clock(chain, 0, 0);
chain_clock(chain, 0, 0, 1);
else
/* progress to Update_DR */
chain_clock(chain, 1, 0);
chain_clock(chain, 1, 0, 1);
break;
case Exit2_IR:
if (new_state == Shift_IR)
/* enter Shift_IR state */
chain_clock(chain, 0, 0);
chain_clock(chain, 0, 0, 1);
else
/* progress to Update_IR */
chain_clock(chain, 1, 0);
chain_clock(chain, 1, 0, 1);
break;
case Update_DR:
case Update_IR:
if (new_state == Run_Test_Idle)
/* enter Run_Test_Idle */
chain_clock(chain, 0, 0);
chain_clock(chain, 0, 0, 1);
else
/* progress to Select_DR/IR */
chain_clock(chain, 1, 0);
chain_clock(chain, 1, 0, 1);
break;
default:
@ -706,9 +704,12 @@ svf_runtest(struct runtest *params)
ualarm(max_time, 0);
}
while (run_count-- > 0 && !max_time_reached) {
chain_clock(chain, 0, 0);
}
if (params->max_time > 0.0)
while (run_count-- > 0 && !max_time_reached) {
chain_clock(chain, 0, 0, 1);
}
else
chain_clock(chain, 0, 0, run_count);
svf_goto_state(runtest_end_state);

@ -58,6 +58,7 @@ endif
if HAVE_LIBFTDI
libtap_a_SOURCES += \
parport/ftdi.c \
cable/usbblaster.c
cable/usbblaster.c \
cable/ft2232.c
endif

@ -39,6 +39,8 @@ extern cable_driver_t arcom_cable_driver;
extern cable_driver_t byteblaster_cable_driver;
#ifdef HAVE_LIBFTDI
extern cable_driver_t usbblaster_cable_driver;
extern cable_driver_t ft2232_cable_driver;
extern cable_driver_t ft2232_armusbocd_cable_driver;
#endif
extern cable_driver_t dlc5_cable_driver;
extern cable_driver_t ea253_cable_driver;
@ -61,6 +63,8 @@ cable_driver_t *cable_drivers[] = {
&byteblaster_cable_driver,
#ifdef HAVE_LIBFTDI
&usbblaster_cable_driver,
&ft2232_cable_driver,
&ft2232_armusbocd_cable_driver,
#endif
&dlc5_cable_driver,
&ea253_cable_driver,
@ -98,9 +102,9 @@ cable_done( cable_t *cable )
}
void
cable_clock( cable_t *cable, int tms, int tdi )
cable_clock( cable_t *cable, int tms, int tdi, int n )
{
cable->driver->clock( cable, tms, tdi );
cable->driver->clock( cable, tms, tdi, n );
}
int
@ -149,7 +153,7 @@ cable_set_frequency( cable_t *cable, uint32_t new_frequency )
start = frealtime();
for (i = 0; i < loops; ++i) {
chain_clock(chain, 0, 0);
chain_clock(chain, 0, 0, 1);
}
end = frealtime();

@ -67,15 +67,19 @@ arcom_init( cable_t *cable )
}
static void
arcom_clock( cable_t *cable, int tms, int tdi )
arcom_clock( cable_t *cable, int tms, int tdi, int n )
{
int i;
tms = tms ? 1 : 0;
tdi = tdi ? 1 : 0;
parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (0 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (1 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
for (i = 0; i < n; i++) {
parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (0 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (1 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
}
}
static int

@ -96,15 +96,19 @@ byteblaster_init( cable_t *cable )
}
static void
byteblaster_clock( cable_t *cable, int tms, int tdi )
byteblaster_clock( cable_t *cable, int tms, int tdi, int n )
{
int i;
tms = tms ? 1 : 0;
tdi = tdi ? 1 : 0;
parport_set_data( cable->port, (0 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
parport_set_data( cable->port, (1 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
for (i = 0; i < n; i++) {
parport_set_data( cable->port, (0 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
parport_set_data( cable->port, (1 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
}
}
static int

@ -67,15 +67,19 @@ dlc5_init( cable_t *cable )
}
static void
dlc5_clock( cable_t *cable, int tms, int tdi )
dlc5_clock( cable_t *cable, int tms, int tdi, int n )
{
int i;
tms = tms ? 1 : 0;
tdi = tdi ? 1 : 0;
parport_set_data( cable->port, (1 << PROG) | (0 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
parport_set_data( cable->port, (1 << PROG) | (1 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
for (i = 0; i < n; i++) {
parport_set_data( cable->port, (1 << PROG) | (0 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
parport_set_data( cable->port, (1 << PROG) | (1 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
}
}
static int

@ -67,15 +67,19 @@ ea253_init( cable_t *cable )
}
static void
ea253_clock( cable_t *cable, int tms, int tdi )
ea253_clock( cable_t *cable, int tms, int tdi, int n )
{
int i;
tms = tms ? 1 : 0;
tdi = tdi ? 1 : 0;
parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (0 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (1 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
for (i = 0; i < n; i++) {
parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (0 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (1 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
}
}
static int

@ -69,15 +69,19 @@ ei012_init( cable_t *cable )
}
static void
ei012_clock( cable_t *cable, int tms, int tdi )
ei012_clock( cable_t *cable, int tms, int tdi, int n )
{
int i;
tms = tms ? 1 : 0;
tdi = tdi ? 1 : 0;
parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (0 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (1 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
for (i = 0; i < n; i++) {
parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (0 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (1 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
}
}
static int

@ -0,0 +1,480 @@
/*
* $Id$
*
* Generic cable driver for FTDI's FT2232C chip in MPSSE mode.
* Copyright (C) 2007 A. Laeuger
*
* 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.
*
* Written by Arnim Laeuger, 2007.
*
*/
#include <ftdi.h>
#include "sysdep.h"
#include "cable.h"
#include "parport.h"
#include "chain.h"
#include "generic.h"
/* Define MULTI_BYTE to activate block read transfer from parport
no benefit over single byte read observed. */
#undef MULTI_BYTE
/* Maximum chunk to write to parport driver.
Larger values might speed up comm, but there's an upper limit
when too many bytes are sent and libftdi doesn't fetch the
returned data in time -> deadlock */
#define MAXCHUNK (4 * 64)
/* Enable caching of last TDO to speed up things a bit.
Should be left define'd unless comm/sync problems occur. */
#define LAST_TDO_CACHE
/* Maximum TCK frequency of FT2232 */
#define FT2232_MAX_TCK_FREQ 6000000
#define BIT_TCK 0
#define BIT_TDI 1
#define BIT_TDO 2
#define BIT_TMS 3
#define BIT_ARMUSBOCD_nOE 4
#define BITMASK_TDO (1 << BIT_TDO)
#define BITMASK_TDI (1 << BIT_TDI)
#define BITMASK_TCK (1 << BIT_TCK)
#define BITMASK_TMS (1 << BIT_TMS)
#define BITMASK_ARMUSBOCD_nOE (1 << BIT_ARMUSBOCD_nOE)
/* global variables to save last TDO value
this acts as a cache to prevent multiple "Read Data Bits Low" transfer
over USB for ft2232_get_tdo */
static unsigned int last_tdo_valid;
static unsigned int last_tdo;
static uint32_t mpsse_frequency;
#ifdef MULTIBYTE
static uint8_t local_buffer[MAXCHUNK+16];
#endif
static void
update_frequency( cable_t *cable )
{
parport_t *p = cable->port;
uint32_t new_frequency = cable_get_frequency( cable );
if (!new_frequency || new_frequency > FT2232_MAX_TCK_FREQ)
new_frequency = FT2232_MAX_TCK_FREQ;
/* update ft2232 frequency if cable setting changed */
if (new_frequency != mpsse_frequency) {
uint32_t div;
div = FT2232_MAX_TCK_FREQ / new_frequency;
if (FT2232_MAX_TCK_FREQ % new_frequency)
div++;
if (div >= (1 << 16)) {
div = (1 << 16) - 1;
printf( _("Warning: Setting lowest supported frequency for FT2232: %d\n"), FT2232_MAX_TCK_FREQ/div );
}
/* send new divisor to device */
div -= 1;
parport_set_data( p, TCK_DIVISOR );
parport_set_data( p, div & 0xff );
parport_set_data( p, (div >> 8) & 0xff );
parport_set_control( p, 1 ); // flush
parport_set_control( p, 0 ); // noflush
mpsse_frequency = FT2232_MAX_TCK_FREQ / (div + 1);
}
}
static int
ft2232_generic_init( cable_t *cable )
{
parport_t *p = cable->port;
if (parport_open( p ))
return -1;
/* Set Data Bits Low Byte
TCK = 0, TMS = 1, TDI = 0 */
parport_set_data( p, SET_BITS_LOW );
parport_set_data( p, BITMASK_TMS );
parport_set_data( p, BITMASK_TCK | BITMASK_TDI | BITMASK_TMS );
parport_set_control( p, 1 ); // flush
parport_set_control( p, 0 ); // noflush
/* Set TCK/SK Divisor */
parport_set_data( p, TCK_DIVISOR );
parport_set_data( p, 0 );
parport_set_data( p, 0 );
parport_set_control( p, 1 ); // flush
parport_set_control( p, 0 ); // noflush
mpsse_frequency = FT2232_MAX_TCK_FREQ;
last_tdo_valid = 0;
return 0;
}
static int
ft2232_armusbocd_init( cable_t *cable )
{
parport_t *p = cable->port;
if (parport_open( p ))
return -1;
/* set loopback off */
parport_set_data( p, LOOPBACK_END );
parport_set_control( p, 1 ); // flush
parport_set_control( p, 0 ); // noflush
/* Set Data Bits Low Byte
TCK = 0, TMS = 1, TDI = 0, nOE = 0 */
parport_set_data( p, SET_BITS_LOW );
parport_set_data( p, BITMASK_TMS );
parport_set_data( p, BITMASK_TCK | BITMASK_TDI | BITMASK_TMS | BITMASK_ARMUSBOCD_nOE );
parport_set_control( p, 1 ); // flush
parport_set_control( p, 0 ); // noflush
/* Set TCK/SK Divisor */
parport_set_data( p, TCK_DIVISOR );
parport_set_data( p, 0 );
parport_set_data( p, 0 );
parport_set_control( p, 1 ); // flush
parport_set_control( p, 0 ); // noflush
mpsse_frequency = FT2232_MAX_TCK_FREQ;
last_tdo_valid = 0;
return 0;
}
static void
ft2232_generic_done( cable_t *cable )
{
parport_t *p = cable->port;
/* Set Data Bits Low Byte
set all to input */
parport_set_data( p, SET_BITS_LOW );
parport_set_data( p, 0 );
parport_set_data( p, 0 );
parport_set_control( p, 1 ); // flush
parport_set_control( p, 0 ); // noflush
parport_close( p );
}
static void
ft2232_armusbocd_done( cable_t *cable )
{
parport_t *p = cable->port;
/* Set Data Bits Low Byte
disable output drivers */
parport_set_data( p, SET_BITS_LOW );
parport_set_data( p, BITMASK_ARMUSBOCD_nOE );
parport_set_data( p, BITMASK_ARMUSBOCD_nOE );
parport_set_control( p, 1 ); // flush
parport_set_control( p, 0 ); // noflush
/* Set Data Bits Low Byte
set all to input */
parport_set_data( p, SET_BITS_LOW );
parport_set_data( p, BITMASK_ARMUSBOCD_nOE );
parport_set_data( p, 0 );
parport_set_control( p, 1 ); // flush
parport_set_control( p, 0 ); // noflush
parport_close( p );
}
static void
ft2232_clock( cable_t *cable, int tms, int tdi, int n )
{
parport_t *p = cable->port;
tms = tms ? 0x7f : 0;
tdi = tdi ? 1 << 7 : 0;
/* check for new frequency setting */
update_frequency( cable );
while (n > 0) {
/* Clock Data to TMS/CS Pin (no Read) */
parport_set_data( p, MPSSE_WRITE_TMS |
MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG );
if (n <= 7) {
parport_set_data( p, n-1 );
n = 0;
} else {
parport_set_data( p, 7-1 );
n -= 7;
}
parport_set_data( p, tdi | tms );
}
parport_set_control( p, 1 ); // flush
parport_set_control( p, 0 ); // noflush
last_tdo_valid = 0;
}
static int
ft2232_get_tdo( cable_t *cable )
{
parport_t *p = cable->port;
if (!last_tdo_valid) {
/* Read Data Bits Low Byte */
parport_set_data( p, GET_BITS_LOW );
parport_set_control( p, 1 ); // flush
parport_set_control( p, 0 ); // noflush
last_tdo = ( parport_get_data( p ) & BITMASK_TDO) ? 1 : 0;
#ifdef LAST_TDO_CACHE
last_tdo_valid = 1;
#endif
}
return last_tdo;
}
static int
ft2232_set_trst( cable_t *cable, int trst )
{
return 1;
}
static int
ft2232_transfer( cable_t *cable, int len, char *in, char *out )
{
parport_t *p = cable->port;
int in_offset = 0;
int out_offset = 0;
int bitwise_len;
/* check for new frequency setting */
update_frequency( cable );
#ifdef LAST_TDO_CACHE
/* invalidate TDO cache */
last_tdo_valid = 0;
#endif
while (len - in_offset > 0) {
int byte_idx;
int chunkbytes = (len - in_offset) >> 3;
if (chunkbytes > MAXCHUNK)
chunkbytes = MAXCHUNK;
if ((chunkbytes < MAXCHUNK) &&
((len - in_offset) % 8 > 0))
bitwise_len = (len - in_offset) % 8;
else
bitwise_len = 0;
if (chunkbytes > 0) {
/***********************************************************************
* Step 1:
* Determine data shifting command (bytewise).
* Either with or without read
***********************************************************************/
if (out)
/* Clock Data Bytes In and Out LSB First
out on negative edge, in on positive edge */
parport_set_data( p, MPSSE_DO_READ | MPSSE_DO_WRITE |
MPSSE_LSB | MPSSE_WRITE_NEG );
else
/* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */
parport_set_data( p, MPSSE_DO_WRITE |
MPSSE_LSB | MPSSE_WRITE_NEG );
/* set byte count */
parport_set_data( p, (chunkbytes - 1) & 0xff );
parport_set_data( p, ((chunkbytes - 1) >> 8) & 0xff );
/*********************************************************************
* Step 2:
* Write TDI data in bundles of 8 bits.
*********************************************************************/
for (byte_idx = 0; byte_idx < chunkbytes; byte_idx++) {
int bit_idx;
unsigned char b = 0;
for (bit_idx = 1; bit_idx < 256; bit_idx <<= 1)
if (in[in_offset++])
b |= bit_idx;
parport_set_data( p, b );
}
}
if (bitwise_len > 0) {
/***********************************************************************
* Step 3:
* Determine data shifting command (bitwise).
* Either with or without read
***********************************************************************/
if (out)
/* Clock Data Bytes In and Out LSB First
out on negative edge, in on positive edge */
parport_set_data( p, MPSSE_DO_READ | MPSSE_DO_WRITE |
MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG );
else
/* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */
parport_set_data( p, MPSSE_DO_WRITE |
MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG );
/* determine bit count */
parport_set_data( p, bitwise_len - 1 );
/***********************************************************************
* Step 4:
* Write TDI data bitwise
***********************************************************************/
{
int bit_idx;
unsigned char b = 0;
for (bit_idx = 1; bit_idx <= 1 << bitwise_len; bit_idx <<= 1) {
if (in[in_offset++])
b |= bit_idx;
}
parport_set_data( p, b );
}
}
#ifdef LAST_TDO_CACHE
if (out) {
/* Read Data Bits Low Byte to get current TDO,
Do this only if we'll read out data nonetheless */
parport_set_data( p, GET_BITS_LOW );
}
#endif
parport_set_control( p, 1 ); // flush
parport_set_control( p, 0 ); // noflush
if (out) {
if (chunkbytes > 0) {
#ifdef MULTI_BYTE
int buf_idx;
#endif
uint32_t xferred;
/*********************************************************************
* Step 5:
* Read TDO data in bundles of 8 bits if read is requested.
*********************************************************************/
#ifdef MULTI_BYTE
parport_get_block( p, local_buffer, chunkbytes, &xferred );
if (chunkbytes != xferred)
printf("Bummer\n");
buf_idx = 0;
#else
xferred = chunkbytes;
#endif
for (; xferred > 0; xferred--) {
int bit_idx;
unsigned char b;
#ifdef MULTI_BYTE
b = local_buffer[buf_idx++];
#else
b = parport_get_data( p );
#endif
for (bit_idx = 1; bit_idx < 256; bit_idx <<= 1)
out[out_offset++] = (b & bit_idx) ? 1 : 0;
}
}
if (bitwise_len > 0) {
/***********************************************************************
* Step 6:
* Read TDO data bitwise if read is requested.
***********************************************************************/
int bit_idx;
unsigned char b;
b = parport_get_data( p );
for (bit_idx = (1 << (8 - bitwise_len)); bit_idx < 256; bit_idx <<= 1)
out[out_offset++] = (b & bit_idx) ? 1 : 0;
}
}
#ifdef LAST_TDO_CACHE
if (out) {
/* gather current TDO */
last_tdo = ( parport_get_data( p ) & BITMASK_TDO) ? 1 : 0;
last_tdo_valid = 1;
}
#endif
}
return 0;
}
cable_driver_t ft2232_cable_driver = {
"FT2232",
N_("Generic FTDI FT2232 Cable"),
generic_connect,
generic_disconnect,
generic_cable_free,
ft2232_generic_init,
ft2232_generic_done,
ft2232_clock,
ft2232_get_tdo,
ft2232_transfer,
ft2232_set_trst,
generic_get_trst
};
cable_driver_t ft2232_armusbocd_cable_driver = {
"ARM-USB-OCD",
N_("Olimex ARM-USB-OCD (FT2232) Cable"),
generic_connect,
generic_disconnect,
generic_cable_free,
ft2232_armusbocd_init,
ft2232_armusbocd_done,
ft2232_clock,
ft2232_get_tdo,
ft2232_transfer,
ft2232_set_trst,
generic_get_trst
};
/*
Local Variables:
mode:C
tab-width:2
indent-tabs-mode:t
End:
*/

@ -78,11 +78,11 @@ generic_transfer( cable_t *cable, int len, char *in, char *out )
if(out)
for(i=0; i<len; i++) {
out[i] = cable_get_tdo( cable );
cable_clock( cable, 0, in[i] );
cable_clock( cable, 0, in[i], 1 );
}
else
for(i=0; i<len; i++) {
cable_clock( cable, 0, in[i] );
cable_clock( cable, 0, in[i], 1 );
}
return i;

@ -76,15 +76,19 @@ keithkoep_init( cable_t *cable )
}
static void
keithkoep_clock( cable_t *cable, int tms, int tdi )
keithkoep_clock( cable_t *cable, int tms, int tdi, int n )
{
int i;
tms = tms ? 1 : 0;
tdi = tdi ? 1 : 0;
parport_set_data( cable->port, (0 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
parport_set_data( cable->port, (1 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
for (i = 0; i < n; i++) {
parport_set_data( cable->port, (0 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
parport_set_data( cable->port, (1 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
}
}
static int

@ -62,15 +62,19 @@ lattice_init( cable_t *cable )
}
static void
lattice_clock( cable_t *cable, int tms, int tdi )
lattice_clock( cable_t *cable, int tms, int tdi, int n )
{
int i;
tms = tms ? 1 : 0;
tdi = tdi ? 1 : 0;
parport_set_data( cable->port, (0 << TCK) | (tms << TMS) | (tdi << TDI) | (1 << TRST) );
cable_wait();
parport_set_data( cable->port, (1 << TCK) | (tms << TMS) | (tdi << TDI) | (1 << TRST) );
cable_wait();
for (i = 0; i < n; i++) {
parport_set_data( cable->port, (0 << TCK) | (tms << TMS) | (tdi << TDI) | (1 << TRST) );
cable_wait();
parport_set_data( cable->port, (1 << TCK) | (tms << TMS) | (tdi << TDI) | (1 << TRST) );
cable_wait();
}
}
static int

@ -73,15 +73,19 @@ mpcbdm_init( cable_t *cable )
}
static void
mpcbdm_clock( cable_t *cable, int tms, int tdi )
mpcbdm_clock( cable_t *cable, int tms, int tdi, int n )
{
int i;
tms = tms ? 1 : 0;
tdi = tdi ? 1 : 0;
parport_set_data( cable->port, (0 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
parport_set_data( cable->port, (1 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
for (i = 0; i < n; i++) {
parport_set_data( cable->port, (0 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
parport_set_data( cable->port, (1 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
}
}
static int

@ -78,15 +78,19 @@ triton_init( cable_t *cable )
}
static void
triton_clock( cable_t *cable, int tms, int tdi )
triton_clock( cable_t *cable, int tms, int tdi, int n )
{
int i;
tms = tms ? 1 : 0;
tdi = tdi ? 1 : 0;
parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (PARAM_SRESET(cable) << SRESET) | (0 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (PARAM_SRESET(cable) << SRESET) | (1 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
for (i = 0; i < n; i++) {
parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (PARAM_SRESET(cable) << SRESET) | (0 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (PARAM_SRESET(cable) << SRESET) | (1 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
}
}
static int

@ -58,15 +58,19 @@ usbblaster_init( cable_t *cable )
}
static void
usbblaster_clock( cable_t *cable, int tms, int tdi )
usbblaster_clock( cable_t *cable, int tms, int tdi, int n )
{
int i;
tms = tms ? 1 : 0;
tdi = tdi ? 1 : 0;
parport_set_data( cable->port, OTHERS | (0 << TCK) | (tms << TMS) | (tdi << TDI) );
parport_set_data( cable->port, OTHERS | (1 << TCK) | (tms << TMS) | (tdi << TDI) );
parport_set_control( cable->port, 1 ); // flush
parport_set_control( cable->port, 0 ); // noflush
for (i = 0; i < n; i++) {
parport_set_data( cable->port, OTHERS | (0 << TCK) | (tms << TMS) | (tdi << TDI) );
parport_set_data( cable->port, OTHERS | (1 << TCK) | (tms << TMS) | (tdi << TDI) );
parport_set_control( cable->port, 1 ); // flush
parport_set_control( cable->port, 0 ); // noflush
}
}
static int

@ -76,14 +76,19 @@ wiggler_init( cable_t *cable )
}
static void
wiggler_clock( cable_t *cable, int tms, int tdi )
wiggler_clock( cable_t *cable, int tms, int tdi, int n )
{
int i;
tms = tms ? 1 : 0;
tdi = tdi ? 1 : 0;
parport_set_data( cable->port, (PARAM_TRST(cable) << nTRST) | (0 << TCK) | (tms << TMS) | (tdi << TDI) | UNUSED_BITS );
cable_wait();
parport_set_data( cable->port, 0xe0 | (PARAM_TRST(cable) << nTRST) | (1 << TCK) | (tms << TMS) | (tdi << TDI) | UNUSED_BITS );
cable_wait();
for (i = 0; i < n; i++) {
parport_set_data( cable->port, (PARAM_TRST(cable) << nTRST) | (0 << TCK) | (tms << TMS) | (tdi << TDI) | UNUSED_BITS );
cable_wait();
parport_set_data( cable->port, 0xe0 | (PARAM_TRST(cable) << nTRST) | (1 << TCK) | (tms << TMS) | (tdi << TDI) | UNUSED_BITS );
cable_wait();
}
}
static int

@ -83,15 +83,19 @@ wiggler2_init( cable_t *cable )
}
static void
wiggler2_clock( cable_t *cable, int tms, int tdi )
wiggler2_clock( cable_t *cable, int tms, int tdi, int n )
{
int i;
tms = tms ? 1 : 0;
tdi = tdi ? 1 : 0;
parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (0 << TCK) | (tms << TMS) | (tdi << TDI) | UNUSED_BITS );
cable_wait();
parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (1 << TCK) | (tms << TMS) | (tdi << TDI) | UNUSED_BITS );
cable_wait();
for (i = 0; i < n; i++) {
parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (0 << TCK) | (tms << TMS) | (tdi << TDI) | UNUSED_BITS );
cable_wait();
parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (1 << TCK) | (tms << TMS) | (tdi << TDI) | UNUSED_BITS );
cable_wait();
}
}
static int

@ -65,17 +65,21 @@ xpc_ext_init( cable_t *cable )
#define TDO 0
static void
xpc_clock( cable_t *cable, int tms, int tdi )
xpc_clock( cable_t *cable, int tms, int tdi, int n )
{
int i;
tms = tms ? 1 : 0;
tdi = tdi ? 1 : 0;
parport_set_data( cable->port, (1 << PROG) | (0 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
parport_set_data( cable->port, (1 << PROG) | (1 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
parport_set_data( cable->port, (1 << PROG) | (0 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
for (i = 0; i < n; i++) {
parport_set_data( cable->port, (1 << PROG) | (1 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
parport_set_data( cable->port, (1 << PROG) | (0 << TCK) | (tms << TMS) | (tdi << TDI) );
cable_wait();
}
}
static int

@ -70,13 +70,17 @@ chain_disconnect( chain_t *chain )
}
void
chain_clock( chain_t *chain, int tms, int tdi )
chain_clock( chain_t *chain, int tms, int tdi, int n )
{
int i;
if (!chain || !chain->cable)
return;
cable_clock( chain->cable, tms, tdi );
tap_state_clock( chain, tms );
cable_clock( chain->cable, tms, tdi, n );
for (i = 0; i < n; i++)
tap_state_clock( chain, tms );
}
int

@ -34,6 +34,7 @@ extern parport_driver_t ppdev_parport_driver;
#endif /* HAVE_LINUX_PPDEV_H */
#ifdef HAVE_LIBFTDI
extern parport_driver_t ftdi_parport_driver;
extern parport_driver_t ftdi_mpsse_parport_driver;
#endif /* HAVE_LIBFTDI */
#ifdef HAVE_LIBUSB
extern parport_driver_t xpcu_pp_driver;
@ -48,6 +49,7 @@ parport_driver_t *parport_drivers[] = {
#endif /* HAVE_LINUX_PPDEV_H */
#ifdef HAVE_LIBFTDI
&ftdi_parport_driver,
&ftdi_mpsse_parport_driver,
#endif /* HAVE_LIBFTDI */
#ifdef HAVE_LIBUSB
&xpcu_pp_driver,

@ -42,6 +42,7 @@
#include "cable.h"
parport_driver_t ftdi_parport_driver;
parport_driver_t ftdi_mpsse_parport_driver;
typedef struct port_node_t port_node_t;
@ -52,7 +53,8 @@ struct port_node_t {
static port_node_t *ports = NULL; /* devices */
#define OUTBUF_LEN 64
#define OUTBUF_LEN_STD 64
#define OUTBUF_LEN_MPSSE 4096
typedef struct {
char *serial;
@ -60,20 +62,21 @@ typedef struct {
unsigned int product_id;
char autoflush;
struct ftdi_context *fc;
unsigned char outcount;
int outcount;
unsigned char *outbuf;
int outbuf_len;
} ftdi_params_t;
static int ftdi_flush_output ( ftdi_params_t *p );
static parport_t *
ftdi_parport_alloc( const char *vidpid )
ftdi_parport_alloc( const char *vidpid, parport_driver_t * parport_driver, size_t outbuf_len )
{
ftdi_params_t *params = malloc( sizeof *params );
parport_t *parport = malloc( sizeof *parport );
port_node_t *node = malloc( sizeof *node );
struct ftdi_context *fc = malloc( sizeof(struct ftdi_context) );
unsigned char *outbuf = malloc( OUTBUF_LEN );
unsigned char *outbuf = malloc( outbuf_len );
if (!node || !parport || !params || !fc || !outbuf) {
free( node );
@ -85,6 +88,7 @@ ftdi_parport_alloc( const char *vidpid )
ftdi_init(fc);
params->outbuf = outbuf;
params->outbuf_len = outbuf_len;
params->outcount = 0;
params->autoflush = 0;
params->product_id = 0;
@ -104,7 +108,7 @@ ftdi_parport_alloc( const char *vidpid )
};
parport->params = params;
parport->driver = &ftdi_parport_driver;
parport->driver = parport_driver;
parport->cable = NULL;
node->port = parport;
@ -137,13 +141,12 @@ ftdi_parport_free( parport_t *port )
free( port );
}
static cable_t *
ftdi_connect( const char **par, int parnum )
static cable_driver_t *
ftdi_pre_connect( const char **par, int parnum )
{
int i;
port_node_t *pn;
parport_t *parport;
cable_t *cable;
if (parnum != 2) {
printf( _("Syntax error!\n") );
@ -173,21 +176,62 @@ ftdi_connect( const char **par, int parnum )
printf( _("Initializing %s on FTDI device %s\n"), _(cable_drivers[i]->description), par[0] );
parport = ftdi_parport_alloc( par[0] );
return cable_drivers[i];
}
static cable_t *
ftdi_std_connect( const char **par, int parnum )
{
parport_t *parport;
cable_driver_t *cable_driver;
cable_t *cable;
cable_driver = ftdi_pre_connect(par, parnum);
if (!cable_driver)
return NULL;
parport = ftdi_parport_alloc( par[0], &ftdi_parport_driver, OUTBUF_LEN_STD );
if (!parport) {
printf( _("%s(%d) Out of memory.\n"), __FILE__, __LINE__ );
return NULL;
}
cable = cable_drivers[i]->connect( cable_drivers[i], parport );
cable = cable_driver->connect( cable_driver, parport );
if (!cable)
ftdi_parport_free( parport );
return cable;
}
static cable_t *
ftdi_mpsse_connect( const char **par, int parnum )
{
parport_t *parport;
cable_driver_t *cable_driver;
cable_t *cable;
cable_driver = ftdi_pre_connect(par, parnum);
if (!cable_driver)
return NULL;
parport = ftdi_parport_alloc( par[0], &ftdi_mpsse_parport_driver, OUTBUF_LEN_MPSSE );
if (!parport) {
printf( _("%s(%d) Out of memory.\n"), __FILE__, __LINE__ );
return NULL;
}
cable = cable_driver->connect( cable_driver, parport );
if (!cable)
ftdi_parport_free( parport );
return cable;
}
static int
ftdi_open( parport_t *parport )
ftdi_generic_open( parport_t *parport )
{
int r;
ftdi_params_t *p = parport->params;
@ -203,16 +247,32 @@ ftdi_open( parport_t *parport )
if(r<0) r = ftdi_usb_open_desc(fc, 0x09FB, 0x6002, NULL, p->serial); /* Cubic Cyclonium */
if(r<0) r = ftdi_usb_open_desc(fc, 0x09FB, 0x6003, NULL, p->serial); /* NIOS II Evaluation board */
if(r<0) r = ftdi_usb_open_desc(fc, 0x16C0, 0x06AD, NULL, p->serial); /* http://www.ixo.de/info/usb_jtag/ */
if(r<0) r = ftdi_usb_open_desc(fc, 0x15BA, 0x0003, NULL, p->serial); /* Olimex ARM-USB-OCD */
};
if(r<0)
{
fprintf (stderr, "Can't open ftdi device: %s\n",
ftdi_get_error_string (fc));
ftdi_get_error_string (fc));
ftdi_deinit(fc);
return -1;
};
return 0;
}
static int
ftdi_std_open( parport_t *parport )
{
int r;
ftdi_params_t *p = parport->params;
struct ftdi_context *fc = p->fc;
r = ftdi_generic_open(parport);
if (r < 0)
return r;
(void)ftdi_disable_bitbang(fc);
if(ftdi_set_latency_timer(fc, 2)<0)
@ -249,6 +309,86 @@ ftdi_open( parport_t *parport )
return 0;
}
static int
ftdi_mpsse_open( parport_t *parport )
{
int r;
ftdi_params_t *p = parport->params;
struct ftdi_context *fc = p->fc;
r = ftdi_generic_open(parport);
if (r < 0)
return r;
/* This sequence might seem weird and containing superfluous stuff.
However, it's built after the description of JTAG_InitDevice
Ref. FTCJTAGPG10.pdf
Intermittent problems will occur when certain steps are skipped. */
if (ftdi_usb_reset(fc) < 0)
{
fprintf (stderr, "Can't reset USB: %s\n",
ftdi_get_error_string (fc));
ftdi_usb_close(fc);
ftdi_deinit(fc);
return -1;
}
if (ftdi_usb_purge_buffers(fc) < 0)
{
fprintf (stderr, "Can't purge USB buffers: %s\n",
ftdi_get_error_string (fc));
ftdi_usb_close(fc);
ftdi_deinit(fc);
return -1;
}
if (ftdi_set_bitmode(fc, 0x0b, BITMODE_RESET) < 0)
{
fprintf (stderr, "Can't reset bitmode: %s\n",
ftdi_get_error_string (fc));
ftdi_usb_close(fc);
ftdi_deinit(fc);
return -1;
};
if (ftdi_set_bitmode(fc, 0x0b, BITMODE_MPSSE) < 0)
{
fprintf (stderr, "Can't set mpsse mode: %s\n",
ftdi_get_error_string (fc));
ftdi_usb_close(fc);
ftdi_deinit(fc);
return -1;
};
if (ftdi_usb_reset(fc) < 0)
{
fprintf (stderr, "Can't reset USB: %s\n",
ftdi_get_error_string (fc));
ftdi_usb_close(fc);
ftdi_deinit(fc);
return -1;
}
if (ftdi_usb_purge_buffers(fc) < 0)
{
fprintf (stderr, "Can't purge USB buffers: %s\n",
ftdi_get_error_string (fc));
ftdi_usb_close(fc);
ftdi_deinit(fc);
return -1;
}
if(ftdi_set_latency_timer(fc, 2) < 0)
{
fprintf (stderr, "Can't set minimum latency: %s\n",
ftdi_get_error_string (fc));
ftdi_usb_close(fc);
ftdi_deinit(fc);
return -1;
};
return 0;
}
static int
ftdi_flush_output ( ftdi_params_t *p )
{
@ -289,6 +429,7 @@ ftdi_close( parport_t *parport )
if(p->outcount > 0) ftdi_flush_output( p );
p->outcount = 0;
ftdi_disable_bitbang(p->fc);
ftdi_usb_close(p->fc);
ftdi_deinit(p->fc);
@ -308,7 +449,7 @@ ftdi_set_data( parport_t *parport, uint8_t data )
{
p->outbuf[p->outcount++] = data;
if(p->outcount >= OUTBUF_LEN)
if(p->outcount >= p->outbuf_len)
return ftdi_flush_output( p );
};
@ -344,9 +485,21 @@ ftdi_set_control( parport_t *parport, uint8_t data )
parport_driver_t ftdi_parport_driver = {
"ftdi",
ftdi_connect,
ftdi_std_connect,
ftdi_parport_free,
ftdi_std_open,
ftdi_close,
ftdi_set_data,
ftdi_get_data,
ftdi_get_status,
ftdi_set_control
};
parport_driver_t ftdi_mpsse_parport_driver = {
"ftdi-mpsse",
ftdi_mpsse_connect,
ftdi_parport_free,
ftdi_open,
ftdi_mpsse_open,
ftdi_close,
ftdi_set_data,
ftdi_get_data,

@ -36,13 +36,9 @@ tap_reset( chain_t *chain )
{
tap_state_reset( chain );
chain_clock( chain, 1, 0 );
chain_clock( chain, 1, 0 );
chain_clock( chain, 1, 0 );
chain_clock( chain, 1, 0 );
chain_clock( chain, 1, 0 ); /* Test-Logic-Reset */
chain_clock( chain, 1, 0, 5 ); /* Test-Logic-Reset */
chain_clock( chain, 0, 0 ); /* Run-Test/Idle */
chain_clock( chain, 0, 0, 1 ); /* Run-Test/Idle */
}
void
@ -55,7 +51,7 @@ tap_shift_register( chain_t *chain, const tap_register *in, tap_register *out, i
/* Capture-DR, Capture-IR, Shift-DR, Shift-IR, Exit2-DR or Exit2-IR state */
if (tap_state( chain ) & TAPSTAT_CAPTURE)
chain_clock( chain, 0, 0 ); /* save last TDO bit :-) */
chain_clock( chain, 0, 0, 1 ); /* save last TDO bit :-) */
i = in->len;
if(exit) i--;
@ -69,12 +65,12 @@ tap_shift_register( chain_t *chain, const tap_register *in, tap_register *out, i
for (; i < in->len; i++) {
if (out && (i < out->len))
out->data[i] = cable_get_tdo( chain->cable );
chain_clock( chain, (exit != EXITMODE_SHIFT && ((i + 1) == in->len)) ? 1 : 0, in->data[i] ); /* Shift (& Exit1) */
chain_clock( chain, (exit != EXITMODE_SHIFT && ((i + 1) == in->len)) ? 1 : 0, in->data[i], 1 ); /* Shift (& Exit1) */
}
/* Shift-DR, Shift-IR, Exit1-DR or Exit1-IR state */
if (exit == EXITMODE_IDLE) {
chain_clock( chain, 1, 0 ); /* Update-DR or Update-IR */
chain_clock( chain, 0, 0 ); /* Run-Test/Idle */
chain_clock( chain, 1, 0, 1 ); /* Update-DR or Update-IR */
chain_clock( chain, 0, 0, 1 ); /* Run-Test/Idle */
}
}
@ -85,8 +81,8 @@ tap_capture_dr( chain_t *chain )
printf( _("%s: Invalid state: %2X\n"), "tap_capture_dr", tap_state( chain ) );
/* Run-Test/Idle or Update-DR or Update-IR state */
chain_clock( chain, 1, 0 ); /* Select-DR-Scan */
chain_clock( chain, 0, 0 ); /* Capture-DR */
chain_clock( chain, 1, 0, 1 ); /* Select-DR-Scan */
chain_clock( chain, 0, 0, 1 ); /* Capture-DR */
}
void
@ -96,7 +92,6 @@ tap_capture_ir( chain_t *chain )
printf( _("%s: Invalid state: %2X\n"), "tap_capture_ir", tap_state( chain ) );
/* Run-Test/Idle or Update-DR or Update-IR state */
chain_clock( chain, 1, 0 ); /* Select-DR-Scan */
chain_clock( chain, 1, 0 ); /* Select-IR-Scan */
chain_clock( chain, 0, 0 ); /* Capture-IR */
chain_clock( chain, 1, 0, 2 ); /* Select-DR-Scan, then Select-IR-Scan */
chain_clock( chain, 0, 0, 1 ); /* Capture-IR */
}

Loading…
Cancel
Save