This email address is being protected from spambots. You need JavaScript enabled to view it.

  • Home
  • Blog
  • FPGA meets DevOps - Xilinx Vivado and Git

FPGA meets DevOps - Xilinx Vivado and Git

In this blog post of the series “FPGA meets DevOps”, I am going to show you how to use source version control with Xilinx Vivado.

Most of the existing documentation about source version control and Vivado, i.e. User Guide 1198 (, requires the developer to write a TCL script to recreate the project.

The problem with this approach is that changes to the project in Vivado (i.e. changing the implementation strategy or place and route parameters) have to be manually ported to the TCL file.

My typical Xilinx Vivado FPGA project has a block design as top level with automatically generated and managed wrapper. It has a mix of Xilinx and custom IP cores and I use the Out Of Context flow for synthesis since it reduces build time by caching IP cores that haven’t been modified or updated.

When I started researching how to better integrate Vivado with source version control, I defined the following requirements:

  1. The block design is the primary source to recreate the design (IP cores configuration, wiring, etc)
  2. The top level wrapper HDL file shouldn’t be under version control since it can be recreated from the block diagram
  3. Minimum TCL scripts coding for each project
  4. Easy to save changes made in Vivado GUI (i.e. implementation settings)
  5. Use the project-based out of context flow to reduces build time
  6. Continuous Integration friendly

I am going to use Git as source version control tool, but others can be used as well (SVN, etc.).

Vivado can do most of the leg work generating a TCL script to recreate the project using the command write_project_tcl. By default it embeds the block design in the TCL script, but it can be configured to use an existing .bd file. The only issue is that the top level wrapper HDL file is part of the source set and it is not generated automatically, but I have created a simple script to get around it.

You can download a template folder structure with the scripts from github ( Let’s decompress the archive and see what’s inside.

$ wget
--2019-02-24 18:08:20--
Resolving (,
Connecting to (||:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: [following]
--2019-02-24 18:08:20--
Resolving (,
Connecting to (||:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [application/zip]
Saving to: ‘’ [ <=> ] 3.07K --.-KB/s in 0.1s
2019-02-24 18:08:21 (30.3 KB/s) - ‘’ saved [3145]

$ unzip
creating: vivado-project-template-master/
inflating: vivado-project-template-master/.gitignore
creating: vivado-project-template-master/bd/
extracting: vivado-project-template-master/bd/.gitignore
creating: vivado-project-template-master/ci/
inflating: vivado-project-template-master/ci/Jenkinsfile
creating: vivado-project-template-master/scripts/
inflating: vivado-project-template-master/scripts/build_bitstream.tcl
inflating: vivado-project-template-master/scripts/
inflating: vivado-project-template-master/scripts/create_project_tcl.tcl
creating: vivado-project-template-master/vivado/
extracting: vivado-project-template-master/vivado/.gitignore

$ cd vivado-project-template-master

There is a bd directory that is where we’re going to save the block design file. CI stands for continuous integration and we’re going to have a look at that in the next blog post.

Vivado is where the temporary Vivado project files are going to be stored and it is not under version control.

The scripts folder contains a couple of TCL utility scripts and in particular we’re going to use create_project.tcl.

This script calls the write_project_tcl Vivado command with the correct parameters for this folder structure, store the generated file in the scripts folder and modify it to regenerate the top level wrapper file when the script is executed.

Let’s create a new git local repository and add the current files to it.

$ git init
Initialized empty Git repository in /work/projects/blog/tmp/blog01/vivado-project-template-master/.git/

$ git add .

Now let’s create an example Vivado project and use vivado as the target directory.  Make sure create new directory is not selected.

blog01 01

For example we can create a project with Zynq FPGA based on the Zedboard. 

blog01 02

We then create a block design with i.e. LEDs and buttons. The block design has the same name as the project and it is saved in the bd directory.

blog01 03


blog01 04

Generate the top level wrapper and let Vivado manage it.

Now from the Vivado TCL console we can run the create_project_tcl to create a script that will re-generate the Vivado project.

source scripts/create_project_tcl.tcl

blog01 05

We can now exit Vivado and add two files to the git repo: the block design file and the script that was generated when we executed create_project_tcl.

$ git add bd/example_blog1/
$ git add scripts/recreate_prj.tcl
$ git commit -am "Initial commit"
[master (root-commit) ed68db8] Initial commit
8 files changed, 1742 insertions(+)
create mode 100644 .gitignore
create mode 100644 bd/.gitignore
create mode 100644 bd/example_blog1/
create mode 100644 ci/Jenkinsfile
create mode 100644 scripts/build_bitstream.tcl
create mode 100755 scripts/
create mode 100644 scripts/create_project_tcl.tcl
create mode 100644 scripts/recreate_prj.tcl

All the other files can be regenerated so they don’t need to be under version control.

To show how to recreate the project, we can delete all the files that aren’t under version control

$ tree
├── bd
│   └── example_blog1
│   ├──
│   ├── example_blog1.bxml
│   ├── example_blog1_ooc.xdc
│   ├── hdl
│   │   └── example_blog1_wrapper.v
│   ├── ip
│   │   ├── example_blog1_auto_pc_0
│   │   │   ├── example_blog1_auto_pc_0.xci
│   │   │   └── example_blog1_auto_pc_0.xml
│   │   ├── example_blog1_axi_gpio_0_0
│   │   │   ├── example_blog1_axi_gpio_0_0.xci
│   │   │   └── example_blog1_axi_gpio_0_0.xml
│   │   ├── example_blog1_processing_system7_0_0
│   │   │   ├── example_blog1_processing_system7_0_0.xci
│   │   │   └── example_blog1_processing_system7_0_0.xml
│   │   ├── example_blog1_ps7_0_axi_periph_0
│   │   │   ├── example_blog1_ps7_0_axi_periph_0.xci
│   │   │   └── example_blog1_ps7_0_axi_periph_0.xml
│   │   └── example_blog1_rst_ps7_0_100M_0
│   │   ├── example_blog1_rst_ps7_0_100M_0.xci
│   │   └── example_blog1_rst_ps7_0_100M_0.xml
│   ├── sim
│   │   └── example_blog1.v
│   ├── synth
│   │   └── example_blog1.v
│   └── ui
│   └── bd_ba885a1a.ui
├── ci
│   └── Jenkinsfile
├── example_blog1.cache
│   ├── compile_simlib
│   │   ├── ies
│   │   ├── modelsim
│   │   ├── questa
│   │   ├── riviera
│   │   ├── vcs
│   │   └── xcelium
│   └── wt
│   ├── gui_handlers.wdf
│   ├── java_command_handlers.wdf
│   ├── project.wpc
│   └── webtalk_pa.xml
├── example_blog1.hw
│   └── example_blog1.lpr
├── example_blog1.ip_user_files
├── example_blog1.sim
├── example_blog1.xpr
├── scripts
│   ├── build_bitstream.tcl
│   ├──
│   ├── create_project_tcl.tcl
│   └── recreate_prj.tcl
├── vivado
├── vivado.jou
└── vivado.log

$ git clean -f -x -d
Removing .Xil/
Removing bd/example_blog1/hdl/
Removing bd/example_blog1/ip/
Removing bd/example_blog1/sim/
Removing bd/example_blog1/synth/
Removing bd/example_blog1/ui/
Removing example_blog1.cache/
Removing example_blog1.hw/
Removing example_blog1.ip_user_files/
Removing example_blog1.sim/
Removing vivado/

$ tree
├── bd
│   └── example_blog1
│   └──
├── ci
│   └── Jenkinsfile
└── scripts
├── build_bitstream.tcl
├── create_project_tcl.tcl
└── recreate_prj.tcl

4 directories, 6 files

Launch the script recreate_prj

vivado -mode batch -source scripts/recreate_prj.tcl
****** Vivado v2018.3 (64-bit)
**** SW Build 2405991 on Thu Dec 6 23:36:41 MST 2018
**** IP Build 2404404 on Fri Dec 7 01:43:56 MST 2018
** Copyright 1986-2018 Xilinx, Inc. All Rights Reserved.

source scripts/recreate_prj.tcl
# set origin_dir "scripts"
# if { [info exists ::origin_dir_loc] } {
# set origin_dir $::origin_dir_loc
vivado -mode batch -source scripts/recreate_prj.tcl


# current_dashboard default_dashboard
INFO: [Common 17-206] Exiting Vivado at Sun Feb 24 19:15:32 2019...

And now we have recreated the project with the minimum source code files, but we can i.e. configure using the Xilinx Vivado GUI.


  • The various scripts assume a folders tree as described above
  • Before launching recreate_prj.tcl, the vivado folder must be deleted. This is "by design" since it avoids overwriting the project by mistake
  • The file recreate_prj.tcl must be under source version control

In the sample project, you can see how .gitignore files can be used to avoid adding files generated by Vivado to the source version control repo.

$ cat .gitignore


In the next blog post we’re going to see how to run Vivado inside a Docker container and integrate it with a tool for continuous integration called Jenkins.

Tags: devops, Xilinx, fpga

About us

Starware Design provides design and consulting services for FPGA, board-level, embedded software and edge AI projects.

Whether you need a consultant to be part of your team on-site or a turnkey solution, Starware Design has the capability to suit your requirements.