######################################################################
# Copyright (c) 2006 Xilinx, Inc.  All rights reserved.
#
#                 XILINX CONFIDENTIAL PROPERTY                        
# This   document  contains  proprietary information  which   is    
# protected by  copyright. All rights  are reserved. No  part of    
# this  document may be photocopied, reproduced or translated to    
# another  program  language  without  prior written  consent of    
# XILINX Inc., San Jose, CA. 95124                                  
# 
# Xilinx, Inc.
# XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
# COURTESY TO YOU.  BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
# ONE POSSIBLE   IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
# STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
# IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
# FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
# XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
# THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
# ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
# FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS FOR A PARTICULAR PURPOSE.
#
######################################################################

#
#  For Tcl Manual for builtin commands, see
#        http://www.tcl.tk/man/tcl8.3
#
#
#

#  Example scanning devices and ChipScope cores, in a JTAG Chain,
#  using the Cse api.

# Get the Cse DLL's and globals
cd F:\\Xilinx9\\ChipScope_Pro_9_1i\\bin\\nt
source csejtag.tcl

namespace import ::chipscope::*

# Create global variables

# Parallel IV Cable
set PARALLEL_CABLE_ARGS [list "port=LPT1" \
                              "frequency=200000"]
                              # "frequency=5000000 | 2500000 | 200000"

# Platform USB Cable
set PLATFORM_USB_CABLE_ARGS [list "port=USB2" \
                                  "frequency=3000000"]
                                  # frequency="24000000 | 12000000 | 6000000 | 3000000 | 1500000 | 750000"

set CABLE_NAME $CSEJTAG_TARGET_PLATFORMUSB                                  
set CABLE_ARGS $PLATFORM_USB_CABLE_ARGS
set debug 0

proc main {argc argv} {
    global debug
    global PLATFORM_USB_CABLE_ARGS
    global CSEJTAG_TARGET_PLATFORMUSB
    global CABLE_NAME
    global CABLE_ARGS
    global CSE_MSG_INFO
    
    if {[expr ($argc > 0) && [string equal "-h" [lindex $argv 0]]]} {
        writeMessage 0 $CSE_MSG_INFO "Usage: xtclsh csejtag_examplel1.tcl \[-usb\] \[-d\]\n"
        exit
    }
    
    # for CseServer/CseClient use
    set serverflag_idx 0
    set serveraddress_idx 0
    
    # Checks to see if usb or debug flag is set
    for {set i 0} {$i < $argc} {incr i} {
        if {[string equal "-usb" [lindex $argv $i]]} {
            set CABLE_NAME $CSEJTAG_TARGET_PLATFORMUSB
            set CABLE_ARGS $PLATFORM_USB_CABLE_ARGS
        } elseif {[string equal "-d" [lindex $argv $i]]} {
            set debug 1
        } elseif {[string equal "-server" [lindex $argv $i]]} {
			set serverflag_idx $i
			set serveraddress_idx [expr $i + 1]
        }
    }
    
    # Create Session. Pass location of idcode.lst to override default.
    set handle [csejtag_session create "writeMessage" [lindex $argv $serverflag_idx] [lindex $argv $serveraddress_idx] ]
    
    # Scan the JTAG chain
    scanChain $handle
    
    csejtag_session destroy $handle    
}

proc scanChain {handle} {
    global CABLE_NAME
    global CABLE_ARGS
    global CSE_MSG_ERROR
    global CSE_MSG_INFO
    global CSEJTAG_SCAN_DEFAULT
    global CSEJTAG_LOCKED_ME
    global CSEJTAG_TEST_LOGIC_RESET
    global CSEJTAG_SHIFT_READ
    global CSEJTAG_RUN_TEST_IDLE

    # Open cable
    csejtag_target open $handle \
                        $CABLE_NAME \
                        0 \
                        [lindex $CABLE_ARGS 0] \
                        [lindex $CABLE_ARGS 1]

    # CseJtag_session sendMessage will call the messageRouter
    # function specified in csejtag_session create
    csejtag_session send_message $handle $CSE_MSG_INFO "Open Cable successfully\n"
    
    # Need to lock cable before actually accessing JTAG chain
    set cablelock [csejtag_target lock $handle 5000]
    if {$cablelock != $CSEJTAG_LOCKED_ME} {
        csejtag_session send_message $handle $CSE_MSG_ERROR "cse_lock_target failed"
        csejtag_target close $handle
        return
    }
    
    csejtag_session send_message $handle $CSE_MSG_INFO "Obtained cable lock\n"
    
    # Scan the JTAG chain, reading idcodes, 
    # setting IR lengths for known devices in the CseJtag 
    # data structures.  
    # CseJtag needs to know in order to do JTAG shifts.
    csejtag_tap autodetect_chain $handle $CSEJTAG_SCAN_DEFAULT
    
    # Get number of devices
    set deviceCount [csejtag_tap get_device_count $handle]
    
    set str [format "Found %u devices\n" $deviceCount]
    csejtag_session send_message $handle $CSE_MSG_INFO $str
    
    # Get a byte array of all idcodes by scanning the JTAG chain.
    csejtag_tap navigate $handle $CSEJTAG_TEST_LOGIC_RESET 0 0
    
    set idcodeBuffer [csejtag_tap shift_chain_dr $handle\
                                                 $CSEJTAG_SHIFT_READ \
                                                 $CSEJTAG_RUN_TEST_IDLE \
                                                 0 \
                                                 [expr $deviceCount * 32] \
                                                 0 \
                                                 -hextdimask 0 \
                                                 -hextdomask 0]
    
    for {set deviceIndex 0} {$deviceIndex < $deviceCount} {incr deviceIndex} {
        scanDevice $handle $deviceIndex $deviceCount $idcodeBuffer
    }
    
    csejtag_target unlock $handle
    csejtag_target close $handle
    csejtag_session send_message $handle $CSE_MSG_INFO "Closed cable successfully\n"
}

# Note that this function (with the exception of the call to
# scanUserReg() ) does not get any information
# which requires a new scan of the device chain.
# It is just lookup in the 'idcode.lst' file or
# information which CseJtag data structures already has such as:
# deviceCount and device idcodes.
proc scanDevice {handle deviceIndex deviceCount idcodeBuffer} {
    global CSE_MSG_INFO
    
    # position of buffer
    set startofidcodeBuf [expr $deviceIndex * 8 ]
    set idcodeBuf [string range $idcodeBuffer $startofidcodeBuf [expr $startofidcodeBuf + 7] ]

    # Get idcode without scanning the JTAG chain
    set idcodeBuffer2 [csejtag_tap get_device_idcode $handle $deviceIndex]
    
    # Convert idcodeFromBuffer and idcodeFromBuffer2 to unsigned integers
    set idcodeFromBuffer [expr "0x0$idcodeBuf"]
            
    set idcode [expr [format "%u" [binaryStringToInt $idcodeBuffer2] ] ]
    
    # Get IR length without scanning JTAG chain
    set irLength 0
    set irLength [csejtag_db get_irlength_for_idcode $handle $idcodeBuffer2]
    
    # NOTE If (irLength == 0) an application program needs to set it,
    #     ( using function csejtag_tap_set_irlength $handle $deviceIndex $irLength)
    #     perhaps after asking the user or looking it up someway.
    #     Without irLength known for all devices in the chain,
    #     JTAG communication will fail.
    
    # Get device name
    set deviceName [csejtag_db get_device_name_for_idcode $handle $idcodeBuffer2]
    
    # print out device info
    set str [format "\nDEVICE %u, idcode:%x, Scanned idcode:%x, IRLength:%u, %s\n" \
                    $deviceIndex $idcode $idcodeFromBuffer $irLength $deviceName]
    csejtag_session send_message $handle $CSE_MSG_INFO $str
    
    # Compares the two methods of obtaining the idcode,
    # prints a message if they are different.
    
    if {$idcode != $idcodeFromBuffer} {
        csejtag_session send_message $handle $CSE_MSG_INFO "IDCODES ARE NOT EQUAL!!!\n"
    }
}

proc writeMessage {handle msgFlags msg} {
    global debug
    global CSE_MSG_ERROR
    global CSE_MSG_WARNING
    global CSE_MSG_STATUS
    global CSE_MSG_INFO
    global CSE_MSG_NOISE
    global CSE_MSG_DEBUG
    if {[expr $debug || ($msgFlags != $CSE_MSG_DEBUG)]} {
        if {$msgFlags == $CSE_MSG_ERROR}      {
            puts -nonewline "Error:"
        } elseif {$msgFlags == $CSE_MSG_WARNING}         {
            puts -nonewline "Warning:"
        } elseif {$msgFlags == $CSE_MSG_INFO}            {
            puts -nonewline "Info:"
        } elseif {$msgFlags == $CSE_MSG_STATUS}          {
            puts -nonewline "Status:"
        } elseif {$msgFlags == $CSE_MSG_DEBUG}           {
            puts -nonewline "Debug:"
        }        
        puts -nonewline $msg
        flush stdout
    }
}

proc binaryStringToInt {binarystring} {
    set len [string length $binarystring]
    set retval 0
    for {set i 0} {$i < $len} {incr i} {
        set retval [expr $retval << 1]
        if {[string index $binarystring $i] == "1"} {
            set retval [expr $retval | 1]
        }
    }
    return $retval
}

# Start the program
main $argc $argv
