View on GitHub

Adapt

Linux USB JTAG controller for Digilent boards.

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

Protocol documentation for Digilent USB JTAG controllers.

The Digilent Adept USB protocol is found in many development boards and programming cables made by Digilent. The protocol supports SPI, JTAG, etc, and Controllers build into development boards often support additional features like reading sensor values.

Digilent's API abstracts out their controllers and allows users to transparently speak any supported protocol through their branded controllers. Adapt's goal is similar, but with many more controllers, so adding digilent support will open up many controllers.

Protocol Description:


There are two major types of USB message used in the Digilent Adept protocol: Control and Bulk. Control messages read or write information about the controller itself. Bulk messages are primarily used to instruct the controller to send data out to the connected target.

Control Messages

Messages to query or set fields in the controller. bRequestType field depends on direction (OUT=0x40; IN=0xC0). All unspecified USB message fields are 0.

Name RQ* Direction* Length Description
Product Name E1 IN 28 ASCII
User Name E2 IN 16 ASCII
Serial Number E4 IN 12 ASCII
Firmware Version E6 IN 2 or 4 RAW BYTES Little Endian.
Device Capabilities E7 IN 8 Bitflag showing features supported by the board.
Its use is a bit inconsistent:
  • Controllers with no firmware usually report their supported features.
  • Some flashable controllers report their possible features.
  • Some flashable controllers report the feature set of their current firmware (default 0).
Bitfield meaning in DCAP Enum
Set OEM Seed E8 OUT 2 Sets a seed that determines the data returned by the 0xEC request.
See the Description of OEM Verify
Product ID E9 IN 4 The product ID is not consistently handled. Sometimes a controller will always report its product id, sometimes it will only report the product id after being flashed with firmware. Sometimes the product id is used to determine what firmware to flash the controller with, if any.
OEM ID CHECK EC IN 4 Returns a value based on the OEM SEED (0xE8) request. A check that digilent drivers do to ensure the controller is running official firmware. Unnecessary to call in open drivers.
Example implementation (python):
seed = {Seed from 0xEC cmd}
key = (seed & 0xFF) ^ ((seed>>8) & 0xFF)
"".join([chr(ord(c) ^ key) for c in 'igiD'])
See the Description of OEM Verify

Terms:
(RQ is Request Code)
USB message direction: IN=to computer; OUT=to device

Bulk Requests


Most bulk messages cause electrical activity on the controller's output pins.

Initial Request Message Format:

All bulk requests start with the same Initial Request and end with a Response Code from the device. Some requests transfer additional data in between the initial request and the response code, and are described below.

Initial Request messages are sent to USB endpoint (1). The endpoints for reading response codes and sending/receiving addtional data depends on the device, and is detailed in the Known Device Table.

AVD Response protocol:
SZ:CT:RQ:00:{Parameters to the request if any}

Where
SZ: Length of bulk packet minus 1.
CT: Category or request. Category 0x02 appears to be JTAG.
RQ: Request Code

Full Message Sequence:

BULK IN (USB ENDPOINT 2) 01:XX #Status code. 1 byte long. 00 known to be 'good'. 03 is a fail of some kind (when the device is already in use).

  1. Initialization message (In table below).
  2. Status Code message (described above).
  3. YY* Raw bit data rounded to the byte. XX bits. USB Endpoint 3.
  4. YY* Raw bit data rounded to the byte. XX bits. USB Endpoint 4. Only sent if RV in init message is 1.
  5. 03:02:ZZ:00 to USB Endpoint 1. ZZ = 80|RQ. RQ is the RQ of the init message. Requests number of bits transferred.
  6. SZ:FL:(XX:XX:XX:XX)* SZ = bitcount(FL)*4 + 1. FL is a bit field for 0x80 and 0x40. 0x80 requests for the number of bits sent. 0x40 Requests for the number of bits received. For each flag there is a 4 byte number for the number of bits.
Bulk JTAG Control Request Commands:
Name CT RQ Transaction Type SZ Parameters
ENABLE JTAG 02 00 Simple 3 None
DISABLE JTAG 02 01 Simple 4 None
PORT INFO 02 02 Simple 4 1 byte detail type. 0x01: Port Count. 0x05: Port Properties.
SET SPEED 02 03 Simple 7 4 byte speed in bps
Returns status 0 and the 4 byte (little endian) actual bit rate the controller selected.
If JTAG is not enabled, will return status code 0x04 and no data.
GET SPEED 02 04 Simple 3 No Parameters
Returns status 0 and the 4 byte (little endian) actual bit rate the controller selected.
If JTAG is not enabled, will return status code 0x04 and no data.
SET Tms Tdi Tdo 02 05 Simple 6 MS:DI:DO One byte each.
GET Tms Tdi Tdo Tck 02 06 Simple 3 None
Clock Tick 02 07 Special (Status, Send 02:02:87 to endpoint 1. Status) 9 MS:DI:XX:XX:XX:XX In this case X implies clock cycles, but bits are shifted.
WRITE TDI BITS 02 08 ADV 9 RV:MS:XX:XX:XX:XX
READ TDO BITS 02 09 ADV 9 MS:DI:XX:XX:XX:XX
WRITE TMS/TDI BITS 02 10 ADV 8 RV:XX:XX:XX:XX
WRITE TMS BITS 02 11 ADV 9 RV:DI:XX:XX:XX:XX
(XX is the number of bits to transfer. Little Endian Number. 4 bytes.)
(MS, DI, DO, and CK are Boolean values for the state of the pins TMS, TDI, TDO, and TCK respectively. )
(RV is 1 if the values shifted out of TDO should be returned. This causes an additional packet to be sent from the device after the transfer of the provided input data.)

Known Devides:

The Endpnum column refers to which bulk endpoints are used to:

  1. Send initial Bulk Requests
  2. Receive Status Code responses
  3. Send additional command data (like JTAG transition data)
  4. Receive additional command data (like JTAG TDO states read from target)

All devices listed here have a vendorID of 0x1443.

.
Name Endpnum deviceID FW? ProdName DCAP ProdID
Cr2s2 1 2 3 4 0007 No Cr2s2 0x15
(0)dJtg
(2)dEpp
(4)dSpi
0x00900126
Basys2 1 2 3 4 0007 No Basys2 0x05
(0)dJtg
(2)dEpp
0x00800223
Nexys2 1 1 2 6 0005 FX2FW_05_0000000D_
00000000_030A.HEX
PreFW:
OnbUsb1 V2.0
PostFW:
Onboard USB'
0x0D
(0)dJtg
(2)dEpp
(3)dStm
PreFW: Unsupported
PostFW: 0x00100005
Nexys3 1 1 2 6 0007 FX2FW_0D_0000000D_
00000000_030A.HEX
Nexys3 PreFW: 0
PostFW: 0x0D
(0)dJtg
(2)dEpp
(3)dStm
0x00D0010D
Atlys 1 1 2 6 0007 FX2FW_0C_0000000D_
00000000_030A.HEX
Atlys PreFW: Unsupported
PostFW: 0x0D
(0)dJtg
(2)dEpp
(3)dStm
0x00C0010C
Digilent Device Capabilities Enum:
VALUE NAME DESCRIPTION
0x00000001dcapJtg Jtag....
0x00000002dcapPio Pin I/O
0x00000004dcapEpp Async Parallel Interface
0x00000008dcapStm Sync Parallel Interface (High Speed Stream)
0x00000010dcapSpi Serial Peripheral Interface
0x00000020dcapTwi Two Wire (Serial) Interface (i2c)
0x00000040dcapAci Async Comm Interface (UART)
0x00000080dcapAio Analog IN/OUT
0x00000100dcapEmc Electro-Mechanical Control
0x00000200dcapDci Not Documented
0x00000400dcapGio General Sensor & User I/O Libraries
0x00000800dcapPti Not Documented

OEM Verification Procedure:

OEM Verification is an unrequired step for initialzing a digilent controller. The process it usually done once at startup, and entails setting a seed, asking the board to generate a response based off the seed, and confirming if that response is valid for the provided seed. No open drivers need to implement this.

  1. Set OEM Check Seed (0xE8) request. This seed is often based on time, or sometimes just '14'.
  2. Read OEM Check (0xEC) retuest.
  3. XOR the two bytes from the OEM seed
  4. XOR each byte returned from the OEM Check request with the value calculated in step 3.
  5. The resulting 4 bytes (after xoring) should equal 'Digi'. If not, the oem check fails.