Xilinx Vivado HLS Beginners Tutorial : Integrating IP Core into Vivado Design

Chathura Rajapaksha
9 min readJul 7, 2018

--

This is the second article of the Xilinx Vivado HLS Beginners Tutorial series. You can find the first article here, which designs a 2D convolution IP core using Vivado HLS. In this article, integrating the generated IP core into a Vivado ZYNQ based design will be discussed. I plan to write the next article on developing a simple Linux driver to control the IP core from the Linux side (PS) of ZYNQ.

I like to highlight few important things before getting started. In this article, I will also talk about enabling / enforcing cache coherency on ZYNQ ACP port. I had to search many places before I find the correct way of doing this. Cache coherency is a very important concept in shared memory systems, for an example, in ZYNQ ZC702 board, on-board DDR3 RAM is shared by the processing system(PS) and programmable logic (PL) of ZYNQ SoC. There are many sources to learn this concept, just Google it.

Lets get down to business.

Prerequisites

  1. Xilinx Vivado installed, licensed and working
  2. Generated IP core files, following my previous article.

That’s all you need for this tutorial and I use Vivado 2015.4, procedure should be the same for any closer version.

Step 1 : Create a new project in Vivado

Open Vivado and create a new project. I have selected my board as Xilinx ZC702. Any device that has a ZYNQ SoC can be used for this tutorial. Keep other settings as they are and finish creating the project.

Step 2 : Add ZYNQ PS to the Design and Configure

After you create the new project, select ‘Create Block Design’ option under Project Manager in to the right of the screen, as seen from the following figure. Put whatever name you want to the design in the pop-up window and click ok.

Click on ADD IP button in Block Design tool box and type in ‘zynq processing system’ and add that to the design by double clicking on it. As soon as IP added, there will be a Designer assistance prompt for “Run Block Automation”. Click on that, select OK on the pop-up window, it will add the board presets to the ZYNQ processing system IP. After running block automation, the IP will look like the following.

ZYNQ PS IP After running block automation

Now we need to configure the interfaces for interfacing our custom IP created by Vivado HLS in the previous tutorial. Before doing that lets remind few things about the custom IP we created in the previous tutorial. Our custom IP has the following interfaces,

  • For data input and output : AXI Master (AXI Full) interface
  • For configuring the IP at run-time : AXI Lite (slave) interface

We need to keeps these interfaces in mind when customizing ZYNQ PS. Since we have a AXI Full master port and AXI Lite slave port in our IP, we need an AXI Full slave and an AXI Lite master in the ZYNQ PS IP to connect our IP.

Now lets go ahead and customize the ZYNQ PS IP. To customize, double click on it. In the pop-up window select PS-PL Configuration in the Page Navigator. Then expand ACP Slave AXI Interface and tick both options under that, as in the following figure.

Enabling AXI ACP Port

Now we need to do something specific to Vivado 2015.4, which can be considered as a bug in this version. Go to General -> Address Editor and tick Allow access to High OCM, as shown from the figure. This option was enabled by default in previous version I used. If you don’t do this, you will get an error if you try to verify or elaborate.

Then go to Interrupts section in the page navigator and enable interrupts if you want them in your design. We actually don’t need interrupts for the IP we created, you can keep it disabled if you want. I mentioned it just for the completeness.

You can also change the clock frequency of the programmable logic (PL), that means the clock frequency of your custom IP. Following figure shows where you can find this option. I will keep the default clock configuration for now.

Clock Configuration

We are done customizing, click OK. ZYNQ PS IP should look like the following, after customizing.

Customized ZYNQ PS

Step 3: Adding our Custom IP to the Design

Go to IP settings in the block design tool box, as shown in the figure.

IP Settings

In the IP Settings pop-up window, go to Repository Manager tab and click on + sign. Then give the Vivado HLS project folder and select ok. If you have exported your custom IP in Vivado HLS project correctly, this will show something like below.

Click OK on this window and and Repository Manager window. Then click Add IP again and type our custom IP name. In my case its “conv”, then add it by double clicking on it.

After adding IP Core to the design

Step 4 : Connecting IP Cores

In this step, usually you don’t have to do anything manually, Designer Assistance will do all the connections for you. But sometimes it fails to do all the connections. Click on Run Connection Automation and tick All Automation in the pop-up window. You can verify which is connecting to what by selecting each of the ports separately, details of the connections can be seen in the right side of the window. Click OK, after the connections are done, you will see something like below figure.

Design after connection automation

As you can see in this design, Vivado connection automation has done all the connecting for us.

Step 5 : Setting address spaces

Since we are using AXI M Full interface in our IP core, each memory address that our IP core access, is mapped into a specific address in ZYNQ SoC (This is because AXI M i a memory mapped interface). This is a common way that is used to control the peripheral connected to a processor.

Now we have to decide what address range of ZYNQ PS will be mapped in to each port of our IP core. In my next tutorial, I will discuss how we are controlling our IP core from the Linux installed on ZYNQ PS by accessing these mapped memories.

When designing our IP core, I have bundled all control signals (AXI Lite signals) of the IP core to a bundle named “CRTL_BUS”. And I have configured the AXI M interfaces such that we can set the address of these memory mapped ports at the run time using a AXI Lite control signal, which is also bundled to CRTL_BUS.

Go to Address Editor in the block diagram window, expand the entries and you will see something like below.

Address space before change

Correct these address spaces as below, some required address spaces are excluded by default due to a bug in this Vivado version. Unmap all ports under conv_0 IP core and map and include only the two ports as below.

Updated Address Spaces

Click on Validate design button just to check whether all is correct. Validation should be successful before you proceed.

Step 6 : Enabling Cache Coherency in ZYQN

This is the most important information in this entire tutorial, so follow carefully. Let me explain a bit about why the cache coherency is needed in ZYNQ.

We have created and connected our IP core that it access the onboard DDR RAM. By default, ZYNQ PS also have direct access to onboard RAM. Now, since two parties use the same RAM, we have a shared memory. Coherency issue occurs due to the cache of ZYNQ PS. I will explain with an example.

Lets say ZYQN PS writes value of 0xFF in the memory address 0x000100 in our onboard RAM. This value will be in the cache of ZYNQ PS now. Now we trigger some operation in our IP core that overwrites the value in address 0x000100 to 0x11. When we try to read the result of the IP core from the ZYNQ PS, you will still see 0xFF in that memory location. Reason for this is no one informs the cache of ZYNQ PS that value in the memory location is updated from the PL side (our IP core is implemented in PL). Because of this you won’t be able to see any outputs from our IP core.

You can do few things to resolve this,

  • Disable the data cache from the firmware/software in ZYNQ PS (Baremetal or Linux)
  • Enforce cache coherency at the hardware level (Dosen’t depend on firmware/software)

First point can be achieved in Xilinx SDK if you are using baremetal mode, there is a seperate function for disabling data cache. But in Linux, there is no way to disable the data cache from the userspace. You have to write kernel space driver for this, which can be really hard for a beginner in Linux driver development.

Therefore second point can be the best solution, since it doesn’t depend on the software/firmware you use. But you will loose the ability of enabling and disabling cache at run time.

NOTE : If you don’t understand anything I said in this step of the tutorial, don’t worry. Just do as I say and everything will work.

Lets follow the second point and do the required changes in the hardware to enforce cache coherency.

In the block diagram, expand the S_AXI_ACP port on ZYNQ PS IP by clicking on the + sign. Now you will see side signals of AXI ACP port. According to the Xilinx documentation, we need to set following signals to 1 (HIGH) ,

  • ARCACHE[3:0]
  • AWCACHE[3:0]
  • ARUSER[4:0]
  • AWUSER[4:0]

We will use constant block to override the values of these signals. Add two constant IP blocks to the design and configure them as below.

Configuration of constant IP block 1
Configuration of constant IP block 2

Maximum value of a 5-bit binary number is 31, that’s why we set the value of first block as 31, so that every bit in the signal that we gonna override will set to 1. Same goes for other block (4-bit -> 15). Connect the contant blocks as below.

Overriding signals by constants

Now we are finished with our block design. Next step is to synthesize the whole design.

Step 7 : Synthesize and implement the design

First validate the design once to make sure all the connections are correct. Once you confirm that the validation is successful. We need to create a HDL wrapper for our block design before synthesizing. Right click one the design name in the sources tab as below and select Create HDL Wrapper. Tick “Let Vivado manage wrapper and auto-update” and click OK.

Creating HDL wrapper

Let’s proceed to synthesize the design. You can do this step by step ( RTL simulation -> Elaboration -> Synthesis -> Bit stream generation ), analyzing the results of each step. But I will skip the RTL simulation and run the whole thing by clicking Generate Bitstream. Vivado will say that there are no previous results available and ask to run previous steps as well. Select Yes and it will start the process.

After synthesis finishes successfully (this will need a valid license ofcourse ), you can export the implemented hardware to be used in Xilinx SDK. Next tutorial will be focused on running our design on the Xilinx ZC702 board itself using Xilinx SDK in baremetal mode.

You can find the source of the Vivado project in this repo.

Don’t forget to post your ideas and comments, farewell till next tutorial !

--

--