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

