Project F

Vivado Tcl Build Script


Are you tired of firing up the Vivado GUI to build an FPGA project? You can automate your Xilinx FPGA build using a little Tcl. And you don’t even need to know any Tcl. Building your design from a script also comes in handy for continuous integration (CI) and Makefiles. Plus, I’ll show you how to quickly program your dev board with openFPGALoader.

Share your thoughts with @WillFlux on Mastodon or Twitter. If you like what I do, sponsor me. 🙏

Build Script

A basic Tcl build script replicates the typical FPGA workflow of synthesis, place, route, and write bitstream. The whole build takes place in memory without creating project files, so it’s faster than building in the GUI.

The only external info you need is the name of the FPGA part on your dev board. For example, the Arty A7-35T is xc7a35ticsg324-1L, and the Nexys Video is xc7a200tsbg484-1.

Create a file called build.tcl in the same directory as your source and XDC constraints file:

# read design sources (add one line for each file)
read_verilog -sv ""

# read constraints
read_xdc "arty.xdc"

# synth
synth_design -top "top" -part "xc7a35ticsg324-1L"

# place and route

# write bitstream
write_bitstream -force "hello.bit"

Use your own source files, or grab a simple example from the Hello Arty tutorial series. You can build the “Hello Arty” examples even if you don’t have an Arty board.

Here’s a quick summary of the Tcl commands in our script:

  • read_verilog - read Verilog source (with -sv for SystemVerilog). Use read_vhdl for VHDL.
  • read_xdc - read XDC constraints file
  • synth_design - synthesize (generate netlist) with specified top module and FPGA part
  • opt_design - optimize netlist for target part
  • place_design - place logic and I/O ports on device resources
  • route_design - routes the design on target part
  • write_bitstream - write bitstream to disk (-force overwrites existing file)

All the commands are covered in UG835 - Vivado Design Suite Tcl Command Reference Guide.

If you’re having trouble meeting timing with this simple script, take a look at the following commands:

  • route_design -directive Explore
  • phys_opt_design

There are many more options and optimizations you can play with. I might cover these in a subsequent post if there’s enough interest.

Pong Build

Here’s a slightly more complex example I use to build FPGA Pong for Arty A7-35T:

# build settings
set design_name "pong"
set arch "xc7"
set board_name "arty"
set fpga_part "xc7a35ticsg324-1L"

# set reference directories for source files
set lib_dir [file normalize "./../../../../lib"]
set origin_dir [file normalize "./../../"]

# read design sources
read_verilog -sv "${lib_dir}/clock/xc7/"
read_verilog -sv "${lib_dir}/essential/"
read_verilog -sv "${origin_dir}/${arch}/top_${design_name}.sv"
read_verilog -sv "${origin_dir}/"
read_verilog -sv "${origin_dir}/"

# read constraints
read_xdc "${origin_dir}/${arch}/${board_name}.xdc"

# synth
synth_design -top "top_${design_name}" -part ${fpga_part}

# place and route

# write bitstream
write_bitstream -force "${origin_dir}/${arch}/${design_name}.bit"

This script uses set to create variables and file normalize to create absolute paths.

You can find this build script in git: projf-explore/graphics/pong/xc7/vivado/build.tcl

Run Build Script

Before you can run the script from the command line (shell), you need to source the Vivado environment. Replace “<version>” with your Vivado version, such as 2022.2.

On Linux source the settings file:

. Xilinx/Vivado/<version>/

On Windows run the batch script from a command prompt:


You can then run your build script in the same shell:

vivado -mode batch -source build.tcl

If you’d rather Vivado not generate a journal and log files:

vivado -mode batch -nolog -nojournal -source build.tcl

Board Programming


Dev board programming is a bit of a faff with Vivado.

This program-board.tcl script should suffice for simple cases (replace hello.bit with your file):

set_property PROGRAM.FILE hello.bit [current_hw_device]
program_hw_devices [current_hw_device]

You run the script as before:

vivado -mode batch -source program-board.tcl

If you get an error, try disconnecting and reconnecting your board.

The script only programs FPGA memory. Programming SPI flash with Vivado involves additional steps I’m not going to go into; use openFPGALoader instead.


I use openFPGALoader to program my FPGA dev boards. It’s much smaller than Vivado and can program FPGA memory or SPI flash with one command. openFPGALoader supports a wide range FPGAs (not just Xilinx) and runs on Linux, macOS, and Windows.

openFPGALoader is included in the free OSS CAD Suite (release 2023-04-19 or later recommended).

Example commands:

# program memory on Arty S7-25
openFPGALoader -b arty_s7_25 hello.bit

# program memory on Nexys Video
openFPGALoader -b nexysVideo hello.bit

# program SPI flash on Nexys Video
openFPGALoader -b nexysVideo -f hello.bit

See the openFPGALoader docs for detailed instructions.

What’s Next?

If you enjoyed this post, please sponsor me. Sponsors help me create more FPGA and RISC-V projects for everyone, and they get early access to blog posts and source code. 🙏

Project F has loads more FPGA content. Quickly check your designs with Verilator lint, or perhaps you want to initialize memory or get to grips with Verilog numbers?