FPGA meets DevOps UPDATED! - AMD / Xilinx Vivado and Petalinux + Git
A couple of years ago I wrote a few blog posts regarding FPGA and devops; in particular on how to use Xilinx/AMD Vivado with git, Jenkins and docker.
With these new blog posts, I am going to update that content using Vivado 2022.2. I will also replace Jenkins with Gitlab for continuous integration.
I want to show you that it is not difficult nor expensive to get started with devops for FPGA development.
In this blog post, I am going to show you how to use version control for Xilinx/AMD Vivado and Petalinux projects. I am going to use git, but you can use SVN or other version control tools.
Requirements
My typical Vivado FPGA project has a block design as top level with an automatically generated and managed wrapper.
It has a mix of Vivado 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 was researching how to better integrate Vivado with source version control, I defined the following requirements:
- The block design is the primary source to recreate the design (IP cores configuration, wiring, etc)
- The top level wrapper HDL file shouldn’t be under version control since it can be recreated from the block diagram
- Minimum TCL scripts coding for each project
- Easy to save changes made in the Vivado user interface (i.e. implementation settings)
- Use the project-based out of context flow to reduces build time
- Continuous Integration friendly
Vivado can do most of the heavy lifting by 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 block design file.
There is only one issue. 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 (https://github.com/starwaredesign/vivado-project-template).
Let’s checkout the template and see what’s inside.
$ git clone This email address is being protected from spambots. You need JavaScript enabled to view it.:starwaredesign/vivado-project-template.git
$ cd vivado-project-template
$ tree
.
├── fpga
│ ├── bd
│ └── scripts
│ ├── build_bitstream.tcl
│ ├── build_fpga.sh
│ ├── create_project_tcl.tcl
│ └── export_design.tcl
├── LICENSE
├── linux
│ └── scripts
│ └── build_image.sh
└── README.md
5 directories, 7 files
There is one directory for the FPGA design and one for the Petalinux project. Inside the FPGA directory there is a bd directory that is where we’re going to save the block design file.
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 command with the correct parameters for this folder structure, stores the generated file in the scripts folder and modifies it to regenerate the top level wrapper file when the script is executed.
$ cat fpga/scripts/create_project_tcl.tcl
set script_name "scripts/recreate_prj.tcl"
set tmp_script_name [ string map { ".tcl" "_old.tcl" } ${script_name} ]
write_project_tcl -no_copy_sources -force -use_bd_files -origin_dir_override "scripts" -target_proj_dir "vivado" ${script_name}
file copy -force $script_name $tmp_script_name
set origfile [open $tmp_script_name r]
set newfile [open $script_name w+]
while {[eof $origfile] != 1} {
gets $origfile lineInfo
if [ string equal $lineInfo "# Set 'sources_1' fileset file properties for local files"] {
puts $newfile "make_wrapper -files \[get_files *\${_xil_proj_name_}.bd\] -top -import"
}
if {! [string match "*file normalize *_wrapper.v*" $lineInfo]} {
puts $newfile $lineInfo
}
}
close $origfile
close $newfile
file delete -force scripts/recreate_prj_old.tcl
Let’s create a new git repository and add the current files to it. For this example I am using a cloud based gitlab installation, but it could be hosted locally. Change the git repository to point to your project.
$ git clone This email address is being protected from spambots. You need JavaScript enabled to view it.:swddevops/devopsexample.git
And copy the files from the template.
$ cp -a vivado-project-template/* devopsexample/
Add all the files to the git repo and do an initial commit:
$ git add .
$ git commit -am "Initial commit"
$ git push
Vivado
Now let’s create an example Vivado project called devopsexample and use vivado as the target directory. Make sure “create new directory” is not selected.
For example we can create a project targeting a Zedboard which is based on the Zynq 7000 SoC. You might need to download the board files.
We then create a block design with LEDs and buttons. The block design has the same name as the project and it is saved in the bd directory.
Generate the top level wrapper and let Vivado manage it.
I generally build the project to make sure everything is fine.
Now from the Vivado TCL console we can run create_project_tcl to create a script that will re-generate the Vivado project.
Make sure you’re inside the fpga directory.
$ pwd
$ cd fpga
$ source scripts/create_project_tcl.tcl
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 status
$ git add fpga/bd/devopsexample/devopsexample.bd
$ git add fpga/scripts/recreate_prj.tcl
$ git commit -m “Add FPGA project.”
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
$ git clean -f -x -d
$ tree
And now execute the script recreate_prj.tcl
$ cd fpga
$ vivado -mode batch -source scripts/recreate_prj.tcl
And now we have recreated the project with the minimum source code files, but we can for example configure it using the Xilinx Vivado GUI.
A couple of notes on the scripts:
- The various scripts assume a directory 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
- create_project_tcl must be called every time you change settings in vivado
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
PetaLinux
What about Petalinux? It is a bit easier and doesn’t require any scripting.
Let’s build the bitstream and export the design with the bitstream.
Now let’s create a simple Petalinux project using the design we have just exported.
$ cd ../linux
$ petalinux-create --type project --template zynq --name devopsexample
$ cd devopsexample
$ petalinux-config --get-hw-description ../../fpga/vivado/devopsexample_wrapper.xsa
Use the default options for now.
Let’s add the Petalinux project to source version control. Note that Petalinux automatically creates the .gitignore file.
$ cat .gitignore
$ git add .
$ git commit -am “Initial petalinux commit.”
Build the petalinux image
$ petalinux-build
And create the deployment files
$ petalinux-package --force --boot --fpga ../../fpga/vivado/devopsexample.runs/impl_1/devopsexample_wrapper.bit --uboot
Let’s copy the generated files to the SD card.
$ cp images/linux/image.ub images/linux/BOOT.BIN images/linux/boot.scr /media/matteo/BOOT/
$ umount /dev/sdc1
Insert the SD card and turn on the board. Use picocom to view the console.
$ dmesg
$ picocom -b 115200 /dev/ttyS1
Conclusion
In the next blog post I am going to show you how to integrate Vivado and Petalinux with Gitlab continuous integration.