From 03aeb3783e03d0ff3d8f7fc88e52186d3ee23531 Mon Sep 17 00:00:00 2001 From: Kolja Waschk Date: Fri, 1 Feb 2008 07:52:36 +0000 Subject: [PATCH] Merged from jtag_kawk#978: New functions to queue "deferred" JTAG activity. New code in cable drivers to flush the activity queue, both generic (for parport-based and new drivers) and optimized implementations for FT2232-based cables (by Arnim Laeuger) and USB-Blaster (by me) (#1832990) git-svn-id: https://urjtag.svn.sourceforge.net/svnroot/urjtag/trunk@979 b68d4a1b-bc3d-0410-92ed-d4ac073336b7 --- jtag/ChangeLog | 25 ++- jtag/include/cable.h | 63 ++++++- jtag/include/chain.h | 1 + jtag/src/tap/cable.c | 288 +++++++++++++++++++++++++++-- jtag/src/tap/cable/arcom.c | 7 +- jtag/src/tap/cable/byteblaster.c | 7 +- jtag/src/tap/cable/dlc5.c | 7 +- jtag/src/tap/cable/ea253.c | 7 +- jtag/src/tap/cable/ei012.c | 7 +- jtag/src/tap/cable/ft2232.c | 232 +++++++++++++++++++++-- jtag/src/tap/cable/generic.c | 276 ++++++++++++++++++++++++++- jtag/src/tap/cable/generic.h | 2 + jtag/src/tap/cable/jim.c | 1 + jtag/src/tap/cable/keithkoep.c | 7 +- jtag/src/tap/cable/lattice.c | 7 +- jtag/src/tap/cable/mpcbdm.c | 7 +- jtag/src/tap/cable/triton.c | 7 +- jtag/src/tap/cable/usbblaster.c | 147 ++++++++++++++- jtag/src/tap/cable/vision_ep9307.c | 1 + jtag/src/tap/cable/wiggler.c | 8 +- jtag/src/tap/cable/wiggler2.c | 7 +- jtag/src/tap/cable/xpc.c | 8 +- jtag/src/tap/chain.c | 14 ++ jtag/src/tap/tap.c | 41 ++-- 24 files changed, 1080 insertions(+), 97 deletions(-) diff --git a/jtag/ChangeLog b/jtag/ChangeLog index 778982f4..5e2e9e11 100644 --- a/jtag/ChangeLog +++ b/jtag/ChangeLog @@ -1,3 +1,20 @@ +2008-02-01 Kolja Waschk + + * include/cable.h, include/chain.h, src/tap/chain.c, src/tap/tap.c, + src/tap/cable/wiggler.c, src/tap/cable/arcom.c, src/tap/cable/mpcbdm.c, + src/tap/cable/usbblaster.c, src/tap/cable/generic.c, + src/tap/cable/vision_ep9307.c, src/tap/cable/ea253.c, + src/tap/cable/triton.c, src/tap/cable/jim.c, src/tap/cable/byteblaster.c, + src/tap/cable/ei012.c, src/tap/cable/generic.h, src/tap/cable/ft2232.c, + src/tap/cable/wiggler2.c, src/tap/cable/keithkoep.c, + src/tap/cable/lattice.c, src/tap/cable/dlc5.c, src/tap/cable/xpc.c, + src/tap/cable.c: New functions to queue "deferred" JTAG activity. + New code in cable drivers to flush the activity queue, both generic + (for parport-based and new drivers) and optimized implementations + for FT2232-based cables (by Arnim Laeuger) and USB-Blaster (by me). + Result is a vast speed improvement at least for FT2232; this + implements [ 1832990 ] Speed improvements for USB cables + 2008-01-30 Arnim Laeuger * src/tap/tap.c (tap_reset): set instructions of all parts to BYPASS, fix @@ -8,7 +25,7 @@ * include/jim.h, src/jim/tap.c, intel_28f800b3.c, Makefile.am, some_cpu.c: Code skeleton and alloc/free calls for actual parts - connected to JIM's some_cpu + connected to JIM's some_cpu 2008-01-24 Kolja Waschk @@ -171,9 +188,9 @@ 2007-12-29 Arnim Laeuger * data/altera/PARTS: ep2c8 added - '[ 1859032 ] jtag support for Altera EP2C8' (Hartley Sweeten) + '[ 1859032 ] jtag support for Altera EP2C8' (Hartley Sweeten) * data/Makefile.am (nobase_dist_pkgdata_DATA): ep2c8 files added - '[ 1859032 ] jtag support for Altera EP2C8' (Hartley Sweeten) + '[ 1859032 ] jtag support for Altera EP2C8' (Hartley Sweeten) 2007-12-27 Arnim Laeuger @@ -183,7 +200,7 @@ 2007-12-26 Kolja Waschk * tap/cable/vision_ep9307.c, tap/cable.c, tap/Makefile.am, configure.ac: - Integrated first modern (single-file w/o parport) cable driver + Integrated first modern (single-file w/o parport) cable driver (1858709: EP9307 target specific cable driver, from Hartley Sweeten) 2007-12-23 Kolja Waschk diff --git a/jtag/include/cable.h b/jtag/include/cable.h index dbfcdeff..32fc8594 100644 --- a/jtag/include/cable.h +++ b/jtag/include/cable.h @@ -48,28 +48,89 @@ struct cable_driver_t { int (*transfer)( cable_t *, int, char *, char * ); int (*set_trst)( cable_t *, int ); int (*get_trst)( cable_t * ); + void (*flush)( cable_t * ); void (*help)( const char * ); }; +typedef struct cable_queue_t cable_queue_t; + +struct cable_queue_t { + enum { + CABLE_CLOCK, + CABLE_GET_TDO, + CABLE_TRANSFER, + CABLE_SET_TRST, + CABLE_GET_TRST + } action; + union { + struct { + int tms; + int tdi; + int n; + } clock; + struct { + int tdo; + int trst; + int val; + } value; + struct { + int len; + char *in; + char *out; + } transfer; + struct { + int len; + int res; + char *out; + } xferred; + } arg; +}; + +typedef struct cable_queue_info_t cable_queue_info_t; + +struct cable_queue_info_t { + cable_queue_t *data; + int max_items; + int num_items; + int next_item; + int next_free; +}; + struct cable_t { cable_driver_t *driver; parport_t *port; void *params; chain_t *chain; + cable_queue_info_t todo; + cable_queue_info_t done; + uint32_t delay; + uint32_t frequency; }; void cable_free( cable_t *cable ); int cable_init( cable_t *cable ); void cable_done( cable_t *cable ); +void cable_flush( cable_t *cable ); void cable_clock( cable_t *cable, int tms, int tdi, int n ); + int cable_defer_clock( cable_t *cable, int tms, int tdi, int n ); int cable_get_tdo( cable_t *cable ); + int cable_get_tdo_late( cable_t *cable ); + int cable_defer_get_tdo( cable_t *cable ); int cable_set_trst( cable_t *cable, int trst ); + int cable_defer_set_trst( cable_t *cable, int trst ); int cable_get_trst( cable_t *cable ); + int cable_get_trst_late( cable_t *cable ); + int cable_defer_get_trst( cable_t *cable ); int cable_transfer( cable_t *cable, int len, char *in, char *out ); + int cable_transfer_late( cable_t *cable, char *out ); + int cable_defer_transfer( cable_t *cable, int len, char *in, char *out ); void cable_set_frequency( cable_t *cable, uint32_t frequency ); uint32_t cable_get_frequency( cable_t *cable ); -void cable_wait( void ); +void cable_wait( cable_t *cable ); +void cable_purge_queue( cable_queue_info_t *q, int io ); +int cable_add_queue_item( cable_t *cable, cable_queue_info_t *q ); +int cable_get_queue_item( cable_t *cable, cable_queue_info_t *q ); extern cable_driver_t *cable_drivers[]; diff --git a/jtag/include/chain.h b/jtag/include/chain.h index a835b7a1..a2ba82f4 100644 --- a/jtag/include/chain.h +++ b/jtag/include/chain.h @@ -46,6 +46,7 @@ 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, int n ); +void chain_defer_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 ); diff --git a/jtag/src/tap/cable.c b/jtag/src/tap/cable.c index 22274e81..2794f4e6 100644 --- a/jtag/src/tap/cable.c +++ b/jtag/src/tap/cable.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "fclock.h" #include "jtag.h" @@ -106,51 +107,314 @@ cable_free( cable_t *cable ) int cable_init( cable_t *cable ) { + cable->delay = 0; + cable->frequency = 0; + + cable->todo.max_items = 128; + cable->todo.num_items = 0; + cable->todo.next_item = 0; + cable->todo.next_free = 0; + cable->todo.data = malloc(cable->todo.max_items*sizeof(cable_queue_t)); + + cable->done.max_items = 128; + cable->done.num_items = 0; + cable->done.next_item = 0; + cable->done.next_free = 0; + cable->done.data = malloc(cable->done.max_items*sizeof(cable_queue_t)); + + if(cable->todo.data == NULL || cable->done.data == NULL) + { + printf(_("Failed to allocate memory for cable activity queue.\n")); + if(cable->todo.data != NULL) free(cable->todo.data); + if(cable->done.data != NULL) free(cable->done.data); + return 1; + }; + return cable->driver->init( cable ); } +void +cable_flush ( cable_t *cable ) +{ + cable->driver->flush( cable ); +} + void cable_done( cable_t *cable ) { + cable_flush( cable ); + if( cable->todo.data != NULL) + { + free( cable->todo.data ); + free( cable->done.data ); + } return cable->driver->done( cable ); } +int +cable_add_queue_item( cable_t *cable, cable_queue_info_t *q ) +{ + int i,j; + if( q->num_items >= q->max_items ) /* queue full? */ + { + /* TODO: try to alloc more space for queue */ + // printf("add_queue_item to %p: %d\n", q, -1); + return -1; /* report failure */ + } + + i = q->next_free; + j = i+1; + if( j >= q->max_items ) j = 0; + q->next_free = j; + q->num_items ++; + + // printf("add_queue_item to %p: %d\n", q, i); + return i; +} + +int +cable_get_queue_item( cable_t *cable, cable_queue_info_t *q ) +{ + if(q->num_items > 0) + { + int i = q->next_item; + int j = i+1; + if( j >= q->max_items ) j = 0; + q->next_item = j; + q->num_items --; + // printf("get_queue_item from %p: %d\n", q, i); + return i; + } + + // printf("get_queue_item from %p: %d\n", q, -1); + return -1; +} + +void +cable_purge_queue( cable_queue_info_t *q, int io ) +{ + while(q->num_items > 0) + { + int i = q->next_item; + if(q->data[i].action == CABLE_TRANSFER) + { + if(io == 0) /* todo queue */ + { + if(q->data[i].arg.transfer.in != NULL) free(q->data[i].arg.transfer.in); + if(q->data[i].arg.transfer.out != NULL) free(q->data[i].arg.transfer.out); + } + else /* done queue */ + { + if(q->data[i].arg.xferred.out != NULL) free(q->data[i].arg.xferred.out); + } + } + + i++; + if(i >= q->max_items) i = 0; + q->num_items--; + }; + + q->num_items = 0; + q->next_item = 0; + q->next_free = 0; +} + void cable_clock( cable_t *cable, int tms, int tdi, int n ) { + cable_flush( cable ); cable->driver->clock( cable, tms, tdi, n ); } +int +cable_defer_clock ( cable_t *cable, int tms, int tdi, int n ) +{ + int i = cable_add_queue_item( cable, &(cable->todo) ); + if( i < 0 ) return 1; /* report failure */ + cable->todo.data[i].action = CABLE_CLOCK; + cable->todo.data[i].arg.clock.tms = tms; + cable->todo.data[i].arg.clock.tdi = tdi; + cable->todo.data[i].arg.clock.n = n; + return 0; /* success */ +} + int cable_get_tdo( cable_t *cable ) { + cable_flush( cable ); return cable->driver->get_tdo( cable ); } +int +cable_get_tdo_late( cable_t *cable ) +{ + int i; + cable_flush( cable ); + i = cable_get_queue_item( cable, &(cable->done) ); + if( i >= 0 ) + { + if(cable->done.data[i].action != CABLE_GET_TDO) + { + printf(_("Internal error: Got wrong type of result from queue (%d? %p.%d)\n"), + cable->done.data[i].action, &(cable->done), i); + cable_purge_queue( &(cable->done), 1 ); + } + else + { + return cable->done.data[i].arg.value.tdo; + } + }; + return cable->driver->get_tdo( cable ); +} + +int +cable_defer_get_tdo( cable_t *cable ) +{ + int i = cable_add_queue_item( cable, &(cable->todo) ); + if( i < 0 ) return 1; /* report failure */ + cable->todo.data[i].action = CABLE_GET_TDO; + return 0; /* success */ +} + int cable_set_trst( cable_t *cable, int trst ) { + cable_flush( cable ); return cable->driver->set_trst( cable, trst ); } +int +cable_defer_set_trst( cable_t *cable, int trst ) +{ + int i = cable_add_queue_item( cable, &(cable->todo) ); + if( i < 0 ) return 1; /* report failure */ + cable->todo.data[i].action = CABLE_SET_TRST; + cable->todo.data[i].arg.value.trst = trst; + return 0; /* success */ +} + int cable_get_trst( cable_t *cable ) { + cable_flush( cable ); + return cable->driver->get_trst( cable ); +} + +int +cable_get_trst_late( cable_t *cable ) +{ + int i; + cable_flush( cable ); + i = cable_get_queue_item( cable, &(cable->done) ); + if( i >= 0 ) + { + if(cable->done.data[i].action != CABLE_GET_TRST) + { + printf(_("Internal error: Got wrong type of result from queue (%d? %p.%d)\n"), + cable->done.data[i].action, &(cable->done), i); + cable_purge_queue( &(cable->done), 1 ); + } + else + { + return cable->done.data[i].arg.value.trst; + } + }; return cable->driver->get_trst( cable ); } -static uint32_t delay = 0; -static uint32_t frequency = 0; +int +cable_defer_get_trst( cable_t *cable ) +{ + int i = cable_add_queue_item( cable, &(cable->todo) ); + if( i < 0 ) return 1; /* report failure */ + cable->todo.data[i].action = CABLE_GET_TRST; + return 0; /* success */ +} + +int +cable_transfer( cable_t *cable, int len, char *in, char *out ) +{ + cable_flush( cable ); + return cable->driver->transfer( cable, len, in, out ); +} + +int +cable_transfer_late( cable_t *cable, char *out ) +{ + int i; + cable_flush( cable ); + i = cable_get_queue_item( cable, &(cable->done) ); + + if( i >= 0 && cable->done.data[i].action == CABLE_TRANSFER) + { +#if 0 + printf("Got queue item (%p.%d) len=%d out=%p\n", + &(cable->done), i, + cable->done.data[i].arg.xferred.len, + cable->done.data[i].arg.xferred.out); +#endif + if(out) memcpy(out, + cable->done.data[i].arg.xferred.out, + cable->done.data[i].arg.xferred.len); + free(cable->done.data[i].arg.xferred.out); + return cable->done.data[i].arg.xferred.res; + }; + + if(cable->done.data[i].action != CABLE_TRANSFER) + { + printf(_("Internal error: Got wrong type of result from queue (#%d %p.%d)\n"), + cable->done.data[i].action, &(cable->done), i); + cable_purge_queue( &(cable->done), 1 ); + } + else + { + printf(_("Internal error: Wanted transfer result but none was queued\n")); + } + return 0; +} + +int +cable_defer_transfer( cable_t *cable, int len, char *in, char *out ) +{ + char *dbuf; + int i = cable_add_queue_item( cable, &(cable->todo) ); + if( i < 0 ) return 1; /* report failure */ + cable->todo.data[i].action = CABLE_TRANSFER; + cable->todo.data[i].arg.transfer.len = len; + + dbuf = malloc(len); + if(dbuf == NULL) return 1; /* report failure */ + if(in) memcpy(dbuf, in, len); + cable->todo.data[i].arg.transfer.in = dbuf; + + if(out) + { + dbuf = malloc(len); + if(dbuf == NULL) + { + free(cable->todo.data[i].arg.transfer.in); + return 1; /* report failure */ + } + cable->todo.data[i].arg.transfer.out = dbuf; + } + else + { + cable->todo.data[i].arg.transfer.out = NULL; + } + return 0; /* success */ +} void cable_set_frequency( cable_t *cable, uint32_t new_frequency ) { if (new_frequency == 0) { - delay = 0; - frequency = 0; + cable->delay = 0; + cable-> frequency = 0; } else { const double tolerance = 0.1; uint32_t loops; + uint32_t delay = cable->delay; + uint32_t frequency = cable->frequency; printf("requested frequency %u, now calibrating delay loop\n", new_frequency); @@ -201,29 +465,23 @@ cable_set_frequency( cable_t *cable, uint32_t new_frequency ) } } - frequency = new_frequency; + cable->delay = delay; + cable->frequency = frequency; } } uint32_t cable_get_frequency( cable_t *cable ) { - return frequency; -} - -int -cable_transfer( cable_t *cable, int len, char *in, char *out ) -{ - int r; - r=cable->driver->transfer( cable, len, in, out ); - return r; + return cable->frequency; } void -cable_wait( void ) +cable_wait( cable_t *cable ) { int i; volatile int j; + uint32_t delay = cable->delay; if (delay == 0) return; diff --git a/jtag/src/tap/cable/arcom.c b/jtag/src/tap/cable/arcom.c index 3855fb82..54b82475 100644 --- a/jtag/src/tap/cable/arcom.c +++ b/jtag/src/tap/cable/arcom.c @@ -76,9 +76,9 @@ arcom_clock( cable_t *cable, int tms, int tdi, int n ) for (i = 0; i < n; i++) { parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (0 << TCK) | (tms << TMS) | (tdi << TDI) ); - cable_wait(); + cable_wait( cable ); parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (1 << TCK) | (tms << TMS) | (tdi << TDI) ); - cable_wait(); + cable_wait( cable ); } } @@ -86,7 +86,7 @@ static int arcom_get_tdo( cable_t *cable ) { parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (0 << TCK) ); - cable_wait(); + cable_wait( cable ); return (parport_get_status( cable->port ) >> TDO) & 1; } @@ -112,5 +112,6 @@ cable_driver_t arcom_cable_driver = { generic_transfer, arcom_set_trst, generic_get_trst, + generic_flush_one_by_one, generic_lptcable_help }; diff --git a/jtag/src/tap/cable/byteblaster.c b/jtag/src/tap/cable/byteblaster.c index 0da81712..0b6f7dea 100644 --- a/jtag/src/tap/cable/byteblaster.c +++ b/jtag/src/tap/cable/byteblaster.c @@ -105,9 +105,9 @@ byteblaster_clock( cable_t *cable, int tms, int tdi, int n ) for (i = 0; i < n; i++) { parport_set_data( cable->port, (0 << TCK) | (tms << TMS) | (tdi << TDI) ); - cable_wait(); + cable_wait( cable ); parport_set_data( cable->port, (1 << TCK) | (tms << TMS) | (tdi << TDI) ); - cable_wait(); + cable_wait( cable ); } } @@ -115,7 +115,7 @@ static int byteblaster_get_tdo( cable_t *cable ) { parport_set_data( cable->port, 0 << TCK ); - cable_wait(); + cable_wait( cable ); return (parport_get_status( cable->port ) >> TDO) & 1; } @@ -138,5 +138,6 @@ cable_driver_t byteblaster_cable_driver = { generic_transfer, byteblaster_set_trst, generic_get_trst, + generic_flush_one_by_one, generic_lptcable_help }; diff --git a/jtag/src/tap/cable/dlc5.c b/jtag/src/tap/cable/dlc5.c index 25abba28..6fb224e9 100644 --- a/jtag/src/tap/cable/dlc5.c +++ b/jtag/src/tap/cable/dlc5.c @@ -76,9 +76,9 @@ dlc5_clock( cable_t *cable, int tms, int tdi, int n ) for (i = 0; i < n; i++) { parport_set_data( cable->port, (1 << PROG) | (0 << TCK) | (tms << TMS) | (tdi << TDI) ); - cable_wait(); + cable_wait( cable ); parport_set_data( cable->port, (1 << PROG) | (1 << TCK) | (tms << TMS) | (tdi << TDI) ); - cable_wait(); + cable_wait( cable ); } } @@ -86,7 +86,7 @@ static int dlc5_get_tdo( cable_t *cable ) { parport_set_data( cable->port, (1 << PROG) | (0 << TCK) ); - cable_wait(); + cable_wait( cable ); return (parport_get_status( cable->port ) >> TDO) & 1; } @@ -109,5 +109,6 @@ cable_driver_t dlc5_cable_driver = { generic_transfer, dlc5_set_trst, generic_get_trst, + generic_flush_one_by_one, generic_lptcable_help }; diff --git a/jtag/src/tap/cable/ea253.c b/jtag/src/tap/cable/ea253.c index f04010d7..36552586 100644 --- a/jtag/src/tap/cable/ea253.c +++ b/jtag/src/tap/cable/ea253.c @@ -76,9 +76,9 @@ ea253_clock( cable_t *cable, int tms, int tdi, int n ) for (i = 0; i < n; i++) { parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (0 << TCK) | (tms << TMS) | (tdi << TDI) ); - cable_wait(); + cable_wait( cable ); parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (1 << TCK) | (tms << TMS) | (tdi << TDI) ); - cable_wait(); + cable_wait( cable ); } } @@ -86,7 +86,7 @@ static int ea253_get_tdo( cable_t *cable ) { parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (0 << TCK) ); - cable_wait(); + cable_wait( cable ); return (parport_get_status( cable->port ) >> TDO) & 1; } @@ -112,5 +112,6 @@ cable_driver_t ea253_cable_driver = { generic_transfer, ea253_set_trst, generic_get_trst, + generic_flush_one_by_one, generic_lptcable_help }; diff --git a/jtag/src/tap/cable/ei012.c b/jtag/src/tap/cable/ei012.c index 8cd08d30..cc31b884 100644 --- a/jtag/src/tap/cable/ei012.c +++ b/jtag/src/tap/cable/ei012.c @@ -78,9 +78,9 @@ ei012_clock( cable_t *cable, int tms, int tdi, int n ) for (i = 0; i < n; i++) { parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (0 << TCK) | (tms << TMS) | (tdi << TDI) ); - cable_wait(); + cable_wait( cable ); parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (1 << TCK) | (tms << TMS) | (tdi << TDI) ); - cable_wait(); + cable_wait( cable ); } } @@ -88,7 +88,7 @@ static int ei012_get_tdo( cable_t *cable ) { parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (0 << TCK) ); - cable_wait(); + cable_wait( cable ); return (parport_get_status( cable->port ) >> TDO) & 1; } @@ -114,5 +114,6 @@ cable_driver_t ei012_cable_driver = { generic_transfer, ei012_set_trst, generic_get_trst, + generic_flush_one_by_one, generic_lptcable_help }; diff --git a/jtag/src/tap/cable/ft2232.c b/jtag/src/tap/cable/ft2232.c index 5fd7f380..899b206c 100644 --- a/jtag/src/tap/cable/ft2232.c +++ b/jtag/src/tap/cable/ft2232.c @@ -24,6 +24,8 @@ * */ +#include + #include "sysdep.h" #include "cable.h" @@ -93,11 +95,13 @@ #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 static uint32_t mpsse_frequency; @@ -166,7 +170,9 @@ ft2232_generic_init( cable_t *cable ) mpsse_frequency = FT2232_MAX_TCK_FREQ; +#ifdef LAST_TDO_CACHE last_tdo_valid = 0; +#endif return 0; } @@ -201,7 +207,9 @@ ft2232_jtagkey_init( cable_t *cable ) mpsse_frequency = FT2232_MAX_TCK_FREQ; +#ifdef LAST_TDO_CACHE last_tdo_valid = 0; +#endif return 0; } @@ -236,7 +244,9 @@ ft2232_armusbocd_init( cable_t *cable ) mpsse_frequency = FT2232_MAX_TCK_FREQ; +#ifdef LAST_TDO_CACHE last_tdo_valid = 0; +#endif return 0; } @@ -304,7 +314,7 @@ ft2232_armusbocd_done( cable_t *cable ) } static void -ft2232_clock( cable_t *cable, int tms, int tdi, int n ) +ft2232_clock_defer( cable_t *cable, int defer, int tms, int tdi, int n ) { parport_t *p = cable->port; @@ -327,29 +337,56 @@ ft2232_clock( cable_t *cable, int tms, int tdi, int n ) } parport_set_data( p, tdi | tms ); } - parport_set_control( p, 1 ); // flush - parport_set_control( p, 0 ); // noflush + if (!defer) { + parport_set_control( p, 1 ); // flush + parport_set_control( p, 0 ); // noflush - last_tdo_valid = 0; +#ifdef LAST_TDO_CACHE + last_tdo_valid = 0; +#endif + } +} + +static void +ft2232_clock( cable_t *cable, int tms, int tdi, int n ) +{ + ft2232_clock_defer( cable, 0, tms, tdi, n ); +} + +static void +ft2232_get_tdo_schedule( cable_t *cable ) +{ + parport_t *p = cable->port; + + /* Read Data Bits Low Byte */ + parport_set_data( p, GET_BITS_LOW ); } static int -ft2232_get_tdo( cable_t *cable ) +ft2232_get_tdo_finish( cable_t *cable ) { parport_t *p = cable->port; + int value; - 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; + value = ( parport_get_data( p ) & BITMASK_TDO) ? 1 : 0; #ifdef LAST_TDO_CACHE - last_tdo_valid = 1; + last_tdo = value; + last_tdo_valid = 1; #endif - } - return last_tdo; + + return value; +} + +static int +ft2232_get_tdo( cable_t *cable ) +{ + parport_t *p = cable->port; + + ft2232_get_tdo_schedule( cable ); + parport_set_control( p, 1 ); // flush + parport_set_control( p, 0 ); // noflush + return ft2232_get_tdo_finish( cable ); } static int @@ -369,10 +406,11 @@ ft2232_transfer( cable_t *cable, int len, char *in, char *out ) /* check for new frequency setting */ update_frequency( cable ); -#ifdef LAST_TDO_CACHE - /* invalidate TDO cache */ - last_tdo_valid = 0; -#endif + /* Set Data Bits Low Byte to lower TMS for transfer + TCK = 0, TMS = 0, TDI = 0, nOE = 0 */ + parport_set_data( p, SET_BITS_LOW ); + parport_set_data( p, 0 ); + parport_set_data( p, BITMASK_TCK | BITMASK_TDI | BITMASK_TMS | BITMASK_ARMUSBOCD_nOE ); while (len - in_offset > 0) { int byte_idx; @@ -466,6 +504,11 @@ ft2232_transfer( cable_t *cable, int len, char *in, char *out ) parport_set_control( p, 1 ); // flush parport_set_control( p, 0 ); // noflush +#ifdef LAST_TDO_CACHE + /* invalidate TDO cache */ + last_tdo_valid = 0; +#endif + if (out) { if (chunkbytes > 0) { @@ -527,6 +570,155 @@ ft2232_transfer( cable_t *cable, int len, char *in, char *out ) return 0; } +#undef FLUSH_PUTS + +static void +ft2232_flush( cable_t *cable ) +{ +#ifdef FLUSH_PUTS + puts("flush()"); +#endif + 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 + + for(j=i=cable->todo.next_item, n=0; to_send < 64 && ntodo.num_items; n++) + { + if(cable->todo.data[i].action == CABLE_TRANSFER) { +#ifdef FLUSH_PUTS + puts("transfer"); +#endif + break; + } + + switch(cable->todo.data[i].action) { + case CABLE_CLOCK: +#ifdef FLUSH_PUTS + puts("clock"); +#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 + { +#endif + ft2232_get_tdo_schedule( cable ); +#ifdef FLUSH_PUTS + puts("get_tdo"); +#endif + to_send += 1; + to_rec += 1; +#ifdef LAST_TDO_CACHE + last_tdo_valid_schedule = 1; +#endif + } + break; + + default: + break; + } + + i++; + if (i >= cable->todo.max_items) i=0; + } + + if(to_rec > 0) + { +#ifdef FLUSH_PUTS + puts("flush"); +#endif + parport_set_control( cable->port, 1 ); // flush + parport_set_control( cable->port, 0 ); + } + + 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; +#ifdef FLUSH_PUTS + puts("tdo cached"); +#endif + } 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; + break; + } + case CABLE_GET_TRST: + { + int m = cable_add_queue_item( cable, &(cable->done) ); + cable->done.data[m].action = CABLE_GET_TRST; + cable->done.data[m].arg.value.trst = 1; + break; + } + default: + break; + }; + + j++; + 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; + + }; + + i++; + if (i >= cable->todo.max_items) i=0; + cable->todo.num_items --; + }; + + cable->todo.next_item = i; + } +} + void ft2232_usbcable_help( const char *cablename ) { @@ -552,6 +744,7 @@ cable_driver_t ft2232_cable_driver = { ft2232_transfer, ft2232_set_trst, generic_get_trst, + ft2232_flush, ft2232_usbcable_help }; @@ -568,6 +761,8 @@ cable_driver_t ft2232_armusbocd_cable_driver = { ft2232_transfer, ft2232_set_trst, generic_get_trst, +// generic_flush_using_transfer, + ft2232_flush, ft2232_usbcable_help }; @@ -584,6 +779,7 @@ cable_driver_t ft2232_jtagkey_cable_driver = { ft2232_transfer, ft2232_set_trst, generic_get_trst, + ft2232_flush, ft2232_usbcable_help }; diff --git a/jtag/src/tap/cable/generic.c b/jtag/src/tap/cable/generic.c index 38c21370..ca5427f9 100644 --- a/jtag/src/tap/cable/generic.c +++ b/jtag/src/tap/cable/generic.c @@ -36,6 +36,17 @@ #include +#undef VERBOSE + +#ifdef VERBOSE +void +print_vector(int len, char *vec) +{ + int i; + for(i=0;idriver->get_tdo( cable ); + cable->driver->clock( cable, 0, in[i], 1 ); } else for(i=0; idriver->clock( cable, 0, in[i], 1 ); } return i; @@ -124,6 +135,265 @@ generic_get_trst( cable_t *cable ) return PARAM_TRST(cable); } +int +do_one_queued_action( cable_t *cable ) +{ + int i; + +#ifdef VERBOSE + printf("do_one_queued\n"); +#endif + + if ( (i = cable_get_queue_item( cable, &(cable->todo) )) >= 0 ) + { + int j; + + if( cable->done.num_items >= cable->done.max_items ) + { + if( cable->todo.data[i].action == CABLE_GET_TDO + || cable->todo.data[i].action == CABLE_GET_TRST + || cable->todo.data[i].action == CABLE_TRANSFER ) + { + printf(_("No space in cable activity results queue.\n")); + cable_purge_queue( &(cable->done), 1 ); + } + }; + + switch(cable->todo.data[i].action) + { + case CABLE_CLOCK: + cable->driver->clock( cable, + cable->todo.data[i].arg.clock.tms, + cable->todo.data[i].arg.clock.tdi, + cable->todo.data[i].arg.clock.n ); + break; + case CABLE_SET_TRST: + cable_set_trst( cable, + cable->todo.data[i].arg.value.trst ); + break; + case CABLE_TRANSFER: + { + int r = cable->driver->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) + { + j = cable_add_queue_item( cable, &(cable->done) ); +#ifdef VERBOSE + printf("add result from transfer to %p.%d (out=%p)\n", &(cable->done), j, cable->todo.data[i].arg.transfer.out); +#endif + cable->done.data[j].action = CABLE_TRANSFER; + cable->done.data[j].arg.xferred.len = cable->todo.data[i].arg.transfer.len; + cable->done.data[j].arg.xferred.res = r; + cable->done.data[j].arg.xferred.out = cable->todo.data[i].arg.transfer.out; + }; + break; + }; + case CABLE_GET_TDO: + j = cable_add_queue_item( cable, &(cable->done) ); +#ifdef VERBOSE + printf("add result from get_tdo to %p.%d\n", &(cable->done), j); +#endif + cable->done.data[j].action = CABLE_GET_TDO; + cable->done.data[j].arg.value.tdo = + cable->driver->get_tdo( cable ); + break; + case CABLE_GET_TRST: + j = cable_add_queue_item( cable, &(cable->done) ); +#ifdef VERBOSE + printf("add result from get_trst to %p.%d\n", &(cable->done), j); +#endif + cable->done.data[j].action = CABLE_GET_TRST; + cable->done.data[j].arg.value.trst = + cable->driver->get_trst( cable ); + break; + }; +#ifdef VERBOSE + printf("do_one_queued done\n"); +#endif + + return 1; + } +#ifdef VERBOSE + printf("do_one_queued abort\n"); +#endif + + return 0; +} + +void +generic_flush_one_by_one( cable_t *cable ) +{ + while( do_one_queued_action( cable ) ); +} + +void +generic_flush_using_transfer( cable_t *cable ) +{ + int i, j, n; + char *in, *out; + + if(cable->todo.num_items == 0) return; + + do + { + int r, bits = 0, tdo; + +#ifdef VERBOSE + printf("flush(%d)\n", cable->todo.num_items); +#endif + + /* Combine as much as possible into transfer() */ + + /* Step 1: Count clocks. Can do only clock(TMS=0), get_tdo, transfer */ + + for(i = cable->todo.next_item, n=0; n < cable->todo.num_items; n++) + { + if(cable->todo.data[i].action != CABLE_CLOCK + && cable->todo.data[i].action != CABLE_TRANSFER + && cable->todo.data[i].action != CABLE_GET_TDO) + { +#ifdef VERBOSE + printf("cutoff at n=%d because action unsuitable for transfer\n", n); +#endif + break; + } + if(cable->todo.data[i].action == CABLE_CLOCK + && cable->todo.data[i].arg.clock.tms != 0) + { +#ifdef VERBOSE + printf("cutoff at n=%d because clock.tms=1 is unsuitable for transfer\n", n); +#endif + break; + } + if(cable->todo.data[i].action == CABLE_CLOCK) + { + int k = cable->todo.data[i].arg.clock.n; +#ifdef VERBOSE + printf("%d clock(s)\n", k); +#endif + bits += k; + } + else if(cable->todo.data[i].action == CABLE_TRANSFER) + { + int k = cable->todo.data[i].arg.transfer.len; +#ifdef VERBOSE + printf("%d transfer\n", k); +#endif + bits += k; + } + i++; + if(i >= cable->todo.max_items) i = 0; + }; + +#ifdef VERBOSE + printf("%d combined into one (%d bits)\n", n, bits); +#endif + + if(bits == 0 || n <= 1) + { + do_one_queued_action( cable ); + } + else + { + /* Step 2: Combine into single transfer. */ + + in = malloc(bits); + out = malloc(bits); + + if(in == NULL || out == NULL) + { + if(in != NULL) free(in); + if(out != NULL) free(out); + generic_flush_one_by_one( cable ); + break; + }; + + for(j=0, bits=0, i=cable->todo.next_item; jtodo.data[i].action == CABLE_CLOCK) + { + int k; + for(k=0;ktodo.data[i].arg.clock.n;k++) + in[bits++] = cable->todo.data[i].arg.clock.tdi; + } + else if(cable->todo.data[i].action == CABLE_TRANSFER) + { + int len = cable->todo.data[i].arg.transfer.len; + if(len>0) + { + memcpy(in+bits, cable->todo.data[i].arg.transfer.in, len); + bits += len; + }; + }; + i++; + if(i >= cable->todo.max_items) i = 0; + }; + + /* Step 3: Do the transfer */ + + r = cable->driver->transfer( cable, bits, in, out ); +#ifdef VERBOSE + printf("in: "); print_vector(bits,in); printf("\n"); + if(out) { printf("out: "); print_vector(bits,out); printf("\n"); }; +#endif + + /* Step 4: Pick results from transfer */ + + for(j=0, bits=0, i=cable->todo.next_item; jtodo.data[i].action == CABLE_CLOCK) + { + int k; + for(k=0;ktodo.data[i].arg.clock.n;k++) + tdo = out[bits++]; + } + else if(cable->todo.data[i].action == CABLE_GET_TDO) + { + int c = cable_add_queue_item( cable, &(cable->done) ); +#ifdef VERBOSE + printf("add result from transfer to %p.%d\n", &(cable->done), c); +#endif + cable->done.data[c].action = CABLE_GET_TDO; + cable->done.data[c].arg.value.tdo = tdo; + } + else if(cable->todo.data[i].action == CABLE_TRANSFER) + { + char *p = cable->todo.data[i].arg.transfer.out; + int len = cable->todo.data[i].arg.transfer.len; + free(cable->todo.data[i].arg.transfer.in); + if(p != NULL) + { + int c = cable_add_queue_item( cable, &(cable->done) ); +#ifdef VERBOSE + printf("add result from transfer to %p.%d\n", &(cable->done), c); +#endif + cable->done.data[c].action = CABLE_TRANSFER; + cable->done.data[c].arg.xferred.len = len; + cable->done.data[c].arg.xferred.res = r; + cable->done.data[c].arg.xferred.out = p; + if(len > 0) memcpy(p, out+bits, len); + } + if(len>0) bits += len; + if(bits>0) tdo = out[bits-1]; + }; + i++; + if(i >= cable->todo.max_items) i = 0; + } + + cable->todo.next_item = i; + cable->todo.num_items -= n; + + free(in); + free(out); + } + } + while(cable->todo.num_items > 0); +} + void generic_lptcable_help( const char *cablename ) { diff --git a/jtag/src/tap/cable/generic.h b/jtag/src/tap/cable/generic.h index 04343352..44e4d227 100644 --- a/jtag/src/tap/cable/generic.h +++ b/jtag/src/tap/cable/generic.h @@ -42,6 +42,8 @@ void generic_cable_free( cable_t *cable ); void generic_done( cable_t *cable ); int generic_transfer( cable_t *cable, int len, char *in, char *out ); int generic_get_trst( cable_t *cable ); +void generic_flush_one_by_one( cable_t *cable ); +void generic_flush_using_transfer( cable_t *cable ); void generic_lptcable_help( const char *name ); #endif /* GENERIC_H */ diff --git a/jtag/src/tap/cable/jim.c b/jtag/src/tap/cable/jim.c index a65e92d3..76216b51 100644 --- a/jtag/src/tap/cable/jim.c +++ b/jtag/src/tap/cable/jim.c @@ -171,6 +171,7 @@ cable_driver_t jim_cable_driver = { generic_transfer, jim_cable_set_trst, jim_cable_get_trst, + generic_flush_using_transfer, jim_cable_help }; diff --git a/jtag/src/tap/cable/keithkoep.c b/jtag/src/tap/cable/keithkoep.c index 3c91e03c..90028409 100644 --- a/jtag/src/tap/cable/keithkoep.c +++ b/jtag/src/tap/cable/keithkoep.c @@ -85,9 +85,9 @@ keithkoep_clock( cable_t *cable, int tms, int tdi, int n ) for (i = 0; i < n; i++) { parport_set_data( cable->port, (0 << TCK) | (tms << TMS) | (tdi << TDI) ); - cable_wait(); + cable_wait( cable ); parport_set_data( cable->port, (1 << TCK) | (tms << TMS) | (tdi << TDI) ); - cable_wait(); + cable_wait( cable ); } } @@ -95,7 +95,7 @@ static int keithkoep_get_tdo( cable_t *cable ) { parport_set_data( cable->port, 0 << TCK ); - cable_wait(); + cable_wait( cable ); return (parport_get_status( cable->port ) >> TDO) & 1; } @@ -121,5 +121,6 @@ cable_driver_t keithkoep_cable_driver = { generic_transfer, keithkoep_set_trst, generic_get_trst, + generic_flush_one_by_one, generic_lptcable_help }; diff --git a/jtag/src/tap/cable/lattice.c b/jtag/src/tap/cable/lattice.c index 92916afd..e99ed371 100644 --- a/jtag/src/tap/cable/lattice.c +++ b/jtag/src/tap/cable/lattice.c @@ -71,9 +71,9 @@ lattice_clock( cable_t *cable, int tms, int tdi, int n ) for (i = 0; i < n; i++) { parport_set_data( cable->port, (0 << TCK) | (tms << TMS) | (tdi << TDI) | (1 << TRST) ); - cable_wait(); + cable_wait( cable ); parport_set_data( cable->port, (1 << TCK) | (tms << TMS) | (tdi << TDI) | (1 << TRST) ); - cable_wait(); + cable_wait( cable ); } } @@ -81,7 +81,7 @@ static int lattice_get_tdo( cable_t *cable ) { parport_set_data( cable->port, (0 << TCK) | (1 << TRST) ); - cable_wait(); + cable_wait( cable ); return (parport_get_status( cable->port ) >> TDO) & 1; } @@ -104,5 +104,6 @@ cable_driver_t lattice_cable_driver = { generic_transfer, lattice_set_trst, generic_get_trst, + generic_flush_one_by_one, generic_lptcable_help }; diff --git a/jtag/src/tap/cable/mpcbdm.c b/jtag/src/tap/cable/mpcbdm.c index 8d56f773..e115e78a 100644 --- a/jtag/src/tap/cable/mpcbdm.c +++ b/jtag/src/tap/cable/mpcbdm.c @@ -82,9 +82,9 @@ mpcbdm_clock( cable_t *cable, int tms, int tdi, int n ) for (i = 0; i < n; i++) { parport_set_data( cable->port, (0 << TCK) | (tms << TMS) | (tdi << TDI) ); - cable_wait(); + cable_wait( cable ); parport_set_data( cable->port, (1 << TCK) | (tms << TMS) | (tdi << TDI) ); - cable_wait(); + cable_wait( cable ); } } @@ -92,7 +92,7 @@ static int mpcbdm_get_tdo( cable_t *cable ) { parport_set_data( cable->port, 0 << TCK ); - cable_wait(); + cable_wait( cable ); return (parport_get_status( cable->port ) >> TDO) & 1; } @@ -118,5 +118,6 @@ cable_driver_t mpcbdm_cable_driver = { generic_transfer, mpcbdm_set_trst, generic_get_trst, + generic_flush_one_by_one, generic_lptcable_help }; diff --git a/jtag/src/tap/cable/triton.c b/jtag/src/tap/cable/triton.c index 976a0419..a197fade 100644 --- a/jtag/src/tap/cable/triton.c +++ b/jtag/src/tap/cable/triton.c @@ -87,9 +87,9 @@ triton_clock( cable_t *cable, int tms, int tdi, int n ) 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(); + cable_wait( cable ); parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (PARAM_SRESET(cable) << SRESET) | (1 << TCK) | (tms << TMS) | (tdi << TDI) ); - cable_wait(); + cable_wait( cable ); } } @@ -97,7 +97,7 @@ static int triton_get_tdo( cable_t *cable ) { parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (PARAM_SRESET(cable) << SRESET) | (0 << TCK) ); - cable_wait(); + cable_wait( cable ); return (parport_get_status( cable->port ) >> TDO) & 1; } @@ -123,5 +123,6 @@ cable_driver_t triton_cable_driver = { generic_transfer, triton_set_trst, generic_get_trst, + generic_flush_one_by_one, generic_lptcable_help }; diff --git a/jtag/src/tap/cable/usbblaster.c b/jtag/src/tap/cable/usbblaster.c index a95d060b..d865d7ee 100644 --- a/jtag/src/tap/cable/usbblaster.c +++ b/jtag/src/tap/cable/usbblaster.c @@ -25,6 +25,8 @@ #include "sysdep.h" +#include + #include "cable.h" #include "parport.h" #include "chain.h" @@ -62,12 +64,14 @@ usbblaster_clock( cable_t *cable, int tms, int tdi, int n ) { int i; - tms = tms ? 1 : 0; - tdi = tdi ? 1 : 0; + tms = tms ? (1<port, OTHERS | (0 << TCK) | (tms << TMS) | (tdi << TDI) ); - parport_set_data( cable->port, OTHERS | (1 << TCK) | (tms << TMS) | (tdi << TDI) ); + parport_set_data( cable->port, OTHERS | (0 << TCK) | tms | tdi ); + parport_set_data( cable->port, OTHERS | (1 << TCK) | tms | tdi ); parport_set_control( cable->port, 1 ); // flush parport_set_control( cable->port, 0 ); // noflush } @@ -106,6 +110,15 @@ usbblaster_transfer( cable_t *cable, int len, char *in, char *out ) parport_set_control( cable->port, 0 ); parport_set_data( cable->port, OTHERS ); /* TCK low */ +#if 0 + { + int o; + printf("%d in: ", len); + for(o=0;o= 8) { int i; @@ -158,11 +171,134 @@ usbblaster_transfer( cable_t *cable, int len, char *in, char *out ) while(len > out_offset) out[out_offset++] = ( parport_get_data( cable->port ) & (1 << TDO)) ? 1 : 0; + +#if 0 + { + int o; + printf("%d out: ", len); + for(o=0;otodo.num_items > 0) + { + int i, j, n, to_send = 0; + + for(j=i=cable->todo.next_item, n=0; to_send < 64 && ntodo.num_items; n++) + { + if(cable->todo.data[i].action == CABLE_TRANSFER) break; + + switch(cable->todo.data[i].action) + { + case CABLE_CLOCK: + { + int tms = cable->todo.data[i].arg.clock.tms ? (1<todo.data[i].arg.clock.tdi ? (1<todo.data[i].arg.clock.n; + // printf("clock: %d %d %d\n", tms, tdi, m); + for(; m>0; m--) + { + parport_set_data( cable->port, OTHERS | tms | tdi ); + parport_set_data( cable->port, OTHERS | (1 << TCK) | tms | tdi ); + to_send += 2; + } + break; + } + case CABLE_GET_TDO: + { + parport_set_data( cable->port, OTHERS ); /* TCK low */ + parport_set_data( cable->port, OTHERS | (1 << READ) ); /* TCK low */ + // printf("get_tdo\n"); + to_send += 2; + break; + } + default: + break; + }; + + i++; + if (i >= cable->todo.max_items) i=0; + }; + +#if 0 + if(cable->todo.num_items > 0 && cable->todo.data[i].action == CABLE_TRANSFER) + { + parport_set_data( cable->port, OTHERS ); /* TCK low */ + }; +#endif + + if(to_send > 0) + { + parport_set_control( cable->port, 1 ); // flush + parport_set_control( cable->port, 0 ); + } + + while(j!=i) + { + switch(cable->todo.data[j].action) + { + case CABLE_GET_TDO: + { + int tdo = (parport_get_data( cable->port ) & (1<done) ); + cable->done.data[m].action = CABLE_GET_TDO; + cable->done.data[m].arg.value.tdo = tdo; + break; + } + case CABLE_GET_TRST: + { + int m = cable_add_queue_item( cable, &(cable->done) ); + cable->done.data[m].action = CABLE_GET_TRST; + cable->done.data[m].arg.value.trst = 1; + break; + } + default: + break; + }; + + j++; + 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 = usbblaster_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; + + }; + + i++; + if (i >= cable->todo.max_items) i=0; + cable->todo.num_items --; + }; + + cable->todo.next_item = i; + } +} + + void usbblaster_help( const char *cablename ) { @@ -188,5 +324,8 @@ cable_driver_t usbblaster_cable_driver = { usbblaster_transfer, usbblaster_set_trst, generic_get_trst, +// generic_flush_one_by_one, +// generic_flush_using_transfer, + usbblaster_flush, usbblaster_help, }; diff --git a/jtag/src/tap/cable/vision_ep9307.c b/jtag/src/tap/cable/vision_ep9307.c index 84aa5bfe..50d99eeb 100644 --- a/jtag/src/tap/cable/vision_ep9307.c +++ b/jtag/src/tap/cable/vision_ep9307.c @@ -319,5 +319,6 @@ cable_driver_t ep9307_cable_driver = { generic_transfer, ep9307_set_trst, ep9307_get_trst, + generic_flush_one_by_one, ep9307_help }; diff --git a/jtag/src/tap/cable/wiggler.c b/jtag/src/tap/cable/wiggler.c index 75711f12..f03bff74 100644 --- a/jtag/src/tap/cable/wiggler.c +++ b/jtag/src/tap/cable/wiggler.c @@ -245,13 +245,13 @@ wiggler_clock( cable_t *cable, int tms, int tdi, int n ) (tms ? PRM_TMS_ACT(cable) : PRM_TMS_INACT(cable)) | (tdi ? PRM_TDI_ACT(cable) : PRM_TDI_INACT(cable)) | PRM_UNUSED_BITS(cable) ); - cable_wait(); + cable_wait( cable ); parport_set_data( cable->port, PRM_TRST_LVL(cable) | PRM_TCK_ACT(cable) | (tms ? PRM_TMS_ACT(cable) : PRM_TMS_INACT(cable)) | (tdi ? PRM_TDI_ACT(cable) : PRM_TDI_INACT(cable)) | PRM_UNUSED_BITS(cable) ); - cable_wait(); + cable_wait( cable ); } } @@ -261,7 +261,7 @@ wiggler_get_tdo( cable_t *cable ) parport_set_data( cable->port, PRM_TRST_LVL(cable) | PRM_TCK_INACT(cable) | PRM_UNUSED_BITS(cable) ); - cable_wait(); + cable_wait( cable ); return (parport_get_status( cable->port ) & (PRM_TDO_ACT(cable) | PRM_TDO_INACT(cable))) ^ PRM_TDO_ACT(cable) ? 0 : 1; } @@ -329,6 +329,7 @@ cable_driver_t wiggler_cable_driver = { generic_transfer, wiggler_set_trst, wiggler_get_trst, + generic_flush_one_by_one, wiggler_help }; @@ -345,6 +346,7 @@ cable_driver_t igloo_cable_driver = { generic_transfer, wiggler_set_trst, wiggler_get_trst, + generic_flush_one_by_one, wiggler_help }; diff --git a/jtag/src/tap/cable/wiggler2.c b/jtag/src/tap/cable/wiggler2.c index c62efc8a..16d0a81e 100644 --- a/jtag/src/tap/cable/wiggler2.c +++ b/jtag/src/tap/cable/wiggler2.c @@ -92,9 +92,9 @@ wiggler2_clock( cable_t *cable, int tms, int tdi, int n ) 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(); + cable_wait( cable ); parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (1 << TCK) | (tms << TMS) | (tdi << TDI) | UNUSED_BITS ); - cable_wait(); + cable_wait( cable ); } } @@ -102,7 +102,7 @@ static int wiggler2_get_tdo( cable_t *cable ) { parport_set_data( cable->port, (PARAM_TRST(cable) << TRST) | (0 << TCK) | UNUSED_BITS ); - cable_wait(); + cable_wait( cable ); return (parport_get_status( cable->port ) >> TDO) & 1; } @@ -128,5 +128,6 @@ cable_driver_t wiggler2_cable_driver = { generic_transfer, wiggler2_set_trst, generic_get_trst, + generic_flush_one_by_one, generic_lptcable_help }; diff --git a/jtag/src/tap/cable/xpc.c b/jtag/src/tap/cable/xpc.c index dff0f142..6cef10e9 100644 --- a/jtag/src/tap/cable/xpc.c +++ b/jtag/src/tap/cable/xpc.c @@ -73,12 +73,12 @@ xpc_clock( cable_t *cable, int tms, int tdi, int n ) tdi = tdi ? 1 : 0; parport_set_data( cable->port, (1 << PROG) | (0 << TCK) | (tms << TMS) | (tdi << TDI) ); - cable_wait(); + cable_wait( cable ); for (i = 0; i < n; i++) { parport_set_data( cable->port, (1 << PROG) | (1 << TCK) | (tms << TMS) | (tdi << TDI) ); - cable_wait(); + cable_wait( cable ); parport_set_data( cable->port, (1 << PROG) | (0 << TCK) | (tms << TMS) | (tdi << TDI) ); - cable_wait(); + cable_wait( cable ); } } @@ -119,6 +119,7 @@ cable_driver_t xpc_int_cable_driver = { generic_transfer, xpc_set_trst, generic_get_trst, + generic_flush_using_transfer, xpcu_usbcable_help }; @@ -135,6 +136,7 @@ cable_driver_t xpc_ext_cable_driver = { generic_transfer, xpc_set_trst, generic_get_trst, + generic_flush_using_transfer, xpcu_usbcable_help }; diff --git a/jtag/src/tap/chain.c b/jtag/src/tap/chain.c index c54371e3..14ca1173 100644 --- a/jtag/src/tap/chain.c +++ b/jtag/src/tap/chain.c @@ -83,6 +83,20 @@ chain_clock( chain_t *chain, int tms, int tdi, int n ) tap_state_clock( chain, tms ); } +void +chain_defer_clock( chain_t *chain, int tms, int tdi, int n ) +{ + int i; + + if (!chain || !chain->cable) + return; + + cable_defer_clock( chain->cable, tms, tdi, n ); + + for (i = 0; i < n; i++) + tap_state_clock( chain, tms ); +} + int chain_set_trst( chain_t *chain, int trst ) { diff --git a/jtag/src/tap/tap.c b/jtag/src/tap/tap.c index 1e497339..9e88d94c 100644 --- a/jtag/src/tap/tap.c +++ b/jtag/src/tap/tap.c @@ -36,9 +36,8 @@ tap_reset( chain_t *chain ) { tap_state_reset( chain ); - chain_clock( chain, 1, 0, 5 ); /* Test-Logic-Reset */ - - chain_clock( chain, 0, 0, 1 ); /* Run-Test/Idle */ + chain_defer_clock( chain, 1, 0, 5 ); /* Test-Logic-Reset */ + chain_defer_clock( chain, 0, 0, 1 ); /* Run-Test/Idle */ parts_set_instruction( chain->parts, "BYPASS" ); } @@ -46,33 +45,43 @@ tap_reset( chain_t *chain ) void tap_shift_register( chain_t *chain, const tap_register *in, tap_register *out, int exit ) { - int i; + int i,j; if (!(tap_state( chain ) & TAPSTAT_SHIFT)) printf( _("%s: Invalid state: %2X\n"), "tap_shift_register", tap_state( chain ) ); /* 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, 1 ); /* save last TDO bit :-) */ + chain_defer_clock( chain, 0, 0, 1 ); /* save last TDO bit :-) */ i = in->len; if(exit) i--; if(out && out->len < i) i = out->len; if(out) - cable_transfer( chain->cable, i, in->data, out->data ); + cable_defer_transfer( chain->cable, i, in->data, out->data ); else - cable_transfer( chain->cable, i, in->data, NULL ); + cable_defer_transfer( chain->cable, i, in->data, NULL ); + j = 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], 1 ); /* Shift (& Exit1) */ + if (out != NULL && (i < out->len)) + out->data[i] = cable_defer_get_tdo( chain->cable ); + chain_defer_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, 1 ); /* Update-DR or Update-IR */ - chain_clock( chain, 0, 0, 1 ); /* Run-Test/Idle */ + chain_defer_clock( chain, 1, 0, 1 ); /* Update-DR or Update-IR */ + chain_defer_clock( chain, 0, 0, 1 ); /* Run-Test/Idle */ + } + + if(out != NULL) + { + /* Asking for the result of the cable transfer actually flushes the queue */ + (void)cable_transfer_late( chain->cable, out->data ); + for (; j < in->len && j < out->len; j++) + out->data[j] = cable_get_tdo_late( chain->cable ); } } @@ -83,8 +92,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, 1 ); /* Select-DR-Scan */ - chain_clock( chain, 0, 0, 1 ); /* Capture-DR */ + chain_defer_clock( chain, 1, 0, 1 ); /* Select-DR-Scan */ + chain_defer_clock( chain, 0, 0, 1 ); /* Capture-DR */ } void @@ -94,6 +103,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, 2 ); /* Select-DR-Scan, then Select-IR-Scan */ - chain_clock( chain, 0, 0, 1 ); /* Capture-IR */ + chain_defer_clock( chain, 1, 0, 2 ); /* Select-DR-Scan, then Select-IR-Scan */ + chain_defer_clock( chain, 0, 0, 1 ); /* Capture-IR */ }