- Part 1: Straight to the Finish Line
- Part 2: Customize our Core
- Part 3: Creating an IP Core Manually (you are here)
- Part 4: Raw AXI Streams
- Part 5: AXI Video Streams
In the previous parts, we used a script to generate our Vivado IP core. This is fine for simple projects but if we want to understand our core as well as how the Xilinx tools interact with it then we will need to build the core manually.
As soon as you know the incantation to build a core the whole process is very easy.
We will use the 'demo_part2' core in the second part.
At a high level- Create a Vivado project
- Create the custom IP
- Map the ports to interfaces (AXI Interface, clocks and reset)
- Package the Project
- Update the Pynq FPGA image with the new IP
- Demonstrate on the Pynq Board
If needed, delete the 'demo_part2_project' folder
If you're continuing on from the previous part we will need to remove the Vivado project that was generated by our script.
Navigate to the base of the 'demo_part2' core directory:
cd <ip-cores repository>/cores/demo_part2
Remove the 'demo_part2_project' directory and all of its subfolders and files:
rm -rf ./demo_part2_project
Source the Xilinx Tools
If not done already source the Xilinx tools:
source /<path>/<to>/<Xilinx>/Xilinx/Vivado/2019.2/settings64.sh
In my case I use the following:
source ~/software/Xilinx/Vivado/2019.2/settings64.sh
Start Vivado and Create a new project
Open Vivado you and create a new project File -> Project -> New
You can name this anything but to simplify both our lives name it 'demo_part2_project'
Click 'next' and when it asks to select 'Add RTL' files select everything within the 'hdl' directory. Make sure the 'Copy sources into the project' is not selected.
Click 'next' until you reach the FPGA selection page where we will select the Pynq Z2 SOC. To reduce the number of choices by setting the following options:
- Family: Zynq-7000
- Package: cg400
- Speed: -1
Then select the xc7z020clg400-1
You should end up with this:
Create the custom IP
Now that a Vivado project is set up with all of our source files, we'll make a core.
In the menu select Tools->Create and Package New IP...
Select 'Package your current project'
I put the generated IP into the 'demo_part2' project directory but it can be placed anywhere, although this will affect where your IP repo will end up.
There are a lot of options for the IP, some specifying the name of your core, some specifying what license you want to use but for now, we're only doing the essentials by specifying how to attach the AXI Lite interface to our core.
Our core has a bunch of input/output signals and we need a way to tell the IP generator how we want those signals to be interpreted.
Mapping PortsSelect the 'Port and Interfaces' within the 'Packaging Steps'
Here you will see a list of all the top-level signals of 'demo_part2.v'
The IP Core generator has already determined that 'i_axi_clk' is a clock and 'i_axi_rst' is a reset signal now we need to tell it that the rest of the signals belong to the 'AXI Lite Slave' interface. To do this select the '+' button pointed to by the purple arrow in the image above. You'll see this:
Here we specify the type of interface we have, in this case, we have 'aximm_rtl'. There is a lot to cover but I want to emphasize this 'Interface Definition', there are a lot of different interfaces including SPI, VGA, UART, DVI, etc...
We have named the interface 'control' and set the 'mode' of the interface to 'slave' meaning that this will respond to commands. next, we move to the 'Port Mapping' tab.
Here we attach all the input/output signals of 'demo_part2.v' to the interface signals.
In the top left column are the interface's signals. on the top right are the input/output signals of 'demo_part2.v '. There are a couple of helpful checkboxes called 'Filter Incompatible Physical Ports' and 'Hide Mapped Ports' check both of these.
Here are all the mapped signals:
- AWADDR - i_awaddr
- AWVALID - i_awvalid
- AWREADY - o_awready
- AWADDR - i_awaddr
- ARADDR - i_araddr
- ARVALID - i_araddr
- ARREADY - o_arready
- WDATA - i_wdata
- WVALID - i_wvalid
- WREADY - o_wready
- WSTRB - i_wstrb
- RDATA - o_rdata
- RVALID - o_rvalid
- RREADY - i_rready
- BRESP - o_bresp
- BVALID - o_bvalid
- BREADY - i_bready
It makes sense, the signals are pretty close, if I didn't use my naming convention of 'i_' for input and 'o_' for output then the tool might automatically infer the results but this is a personal preference.
you will notice that some of the interface's signals are not mapped. We are using the bare minimum signals required for AXI.
Now that we mapped the input/output ports to the interface we need to associate the clocks and resets.
Associating Clocks and ResetsWhen you are integrating your core into a design Vivado needs to know if your AXI bus has an associated clock and reset. It uses this information when attaching the AXI interconnects and will throw warnings or even errors if these are not specified. So after we finished generating our AXI Lite interface close the mapping dialog. right-click on the newly created 'control' interface and select 'Associate clocks...'
Select the only option 'i_axi_clk' and close the dialog, repeat this process for the 'i_axi_rst' signal.
We need to configure the memory or Vivado will not infer an address space for it. Within the 'Packaging Steps' select 'Address and Memory'
Run the 'Addressing and Memory-Map Wizard'
in the 'Choose IP Interface' select 'control'
When it asks for a name use 'control'
Add an Address Block to the 'control' memory block
Name the address block 'main'
Move to the 'Review and Package'
Finally press 'Package IP'
Similar to the last two parts we can quickly demonstrate this project by going back to our Pynq Vivado project and refreshing the IP repositories and updating the 'demo_part2' IP. When we open up the project we should see a notification that the ip-core was updated.
If you don't see this pop up refresh the IP repository
The 'demo_part2_0' will automatically be selected, you should be able to upgrade it by pressing the 'Upgrade Selected'
Select 'Skip' when the next dialog comes up
Upgrade Complete
Check the address editor
If the 'demo_part2' is not mapped then press the 'Auto Assign Address'
Finally, generate the bitstream
Similar to the previous parts, go to your Jupyter notebook again.
Within the Jupyter Notebook web interface move to 'Projects/demo_part2/data' and upload the 'bit' and 'hwh' files that we just generated.
The file locations:
<vivado project base>/<project name>.runs/impl_1/system_wrapper.bit
and
<vivado project base>/<project name>.srcs/sources_1/bd/system/hw_handoff/system.hwh
Change the 'system.hwh' to 'system_wrapper.hwh'
We don't need to change 'demo_part2.py' driver. We just need to restart the kernel
Run the entire notebook.
There are more changes that can be made in the IP core generator. You can change the name or even give it a license. There is also a lot of clever things that can be done with parameters such as tying them to small scripts to automatically set things such as the incoming clock rate. In the next part, we'll add AXI streams. At first, we'll write generic AXI streams to send/receive raw data but later, we will use AXI streams to send video.
Comments