View on GitHub


Linux USB JTAG controller for Digilent boards.

Download this project as a .zip file Download this project as a tar.gz file

Xilinx Platform Cable USB (XPCU) Documentation.

Microprocessor Cypress EZ-USB FX2LP
Hardware Accelerated Yes (Xilinx XC2C256)
Firmware Stored in Flash No. Reloaded every power on.
Firmware State Proprietary. Mostly reversed.
Firmware Path {Latest ISE path}/ISE_DS/ISE/bin/lin/xusb_emb.hex
{Latest ISE path}/ISE_DS/ISE/bin/lin/xusb_xlp.hex
Latest Firmware Version EMB: 1028 (0x0404).
XLP: 5381 (0x1705)
  1. Getting Started
  2. Interface Selection
  3. Protocol Specifications
  4. Device Specifications
  5. Trouble Shooting

Getting Started

The XPCU controller powers on with no firmware. Loading firmware will cause the device to re-enumerate as a different usb device. Checking lsusb for the idvendor and idproduct will show if the device is programmed.


Some cables may have different default values. Please report any you find.

Loading the XPCU with firmware can be done with the fxload tool. It can be used manually through the terminal, but the following udev rule will auto load the firmware every time the XPCU is plugged into the host machine.

Interface Selection

The newer XLP firmware for the Platform Cable 1 requires USB interface claiming, and Interface alternate mode selection to work. Using libusb1.0, run libusb_claim_interface(0), then libusb_set_interface_alt_setting(0, 1). Trying to send bulk commands before these steps are done will fail. Devices requiring this step can be identified with the productID of 0x0D.

UDEV Rule for auto firmware loading

Write the following lines to /etc/udev/rules.d/xusbfwu.rules and set the file permission to 644.

SUBSYSTEM=="usb", ACTION=="add", ATTR{idVendor}=="03fd", ATTR{idProduct}=="000d", MODE="666", RUN+="/sbin/fxload -v -t fx2 -I '/path/to/xusb_emb.hex' -D $tempnode"
SUBSYSTEM=="usb", ACTION=="add", ATTR{idVendor}=="03fd", ATTR{idProduct}=="0008", MODE="666"

When the device is next plugged into USB after a short delay, the led should turn green or red (depending if a JTAG target is detected). If no light turns on, the firmware is not being loaded right. If the light turns on but the device behaves oddly, see the troubleshooting section.

Protocol Specification

The USB specification requires the host to initiate all transfers. Control messages to endpoint 0 control the XPCU. Bulk transfers send jtag data for the command to use (if any).

For all jtag related USB-control messages.
bRequest 0xB0
bmRequestType OUT(To XPCU): 0x40
IN(To PC): 0xC0
wValue Command number (lower byte)
wIndex Parameter to Command
wLength Number of bytes to send in control message.
Bulk OUT Endpoint EP2
Bulk IN Endpoint EP6
Name Dir Value Index LEN Description
Device Disable O 0x10 0 0 Not required, but you should clean up.
Device Enable O 0x18 0 0 Required before the device will behave normally. Before running this command, you seem to still be able to read GPIO states, but and transfer commands will do nothing.
Reverse windex I 0x20 low byte to reverse 1 Returns the lower 8 bits of the windex value passed into it
Set JTAG Speed O 0x28 Speed 0 Specifies a speed class for the target device and changes the speed of all future JTAG transfers. Often 0x11. Bit 4 should always be set in the speed class.
Below is a table of values to send to the controller, and what speed that translates to.
Value Bitrate
0 12 MegaHertz
1 6 MegaHertz
2 3 MegaHertz
3 1.5 MegaHertz
4 750 KiloHertz
Write Single JTAG bit O 0x30 pinstates 0 This command will perform writes on either the JTAG target or the internal CPLD. Which one it targets is controlled by command 0x52.

Perform a single GPIF write to the CPLD. Format is not known for now. Full clock cycle appears appears to happen. Only the lower byte of windex is used.


Bit bang the internal CPLD's JTAG TDI/TMS/TCK lines. Only up to one transition on each line can be done per request. This means that in order to make one clock cycle for the CPLD's TAP, this message must be sent twice: once to raise TCK and another to lower it again. This makes JTAG operations on the embedded CPLD very very slow. Thus it is only used for upgrading the firmware on the CPLD.

windex.0 CPLD TDI
windex.1 CPLD TMS
windex.2 CPLD TCK

Read Single JTAG bit and Status I 0x38 0 1 This command will operate on the JTAG target or the internal CPLD's TAP. Which one it targets is controlled by command 0x52.

0 Always seems to be 1 (not verified).
1 The TDO bit of the JTAG target. Exceptions are as follow:
  • Always 1 if JTAG is disabled. Effect is immediate.
  • If checked immediately after enabling JTAG, returns 1. Check it again right after that and it will be 0 consistently.
  • If the XPCU's JTAG VCC pin is not attached to a valid source, this bit will always be 0 (net verified on the 'always' part).
6 On if the XPCU is attached to a JTAG target (JTAG VCC high).


Read the state of the TDO pin of the internal CPLD. Will return 0 or 1. No clocking is done, the read is passive.

Return Constant I 0x40 0 2 Returns 0xB503
Maybe Read Serial Number? I 0x42 0 0 Available on the XLP firmware. Returns 8 bytes of data. On XPC1, all data is 0. May be a serial number for devices that support it.
Get Version I 0x50 0,1,2,3+ 2 Returns information on version numbers of the software running on the device.
wvalueFirmware to check
0 FX2 firmware(the hex file).
1 CPLD Accelerator
2 returns 0x0400
3+ returns 0x0506
CPLD Upgrade Mode O 0x52 0: Off
1: On
0 Enabling CPLD UPGRADE MODE is only used for upgrading the internal CPLD. The XPCU controller starts with this mode disabled.

  • Normal JTAG operations disables
  • LED set to RED
  • Commands 0x30 and 0x38 now operate write/read onh the internal CPLD as a target


  • Normal JTAG operations restored
  • LED restored to normal operation
  • Single JTAG read/write commands operate on the JTAG port.

UNKNOWN O 0x68 Some count 0 The lower byte of windex is set to the address lines to the CPLD.
The upper byte is written to XGPIFSGLDATLX which triggers a GPIF transaction.
Generate Heat and clock CPLD I 0x7X seems pointless 0/1 This command is very odd. The waveform for talking to the CPLD does nothing except loop waiting for the CPLD to say it is done. windex is set as the data to write to the CPLD but the waveform never asserts data.
windex is incremented by one. Processed min is therefore 1. 0xFFFE becomes 0xFFFF, but there is a maximum enforced that keeps 0xFFFF at 0xFFFF (instead of 0x01000000). Commands runs a single GPIF waveworm if the Value is 0x70 to 0x7F (inclusive).
CPLD EXTEND pin raised.
The value of X determines a few things:
  • CPLD's TMS_LEVEL pin:
    • Lowered for 0, 1, 4, 5, 8, 9, C, D
    • Raised for 2, 3, 6, 7, A, B, E, F
  • Returns 1 byte (the wvalue low byte) if X is odd. Otherwise return nothing.
  • JPT pins to CPLD are set prior to GPIF transaction:
    • JPT=0b000 if X in range 0x08 to 0x0F
    • JPT=0b110 if X in range 0x00 to 0x07
UNKNOWN ?? 6C 88 8A 8c 8E 90 92 94 96 98 9A 9C 9E A2 A4 UNKNOWN ??? Part of a very large block of code with unknown function. No packet captures use these commands. Originally thought to be used for SPI or serial. Unknown function at this time. Appears some of these commands can trigger the same function that 0x7X messages call
Change USB Speed(?) O 0xA0 0 0 Mostly resets the XPCU, disconnects it from USB, forces full speed USB, then reconnects the XPCU to USB.
Bulk JTAG Transfer O 0xa6 0xYYZZ See description 0 Starts a transfer.
  • 24 bit number. 0xXXYYZZ where XX is upper byte of wvalue.
  • 0 indexed. 0 means 1, 1 means 2, etc.
  • JTAG information is provided in following bulk transfers.
Bulk: OUT Endpoint: 2
The data to put on the GPIO lines. The data consists of pairs of bytes (two bytes) where each four bit section is a field. Each bit of the fields line up to form key frames. Up to four (4) key frames can be specified per 2 bytes sent. Details on the order the keyframes are executed is below.

Two Byte Format: 0xABCD

A TMS Bits to put on the TMS line for each keyframe.
B TDI Bits to put on the TDI line for each keyframe.
C TDO Whether of not to read the TDO line for each keyframe.
D TCK Whether to do a full clock cycle on the TCK line for each keyframe.

Please note the following:

  • TCK specifying full cycles instead of just setting the TCK line high or low effectively doubles the transfer rate of the controller.
  • All data must come in pairs of bytes (multiples of 2 bytes).
  • Keyframes are executed least significant bit to most significant bit, starting with the first byte of the array.
  • If a number of transitions is specified in the control message that is not divisible by 4, keyframes from the last two byte group of the bulk message will be clipped starting from the most significant bit.

Example 1:

This example will move the TAP state through TEST_LOGIC_RESET and end in RUN_TEST_IDLE. Red is TMS. Yellow is TCK.

Note: For two byte sections where all four state transitions are used, the Platform cable groups those bits and pushes any fractional section off a little while later (likely because of processing delay).

Bits: 10
Data: 0x80:00:F0:0F:10:03
xpcu_GPIO_transfer(dh, 9, '\x80\x00\xF0\x0F\x10\x03')
Disection (reading each column of the numbers lined up):
TMS: 0x8, 0xf, 0x1 Bin = 1000 1111 0001
TDI: 0x0, 0x0, 0x0 (All 0 means TDI is always low. Ignoring for example.)
TDO: 0x0, 0x0, 0x0 (All 0 means read no bits. Ignoring for example.)
TXK: 0x0, 0xf, 0x3 Bin = 0000 1111 0011
Reverse each 4 bit section bin(hijk)->bin(kjih):
TMS: 1000 1111 0001 -> 0001 1111 1000
TXK: 0000 1111 0011 -> 0000 1111 1100

Example 2:

Bits: 10
Data: 0xD0:00:F0:0F:10:03
xpcu_GPIO_transfer(dh, 9, '\xD0\x00\xF0\x0F\x10\x03')

Example 3:

Bits: 10
Data: 0x00:00:F0:0F:10:03
xpcu_GPIO_transfer(dh, 9, '\x00\x00\x00\x0F\x10\x03')

Example 4:

Bits: 13
Data: 0x80:00:F0:0F:10:0B:00:01
xpcu_GPIO_transfer(dh, 12, '\x80\x00\xF0\x0F\x10\x0B\x00\x01')
Bulk: IN Endpoint: 6
This response message is returned from the Platform Cable after the transfer is completed if any read TDO bits were high in the request message. If no read TDO bits were high, this message is not returned.

The return protocol is rather complicated.

  • Initially a 16 bit little endian shift register (first bit shifts into MSB of 2nd byte).
  • After 16 bits are read, the register grows into a 32 bit little endian register.
  • After 32 bits of data are read, the next bits are put in a new shift register after the first full register, and the process starts again


This is how the 16 register is shifted, and overflows/transforms into the 32 bit register. In this case we are shifting in the number: abcdefghi where each letter is a variable representing a bit (so we can track the bits more easily).

00000000 a0000000
00000000 ba000000
00000000 cba00000
00000000 hgfedcba
a0000000 ihgfedcb
00000000 a0000000 ihgfedcb qponmlkj

The following will show the states of the return data buffer as data is shifter in. The data being read will be the following 32 bit value:

00010110 11010100 11000000 10010011

Here is the state of the return data over time as bits are shifted in.

4 bits 00:30 = 00000000 00110000
5 bits 00:98 = 00000000 10011000
8 bits 00:93 = 00000000 10010011
9 bits 80:49 = 10000000 01001001
15 bits 26:81 = 00100110 10000001
16 bits 93:c0 = 10010011 11000000
17 bits 00:80:49:60 = 00000000 10000000 01001001 01100000
24 bits 00:93:c0:d4 = 00000000 10010011 11000000 11010100
25 bits 80:49:60:6a = 10000000 01001001 01100000 01101010
32 bits 93:c0:d4:16 = 10010011 11000000 11010100 00010110
33 bits 93:c0:d4:16:00:00 = 10010011 11000000 11010100 00010110 00000000 00000000

Blink Green LED O 0x2162 0 for Stop
0x00F0 for Start
0 Available on the XLP firmware. Causes the Green LED to blink for debug or identification purposes.

Device Specifications

Basic Schematic.


If you want to check the version of firmware you have?

  printf "%d" 0x$FW_HEX_VERSION;

Green light solid after firmware load but device acting weird?

The firmware hex file for this device can be found inside the linux install of ISE. There are several files with the same name at various locations, but ignore them and use the one at {Latest ISE path}/ISE_DS/ISE/bin/lin/xusb_emb.hex. If you use the wrong file, it will either refuse to load, or appear to load but not re-enumerate properly and behave oddly despite the green light on the device lighting up.