Objective
This tutorial concerns with explaining use of some basic Serial Vector Format (SVF) instructions assuming that you are familiar with JTAG and TAP.
As an example, reading ID codes of the devices in a JTAG chain of the Digilent Basys2 FPGA board is given. A generic FTDI-MPSSE-based JTAG adapter was used and the tests were conducted in OpenOCD.
The Board and its JTAG Chain
Here is the JTAG chain of the Digilent Basys2 FPGA board:
The first IC (xc3s100e) is the actual FPGA chip from the Spartan 3E family. The second chip (xcf02s) is a flash memory (PROM). For each chip, JTAG-specific instructions and properties of special registers including BSR (boundary scan register) are provided in BSDL files. These files can be retrieved from the vendor's website or from the Xilinx ISE installation. If you have Xilinx ISE already installed, check out the "xc3s100e.bsd" file located at "$XILINX_ISE_PATH/spartan3e/data/" and "xcf02s.bsd" file located at "$XILINX_ISE_PATH/xcf/data/", where $XILINX_ISE_PATH is the installation path, e.g. "/opt/Xilinx/10.1/ISE/".
From the "xc3s100e.bsd" and "xcf02s.bsd" we can learn the Instruction Register lengths
and opcodes for instructions:
Device | IR Length | BYPASS | IDCODE |
xc3s100e | 6 bits | 111111 | 001001 |
xcf02s | 8 bits | 11111111 | 11111110 |
ID code register is always 32 bit long. Required in the standard.
ID code of the xc3s100e device is a 32-bit sequence:
0b(XXXX 0001 1100 0001 0000 0000 1001 0011) == 0x(?1C10093), where 4 most significant bits, denoted by "XXXX", represent version and aren't important.
ID code of the xcf02s device is a 32-bit sequence:
0b(XXXX 0101 0000 0100 0101 0000 1001 0011) == 0x(?5045093), where 4 most significant bits, denoted by "XXXX", represent version and aren't important.
These ID codes can be checked using Digilent's official configuration tools:
1 2 3 4 5 |
[johndoe@ArchLinux]% yaourt -S digilent.adept.runtime digilent.adept.utilities [johndoe@ArchLinux]% djtgcfg init -d Basys2 Initializing scan chain... Found Device ID: f5045093 # PROM, XCF02S Found Device ID: 11C10093 # Spartan 3E, XC3S100E |
Methods to read ID codes of the devices:
- Put both devices into RESET state. According to JTAG specifications, all devices in the chain must choose ID code register as data register. Shift any 64-bit long sequence into TDI while in "ShiftDR" state and observe concatenated pair of ID codes [Spartan 3E, PROM] = "0x?1C10093?5045093" at TDO. Least significant bit (LSB) comes first.
- Load Spartan 3E's instruction register with IDCODE instruction, and load PROM's instruction register with BYPASS instruction. ID code register will be selected as Spartan 3E's data register and a 1-bit long bypass register will selected as PROM's data register. Shift a 32+1 bit long sequence into TDI while in "ShiftDR" state, at the TDO output observe ID code of Spartan 3E padded with an extra bit at LSB position: "0x163820126" (see the explanation in the code below).
- Similarly to option (2), but now PROM will be loaded with IDCODE instruction and Spartan 3E will be bypassed. The scanned out 33-bit long sequence will consist of ID code and an extra bit at MSB position: "0x1?5045093".
All explanations are given in the comments, read them carefully:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
// ============================================================================================================================= // At the RESET state, the IDCODE register (if such exists) is set as data register by default STATE RESET; // Header and trailer data registers. HDR and TDI set to zero indicate that there are no other devices in the chain except given. // Without HDR, TDR, TIR, HIR instructions, OpenOCD can generate errors depending on the present state. // So it's a good practice to put them before SDR and SIR instructions. HDR 0; TDR 0; // Shift 64 bits (2 x size of the IDCODE register) of ones (F...FF)throughout the JTAG chain while in the SHIFT-DR state. // The SMASK set to all ones represents importance of the bits. Not mandatory. // Expected output sequence at TDO is defined by TDO and MASK instructions. // OpenOCD performs the check and gives an error if the expected output and read output don't match. SDR 64 TDI (FFFFFFFFFFFFFFFF) SMASK (FFFFFFFFFFFFFFFF) TDO (11C10093F5045093) MASK (0FFFFFFF0FFFFFFF); // ============================================================================================================================= STATE RESET; // Header padding for the data register. An all-zeros sequence is shifted first, so eventually it will end up in the // ID code register of the PROM memory (second in the chain, TDI -> (1) -> (2) -> TDO, which is TDI -> Spartan 3E -> PROM -> TDO) // Expected output is the ID code of the PROM. HDR 32 TDI (00000000) TDO (F5045093) MASK (0FFFFFFF); // Trailer padding for the data register. There are no devices before (read: "on the left of") the Spartan 3E in the chain! TDR 0; // Shift all-ones sequence into the data register. // Expected output is the ID code of the Spartan 3E. SDR 32 TDI (FFFFFFFF) TDO (11C10093) MASK (0FFFFFFF); // Shifted sequence is "FFFFFFFF00000000" // Expected sequence is "11C10093F5045093" // ============================================================================================================================= STATE RESET; // Header padding for the data register. There are no devices after (read: "on the right of") the PROM in the chain! HDR 0; // Trailer padding for the data register. An all-zeros sequence is shifted last, so eventually it will end up in the // ID code register of the Spartan 3E memory (first in the chain, TDI -> Spartan 3E -> PROM -> TDO) TDR 32 TDI (00000000); SDR 32 TDI (FFFFFFFF) TDO (F5045093) MASK (0FFFFFFF); // Shifted sequence is "00000000FFFFFFFF" // Expected sequence is "XXXXXXXXF5045093" // ============================================================================================================================= STATE RESET; // There are no devices on the left of the Spartan 3E and on the right of the PROM. HIR 0; TIR 0; // Load concatenation of the following instructions: // Spartan 3E, PROM // IDCODE "001001" == (09), BYPASS "11111111" == (FF) // SMASK set to all ones indicate that all bits are important. SIR 14 TDI (09FF) SMASK (3FFF); // After executing the above instructions, JTAG controller of the first device (Spartan 3E FPGA) chooses 32-bit long IDCODE register and // JTAG controller of the second device (PROM flash memory) selects the BYPASS register as data register, which is only 1 bit long. // So we have 32+1 bit long data register in the JTAG chain. If we scan through this register any sequence of 33-bit long, we will get // 32 bits of the ID code number padded with "1" at least significant position (content of the BYPASS register which is logic "1") from the TDO. // There are no devices on the left of the Spartan 3E and on the right of the PROM. HDR 0; TDR 0; SDR 33 TDI (1FFFFFFFE) SMASK (1FFFFFFFE) TDO (003820126) MASK (01FFFFFFE); // Pushed in: // 32 + 1 bit // ----------------------------------------x // TDI: 1 1111 1111 1111 1111 1111 1111 1111 1110 == (0FFFFFFFE) // SMASK: 1 1111 1111 1111 1111 1111 1111 1111 1110 == (1FFFFFFFE) // Expected output is the ID code number of the device padded with one bit at MSB position: // TDO: X XXX0 0011 1000 0010 0000 0001 0010 011X == (003820126), can also be (163820127) etc. due to mask // MASK: 0 0001 1111 1111 1111 1111 1111 1111 1110 == (01FFFFFFE) (we don't care about 4-bit version at MSB position and padded 1 bit at LSB position) // Note: TDO is the ID code of Spartan 3E shifted to the left and padded with one zero // XXXX 0001 1100 0001 0000 0000 1001 0011 // Checking PROM's ID code STATE RESET; HIR 0; TIR 0; SIR 14 TDI (3FFE) SMASK (3FFF); SDR 33 TDI (0FFFFFFFE) SMASK (1FFFFFFFF) TDO (0F5045093) MASK (00FFFFFFF); /////////////////////////////////////////////////////////////////////////////////// // The same IDCODE check but with using Trailing and Header SVF Instructions /////////////////////////////////////////////////////////////////////////////////// // Checking Spartan 3E's ID code STATE RESET; // Header padding (BYPASS opcode for PROM flash memory) HIR 8 TDI (FF) SMASK (FF); // Scan with IDCODE opcode for Spartan 3E. The padded header sequence will be shifted first! SIR 6 TDI (09) SMASK (3F); // Now the PROM flash memory enters BYPASS mode, in which the Data Register is 1-bit long // Header padding (one bit, the value of the bit is not important) HDR 1 TDI (0) SMASK (1); // Shift 32-bit long sequence (here it comprises of zeros) together with the padded header // Padded one bit is removed from the obtained 33-bit sequence at TDO. // Expected output of the remaining 32-bit sequence is ID code of the Spartan 3E SDR 32 TDI (00000000) SMASK (FFFFFFFF) TDO (11C10093) MASK (0FFFFFFF); // Checking PROM flash memory's ID code STATE RESET; // No devices are attached after PROM!!! TDI -> Spartan 3E -> PROM -> [no devices] -> TDO // You don't specify this, OpenOCD can assume that there one more device! HIR 0; // Trailer padding (BYPASS opcode for Spartan 3E) TIR 6 TDI(3F) SMASK (3F); // Scan with IDCODE opcode for Spartan 3E. The padded trailer sequence will shifted after the IDCODE! SIR 8 TDI(FE) SMASK (FF); // No devices are attached after PROM!!! TDI -> Spartan 3E -> PROM -> [no devices] -> TDO // You don't specify this, OpenOCD can assume that there one more device! HDR 0; TDR 1 TDI(1) SMASK(1); SDR 32 TDI (00000000) SMASK (FFFFFFFF) TDO (F5045093) MASK (0FFFFFFF); |
The output should look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
[johndoe@ArchLinux]% telnet localhost 4444 Trying ::1... Connection failed: Connection refused Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Open On-Chip Debugger > scan_chain TapName Enabled IdCode Expected IrLen IrCap IrMask -- ------------------- -------- ---------- ---------- ----- ----- ------ 0 prom.tap Y 0xf5045093 0xf5045093 8 0x01 0x03 1 spartan3e.tap Y 0x11c10093 0x11c10093 6 0x01 0x03 > svf Basys2_IDCODE.svf svf processing file: "Basys2_IDCODE.svf" STATE RESET; HDR 0; TDR 0; SDR 64 TDI (FFFFFFFFFFFFFFFF) SMASK (FFFFFFFFFFFFFFFF) TDO (11C10093F5045093) MASK (0FFFFFFF0FFFFFFF); STATE RESET; HDR 32 TDI (00000000) TDO (F5045093) MASK (0FFFFFFF); TDR 0; SDR 32 TDI (FFFFFFFF) TDO (11C10093) MASK (0FFFFFFF); STATE RESET; HDR 0; TDR 32 TDI (00000000); SDR 32 TDI (FFFFFFFF) TDO (F5045093) MASK (0FFFFFFF); STATE RESET; HIR 0; TIR 0; SIR 14 TDI (09FF) SMASK (3FFF); HDR 0; TDR 0; SDR 33 TDI (1FFFFFFFE) SMASK (1FFFFFFFE) TDO (003820126) MASK (01FFFFFFE); STATE RESET; HIR 0; TIR 0; SIR 14 TDI (3FFE) SMASK (3FFF); SDR 33 TDI (0FFFFFFFE) SMASK (1FFFFFFFF) TDO (0F5045093) MASK (00FFFFFFF); STATE RESET; HIR 8 TDI (FF) SMASK (FF); SIR 6 TDI (09) SMASK (3F); HDR 1 TDI (0) SMASK (1); SDR 32 TDI (00000000) SMASK (FFFFFFFF) TDO (11C10093) MASK (0FFFFFFF); STATE RESET; HIR 0; TIR 6 TDI(3F) SMASK (3F); SIR 8 TDI(FE) SMASK (FF); HDR 0; TDR 1 TDI(1) SMASK(1); SDR 32 TDI (00000000) SMASK (FFFFFFFF) TDO (F5045093) MASK (0FFFFFFF); Time used: 0m0s3ms svf file programmed successfully for 36 commands with 0 errors > |
References
XAPP503 "SVF and XSVF File Formats for Xilinx Devices" application note by Xilinx.
Serial Vector Format Specification by ASSET InterTech, Inc.