Among Spartan-3 generation of FPGAs only families 3A and 3AN have unique device identifier (device DNAs). DNA is a factory programmed unique 57-bit long number, whose the most significant bit is "1" and the second most significant bit is "0":
The Spartan 3A chip (xc3s50a) should be unconfigured (not loaded with any bit-stream either from SPI or JTAG), otherwise attempts to read the DNA will results in getting zeros.
I've tried reading DNA using:
- Impact (from Xilinx ISE) with Digilent HS-3 cable
- UrJTAG with FT232H adapter
- OpenOCD with FT232H adapter
- fireprog (my version of fpgaprog and Papilio-Loader) with FT232H adapter
- A custom VHDL code with displaying on actual hardware (7-segment displays)
Reading DNA using Impact and Digilent HS-3 Programming Cable
Suppose that Xilinx ISE is located at "/media/Windows" folder, so in order to be able to use Xilinx commands such as "impact" we need to run "settings64.sh" script in BASH. Other shells won't work. This script updates $PATH variable, making "impact" callable from the terminal. Reading DNA of a device can be done only in batch mode, GUI mode does not have this feature. When auto-identification of the programming cable is on ("setcable -port auto"), impact finds my Digilent HS-3 cable connected to the Prometheus FPGA board via JTAG port.
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 |
[johndoe@ArchLinux]% source /media/Windows/Xilinx/14.7/ISE_DS/settings64.sh . /media/Windows/Xilinx/14.7/ISE_DS/common/.settings64.sh /media/Windows/Xilinx/14.7/ISE_DS/common . /media/Windows/Xilinx/14.7/ISE_DS/EDK/.settings64.sh /media/Windows/Xilinx/14.7/ISE_DS/EDK . /media/Windows/Xilinx/14.7/ISE_DS/PlanAhead/.settings64.sh /media/Windows/Xilinx/14.7/ISE_DS/PlanAhead . /media/Windows/Xilinx/14.7/ISE_DS/ISE/.settings64.sh /media/Windows/Xilinx/14.7/ISE_DS/ISE [johndoe@ArchLinux]% impact -batch Release 14.7 - iMPACT P.20131013 (lin64) Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. Preference Table Name Setting StartupClock Auto_Correction AutoSignature False KeepSVF False ConcurrentMode False UseHighz False ConfigOnFailure Stop UserLevel Novice MessageLevel Detailed svfUseTime false SpiByteSwap Auto_Correction AutoInfer false SvfPlayDisplayComments false >setmode -bs >setcable -port auto INFO:iMPACT - Digilent Plugin: Plugin Version: 2.4.4 INFO:iMPACT - Digilent Plugin: found 1 device(s). INFO:iMPACT - Digilent Plugin: opening device: "JtagHs3", SN:2XXXXXXXXXX INFO:iMPACT - Digilent Plugin: User Name: JtagHs3 INFO:iMPACT - Digilent Plugin: Product Name: Digilent JTAG-HS3 INFO:iMPACT - Digilent Plugin: Serial Number: 2XXXXXXXXXXXXX INFO:iMPACT - Digilent Plugin: Product ID: 3XXXXXXX INFO:iMPACT - Digilent Plugin: Firmware Version: 010A INFO:iMPACT - Digilent Plugin: JTAG Port Number: 0 INFO:iMPACT - Digilent Plugin: JTAG Clock Frequency: 10000000 Hz >identify Identifying chain contents...'0': : Manufacturer's ID = Xilinx xc3s50a, Version : 0 INFO:iMPACT:1777 - Reading /media/Windows/Xilinx/14.7/ISE_DS/ISE/spartan3a/data/xc3s50a.bsd... INFO:iMPACT:501 - '1': Added Device xc3s50a successfully. ---------------------------------------------------------------------- ----------------------------------------------------------------------' done. Elapsed time = 0 sec. Elapsed time = 0 sec. >identifyMPM Elapsed time = 0 sec. Elapsed time = 0 sec. >readdna -p 1 Maximum TCK operating frequency for this device chain: 10000000. Validating chain... Boundary-scan chain validated successfully. '1': DNA = '101010101100110001011001011000011111011010111110110111111' |
which is 0x15598B2C3ED7DBF in hexadecimal.
Reading DNA using UrJTAG and FT232H-based JTAG Adapter
My custom Prometheus FPGA board has FTDI's FT232H chip with vendor ID 0x0403 and product ID 0x6014 which is used as a JTAG adapter and programmer. This chip requires either libftdi or libftd2xx driver to communicate with a PC. Reading DNA is easy, but the Spartan 3A chip should be set into a blank mode first:
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 |
UrJTAG 0.10 #2052 Copyright (C) 2002, 2003 ETC s.r.o. Copyright (C) 2007, 2008, 2009 Kolja Waschk and the respective authors UrJTAG is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. There is absolutely no warranty for UrJTAG. warning: UrJTAG may damage your hardware! Type "quit" to exit, "help" for help. jtag> cable ft2232 vid=0x0403 pid=0x6014 Connected to libftd2xx driver. jtag> detect IR length: 6 Chain length: 1 Device Id: 00000010001000010000000010010011 (0x02210093) Manufacturer: Xilinx (0x093) Part(0): xc3s50a (0x2210) Stepping: 0 Filename: /usr/share/urjtag/xilinx/xc3s50a/xc3s50a jtag> instruction ISC_ENABLE 010000 DATAREG jtag> instruction JPROGRAM 001011 BYPASS jtag> instruction JPROGRAM jtag> shift ir jtag> instruction CFG_IN jtag> shift ir jtag> instruction ISC_ENABLE jtag> shift ir jtag> instruction ISC_DNA jtag> shift ir jtag> shift dr jtag> dr 111111011011111010110111110000110100110100011001101010101 (0x1FB7D6F869A3355) |
Note that, DNA is displayed in the reverse order, so the actual value is:
1 2 |
[johndoe@ArchLinux]% printf "%x\n" 2#$(echo "111111011011111010110111110000110100110100011001101010101"|rev) 15598b2c3ed7dbf |
which is the same as the one read in Impact.
DATAREG is defined in "/usr/share/urjtag/xilinx/xc3s50a/xc3s50a" as a 57-bit long register:
1 |
register DATAREG 57 |
Unfortunately, the device description file is incomplete, so I had to look into the official BSDL file in my Xilinx ISE distribution:
1 2 3 4 5 6 |
[johndoe@ArchLinux]% grep JPROGRAM /media/Windows/Xilinx/14.7/ISE_DS/ISE/spartan3a/data/xc3s50a.bsd "JPROGRAM (001011)," & -- Not available during configuration with another mode. "JPROGRAM," & [johndoe@ArchLinux]% grep ISC_ENABLE /media/Windows/Xilinx/14.7/ISE_DS/ISE/spartan3a/data/xc3s50a.bsd "ISC_ENABLE (010000)," & "ISC_ENABLE," & |
and define these instructions in the UrJTAG's command line. Every instruction should be associated with a data register which it affects.
Reading DNA using OpenOCD and FT232H-based JTAG Adapter
OpenOCD has a nice scripting support. Let's define a cable driver in a separate file FT232H.cfg:
1 2 3 4 5 6 7 |
interface ftdi ftdi_vid_pid 0x0403 0x6014 ftdi_layout_init 0x0088 0x008b adapter_khz 6000 transport select jtag ftdi_layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi_layout_signal nSRST -data 0x0200 -noe 0x0800 |
Test access point (XC3S50A chip) and DNA reader can be defined in another file called Prometheus.cfg
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 |
# Test Access Port: Spartan3A XC3S50A FPGA jtag newtap spartan3a tap -irlen 6 -expected-id 0x02210093 # Instructions for Spartan3A (6-bit long) set XC3S_CFG_IN 0x05 set XC3S_JSHUTDOWN 0x0d set XC3S_JPROGRAM 0x0b set XC3S_JSTART 0x0c set XC3S_BYPASS 0x3f set XC3S_ISC_ENABLE 0x10 set XC3S_ISC_DISABLE 0x16 set XC3S_ISC_DNA 0x31 # Get the "Device DNA" from the Spartan 3A proc xc3s_get_dna {tap} { global XC3S_ISC_ENABLE XC3S_ISC_DISABLE XC3S_ISC_DNA irscan $tap $XC3S_ISC_ENABLE runtest 64 irscan $tap $XC3S_ISC_DNA # Device DNA is 57 bits long, but we can only read 32 bits at a time with OpenOCD. set dna [drscan $tap 16 0 16 0 16 0 9 0] runtest 64 irscan $tap $XC3S_ISC_DISABLE runtest 64 # Convert the binary data scan $dna "%x %x %x %x" v1 v2 v3 v4 set bin_dna [string reverse [concat [format "%09b" $v4][format "%016b" $v3][format "%016b" $v2][format "%016b" $v1]]] # Hexadecimal version of the binary scan [format "0b%s" $bin_dna] "%i" hex_dna return [concat [format "DNA = 0b%s" $bin_dna][format "\n"][format "DNA = 0h%015x\n" $hex_dna]] } |
Start OpenOCD server in terminal:
1 2 3 4 5 6 7 8 9 10 |
[johndoe@ArchLinux]% openocd -f FT232H.cfg -f Prometheus.cfg Open On-Chip Debugger 0.10.0 Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html adapter speed: 6000 kHz xc3s_get_dna Info : clock speed 6000 kHz Info : JTAG tap: spartan3a.tap tap/device found: 0x02210093 (mfg: 0x049 (Xilinx), part: 0x2210, ver: 0x0) Warn : gdb services need one or more targets defined |
In another terminal connect to the running OpenOCD server and run DNA reader script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[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 spartan3a.tap Y 0x02210093 0x02210093 6 0x01 0x03 > xc3s_get_dna spartan3a.tap DNA = 0b101010101100110001011001011000011111011010111110110111111 DNA = 0h15598b2c3ed7dbf |
A DNA read is exactly same as the DNA read by Impact.
Reading DNA using fireprog
Papilio-Loader and fpgaprog have a bug in the DNA reader code. The bit order of the DNA should be reversed. My version of these programs called "fireprog" was adapted for the Prometheus board and has this bug fixed:
1 2 |
[johndoe@ArchLinux]% fireprog -u DNA = 0x15598b2c3ed7dbf |
A VHDL code for Reading and Displaying DNA on Prometheus FPGA
Based on documentation of the DNA register ("Spartan-3 Generation Configuration User Guide" (UG332)) I wrote a VHDL code to read and display device DNA on Prometheus FPGA board. It uses DNA_PORT primitive to access the DNA register. The source code resides in: https://github.com/isabekov/DNA_Reader_Prometheus
Here are the photos of the board displaying the device DNA:
References
"Spartan-3 Generation Configuration User Guide" (UG332)
OpenOCD configuration for Xilinx XC6S