There are many possibilities of how you might debug your FPGA design. The most straigtforward way is to use the Chipscope (ILA – Integrated Logic Analyzer), which is accessed by JTAG interface. This is very practical, but it is intended for debug only. What if you want to configure a part of your design and optionally debug it as well? Users of SoC devices such as Zynq have the option to usually quite easily prepare a bootable image via petalinux / RTOS and issue the necessary commands to the FPGA fabric through any of the AXI_M interfaces available on the processing system.
If you do however only have an FPGA, you dont have such option. You can use the Microblaze / Nios Softcore processors and run some form of application on these for sure, but this requires additional effort and FPGA resources. The other option is to interface to the outer world via a UART / SPI interface or in advanced cases through interfaces such as PCIe. If you want to quickly build a design and do not require some intense configuration writes, then PCIe is not a good option . What comes quite handy is the JTAG to AXI Master IP.
This IP converts the JTAG traffic to AXI4/AXI4L traffic, so that you can use it as a master for your entire AXI4 infrastructure. The only thing you need is to provide a reset and a clock, thats basically all. The minimum diagram is shown below (PDF here). So if you have ever wondered how to light-up a LED on your board (My favorite task), here is the answer. After programming the device, you have to connect via JTAG and just issue AXI4/AXI4L transactions via TCL. Advanced users can of course implement a full TCL – based DMA framework :-)
If you want, you can of course use the JTAG2AXI Master IP only and get rid of the IP-integrator (Dont forget to assign an address for your slaves in the address editor in case you use it) and build your custom AXI4/AXI4L slave IP. This would be actually the minimal setup. After we are done with programming, here follows the TCL scripting part (From vivado TCL console):
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 |
#################################### ######## CONNECT TO HARDWARE ####### # Note: To find the correct device, use: get_hw_targets # Note: "*/xilinx_tcf/Xilinx/1234-oj1A" is my traget JTAG device name for MiniZed. open_hw connect_hw_server -url localhost:3121 current_hw_target [get_hw_targets */xilinx_tcf/Xilinx/1234-oj1A] #################################################################### ####### OPTIONALLY CHANGE THE JTAG FREQUENCY (Default 15MHz) ####### # Note: To list all properties: list_property [get_hw_targets \ */xilinx_tcf/Xilinx/1234-oj1A] #get_property PARAM.FREQUENCY [get_hw_targets \ */xilinx_tcf/Xilinx/1234-oj1A] #set_property PARAM.FREQUENCY 15000000 [get_hw_targets \ */xilinx_tcf/Xilinx/1234-oj1A] open_hw_target ################################# ####### CONNECT TO DEVICE ####### # Note: Use get_hw_devices to find your device current_hw_device [get_hw_devices xc7z007s_1] # (Optional): set_property PROBES.FILE {H:/MiniZed/Mini_Work/Mini_Work.runs/Default_Impl/Minized_TOP.ltx} [lindex [get_hw_devices] 0] # (Optional): set_property PROGRAM.FILE {H:/MiniZed/Mini_Work/Mini_Work.runs/Default_Impl/Minized_TOP.bit} [lindex [get_hw_devices] 0] refresh_hw_device -update_hw_probes false [lindex [get_hw_devices xc7z007s_1] 0] reset_hw_axi [get_hw_axis hw_axi_1] ########################################### ####### READ JTAG TO AXI PARAMETERS ####### # This is optional to show the JTAG2AXI IP Capabilities: get_property AXI_ADDR_WIDTH [get_hw_axis] get_property AXI_DATA_WIDTH [get_hw_axis] get_property AXI_ID_WIDTH [get_hw_axis] get_property BURST_TYPE_FIXED_SUPPORTED [get_hw_axis] get_property BURST_TYPE_INCR_SUPPORTED [get_hw_axis] get_property BURST_TYPE_WRAP_SUPPORTED [get_hw_axis] get_property CLASS [get_hw_axis] get_property PROTOCOL [get_hw_axis] get_property STATUS.BRESP [get_hw_axis] get_property STATUS.RRESP [get_hw_axis] ####################################################### ####### CREATE AXI4L TRANSACTIONS AS NECESSARY ######## create_hw_axi_txn Led_On [get_hw_axis hw_axi_1] -address 80080004 -data 00000003 -type write create_hw_axi_txn Led_Off [get_hw_axis hw_axi_1] -address 80080004 -data 00000000 -type write create_hw_axi_txn Magic_Read [get_hw_axis hw_axi_1] -address 80080000 -type read ######################## # RUN THE TRANSACTIONS # run_hw_axi Magic_Read run_hw_axi Led_On run_hw_axi Led_Off |
Note: For heavy-duty tests and debugging, it may be convenient to read results from FPGA and write them to a file for offline analysis (via Matlab for example) :
1 2 3 4 5 6 7 8 9 |
# Open File for Writing set Fid [open WriteTest.txt w] set Imax 20 for {set i 0} {$i < $Imax} {incr i} { set CMDX [ format "%08X" $i ] puts $Fid $CMDX } # Close File close $Fid |
Additional good source of information about tcl usage is located in the UG835.
Additional information may be found in the IP guide (PG174) or in UG908 – Vivado Design Suite “Programming and Debugging”. Dont forget to use the docnav to always find the latest version of the associated documents! By the way: I did have 2 leds in my design Red and Green. I dont like red too much, but decided to connect it as well. They are on address 0x8008004 and use the two LSBs (theas why i issue 0x00000003). I do also have a Read-Only random magic value on address 0x80080000 of “7B8177AF” to verify the function of the interface “just in case”. And yes,I do have the most cost-optimized FPGA on the market (xc7z007s – Minized) and of course, you can use JTAG even for Zynq, although this doesnt make much sense O:)