Our offices are closed from August 1, 2020 to August 16, 2020. No orders will be shipped during this time.

Tool Command Language (Tcl)

Tcl (Tool Command Language) is the standard language used to control Vivado® programmatically. Virtually any operation performed within the graphical user interface has a corresponding Tcl command, displayed in the Vivado console.

Getting started

In Tcl, everything is a string. Procedures are called with the procedure name followed by the list of arguments, separated by white spaces:

set a 1

The command set assigns the value 1 to the variable a. The value of a can be accessed with the dollar-sign $:

set b hello$a
# The variable `b` now contains the value `hello1`.

Procedure are defined with the following syntax:

proc concat {x y} {
  return $x$y
set c [concat $a $b]
# The variable `c` contains the value `1hello1`.

The brackets notation [] tells the intepreter to substitute [concat $a $b] with the result of the command concat $a $b. On the contrary, the brace notation {} can be used to prevent substitution:

set d {concat $a $b}
# The variable `d` contains the value `concat $a $b`.

Mathematical expressions are computed with the command expr:

proc add10 {x} {
    return [expr $x + 10]
set thirty [add10 20]

Helper procedures

Helper procedures ease the creation of Vivado block design. View these procedures on GitHub in fpga/lib/utilities.tcl.

Instantiate, Configure and Interconnect IP cores

cell from Pavel Demin

cell xilinx.com:ip:c_counter_binary:12.0 counter {
  CE true
} {
  CLK adc_dac/adc_clk

Instantiates a binary counter from the Xilinx library with the "clock enable" option and connect its clock to the ADC clock.

The command is equivalent to:

create_bd_cell -type ip -vlnv xilinx.com:ip:c_counter_binary:12.0 counter
set_property CONFIG.CE true [get_bd_cells counter]
connect_bd_net [get_bd_pins counter/CLK] [get_bd_pins adc_dac/adc_clk]

Connect cell pins when IP core already exists


# Connects the output of the binary counter to the `count` pin of the status register
connect_cell counter {
  Q  [sts_pin count]

(see sts_pin procedure below).

Connect two pins

connect_pins pin_name1 pin_name2

connect_pins counter/Q [sts_pin count]

Retrieve data from the configuration file

Get a parameter defined in config.yml

set n_adc [get_parameter n_adc]

Get info about a memory mapped region

set memory_name config
set range  [get_memory_range $memory_name]       ;# 4K
set offset [get_memory_offset $memory_name]      ;# 0x60000000
set depth  [get_memory_depth $memory_name]       ;# 1024
set width  [get_memory_addr_width $memory_name]  ;# 10

Procedures that return a pin name

Theses procedures take pin names as inputs and output pin names, allowing to chain IP creation.

Get control/status pins defined in config.yml

ctl_pin name, sts_pin name

# Connect DAC to config and ADC to status
for {set i 0} {$i < $n_adc} {incr i} {
  connect_pins [ctl_pin dac$i] adc_dac/dac[expr $i+1]
  connect_pins [sts_pin adc$i] adc_dac/adc[expr $i+1]

Slice a pin

get_slice_pin pin_name from to

# Connect the 8 least significant bits of the `led` control register to the port `led_o`:
connect_bd_net [get_bd_ports led_o] [get_bd_pins [get_slice_pin [ctl_pin led] 7 0]]

Create a constant

get_constant_pin value width

# Set the first DAC to 0
connect_pins adc_dac/dac0 [get_constant_pin 0 [get_parameter dac_width]]

Concatenate a list of pins

get_concat_pin pin_list

# Equivalent to bitshift: adc1 << 2
set pin [get_concat_pin [list [get_constant_pin 0 2] adc_dac/adc1]]

Perform logical operations on pins

set and_pin [get_and_pin pin1 pin2]
set or_pin [get_or_pin pin1 pin2]
set nor_pin [get_nor_pin pin1 pin2]
set not_pin [get_not_pin pin1]

Compare two pins

set ge_pin [get_GE_pin pin1 pin2] ;# pin1 >= pin2
set gt_pin [get_GT_pin pin1 pin2] ;# pin1 > pin2
set le_pin [get_LE_pin pin1 pin2] ;# pin1 <= pin2
set lt_pin [get_LT_pin pin1 pin2] ;# pin1 < pin2
set eq_pin [get_EQ_pin pin1 pin2] ;# pin1 == pin2
set ne_pin [get_NE_pin pin1 pin2] ;# pin1 != pin2

See also

[email protected]