# SPDX-License-Identifier: GPL-2.0-or-later

proc xilinx_dna_addr {chip} {
	array set addrs {
		Spartan6 0x30
		Series7 0x17
	}
	return $addrs($chip)
}

# Get the "Device DNA".
# Most Xilinx FPGA devices contain an embedded, unique device identifier.
# The identifier is nonvolatile, permanently programmed into
# the FPGA, and is unchangeable providing a great serial / tracking number.
# This function returns the DNA as a 64 bit integer with the 7 LSBs zeroed.
# This is compatible with the FUSE DNA which contains all 64 bits.
proc xilinx_get_dna {tap chip} {
    set XC7_ISC_ENABLE 0x10
    set XC7_ISC_DISABLE 0x16
    set XC7_ISC_DNA [xilinx_dna_addr $chip]

    irscan $tap $XC7_ISC_ENABLE
    runtest 256  ; # add wait time , just for test
    irscan $tap $XC7_ISC_DNA

    # for test , add 64
    set dr_data [drscan $tap 64 0 64 0]
    puts "DR Data: $dr_data"

    scan $dr_data "%016x" combined
    puts "Combined: $combined"  ; # for test

    set hi [expr {$combined >> 32}]
    set lo [expr {$combined & 0xFFFFFFFF}]
    puts "Hi: [format 0x%08x $hi], Lo: [format 0x%08x $lo]"  ; # for test

    runtest 256  ; # add wait time , just for test
    irscan $tap $XC7_ISC_DISABLE
    runtest 256  ; # add wait time , just for test

    # openocd interprets DR scans as LSB first, bit-reverse it
    set reversed_lo [string reverse [format "%032b" $lo]]
    set reversed_hi [string reverse [format "%032b" $hi]]
    puts "Reversed Lo: $reversed_lo, Reversed Hi: $reversed_hi"

    set reversed_combined "$reversed_lo$reversed_hi"
    puts "Reversed Combined: $reversed_combined"  ; # for test

    set dna 0
    set len [string length $reversed_combined]
    for {set i 0} {$i < $len} {incr i} {
        set bit [string index $reversed_combined $i]
        set dna [expr {$dna * 2 + $bit}]
    }
    puts "DNA: $dna"
    return $dna
}









# Print out the "Device DNA" in the same format that impact uses.
proc xilinx_print_dna {dna} {
	set dna [expr {$dna >> 64 - 57}]
	set border "=========================================================="
	set note_border "=============== NOTE ==============="
	set dna_border "=============== FuntowiczRav GET DNA ==============="

	set formatted_output [format {

	%s

	1.) Copy DNA below and send it in your ticket.
	2.) Tag Scarletlab once you sent it.

	%s
	( COPY FROM HERE )

	%057b 
	(0x%016x)

	( TO HERE )
	%s

	} $note_border $dna_border $dna $dna $border]

	echo $formatted_output
}

proc xc7_get_dna {tap} {
	return [xilinx_get_dna $tap Series7]
}

proc xc6s_get_dna {tap} {
	return [xilinx_get_dna $tap Spartan6]
}
