Implemented much faster access method using GPIF transfers via vendor request 0xA6.

git-svn-id: https://urjtag.svn.sourceforge.net/svnroot/urjtag/trunk@1107 b68d4a1b-bc3d-0410-92ed-d4ac073336b7
master
Kolja Waschk 17 years ago
parent d59d0422b4
commit e0b7eebb9b

@ -1,3 +1,8 @@
2008-03-01 Kolja Waschk <kawk>
* src/tap/cable/xpc.c: Implemented much faster access method using GPIF
transfers via vendor request 0xA6.
2008-02-28 Kolja Waschk <kawk>
* doc/UrJTAG.txt: Concretized list of supported USB cables.

@ -35,13 +35,54 @@
#include "usbconn.h"
#include "usbconn/libusb.h"
/* ----------------------------------------------------------------- */
#include <errno.h>
#include <string.h>
int xpcu_select_gpio(struct usb_dev_handle *xpcu, int int_or_ext )
/* Connectivity on Spartan-3E starter kit:
*
* = FX2 Port A =
*
* IOA.0 => green LED (0=off)
* IOA.1 => red LED (0=off)
* IOA.2 is tied to VCC via R25 on my board
* IOA.3 isn't connected
* IOA.4 => CPLD pin 85 (reset?)
* IOA.5 => CPLD pin 86, eventually OE?
* IOA.6 => CPLD pin 83 (reset?)
* IOA.7 => CPLD pin 49 (reset?)
*
* = FX2 Port C =
*
* probably used as GPIFADR 0..7, to CPLD
*
* = FX2 Port E =
*
* IOE.3 => CPLD TCK
* IOE.4 => CPLD TMS
* IOE.5 => CPLD TDO
* IOE.6 => CPLD TDI
*/
/* ---------------------------------------------------------------------- */
int xpcu_output_enable(struct usb_dev_handle *xpcu, int enable)
{
if(usb_control_msg(xpcu, 0x40, 0xB0, 0x0052, int_or_ext, NULL, 0, 1000)<0)
if(usb_control_msg(xpcu, 0x40, 0xB0, enable ? 0x18 : 0x10, 0, NULL, 0, 1000)<0)
{
perror("usb_control_msg(0x52.x) (select gpio)");
perror("usb_control_msg(0x10/0x18)");
return -1;
}
return 0;
}
/* ---------------------------------------------------------------------- */
int xpcu_bit_reverse(struct usb_dev_handle *xpcu, uint8_t bits_in, uint8_t *bits_out)
{
if(usb_control_msg(xpcu, 0xC0, 0xB0, 0x0020, bits_in, (char*)bits_out, 1, 1000)<0)
{
perror("usb_control_msg(0x20.x) (bit reverse)");
return -1;
}
@ -52,7 +93,7 @@ int xpcu_select_gpio(struct usb_dev_handle *xpcu, int int_or_ext )
int xpcu_request_28(struct usb_dev_handle *xpcu, int value)
{
/* Maybe clock speed setting? */
/* Typical values seen during autodetection of chain configuration: 0x11, 0x12 */
if(usb_control_msg(xpcu, 0x40, 0xB0, 0x0028, value, NULL, 0, 1000)<0)
{
@ -115,6 +156,107 @@ int xpcu_read_firmware_version(struct usb_dev_handle *xpcu, uint16_t *buf)
return 0;
}
/* ----------------------------------------------------------------- */
int xpcu_select_gpio(struct usb_dev_handle *xpcu, int int_or_ext )
{
if(usb_control_msg(xpcu, 0x40, 0xB0, 0x0052, int_or_ext, NULL, 0, 1000)<0)
{
perror("usb_control_msg(0x52.x) (select gpio)");
return -1;
}
return 0;
}
/* ---------------------------------------------------------------------- */
/* === A6 transfer (TDI/TMS/TCK/RDO) ===
*
* Vendor request 0xA6 initiates a quite universal shift operation. The data
* is passed directly to the CPLD as 16-bit words.
*
* The argument N in the request specifies the number of state changes/bits.
*
* State changes are described by the following bulk write. It consists
* of ceil(N/4) little-endian 16-bit words, each describing up to 4 changes:
*
* Care has to be taken that N is NOT a multiple of 4.
* The CPLD doesn't seem to handle that well.
*
* Bit 0: Value for first TDI to shift out.
* Bit 1: Second TDI.
* Bit 2: Third TDI.
* Bit 3: Fourth TDI.
*
* Bit 4: Value for first TMS to shift out.
* Bit 5: Second TMS.
* Bit 6: Third TMS.
* Bit 7: Fourth TMS.
*
* Bit 8: Whether to raise/lower TCK for first bit.
* Bit 9: Same for second bit.
* Bit 10: Third bit.
* Bit 11: Fourth bit.
*
* Bit 12: Whether to read TDO for first bit
* Bit 13: Same for second bit.
* Bit 14: Third bit.
* Bit 15: Fourth bit.
*
* After the bulk write, if any of the bits 12..15 was set in any word, a
* bulk_read shall follow to collect the TDO data.
*
* TDO data is shifted in from MSB. In a "full" word with 16 TDO bits, the
* earliest one reached bit 0. The earliest of 15 bits however would be bit 0,
* and if there's only one TDO bit, it arrives as the MSB of the word.
*/
static int
xpcu_shift(struct usb_dev_handle *xpcu, int reqno, int bits, int in_len, uint8_t *in, int out_len, uint8_t *out )
{
if(usb_control_msg(xpcu, 0x40, 0xB0, reqno, bits, NULL, 0, 1000)<0)
{
perror("usb_control_msg(x.x) (shift)");
return -1;
}
#if 0
printf("###\n");
printf("reqno = %02X\n", reqno);
printf("bits = %d\n", bits);
printf("in_len = %d, in_len*2 = %d\n", in_len, in_len * 2);
printf("out_len = %d, out_len*8 = %d\n", out_len, out_len * 8);
printf("a6_display(\"%02X\", \"", bits);
for(i=0;i<in_len;i++) printf("%02X%s", in[i], (i+1<in_len)?",":"");
printf("\", ");
#endif
if(usb_bulk_write(xpcu, 0x02, (char*)in, in_len, 1000)<0)
{
printf("\nusb_bulk_write error(shift): %s\n", strerror(errno));
return -1;
}
if(out_len > 0 && out != NULL)
{
if(usb_bulk_read(xpcu, 0x86, (char*)out, out_len, 1000)<0)
{
printf("\nusb_bulk_read error(shift): %s\n", strerror(errno));
return -1;
}
}
#if 0
printf("\"");
for(i=0;i<out_len;i++) printf("%02X%s", out[i], (i+1<out_len)?",":"");
printf("\")\n");
#endif
return 0;
}
/* ---------------------------------------------------------------------- */
static int
@ -189,11 +331,19 @@ static int
xpc_ext_init( cable_t *cable )
{
struct usb_dev_handle *xpcu;
uint8_t zero[2] = {0,0};
uint8_t iostate;
if (xpcu_common_init( cable )<0) return -1;
xpcu = ((libusb_param_t*)(cable->link.usb->params))->handle;
if (xpcu_request_28(xpcu, 0x11)<0)
if (xpcu_select_gpio(xpcu, 1)<0) return -1;
if (xpcu_output_enable(xpcu, 1)<0) return -1;
if (xpcu_shift(xpcu, 0xA6, 2, 2, zero, 0, NULL)<0) return -1;
if (xpcu_read_gpio(xpcu, &iostate)<0) return -1;
if (xpcu_request_28(xpcu, 0x12)<0) return -1;
return 0;
}
@ -250,6 +400,175 @@ xpc_set_trst( cable_t *cable, int trst )
return 1;
}
/* ---------------------------------------------------------------------- */
static int last_tdo;
static void
xpc_ext_clock( cable_t *cable, int tms, int tdi, int n )
{
int i;
uint8_t tdo[2];
uint8_t clock[2];
struct usb_dev_handle *xpcu;
clock[0] = (tms?0x10:0) | (tdi?0x01:0);
clock[1] = 0x11; /* clock'n read */
xpcu = ((libusb_param_t*)(cable->link.usb->params))->handle;
for(i=0;i<n;i++) xpcu_shift(xpcu, 0xA6, 1, 2, clock, 2, tdo);
last_tdo = tdo[1] ? 1:0;
}
/* ---------------------------------------------------------------------- */
static int
xpc_ext_get_tdo( cable_t *cable )
{
return last_tdo;
}
/* ---------------------------------------------------------------------- */
#define XPC_A6_CHUNKSIZE 1 /* 16-bit words */
typedef struct
{
struct usb_dev_handle *xpcu;
int in_bits;
int out_bits;
int out_done;
uint8_t *out;
uint8_t in[XPC_A6_CHUNKSIZE*2];
}
xpc_ext_transfer_state_t;
/* ---------------------------------------------------------------------- */
static int
xpcu_do_ext_transfer( xpc_ext_transfer_state_t *xts )
{
int r;
int in_len, out_len;
in_len = 2 * (xts->in_bits >> 2);
if ((xts->in_bits & 3) != 0) in_len += 2;
out_len = 2 * (xts->out_bits >> 4);
if ((xts->out_bits & 15) != 0) out_len += 2;
r = xpcu_shift (xts->xpcu, 0xA6, xts->in_bits, in_len, xts->in, out_len, xts->in);
if(r>=0 && xts->out != NULL)
{
int out_idx = 0;
int out_rem = xts->out_bits;
while (out_rem > 0)
{
uint32_t mask, rxw;
rxw = (xts->in[out_idx+1]<<8) | xts->in[out_idx];
mask = (out_rem >= 16) ? 1 : (1<<(16 - out_rem));
for(;mask <= 32768 && out_rem > 0; mask <<= 1)
{
xts->out[xts->out_done++] = (rxw & mask) ? 1 : 0;
out_rem--;
}
out_idx += 2;
}
}
xts->in_bits = 0;
xts->out_bits = 0;
return r;
}
/* ---------------------------------------------------------------------- */
static void
xpcu_add_bit_for_ext_transfer( xpc_ext_transfer_state_t *xts, char in, char is_real )
{
int bit_idx = (xts->in_bits & 3);
int buf_idx = (xts->in_bits - bit_idx) >> 1;
if(bit_idx == 0)
{
xts->in[buf_idx] = 0;
xts->in[buf_idx+1] = 0;
};
xts->in_bits++;
if(is_real)
{
if(in) xts->in[buf_idx] |= (0x01<<bit_idx);
if(xts->out)
{
xts->in[buf_idx+1] |= (0x11<<bit_idx);
xts->out_bits++;
}
else
{
xts->in[buf_idx+1] |= (0x01<<bit_idx);
}
}
}
/* ---------------------------------------------------------------------- */
static int
xpc_ext_transfer( cable_t *cable, int len, char *in, char *out )
{
int i,j;
xpc_ext_transfer_state_t xts;
#if 0
printf("---\n");
printf("transfer size %d, %s output\n", len, (out!=NULL) ? "with" : "without");
printf("tdi: ");
for(i=0;i<len;i++) printf("%c", in[i]?'1':'0');
printf("\n");
#endif
xts.xpcu = ((libusb_param_t*)(cable->link.usb->params))->handle;
xts.out = (uint8_t*)out;
xts.in_bits = 0;
xts.out_bits = 0;
xts.out_done = 0;
for(i=0,j=0; i<len && j>=0; i++)
{
xpcu_add_bit_for_ext_transfer( &xts, in[i], 1 );
if(xts.in_bits == (4*XPC_A6_CHUNKSIZE*4 - 1))
{
j = xpcu_do_ext_transfer( &xts );
}
};
if(xts.in_bits > 0 && j>=0)
{
/* CPLD doesn't like multiples of 4; add one dummy bit */
if((xts.in_bits & 3) == 0)
{
xpcu_add_bit_for_ext_transfer( &xts, 0, 0 );
}
j = xpcu_do_ext_transfer( &xts );
}
return j;
}
/* ---------------------------------------------------------------------- */
cable_driver_t xpc_int_cable_driver = {
"xpc_int",
N_("Xilinx Platform Cable USB internal chain"),
@ -285,9 +604,9 @@ cable_driver_t xpc_ext_cable_driver = {
xpc_ext_init,
generic_usbconn_done,
generic_set_frequency,
xpc_clock,
xpc_get_tdo,
generic_transfer,
xpc_ext_clock,
xpc_ext_get_tdo,
xpc_ext_transfer,
xpc_set_trst,
generic_get_trst,
generic_flush_using_transfer,

Loading…
Cancel
Save