rework flush implementation to benefit from queued deferred transfers

git-svn-id: https://urjtag.svn.sourceforge.net/svnroot/urjtag/trunk@995 b68d4a1b-bc3d-0410-92ed-d4ac073336b7
master
Arnim Läuger 17 years ago
parent eb0aad419b
commit 68b8bdf876

@ -1,3 +1,8 @@
2008-02-04 Arnim Laeuger <arniml@users.sourceforge.net>
* src/tap/cable/ft2232.c (ft2232_flush): rework flush implementation to benefit from
queued deferred transfers
2008-02-04 Kolja Waschk <kawk>
* configure.ac, src/tap/parport/xpcu_common.c, src/tap/parport_xpcu_pp.c,

@ -25,12 +25,14 @@
*/
#include <stdlib.h>
#include <string.h>
#include "sysdep.h"
#include "cable.h"
#include "parport.h"
#include "chain.h"
#include <cable.h>
#include <parport.h>
#include <chain.h>
#include <cmd.h>
#include "generic.h"
@ -41,10 +43,6 @@
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
@ -91,15 +89,27 @@
#define BITMASK_ARMUSBOCD_nOE (1 << BIT_ARMUSBOCD_nOE)
#ifdef LAST_TDO_CACHE
/* 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;
#endif
struct reg_desc {
struct reg_desc *next;
char *in;
char *out;
int len;
};
typedef struct reg_desc reg_desc_t;
typedef struct {
uint32_t mpsse_frequency;
/* 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 */
unsigned int last_tdo_valid;
unsigned int last_tdo;
int total_length;
reg_desc_t *transfer_chain;
} params_t;
static uint32_t mpsse_frequency;
static void
@ -107,12 +117,13 @@ update_frequency( cable_t *cable )
{
parport_t *p = cable->port;
uint32_t new_frequency = cable_get_frequency( cable );
params_t *params = (params_t *)cable->params;
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) {
if (new_frequency != params->mpsse_frequency) {
uint32_t div;
div = FT2232_MAX_TCK_FREQ / new_frequency;
@ -132,7 +143,7 @@ update_frequency( cable_t *cable )
parport_set_control( p, 1 ); // flush
parport_set_control( p, 0 ); // noflush
mpsse_frequency = FT2232_MAX_TCK_FREQ / (div + 1);
params->mpsse_frequency = FT2232_MAX_TCK_FREQ / (div + 1);
}
}
@ -141,6 +152,7 @@ static int
ft2232_generic_init( cable_t *cable )
{
parport_t *p = cable->port;
params_t *params = (params_t *)cable->params;
if (parport_open( p ))
return -1;
@ -160,11 +172,9 @@ ft2232_generic_init( cable_t *cable )
parport_set_control( p, 1 ); // flush
parport_set_control( p, 0 ); // noflush
mpsse_frequency = FT2232_MAX_TCK_FREQ;
params->mpsse_frequency = FT2232_MAX_TCK_FREQ;
#ifdef LAST_TDO_CACHE
last_tdo_valid = 0;
#endif
params->last_tdo_valid = 0;
return 0;
}
@ -173,6 +183,7 @@ static int
ft2232_jtagkey_init( cable_t *cable )
{
parport_t *p = cable->port;
params_t *params = (params_t *)cable->params;
if (parport_open( p ))
return -1;
@ -197,11 +208,9 @@ ft2232_jtagkey_init( cable_t *cable )
parport_set_control( p, 1 ); // flush
parport_set_control( p, 0 ); // noflush
mpsse_frequency = FT2232_MAX_TCK_FREQ;
params->mpsse_frequency = FT2232_MAX_TCK_FREQ;
#ifdef LAST_TDO_CACHE
last_tdo_valid = 0;
#endif
params->last_tdo_valid = 0;
return 0;
}
@ -210,6 +219,7 @@ static int
ft2232_armusbocd_init( cable_t *cable )
{
parport_t *p = cable->port;
params_t *params = (params_t *)cable->params;
if (parport_open( p ))
return -1;
@ -234,11 +244,9 @@ ft2232_armusbocd_init( cable_t *cable )
parport_set_control( p, 1 ); // flush
parport_set_control( p, 0 ); // noflush
mpsse_frequency = FT2232_MAX_TCK_FREQ;
params->mpsse_frequency = FT2232_MAX_TCK_FREQ;
#ifdef LAST_TDO_CACHE
last_tdo_valid = 0;
#endif
params->last_tdo_valid = 0;
return 0;
}
@ -309,6 +317,7 @@ static void
ft2232_clock_defer( cable_t *cable, int defer, int tms, int tdi, int n )
{
parport_t *p = cable->port;
params_t *params = (params_t *)cable->params;
tms = tms ? 0x7f : 0;
tdi = tdi ? 1 << 7 : 0;
@ -333,9 +342,7 @@ ft2232_clock_defer( cable_t *cable, int defer, int tms, int tdi, int n )
parport_set_control( p, 1 ); // flush
parport_set_control( p, 0 ); // noflush
#ifdef LAST_TDO_CACHE
last_tdo_valid = 0;
#endif
params->last_tdo_valid = 0;
}
}
@ -358,14 +365,13 @@ static int
ft2232_get_tdo_finish( cable_t *cable )
{
parport_t *p = cable->port;
params_t *params = (params_t *)cable->params;
int value;
value = ( parport_get_data( p ) & BITMASK_TDO) ? 1 : 0;
#ifdef LAST_TDO_CACHE
last_tdo = value;
last_tdo_valid = 1;
#endif
params->last_tdo = value;
params->last_tdo_valid = 1;
return value;
}
@ -391,6 +397,7 @@ static int
ft2232_transfer( cable_t *cable, int len, char *in, char *out )
{
parport_t *p = cable->port;
params_t *params = (params_t *)cable->params;
int in_offset = 0;
int out_offset = 0;
int bitwise_len;
@ -486,20 +493,17 @@ ft2232_transfer( cable_t *cable, int len, char *in, char *out )
}
}
#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
#ifdef LAST_TDO_CACHE
/* invalidate TDO cache */
last_tdo_valid = 0;
#endif
/* invalidate TDO cache */
params->last_tdo_valid = 0;
if (out) {
@ -536,57 +540,55 @@ ft2232_transfer( cable_t *cable, int len, char *in, char *out )
}
}
#ifdef LAST_TDO_CACHE
if (out) {
/* gather current TDO */
last_tdo = ( parport_get_data( p ) & BITMASK_TDO) ? 1 : 0;
last_tdo_valid = 1;
params->last_tdo = ( parport_get_data( p ) & BITMASK_TDO) ? 1 : 0;
params->last_tdo_valid = 1;
}
#endif
}
return 0;
}
#undef VERBOSE
static void
ft2232_flush( cable_t *cable )
{
params_t *params = (params_t *)cable->params;
while (cable->todo.num_items > 0)
{
int i, j, n, to_send = 0, to_rec = 0;
#ifdef LAST_TDO_CACHE
int last_tdo_valid_schedule = last_tdo_valid;
int last_tdo_valid_finish = last_tdo_valid;
#endif
int last_tdo_valid_schedule = params->last_tdo_valid;
int last_tdo_valid_finish = params->last_tdo_valid;
for ( j = i = cable->todo.next_item, n = 0; to_send < 64 && n < cable->todo.num_items; n++) {
for (j = i = cable->todo.next_item, n = 0; to_rec < 64 && n < cable->todo.num_items; n++) {
if (cable->todo.data[i].action == CABLE_TRANSFER)
break;
switch (cable->todo.data[i].action) {
case CABLE_CLOCK:
#ifdef VERBOSE
puts("clock_defer");
#endif
ft2232_clock_defer( cable, 1,
cable->todo.data[i].arg.clock.tms,
cable->todo.data[i].arg.clock.tdi,
cable->todo.data[i].arg.clock.n );
to_send += 3;
#ifdef LAST_TDO_CACHE
last_tdo_valid_schedule = 0;
#endif
break;
case CABLE_GET_TDO:
#ifdef LAST_TDO_CACHE
if (!last_tdo_valid_schedule) {
#else
{
#ifdef VERBOSE
puts("get_tdo_schedule");
#endif
ft2232_get_tdo_schedule( cable );
to_send += 1;
to_rec += 1;
#ifdef LAST_TDO_CACHE
last_tdo_valid_schedule = 1;
#endif
}
break;
@ -595,35 +597,29 @@ ft2232_flush( cable_t *cable )
}
i++;
if (i >= cable->todo.max_items) i=0;
if (i >= cable->todo.max_items)
i = 0;
}
if(to_rec > 0)
{
if (to_rec > 0) {
parport_set_control( cable->port, 1 ); // flush
parport_set_control( cable->port, 0 );
}
while (j!=i) {
while (j != i) {
switch (cable->todo.data[j].action) {
case CABLE_CLOCK:
#ifdef LAST_TDO_CACHE
last_tdo_valid_finish = 0;
#endif
break;
case CABLE_GET_TDO:
{
int tdo;
int m;
#ifdef LAST_TDO_CACHE
if (last_tdo_valid_finish)
tdo = last_tdo;
tdo = params->last_tdo;
else
tdo = ft2232_get_tdo_finish( cable );
last_tdo_valid_finish = 1;
#else
tdo = ft2232_get_tdo_finish( cable );
#endif
m = cable_add_queue_item( cable, &(cable->done) );
cable->done.data[m].action = CABLE_GET_TDO;
cable->done.data[m].arg.value.tdo = tdo;
@ -641,39 +637,168 @@ ft2232_flush( cable_t *cable )
}
j++;
if (j >= cable->todo.max_items) j=0;
cable->todo.num_items --;
if (j >= cable->todo.max_items)
j = 0;
cable->todo.num_items--;
}
while (cable->todo.num_items > 0 && cable->todo.data[i].action == CABLE_TRANSFER) {
int r = ft2232_transfer( cable,
cable->todo.data[i].arg.transfer.len,
cable->todo.data[i].arg.transfer.in,
cable->todo.data[i].arg.transfer.out);
free( cable->todo.data[i].arg.transfer.in );
if (cable->todo.data[i].arg.transfer.out != NULL) {
int m = cable_add_queue_item( cable, &(cable->done) );
if (m < 0)
printf("out of memory!!\n");
cable->done.data[m].action = CABLE_TRANSFER;
cable->done.data[m].arg.xferred.len = cable->todo.data[i].arg.transfer.len;
cable->done.data[m].arg.xferred.res = r;
cable->done.data[m].arg.xferred.out = cable->todo.data[i].arg.transfer.out;
reg_desc_t *new_reg = (reg_desc_t *)malloc( sizeof(reg_desc_t) );
reg_desc_t *r;
if (!new_reg) {
printf( _("out of memory!\n") );
break;
}
new_reg->next = NULL;
new_reg->in = cable->todo.data[i].arg.transfer.in;
new_reg->out = cable->todo.data[i].arg.transfer.out;
new_reg->len = cable->todo.data[i].arg.transfer.len;
params->total_length += cable->todo.data[i].arg.transfer.len;
if (params->transfer_chain) {
r = params->transfer_chain;
while (r->next)
r = r->next;
r->next = new_reg;
} else
params->transfer_chain = new_reg;
i++;
if (i >= cable->todo.max_items)
i = 0;
cable->todo.num_items--;
}
/* build combined in- and out-strams */
if (params->transfer_chain) {
reg_desc_t *reg = params->transfer_chain;
char *full_in = (char *)malloc( params->total_length );
char *full_out = (char *)malloc( params->total_length );
char *idx;
int do_out = 0;
int r;
if (full_in && full_out) {
/* combine all in-streams */
full_in[0] = '\0';
idx = full_in;
while (reg) {
reg_desc_t *t = reg;
memcpy( idx, reg->in, reg->len );
idx += reg->len;
if (reg->out)
do_out = 1;
reg = reg->next;
free( t );
}
/* and perform the transfer */
#ifdef VERBOSE
printf( "transfer %d %s\n", cable->todo.data[i].arg.transfer.len,
cable->todo.data[i].arg.transfer.out ? "out" : "" );
#endif
r = ft2232_transfer( cable,
params->total_length,
full_in,
do_out ? full_out : NULL );
params->transfer_chain = NULL;
params->total_length = 0;
/* copy the result of the combined transfer to the done queue */
idx = full_out;
while (j != i) {
free( cable->todo.data[j].arg.transfer.in );
if (cable->todo.data[j].arg.transfer.out != NULL) {
int m = cable_add_queue_item( cable, &(cable->done) );
if (m < 0)
printf("out of memory!\n");
memcpy( cable->todo.data[j].arg.transfer.out, idx,
cable->todo.data[j].arg.transfer.len );
cable->done.data[m].action = CABLE_TRANSFER;
cable->done.data[m].arg.xferred.len = cable->todo.data[j].arg.transfer.len;
cable->done.data[m].arg.xferred.res = r;
cable->done.data[m].arg.xferred.out = cable->todo.data[j].arg.transfer.out;
}
idx += cable->todo.data[j].arg.transfer.len;
j++;
if (j >= cable->todo.max_items)
j = 0;
}
} else
printf( _("out of memory!\n") );
if (full_in)
free( full_in );
if (full_out);
free( full_out );
}
cable->todo.next_item = i;
}
}
void
static int
ft2232_connect( char *params[], cable_t *cable )
{
params_t *cable_params = (params_t *)malloc( sizeof(params_t) );
parport_t *port;
int i;
if ( cmd_params( params ) < 3 ) {
printf( _("not enough arguments!\n") );
return 1;
}
/* search parport driver list */
for (i = 0; parport_drivers[i]; i++)
if (strcasecmp( params[1], parport_drivers[i]->type ) == 0)
break;
if (!parport_drivers[i]) {
printf( _("Unknown port driver: %s\n"), params[1] );
return 2;
}
/* set up parport driver */
port = parport_drivers[i]->connect( (const char **) &params[2],
cmd_params( params ) - 2 );
if (port == NULL) {
printf( _("Error: Cable connection failed!\n") );
return 3;
}
if (!cable_params) {
free( cable );
return 4;
}
cable_params->last_tdo_valid = 0;
cable_params->total_length = 0;
cable_params->transfer_chain = NULL;
cable->port = port;
cable->params = cable_params;
cable->chain = NULL;
return 0;
}
static void
ft2232_cable_free( cable_t *cable )
{
cable->port->driver->parport_free( cable->port );
free( cable->params );
free( cable );
}
static void
ft2232_usbcable_help( const char *cablename )
{
printf( _(
@ -689,9 +814,9 @@ ft2232_usbcable_help( const char *cablename )
cable_driver_t ft2232_cable_driver = {
"FT2232",
N_("Generic FTDI FT2232 Cable"),
generic_connect,
ft2232_connect,
generic_disconnect,
generic_cable_free,
ft2232_cable_free,
ft2232_generic_init,
ft2232_generic_done,
ft2232_clock,
@ -706,9 +831,9 @@ cable_driver_t ft2232_cable_driver = {
cable_driver_t ft2232_armusbocd_cable_driver = {
"ARM-USB-OCD",
N_("Olimex ARM-USB-OCD (FT2232) Cable"),
generic_connect,
ft2232_connect,
generic_disconnect,
generic_cable_free,
ft2232_cable_free,
ft2232_armusbocd_init,
ft2232_armusbocd_done,
ft2232_clock,
@ -716,7 +841,6 @@ cable_driver_t ft2232_armusbocd_cable_driver = {
ft2232_transfer,
ft2232_set_trst,
generic_get_trst,
// generic_flush_using_transfer,
ft2232_flush,
ft2232_usbcable_help
};
@ -724,9 +848,9 @@ cable_driver_t ft2232_armusbocd_cable_driver = {
cable_driver_t ft2232_jtagkey_cable_driver = {
"JTAGkey",
N_("Amontec JTAGkey (FT2232) Cable"),
generic_connect,
ft2232_connect,
generic_disconnect,
generic_cable_free,
ft2232_cable_free,
ft2232_jtagkey_init,
ft2232_jtagkey_done,
ft2232_clock,

Loading…
Cancel
Save