Can Pynq be used without a block diagram?

Pynq version: 2.6
Board: Custom, Z020

I am trying to get Pynq to work with an HDL only based image, no block diagram. In Pynq 2.3 I was able to create a basic block diagram and slip in my own BIT file (BIT did not match the BD) and everything worked great. I had access to both AXI Master IFs, could toggle MIO/EMIO, etc.

I’ve recently moved to Pynq 2.6, created some test overlays and was ready to load my BIT file but every time the system crashes after loading the overlay in Jupyter Notebooks, kind of like what happens when you write to an undefined GP AXI address.

In my dummy BD/HWH files (since .tcl, .hwh, .bit files must be present) I have a really basic setup with an interrupt controller and 2 AXI crossbars with some BRAM controllers. This works by itself with the matching BIT file, however, when I slip my custom BIT file into the system the image gets configured but my Pynq drops all ethernet connections (FPGA logic continues to run).

This brought me here…is there a block diagram agnostic method for running Pynq 2.6?

Is there a work around that allows the Pynq framework to access all of the Zynq peripherals: GP AXI, ACP port, HP AXI, irq_f2p(0:0), MIO, EMIO, etc?

My next step for tomorrow is checking to see if the GP AXI bus is being accessed after configuring the FPGA without being told to do so, just to check it off of my list.

This is a question about Zynq, not PYNQ specific.

See some info here, and you can search Xilinx forums for more info:

I don’t think your issue is related to the version of PYNQ, but I could be wrong. Have you switched from using Tcl to HWH with your bitstream?

How do you instantiate the PS block?

The PS is “there” when you boot your board with PYNQ. Your PL design just needs to make sure it is accessing the right ports/addresses. The block diagram helps manage this.

If you think about it, any changes you make to configure the PS have no impact with PYNQ as the PS is already running when you load your bitstream. This means things like “enabling” or “disabling” AXI GP ports don’t matter. They are present in silicon and don’t need to be enabled. Enabling/disabling really just hides these ports in the block diagram for convenience.
You can dynamically update PS settings from PYNQ by manually writing PS config registers. For example, this is how we update clocks.

Perhpas you are trying to make PS changes in your flow that don’t get applied when you are using PYNQ because the PS is already configured from boot?


Thanks for the reply @cathalmccabe

I don’t know how to switch from TCL to HWH, I always import both. How do you switch?

I instantiate the PS with a working BD and bit file, verified by using the Overlay class and reading/writing to BD blocks. Then I reload the same BD (change the name of the .HWH/.TCL and apply the same to my custom .BIT image) and then eth0 hangs and I don’t have access to the system.

I totally agree. In Pynq 2.3 I was leveraging this fact and everything worked as expected.

When I load the custom .BIT image the logic fabric is controlled by an external clock that I need to configure over a the PS SPI0 port first but again, eth0 hangs indefinitely so I lose access to the system.

You may want to ask why I am not using the serial port at that point to do some additional debugging. However, due to a petalinux 2020.1 issue my serial port dies on boot after it prints, “Starting kernel …”. See this thread for the boot failure, “Warning: unable to open an initial console.” which is on my todo list of things to fix.

PYNQ now requires you include the HWH instead of the Tcl file with your bitstream. If you are including the HWH, this is fine.

I’m confused about what you are doing.

In my dummy BD/HWH files (since .tcl, .hwh, .bit files must be present) I have a really basic setup with an interrupt controller and 2 AXI crossbars with some BRAM controllers. This works by itself with the matching BIT file, however, when I slip my custom BIT file into the system the image gets configured but my Pynq drops all ethernet connections (FPGA logic continues to run).

What do you mean by the custom .bit here? What is this design doing?

If you use Overlay() PYNQ will parse the HWH and configure things in your design if necessary. For example, it will configure the PL clocks if present in the HWH.

I would guess that it isn’t just the ethernet hanging. You may have an invalid AXI transaction that is hanging the whole system. Is there something in your design that may be doing this?


I think I see where the confusion is, my apologies for not making it clear. I am giving Pynq a working .HWH file to configure all the Zynq PS-to-PL connections I need for my non-BD (block diagram) .BIT image to work. I’ve tested the .HWH and .BIT overlay to confirm I have a working system. Then I change the .BIT file to my custom .BIT file (same PS-PL connections, different MM offsets and logic), load the overlay in Jupyter Notebooks and then the new overlay does gets loaded (verified using scope) but the processing system hangs.

I agree, that’s what I am trying to find out. I was hoping to get some clues from the forums as to why this is.

This was my first thought, and since my python doesn’t read/write the AXI bus yet (no code written) I am testing to see if the CPU is reading/writing without me telling it to. I’ve added some debug signals to an O-scope to capture any AWVALID/ARVALID transitions from the CPU on GP0/1 to see if this is the case and I’ll update this post on my findings.

My goal here is to use Pynq as a generic Pythonic way to interact with the PL and custom board peripherals (I2C, SPI, etc.) on MIO. I’ve done it before, as I mentioned, on Pynq v2.3. I’ll get there, just trying to figure this out.

Thank you for your help, it is much appreciated!

OK, no problem.

One other thing that may be of use:
The Overlay() class parses the HWH and does some things automatically.
If you use the Bitstream() module instead of Overlay(), it will only download the bitstream (no HWH required and therefore no HWH parsing).


Here is my latest test BD, very simple:

If I use Overlay, Bitstream/Download() or load the bitstream over JTAG just before loading the Pynq image I can verify that the .BIT file is in fact getting loaded but my Pynq 2.6 hangs indefinitely. I have to reboot to get it back.

It seems that loading any .BIT file seems to be a problem. There is one exception to this, when I created my first interrupt test (similar to this BD but with an interrupt controller) the Overlay class method worked.

Can’t debug anything:
I am currently unable to get access to my UART because of the bug I mentioned earlier.
I verified that my .spec file included FPGA_MANAGER_<project_name> := 1
My local Pynq 2.6 build shows no errors in any of the log files.

Is there a log file on the SD card that I could open after reboot to do further troubleshooting?

  1. What about creating your own overlay class??
  2. I think that using Interrupt controller prohibits using realtime reconfiguration of FPGA (There was some error mentioned about kernel drivers).
  3. You could use system call like “fpga-util -b bitstream” and use address map to communicate with IP’s

@bartokon Doing a quick check I started looking for something related to the interrupt causing reconfiguration issues. I didn’t find anything but I am in the process of testing it out. One image with, one image without…although it takes about 3 hours to build I think it’s a worthy test since I’ve had so many issues trying to create a custom build for a custom board.

Linux and Python on Linux have created a lot of headaches for me…like drinking through a firehose.

On your other point about creating an overlay class (#1, #3) I think I understand what you are suggesting. I will give that a shot if this test doesn’t uncover anything. And thanks for the suggestion!

@bartokon @cathalmccabe Unfortunately I am unable to build a new SD image at this time so I can’t test the interrupts theory.

Due to the amount of time it has taken to get a clean build system I wasn’t able to troubleshoot the interrupt theory.

However, I did find a consistent method to build Pynq 2.6.0 on my custom board. I built the Pynq-Z1 project using the makefile system, modified the block diagram, changed the part number, updated the Zynq CPU settings then exported the hardware to my PYNQ/boards directory as a new board.

In my boards directory I created a new board called “test0” and did the following:

Copied over the Pynq-Z1 files in base:,,
Modified those (commented out code specific to Z1) just to have them available later as a template.

Added my files (from my .xsa export) to base and renamed them to base: base.bit, base.hwh

Copied over from Z1: packages/boot_leds/ &
Again, just did this to have them as templates and commented out the code that was relevant to my board.

Copied my .xsa file over to PYNQ/boards/test0/petalinux_bsp/hardware_project/system.xsa

Created a new spec file: test0.spec
ARCH_test0 := arm
BSP_test0 :=
BITSTREAM_test0 := base/base.bit
FPGA_MANAGER_test0 := 1

STAGE4_PACKAGES_test0 := xrt pynq boot_leds ethernet

From here I downloaded the rootfs files for Pynq 2.6 from here: PYNQ - Python productivity for Zynq - Board
Opened a terminal in: <my_repo>/PYNQ/sdbuild
NOTE: I already ran the script successfully (didn’t work out-of-the-box). See the end of this post for details on how I got past the dependency issues. I also had to clone the Pynq repo (having Pynq in a git repo is required!).

From here I just needed to reference the rootfs file and ran this command from the terminal:
make PREBUILT=<abs_path>/bionic.arm.2.6.0_2020_10_19.img BOARDS=test0 2>&1 | tee test0_build.log

This command will build my board (test0) and use the prebuilt rootfs (board agnostic image) and create a log file of build process (super helpful).

Just to try and be helpful, I couldn’t run right out of the box because of dependency issues. Here’s what I did:

  1. Used gitKraken “free” version to visualize the git repo. Checked out branch: image_v2.6.0
  2. Created a new local branch to track my own changes.
  3. Modified sdbuild/packages/gcc-mb/Makefile line 26, to:
    cd ${GCC_MB_WORKDIR} && ct-ng arm-unknown-linux-gnueabihf && sed -i -e ‘s:2.2.6:2.4.1:’ && ct-ng build
  4. Modifed sdbuild/packages/python_packages_bionic/ line 35, to:

Hope this helps someone.