Posts Vivado project for version control, part 1: How to package an IP from sources
Post
Cancel

Vivado project for version control, part 1: How to package an IP from sources

From time to time pops up in the FPGA/Vivado community discussions on how to structure projects for version control. I’ve seen some methods that, IMHO, are not the best approach: they add the project’s generated files to the repository.

We’ll take another approach. This post is about scripting an IP from TCL and HDL sources to be kept in a repository. In the second part of this series, I’ll talk about generating an entire Vivado project from sources.

Keep in mind there are other ways to get the job done. But I’ve been using this flow for at least four years with good results. Feel free to adapt to your needs.

Prerequisites

For this post, we’ll be using Vivado 2020.2. The source code used here is available at:

https://github.com/lucasbrasilino/axis_exec_op

And, yes, please consider starring the repository. ;-)

IP file organization

Our example IP is called axis_exec_op. Its job is to apply some operation over 32-bit words delivered to an AXI4 Stream slave interface. Then, the result is sent out through an AXI4 Stream master interface.

The IP files are organized in three directories:

  • The IP top directory, which name matches the IP: axis_exec_op;
  • A directory for the TCL script named tcl;
  • A directory for HDL files named, surprise surprise, hdl.

Here goes the directory structure:

1
2
3
4
5
6
7
8
9
10
11
12
$ tree axis_exec_op/
axis_exec_op/
├── hdl
│   ├── axis_exec_op.sv
│   ├── axis_exec_op_wrapper.v
│   ├── easyaxil_out.v
│   ├── fallthrough_small_fifo_v2.v
│   └── small_fifo_v3.v
├── Makefile
└── tcl
    ├── axis_exec_op.tcl
    └── metadata.tcl

A Makefile is available in the top directory for helping us executing vivado and cleaning up generated/log files.

TCL scripts

As you can see from above, there are two TCL scripts. The metadata.tcl sets global variables, and the axis_exec_op.tcl creates the IP project, sets properties, and does the packaging.

metadata.tcl

The content of metadata.tcl is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
set design "axis_exec_op"
set top "${design}_wrapper"
set proj_dir "./ip_proj"

set ip_properties [ list \
    vendor "lucasbrasilino.com" \
    library "AXIS" \
    name ${design} \
    version "1.0" \
    taxonomy "/AXIS_Application" \
    display_name "AXIS Op Execution" \
    description "Executes an operation over AXI4-Stream" \
    vendor_display_name "Lucas Brasilino" \
    company_url "http://lucasbrasilino.com" \
    ]

set family_lifecycle { \
  artix7 Production \
  artix7l Production \
  kintex7 Production \
  kintex7l Production \
  kintexu Production \
  kintexuplus Production \
  virtex7 Production \
  virtexu Production \
  virtexuplus Production \
  zynq Production \
  zynquplus Production \
  aartix7 Production \
  azynq Production \
  qartix7 Production \
  qkintex7 Production \
  qkintex7l Production \
  qvirtex7 Production \
  qzynq Production \
}

As you can see it assign values to variables that affect the IP, such as the supported Xilinx FPGA families.

The ip_properties list holds data used by Vivado IP Integrator(IPI) to identify, search, and display information about your IP. Here you might see something already familiar. Vivado uses a unique Version-Library-Name-Version(VLNV). From the example, the VLNV is set using variables vendor, library, name, and version. Thus, it will be lucasbrasilino.com:AXIS:axis_exec_op:1.0.

axis_exec_op.tcl

The file axis_exec_op.tcl is the main script, and its content is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# Source metadata
source ./tcl/metadata.tcl

# Create project 
set ip_project [ create_project -name ${design} -force -dir ${proj_dir} -ip ]
set_property top ${top} [current_fileset]
set_property source_mgmt_mode All ${ip_project}

# Read source files from hdl directory
set v_src_files [glob ./hdl/*.v]
set sv_src_files [glob ./hdl/*.sv]
read_verilog ${v_src_files}
read_verilog -sv ${sv_src_files}
update_compile_order -fileset sources_1

# Package project and set properties
ipx::package_project
set ip_core [ipx::current_core]
set_property -dict ${ip_properties} ${ip_core}
set_property SUPPORTED_FAMILIES ${family_lifecycle} ${ip_core}

# Associate AXI/AXIS interfaces and reset with clock
set aclk_intf [ipx::get_bus_interfaces ACLK -of_objects ${ip_core}]
set aclk_assoc_intf [ipx::add_bus_parameter ASSOCIATED_BUSIF $aclk_intf]
set_property value M_AXIS:S_AXIS:S_AXI $aclk_assoc_intf
set aclk_assoc_reset [ipx::add_bus_parameter ASSOCIATED_RESET $aclk_intf]
set_property value ARESETN $aclk_assoc_reset

# Set reset polarity
set aresetn_intf [ipx::get_bus_interfaces ARESETN -of_objects ${ip_core}]
set aresetn_polarity [ipx::add_bus_parameter POLARITY $aresetn_intf]
set_property value ACTIVE_LOW ${aresetn_polarity}

# Save IP and close project
ipx::check_integrity ${ip_core}
ipx::save_core ${ip_core}
close_project
file delete -force ${proj_dir}

Note the -sv option on the second read_verilog command. That instructs Vivado the file is a SystemVerilog code. If your IP is written in VHDL, you must use the command read_vhdl instead.

One important action you must pay attention is to associate AXI and AXI-Stream interfaces and reset signal to clock done by lines 23 to 27. That will save you a lot of trouble when validating the block design in IPI. With the association, Vivado will automatically infer the interface’s FREQ_HZ parameter with the clock upon validation and also update it when you change the clock frequency. You will avoid problems like this.

Vivado can infer what type of interface or port an IP has based on their name as you can see in the UG1118. In our IP, the reset port aresetn should be correctly inferred. However, I’ve added the commands from lines 30 to 32 to illustrate how you can force the polarity of a reset port.

Importing source files to a version control system

After the IP directory structure is created and in place, we can import its files to a version control system. In this example, I’m using git. I’m supposing the remote repository was created, git init was executed in the top directory, and the remote was properly configured.

You just need to execute:

1
2
3
4
5
$ git add Makefile
$ git add tcl/*
$ git add hdl/*
$ git commit -am "initial import"
$ git push origin master

Packaging the IP

To package the IP, we need first to source Vivado’s configuration. In my system I execute:

1
$ source /opt/Xilinx/Vivado/2020.2/settings64.sh

Then, we just need to run make on the IP’s top directory:

1
$ make

If everything goes ok, you might have a component.xml file at the top directory:

1
2
$ ls
component.xml  hdl  ip_user_files  Makefile  tcl  vivado.jou  vivado.log  xgui

The IP is ready for being used by Vivado’s IPI.

Using the IP

To use our example IP, we need to tell Vivado the top directory is an IP repository. That is all. So, start Vivado and create (or open) a project. In the Flow Navigator, click on Settings, expand IP, click on Repository, click on the + button and select the IP’s top directory, and click Select. The following window should appear:

Repository Window

Then click on Ok, and Ok again. Clicking on IP Catalog, the IP should be shown:

IP Catalog

You can now create a block design and instantiate the IP. Click in Create Block Design, then Ok. Click on the block design canvas and press Ctrl+i to instantiate an IP. Search for Op and you should be able to find it:

IP search

After instantiation, the IP should be available in the block design:

Block Design with IP

I script Vivado project as well. The second part of this series will discuss how to integrate this flow with a complete project, so simply running make all necessary IPs plus project are generated.

Conclusion

In this post, we discussed how to organize the source code of an IP aiming to keep it on a version control system. In the second part of this series, we’ll discuss how to script and generate an entire IP-based Vivado project from sources, also for version control.