Skip to content

Instantly share code, notes, and snippets.

@z4yx
Last active March 1, 2022 13:44
Show Gist options
  • Save z4yx/332d6f1a574ece26e3d7f39b0fa102ce to your computer and use it in GitHub Desktop.
Save z4yx/332d6f1a574ece26e3d7f39b0fa102ce to your computer and use it in GitHub Desktop.
Readback capture on Xilinx Series 7 FPGA
set IR_CFG_IN 5
set IR_CFG_OUT 4
set IR_SHUTDOWN D
set PKT_DUMMY FFFFFFFF
set PKT_SYNC AA995566
set PKT1_NOP 20000000
set PKT1_RD 28000000
set PKT1_WR 30000000
set PKT2_CNT 40000000
set REG_FAR 1
set REG_FDRO 3
set REG_CMD 4
set REG_STAT 7
set REG_BOOT 16
#set RSTAT ${PKT_SYNC}${PKT1_NOP}2800E001${PKT1_NOP}${PKT1_NOP}
#set RBOOT ${PKT_SYNC}${PKT1_NOP}28016001${PKT1_NOP}${PKT1_NOP}
#set RCRC FFFFFFFF${PKT_SYNC}${PKT1_NOP}3000800100000007${PKT1_NOP}${PKT1_NOP}
#set RDBK FFFFFFFF${PKT_SYNC}${PKT1_NOP}300080010000000430002001000000002800600048024090${PKT1_NOP}${PKT1_NOP}
set CNF_FRAMES 0x24f9; # for Artix-7 7A100T
set WORDS_PER_FRAME 0x65; # for Series-7
set RDBK_WORDS [format "0x%08X" [expr ($CNF_FRAMES + 1)*$WORDS_PER_FRAME]]; # one dummy frame
proc build_wr_pkt {reg data} {
global PKT1_WR;
set len [format "0x%X" [expr [string length $data] / 8]]
set hdr [format "%08X" [expr 0x$PKT1_WR | (0x$reg << 13) | $len]]
append hdr $data
return $hdr
}
proc build_rd_pkt {reg words} {
global PKT1_RD;
set hdr [format "%08X" [expr 0x$PKT1_RD | (0x$reg << 13) | 0x$words]]
return $hdr
}
proc setCmds {} {
global PKT_DUMMY;
global PKT_SYNC;
global PKT1_NOP;
global PKT2_CNT;
global REG_FAR;
global REG_FDRO;
global REG_CMD;
global REG_STAT;
global REG_BOOT;
global RSTAT;
global RBOOT;
global GCAP;
global RCRC;
global RDBK;
global RDBK_WORDS;
set RSTAT ${PKT_DUMMY}${PKT_SYNC}${PKT1_NOP}
append RSTAT [build_rd_pkt $REG_STAT 1]
append RSTAT ${PKT1_NOP}${PKT1_NOP}
set RBOOT ${PKT_DUMMY}${PKT_SYNC}${PKT1_NOP}
append RBOOT [build_rd_pkt $REG_BOOT 1]
append RBOOT ${PKT1_NOP}${PKT1_NOP}
set GCAP ${PKT_DUMMY}${PKT_SYNC}${PKT1_NOP}
append GCAP [build_wr_pkt $REG_CMD 0000000C]
append GCAP ${PKT1_NOP}${PKT1_NOP}
set RCRC ${PKT_DUMMY}${PKT_SYNC}${PKT1_NOP}
append RCRC [build_wr_pkt $REG_CMD 00000007]
append RCRC ${PKT1_NOP}${PKT1_NOP}
set RDBK ${PKT_DUMMY}${PKT_SYNC}${PKT1_NOP}
append RDBK [build_wr_pkt $REG_CMD 00000004]
append RDBK [build_wr_pkt $REG_FAR 00000000]
append RDBK [build_rd_pkt $REG_FDRO 0]
append RDBK [format "%08X" [expr 0x$PKT2_CNT | $RDBK_WORDS]]
append RDBK ${PKT1_NOP}${PKT1_NOP}
}
#-----------------------------------------------------------------------------
# Reverse hex values in str
#-----------------------------------------------------------------------------
# Setup array to return reverse of specified hex value
# Ex: 0x5 (binary 0101) when reversed is 0xA (binary 1010)
#-----------------------------------------------------------------------------
proc setHexRevTbl {} {
global arrayHexVal
set arrayHexVal(0) 0
set arrayHexVal(1) 8
set arrayHexVal(2) 4
set arrayHexVal(3) C
set arrayHexVal(4) 2
set arrayHexVal(5) A
set arrayHexVal(6) 6
set arrayHexVal(7) E
set arrayHexVal(8) 1
set arrayHexVal(9) 9
set arrayHexVal(A) 5
set arrayHexVal(B) D
set arrayHexVal(C) 3
set arrayHexVal(D) B
set arrayHexVal(E) 7
set arrayHexVal(F) F
set arrayHexVal(a) 5
set arrayHexVal(b) D
set arrayHexVal(c) 3
set arrayHexVal(d) B
set arrayHexVal(e) 7
set arrayHexVal(f) F
return 1
}
#-----------------------------------------------------------------------------
# Reverse hex values in str
# Ex: 0x80034014 becomes 0x2802C001
# - Note: Chars in string are indexed [0 1 2 .. N-1]
# - = works only for strings where the number of bits represented
# by hex characters is a multiple of 4
#-----------------------------------------------------------------------------
proc revHexData {argHexStr} {
global arrayHexVal
if {![string is xdigit $argHexStr]} {
puts "ERROR: TDI data contains non-hex chars"
return "0x0x0x0"
}
set numchars [string length $argHexStr]
for {set iX 0} {$iX < $numchars} {incr iX} {
set sHex [string index $argHexStr [expr ($numchars - $iX - 1)]]
set sHex $arrayHexVal($sHex)
if {$iX == 0} {
set sStr $sHex
continue;
} else {
append sStr $sHex
}
}; # end of FOR $iX < $numchars
return $sStr
}; # end of revHexData
proc send_ir_and_dr {inst data} {
scan_ir_hw_jtag 6 -tdi $inst
set revdata [revHexData $data]
# puts $revdata
set bitlen [expr ([string length $revdata] * 4)]
return [revHexData [scan_dr_hw_jtag $bitlen -tdi $revdata]]
}
setHexRevTbl
setCmds
if {1} {
puts $GCAP
puts $RDBK
}
if {0} {
# xsct command test on Zynq-7 (not working)
jtag targets 2
set seq [jtag sequence]
$seq state RESET
$seq irshift -hex 4 E; #IDCODE
$seq drshift -capture -tdi 0 32
$seq irshift -hex 4 F; #BYPASS
set result [$seq run]
$seq delete
puts $result
jtag targets 3
set seq [jtag sequence]
$seq state RESET
$seq irshift -hex 6 8
$seq drshift -capture -tdi 0 32
$seq irshift -hex 6 $IR_CFG_IN
set data [revHexData $RBOOT]
puts $data
set bitlen [expr ([string length $data] * 4)]
$seq drshift -hex $bitlen $data
$seq irshift -hex 6 $IR_CFG_OUT
$seq drshift -capture -tdi 0 32
set result [$seq run]
$seq delete
puts $result ;#[revHexData $result]
}
if {1} {
close_hw_target [current_hw_target]
open_hw_target -jtag_mode true
# send_ir_and_dr $IR_CFG_IN $RSTAT
# puts [send_ir_and_dr $IR_CFG_OUT 00000000]
send_ir_and_dr $IR_CFG_IN $GCAP; # Capture the state of all registers
if {1} {
# readback with readback_hw_device command
close_hw_target [current_hw_target]
open_hw_target -jtag_mode false
readback_hw_device [current_hw_device] -readback_file readback.rbd -force
} else {
# readback with scan_dr_hw_jtag command
send_ir_and_dr $IR_CFG_IN $RESETCRC
scan_ir_hw_jtag 6 -tdi $IR_SHUTDOWN
send_ir_and_dr $IR_CFG_IN $RDBK
scan_ir_hw_jtag 6 -tdi $IR_CFG_OUT
set rdbk_hex [scan_dr_hw_jtag [expr $RDBK_WORDS * 32] -tdi 0]
set rdbk_hex [string range $rdbk_hex [expr $WORDS_PER_FRAME * 8] end ]; # discard dummy frame
set fileOutput [open "readback_hex.txt" w 0644]
puts -nonewline $fileOutput $rdbk_hex
close $fileOutput
}
}
#!/usr/bin/python3
PIPELINE_BITS=101*32
import sys
with open(sys.argv[1]) as f1:
with open(sys.argv[2]) as f2:
line = 0
for l1, l2 in zip(f1.readlines(), f2.readlines()):
line+=1
if l1 == l2: continue
for i in range(32):
if l1[i] != l2[i]:
offset = (line-1)*32+31-i-PIPELINE_BITS
print(f"{line}c{i+1}: Bit {offset} {l1[i]}->{l2[i]}")
#!/usr/bin/python3
# Example: rbd_hex2bin.py readback_hex.txt readback.rbd
import sys
with open(sys.argv[1]) as ifile:
hex_str = ifile.read().strip()
with open(sys.argv[2], 'w') as ofile:
bits = 0
for ch in hex_str[::-1]:
bin_str = "{:04b}".format(int(ch, 16))
ofile.write(bin_str[::-1])
bits += 4
if bits % 32 == 0:
ofile.write('\n')
#!/usr/bin/python3
PIPELINE_WORDS=101
import sys
raw_bits = ""
with open(sys.argv[1]) as rbd:
line = 0
for l in rbd.readlines():
# if len(l) == 0: continue
l = l.rstrip()
assert len(l) == 32
line += 1
if line <= PIPELINE_WORDS: continue
raw_bits += l[::-1]
with open(sys.argv[2]) as ll:
elements = []
for l in ll.readlines():
if not l.startswith("Bit"): continue
fields = l.split()
offset = int(fields[1])
net = ""
mem = ""
for f in fields:
if f.startswith("Net="):
net = f[4:]
elif f.startswith("Ram=") or f.startswith("Rom="):
mem = f[4:]
elements.append((offset, net, mem))
elements.sort(key = lambda x: x[1])
for l in elements:
val = int(raw_bits[l[0]]) ^ 1 # value of FF is internally inverted
print(f"Value {val} {l[1]} {l[2]}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment