Last active
March 1, 2022 13:44
-
-
Save z4yx/332d6f1a574ece26e3d7f39b0fa102ce to your computer and use it in GitHub Desktop.
Readback capture on Xilinx Series 7 FPGA
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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]}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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