Tutorial: Creating a hardware design for PYNQ

Creating a new hardware design for PYNQ

The previous tutorial showed how to rebuild the reference base design for the PYNQ-Z1/PYNQ-Z2 boards. This tutorial will show you how to create a new Vivado hardware design for PYNQ. This tutorial is based on the v2.4 PYNQ image and will use Vivado 2018.2. The PYNQ-Z2 board was used to test this design.

If you are using the PYNQ-Z1 or PYNQ-Z2, first make sure the board files have been installed. Download the PYNQ-Z1 board files or the PYNQ-Z2 board files, extract and copy to your Vivado installation, in the ./data/boards/board_files directory.

Create a new Vivado project

This tutorial will create a design for the PYNQ-Z2 (Zynq) board. You should be able to follow the instructions to create a similar design for other Zynq or Zynq Ultrascale+ boards.

  • Open Vivado and create a new project.

  • Pick a project name, and select your Zynq board as the target

    In this example, the PYNQ-Z2 is selected.

  • Select RTL as the project type, and tick the box Do not specify sources at this time

The Vivado project will open.

  • Under IP INTEGRATOR, clock on Create Block Design
  • In the Block Diagram menubar, click on the , search for ZYNQ7 Processing System (PS) and double click to add it to the design.

Note that you will only see IP that can be used with the part you have selected.

Zynq is a System-on-chip. It includes an ARM processor, FPGA logic, and also memory controllers, and peripherals including USB, Ethernet, SD card. The Zynq PS is configured at boot time.

In a Vivado design, the Zynq PS settings can be configured. Vivado is used to generate the Programmable logic design (bitstream). It can also be used to generate a boot image which includes all the code to boot the processor as well as the bitstream.

However, the PYNQ SD card image is used to boot a board. PYNQ overlays can be loaded after the system has booted. This means that when we create a Zynq design in Vivado, we only need to create the programmable logic design and can ignore the Zynq PS configuration settings. However, it is good practice to apply the correct board settings for your board.

You will need to enable ports and interfaces on the PS block so you can connect them to your custom design.

Block Automation

On adding the Zynq PS block, a message should appear giving the option to Run Block Automation.

  • Click on this Run Block Automation to run this process.

This applies a default configuration for the PS for your board.

You are now ready to start creating your design.

Adding blocks to your design

At this point, you can start adding blocks to your design. You can add IP from the Vivado catalog, or add your own custom IP. In this example, we’ll add a IP from the Vivado catalog: a BRAM (a memory in the FPGA fabric), and 3x GPIO (General Purpose Input Output controllers. The GPIO blocks will be used to control LEDs, push buttons and DIP switches on the PYNQ-Z2 board.

In the block diagram, follow the same process as before to search for the following blocks in the IP catalog, and to add them to your design:

  • 3x AXI GPIO controller (you can add one instances of this block, and copy and paste it to add more instances)
  • 1x AXI BRAM (Make sure to select the AXI BRAM)


The block are all given default names. E.g. axi_gpio_0, axi_gpio_1 etc. These names will be visible from Python later, so it is useful to rename them to something meaningful.

  • Select each AXI GPIO block, find the Block Properties window, and rename each IP to leds, buttons, and switches respectively


  • Rename axi_bram_ctrl_0 to bram

You can manually create wires and connect ports by clicking on ports and dragging the cursor to a corresponding port, but IP Integrator can also connect ports automatically.

  • Click on Run connection automation to open the dialog box
  • Check the box beside All Automation
  • For each of the AXI GPIO blocks (buttons, leds, switches), select the GPIO label (make sure you don’t uncheck the box when selecting)
  • For each block, under the Options section select the corresponding interface. i.e. buttons: btns_4bits, leds: leds_4bits, switches: sws_2bits

This will connect each AXI GPIO to the corresponding pins on the board.


  • Click OK to run connection automation

This will automatically connect each IP block in the system, add ports, and any additional interconnect and reset blocks the system requires.

You should notice three extra blocks have been added to your design (orange in the figure above), along with ports for the buttons, LEDs, and switches interfaces. The new IP blocks are a Block Memory Generator, System Reset block, to manage reset signals, and an AXI Interconnect block to connect the three AXI GPIO blocks and the AXI BRAM to a single AXI Master port on the PS.

If we wanted to, we could modify the IP, by double clicking each block and changing the configuration. E.g. we could change the size of the BRAM by configuring the Block Memory Generator. The AXI GPIO have already been automatically configured to match the port the are connected to. E.g. the LED AXI GPIO controller is set to connect to a 4-bit output port for the LEDs. We will leave the default configurations for the other blocks for now.

The design is now finished. We need a top level HDL file for the project, which can be created automatically.

  • In the Source tab, right click on the (block diagram file) and select Create HDL Wrapper


Note that either a VHDL or Verilog wrapper can be created, depending on the project settings. (If you have a preference, you can also set Verilog or VHDL as the default in the Project settings.)

  • In Vivado click on Generate Bitstream (under Program and Debug) from the bottom of the Flow Navigator. (You can click “cancel” when the bitstream is generated, or if you want to you can examine reports, or open the implemented design.)

You may notice a number of information, warning, messages in the (although hopefully there will not be any error messages for this design!). These messages can be ignored for now.

  • Once the bitstream has been created, generate the corresponding Tcl for the design by selecting File > Export > Export Block Design. (Make sure the block design is open when doing this.)

The .tcl file will be available from the path you chose to export it to.

The .bit files should be available from this path:

./<vivado project>/<project name>/<design name>.runs/impl_1/

The .hwh should be available from this path:


Next steps

You will copy all three of these files to you board in order to start using your design within the PYNQ framework. This will be covered in the next tutorial.


AXI - Advanced eXtensible Interface - an interconnect that is part of the ARM AMBA standard. Most Xilinx IP supports this standard, and it is used in Vivado to connect IP together.

GPIO - General Purpose Input Output.

GP - Zynq General Purpose AXI port(s). Used to connect peripherals that will be controller from the Zynq processing system.

HP - Zynq High Performance AXI port(s). Used to connect IP directly to the Zynq memory controller. This allows IP to access the Zynq memory system directly.

(Vivado) IP Integrator - The Vivado graphical environment to create hardware designs (block designs) for Zynq.

BRAM - Block RAM (Memory) on Xilinx devices.

PL - Programmable Logic - the FPGA part of the Zynq chip.

PS - Processing System - the ARM processor, peripherals and memory controller inside a Zynq chip.