FPGA SoC prototyping with Xilinx(R) PYNQ(R) platform

dflynn-University of Southampton
Xilinx ZCU104 ZYNQ UltraSCALE+ development board (dflynn-University of Southampton)

FPGA prototyping a System-on-a-Chip design enables the hardware design to be tested at or near real-time and software development to be started while the SoC implementation, verification, fabrication and packaging proceed in parallel.

The example design flow developed and described here targets the Xilinx ZCU104 development board, which has a large and capable ZYNQ UltraSCALE+ FPGA, and is fully supported out-of-the-box with Xilinx PYNQ development environment support.

The PYNQ platform is recommended in this case as this supports scripted control using Python to manage the FPGA overlays, and all through a built-in web-hosted server implemented on the ZYNQ Arm embedded processors that implements a Jupyter Notebook framework to support documentation and example usage.

Xilinx ZCU104 FPGA development board

Configuring the PYNQ platform

Comprehensive instructions for setting up the board are provided on the PYNQ site:


Follow the instructions for setting up the hostname, non-default password, and network parameters, and ensure the (re-booted) system offers network services.

PYNQ setup for ZCU104 board

FPGA structuring for SoC test-bench

The approach adopted is to use the ZYNQ processing system configuration to provide clocking and reset control to the SoC "Design under Test" (DUT).

The System-on-Chip design is instantiated at the chip level just inside the pad-ring - to present input/output/tri-state-control unidirectional signals rather than bidirectional/tri-stated I/O-s. Care is taken to ensure that the DUT is built independent of Xilinx system IP so in this example flow, the microcontroller design (https://soclabs.org/project/arm-cortex-m0-microcontroller in this case) is imported in the form of an external IP component.

The testbench "wraps" the DUT with a "socket" that is built, customized to the SoC design using the standard Xilinx Vivado "Block Design" IPXact design capture and tools, to include any specific peripherals - a UART communications channel in this case, plus generic General Purpose Input Output (GPIO) control ports to monitor or stimulate the IO ports.

Testbench design captured in Vivado(R)

The Arm-based ZYNQ processing subsystem is completely independent of the SoC DUT but provides the master clock for the device, which can be reconfigured in the Vivado editor. [Set to 20MHz for basic functional testing in the example implementation flow]

PYNQ clocking control (under ZYNQ PS configuration)

FPGA build scripts

Example scripts are provided in the soclabs-cortexm0-mcu gitlab directory:


The worked example was developed and tested with Xilinx(R) Vivado(R) tools version 2021.1, and may require minor updates for later versions of the toolchain.

The scripts should be run from the fpga implementation directory:


     source ./build_fpga_pynq_zcu104.scr

This uses tcl scripts to build the Cortex M) MCU is an "IP" component (using exactly the same RTL build deliverables up to the inside of the pad-ring of the SoC simulation and implementation flows) and then instantiate this in a ZCU104 test-bench wrapper - which uses the standard Vivado Block Design GUI flow.

Target board specific pin map and timing constraints are accessed from the target_fpga_zcu104 directory

The overlay and notebook output files are copied out to the directory:


These files are then ready for use as Xilinx PYNQ programmable logic overlays.


FPGA programming

The PYNQ board, when successfully configured and connected to the network can be mounted as a file system and logged into from a browser.

The build scripts generate both the configuration bit-file (.bit) and hardware description (.hwh) files in the directory:


(default names of design_1.bit and design_1.hwh)

Simply copy the pynq/overlays/soclabs sub-tree in the PYNQ board pynq/overlays/ directory

These can be loaded interactively using an associated Jupyter Notebook.

Jupyter Notebook interaction

An example Jupyter Notebook and python device driver are provided in the directory:


(notebook named soclabs_cm0sdk_mcu.ipynb)

Simply copy the pynq/jupyter_notebooks/soclabs sub-tree in the PYNQ board pynq/jupyter_notebooks/ directory, which also includes a driver subdirectory.

Once correctly transferred over, it should be possible to connect and log into the PYNQ server from a web browser, and select the soclabs folder:

pynq jupyter notebook dir

Select the ipynb notebook document and this will allow the overlay files to be loaded, checked and run to communicate with the MCU in the FPGA design (through a serial communications driver in this case):

pynq jupyter notebook 1
Pynq Jupyter Notebook establishes Cortex-M0 communication


Projects Using This Design Flow

Reference Design
Active Project
d.wf @ soclabs

nanosoc re-usable MCU platform

Experts and Interested People



Log-in to Add to Your Profile


Hi David,

Thank you for sharing this project! I've learned a lot from your code. A few comments on the FPGA Build Scripts:

  • For building the pynq_zcu104 project as well as the FPGA IP, a top level module was required to be set in the .tcl scripts; otherwise, all of the files get imported as "Unreferenced" and the project failed to build. I simply added: 

         set_property top cmsdk_mcu_chip [current_fileset]

    after reading in the verilog files in build_fpga_ip.tcl, and 

        set_property top design_1_wrapper [current_fileset]

    after creating the design wrapper in build_mcu_fpga_pynq_zcu104.tcl to fix this issue. 
  • Additionally, when creating the IP core, the ipx commands added Xilinx IP to a singular directory for some reason. This created the mcu custom IP to become locked, and I couldn't figure out how to "unlock" the IP. (I am using Vivado 2021.1 as well) In this case, I had to start from the beginning of build_mcu_fpga_pynq_zcu104.tcl. I ran all of the script until the ipx commands. I then used the GUI to manually package the IP with the appropriate settings. I then finished running the .tcl scripts to successfully get the bitstream for the chip.

Thank you for sharing your project!


Hi Meredith,

Thank you for your feedback and workaround. We will address these issues and reproduce them. It's great to see it now. This exemplary project is still in development and strengthened by you and other members of our community. We hope to get it run smoother as much as possible.

Many thanks,


Thank you so much Meredith for the detailed review feedback.

I have checked back into git the 'set_property top' fixes identified, but have struggled and failed to get to the bottom of the 'locked' IP issue you reported (which I fail to reproduce in my environment for some reason). I build up the TCL commands from running the IP packaging from the command line and despite spending a fair time digging through the Xilinx documentation have failed to find a clean alternative version. [Would you mind emailing me the journal-transcript when you next run the IPX packaging just in case this is different to what my environment gives?]

Very best wishes and do hope your FPGA prototype is making good progress


Hey David,

I apologize for my late response. I have been working on other projects at the moment. I have tried to recreate the error with no success. The only thing I can think of- I have been running the .tcl script directly instead of the .scr. Maybe that has something to do with it. I plan on picking this project back up in a few weeks. If I run into this error, I'll be sure to document and share.


I have updated the link to the git repository for the SoC Labs' Example Arm Cortex-M0-based microcontroller project. This will ensure that the FPGA implementation build scripts are also synced and updated simultaneously.

John - thanks for reviewing this - and my premature publishing of the confusing hierarchy:

  • https://soclabs.org/design-flow/fpga-prototyping ideally will become the generic Design Flow overview
  • https://soclabs.org/design-flow/fpga-soc-prototyping-xilinxr-pynqr-platform is a project specific example

So in some ways the second is a project that refers (to and from) the Cortex-M0 reference design project and could potentially be linked to form the first as a design-flow example.

Guidance on how to repair hierarchy would be valuable: I could only think of copying to new area and then deleting the original(?)


As a community we are going to have to find our way in structuring information in ways that help us all.

The high level and generic design flow stages are traditionally described from Architectural -> Behavioural -> Logical -> Physical ...

Taking these generic flow stages and instantiating them in say a specific FPGA based flow or a specific ASIC fabrication flow and having the environment, tooling, and implementation specifics described in one place is useful.

I suggest we take some inspiration from object orientation in programming models. Perhaps this item ‘FPGA SoC prototyping with Xilinx…’ is a subclass (or derived class) of the more generic ‘FPGA prototyping’ which is a subclass of all specific design flows including for example ASIC flows.

In that case this should be a child of ‘FPGA prototyping’. You can achieve that by setting the relations in the item.

How to set subclass relations

I hope this helps, John.

image of navigation scheme showing generic high level flows and area for example flows

We have an initial view that has the four high level generic stages of the design flow and then an area where we describe specific example flows. Hopefully we will add some more example flows to David’s initial ‘example flow’ for the Xilinx(R) PYNQ(R) platform. As we develop some additional example flows we will try and discuss how the flow delivers the requirement of the general design flow steps.

Add new comment

To post a comment on this article, please log in to your account. New users can create an account.