-
Notifications
You must be signed in to change notification settings - Fork 3
TclVivado
Vivado can be nearly 100% controlled using Tcl from a command prompt (probably 100% but there are some things we haven't yet figured out how to do in Tcl). This makes it possible to create scripts to do just about everything you may want to do. This tutorial will help you get started.
There are lots of other references out htere you should learn to work with. One is: Vivado Design Suite Tcl Command Reference Guide (2019.1).
Also, typing part of a command name in the Tcl command prompt and hitting ESC will show all the commands that start with that. Then, typing the command name followed by -help will give you all the details on the command.
You can start Vivado multiple ways from an O/S command line (note that the # character starts a comment whenever you see them):
# Start normally with GUI
vivado
# Start in command line mode
vivado -mode tcl
# Just run a tcl script and never create a GUI or a command line
vivado -mode batch -source myscript.tcl
# Specify where to put .log and .jou files
vivado -log /tmp/vivado.log -journal /tmp/vivado.jou
For the first two versons above, you can turn the GUI on and off from the Tcl command line as you like:
start_gui
stop_gui
Thus, you can work in whatever mode is mode comfortable. DON'T FORGET - you can run all the Tcl commands you want even when in GUI mode from the Tcl Command Line. But, commands will operate more slowly in GUI mode - if you have lots of processing to do, turn off the GUI while you do it and it will go faster.
Vivado has two modes of operation: project mode and non-project mode.
- Project mode is what you get when you open the GUI, selected Create New Project, add sources, etc. You know a project was created this way when there is a .xpr file created and in the directory.
- Non-project mode is typically what you get when you just use Tcl commands to read, synthesize, and implement HDL files into bitstreams.
As mentioned above, you can run Vivado in non-GUI mode - non-project mode is what you get when you run Vivado this way and write scripts to create and compile your designs. However, as noted, you can always start and stop the GUI.
Here is a basic compilation script which will compile all the HDL files in the current directory. It is classical non-project mode and gives a starting point for a script you could create for your needs.
# Define a procedure (function)
# It will compile all the .sv, .v, and .vhd files in a directory.
# top is the name of the top level module in the design
proc compile {top} {
puts "Closing any designs that are currently open..."
puts ""
close_project -quiet
puts "Continuing..."
# Create a design for a specific part
link_design -part xc7a100t-csg324-3
# Compile any .sv, .v, and .vhd files that exist in the current directory
if {[glob -nocomplain *.sv] != ""} {
puts "Reading SV files..."
read_verilog -sv [glob *.sv]
}
if {[glob -nocomplain *.v] != ""} {
puts "Reading Verilog files..."
read_verilog [glob *.v]
}
if {[glob -nocomplain *.vhd] != ""} {
puts "Reading VHDL files..."
read_vhdl [glob *.vhd]
}
puts "Synthesizing design..."
synth_design -top $top -flatten_hierarchy full
# Here is how you add a .xdc file to the project
read_xdc $top.xdc
# You will get DRC errors without the next two lineswhen you
# generate a bitstream.
set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]
# If you don't need an .xdc for pinouts (just generating designs for analysis),
# you can include the next line to avoid errors about unconstrained pins.
#set_property BITSTREAM.General.UnconstrainedPins {Allow} [current_design]
puts "Placing Design..."
place_design
puts "Routing Design..."
route_design
puts "Writing checkpoint"
write_checkpoint -force $top.dcp
puts "Writing bitstream"
write_bitstream -force $top.bit
puts "All done..."
# You might want to close the project at this point,
# but probably not since you may want to do things with the design.
#close_project
}
To run this script from a Tcl command prompt, you first need to have put it into a file such as basicCompile.tcl in your directory. Once running Vivado, you can load it from the Tcl console by typing:
source basicCompile.tcl
Then, you need to actually run it:
compile mydesign
NOTE: Vivado, when run, has the notion of a current directory where it is running from. You do an ls from the Tcl console to see what files are in the current directory, a cd to change directories, and a pwd to see what directory you are in. Keep that in mind as you work.
To illustrate some other functionality, here is a script which will print out a report on the currently open design.
# Print the size statistics of an open Vivado design to the specified file.
# Specifically, the number of Cells, number of nets, number of sites, and
# the cell type distribution is printed.
# This may be useful to understand the size of designs being used for
# benchmark purposes.
proc print_cell_statistics { {filename "cell_stats.txt"} } {
set fp [open $filename w]
puts $fp "Benchmark: [get_property TOP [get_design]]"
puts $fp "----------------------"
#print size statistics
puts $fp "\tCell Count: [llength [get_cells -hierarchical -quiet]]"
puts $fp "\tNet Count: [llength [get_nets -hierarchical -quiet]]"
puts $fp "\tSite Count: [llength [get_sites -filter IS_USED -quiet]]\n"
#print distribution statistics
puts $fp "\tCell Distribution: "
set cell_distribution_map [generate_cell_distribution_dictionary]
dict for {group cell_list} $cell_distribution_map {
puts $fp "\t\t$group: [llength $cell_list]"
}
close $fp
}
# Helper function used in print_cell_statistics
proc generate_cell_distribution_dictionary { } {
set cell_dictionary [dict create]
foreach cell [get_cells -hierarchical] {
dict lappend cell_dictionary [get_property PRIMITIVE_GROUP $cell] $cell
}
return $cell_dictionary
}
Some things to note in this code:
There is a single parameter for the print_cell_statistics procedure but it is optional and has a default value given ("cell_stats.txt"). The parameter is called filename.
proc print_cell_statistics { {filename "cell_stats.txt"} } {
It shows how to open files and write to them.
set fp [open $filename w]
...
puts $fp "Benchmark: [get_property TOP [get_design]]"
...
close $fp
It shows how to get the current design, then get the property named TOP associated with it:
[get_property TOP [get_design]]
It shows how to set a variable with something and then later refer to it (with a $ sign in front):
set fp [open $filename w]
...
puts $fp "----------------------"
It shows how to get all the cells in the design (the hierarchical flag says to traverse the hierarchy, the -quiet flag says to not print the resulting list to the console):
[get_cells -hierarchical -quiet]
It shows how to get the length of a list:
[llength [get_cells -hierarchical -quiet]]
Note how commands are wrapped in [ ... ] when they return something you then want to use like in the example above.
If all you wanted was to see a list of cells in the design you could just do this and it would print the list to the screen:
get_cells
If you wanted to assign those to a variable you would use the set command:
set cells [get_cells]
Later, you could refer to that list using $ notation:
puts "Length of list of cells = [llength $cells]"
Or, you could just print the list:
puts "Cells = $cells"
There are similar command for getting all kinds of things: tiles, sites, ports, pins, pips, nets, iiobanks, and bels. In each case, they will return a list.
You can filter what you get. Here is what get_cells returns, then after that, is another query but asking for just cells that start with the letter 'c' in their name:
Vivado% get_cells
a_IBUF_inst b_IBUF_inst cin_IBUF_inst cout_OBUF_inst cout_OBUF_inst_i_1 s_OBUF_inst s_OBUF_inst_i_1
Vivado% get_cells c*
cin_IBUF_inst cout_OBUF_inst cout_OBUF_inst_i_1
When you do a command like get_cells, you can specify you want all the cells inside some other object. This is how you would get the sites inside a specified tile:
get_sites -of [get_tiles CLBLL_L_X5Y23]
and, to assign that to a variable you would do:
set mysite [get_sites -of [get_tiles CLBLL_L_X5Y23]]
There are lots of other filtering and modification options available - see the Xilinx Tcl reference for more information.
Lists are used a lot in Tcl. The code fragment below shows how to loop across the elements of a list:
foreach cell [get_cells -hierarchical] {
dict lappend cell_dictionary [get_property PRIMITIVE_GROUP $cell] $cell
}
And, that code shows how to use other data structures such as a dictionary (dict).
Here is a way to print out the sites in a tile:
foreach s [get_sites -of [get_tiles CLBLL_L_X5Y23]] {
puts "Site: $s"
Everything in Vivado has properties (cells, tiles sites, pins, ...). Above, we saw how to get the TOP property associated with the current design. Here is an example of how to see all the properties associated with a cell:
Vivado% report_property [get_cells a_IBUF_inst]
Property Type Read-only Value
BEL string false IOB33.INBUF_EN
CLASS string true cell
FILE_NAME string true /home/nelson/exampleVivadoDesigns/add/add.sv
IOSTANDARD string true LVCMOS33
IS_BEL_FIXED bool false 0
IS_BLACKBOX bool true 0
IS_DEBUGGABLE bool true 1
IS_LOC_FIXED bool false 1
IS_ORIG_CELL bool true 0
IS_PRIMITIVE bool true 1
IS_REUSED bool true 0
IS_SEQUENTIAL bool true 0
LINE_NUMBER int true 1
LOC site false IOB_X0Y101
NAME string true a_IBUF_inst
PRIMITIVE_COUNT int true 1
PRIMITIVE_GROUP enum true IO
PRIMITIVE_LEVEL enum true LEAF
PRIMITIVE_SUBGROUP enum true ibuf
PRIMITIVE_TYPE enum true IO.ibuf.IBUF
REF_NAME string true IBUF
REUSE_STATUS enum true
SLR_INDEX int true 0
STATUS enum true FIXED
So, how to learn even what properties an object has? The command above is one way. There are others which allow you to get the value of a specific property. One example would be:
get_property LOC -of $c
where c has been assigned to point to a specific cell.
You can filter on properties when you use a command like "get_cells". Here is one:
get_pins * -filter {DIRECTION == IN && NAME !~ "*RESET*"}
This will return all the pins whose direction is IN and whose name does NOT contain the substring RESET in their NAME property.
In order to fully understand the range of things you do you need to get a copy of Vivado Design Suite Tcl Command Reference Guide (2019.1) and use it as your reference.
You should also run the Vivado GUI and do some comparisons. Examples follow.
- Start the Vivado GUI (start_gui), click on the "Netlist Tab", expand list of cells, click on a cell, and see the window below that opens to show you all there is to know about that cell.
- In the Tcl Console figure out the Tcl commands to show you what the GUI is showing you. That is, print out the various cell properties.

- Repeat the above but for the nets in the design.a
- Make sure you have done "Open Implementation" for a design. This will bring up a physical view of the FPGA with your design mapped to it.
- Click on the FPGA layout figure (right side of screen).
- Whatever you clicked will show up where the cell properties window used to be. It will probably be a clock region. Its properties will be displayed in the info window.
- See how to access it and its properties using Tcl.
- Now, zoom in and click on smaller things like tiles, sites, wires, LUTs, etc. In each case, compare what the GUI shows in that info window with what you can query using Tcl.
- Select a cell using Tcl command: "select_objects [get_cells a*].
- Choose "Fit Selection" from the View menu to zoom in on that cell.
- Zoom in and select an object graphically in the device view. Zoom and click until you have selected a tile (you can tell what you have selected by looking in the properties pane to the left of the device view window.
- Assign what you selected to a variable using
set myobj [get_selected_objects]. - Now, use Tcl commands to query that object's properties or to manipulate it some way using the
myobjvariable you set it to.
Now, experiment with mixing graphical and Tcl ways of doing various things. When you are trying to figure something out, this can be a very powerful way to operate. And, remember, if you choose to run a complex Tcl script, you can always stop the GUI, run the script, then restart it - this will make the script run WAY faster.
- Expand the print_cell_statistics Tcl procedure above to print additional information on your design. If the cells are placed, print where they are placed. If the nets are routed, print all the pips or wires that make them up. Print other properties of the cell (the library cell they map to, their type, ...). The point of this is to see how much information you can glean from the Tcl interface about your design. Could you actually print out a complete representation of the design (cells, nets, pins) using Tcl? The answer is Yes - how close can you get to being able to do that.
- Write a script to print an analysis of the loaded device. How many rows and columns does it have? How many I/O pin locations? How many I/O banks? How many CLB tiles? How many LUTs? How many BRAM tiles or sites?
- Write a script to analyze a specific switchbox (an INT_L tile for example). Print out the name of each wire in the tile and anything else interesting about it.
Initially created by Brent Nelson, April 2020.