Execute Microblaze Application from PS DDR


In this article we will discuss how to execute a MicroBlaze application from the PS DDR on the Zynq-7000 SoC. There are some caveats with this flow. For instance, the MicroBlaze upon reset will fetch instructions from where ever the boot vector is pointing to. In this case, we will see issues since we are using PS DDR. The Programmable Logic (PL) is configured before the PS DDR is configured with the App. So, this would lead to a hang of the MicroBlaze. This article discusses how to use the reset mode in the MicroBlaze to workaround this.

In this demo the ZC702 is used. However, the same flow will apply for all Zynq boards. 

Learn how to do this on other Xilinx Devices:

  • If users want to learn how to do something similar on Zynq Ultrascale then see the blog here
  • If users want to learn how to do something similar on Versal then see the blog here

Table of Contents

Hardware Generation

Launch Vivado, and create a project targeting the Zynq device.

Create Block Design (BD):

Create the Block Design (BD), and add the Zynq Processing System, and the MicroBlaze from the IP catalog. Use the Run Block Automation from Designer assistance and select the MicroBlaze. User can set this up as they want for their design.
In this demo I have set the Local memory to None, and Cache Configuration to 64KB (the rest are left as default).

Repeat the same for the Zynq PS, and keep all defaults. Double Click on the Zynq PS. Select the PS-PL Configuration from Page Navigator and select the HP Slave AXI Interface -> S AXI HP0 interface.
Repeat for the GP Slave AXI Interface -> S AXI GP0 interface.

Select the MIO Configuration under the Page Navigator, and go to I/O Peripherals ->GPIO -> EMIO GPIO (Width) = 1.
Click OK to Exit.

Use the Run Connection Automation to connect the MicroBlaze cache interface to HP0 on the Zynq PS and the MicroBlaze DP to the GP0.

Microblaze Configuration:

Now we need to configure the MicroBlaze so that it will go into sleep mode upon coming out of reset until it is woken by the user. Double click on the MicroBlaze IP, and Enable Discrete Port (this is on the first page in the GUI). We will be using the reset_mode set to 01. See the MicroBlaze User Guide here for more information on the reset mode. We want to execute from the PS DDR (at address 0x00100000), so we must tell the MicroBlaze where to boot from. Select the advanced tab in the MicroBlaze configuration GUI, Interrupt & Reset and set the Vector Base Address to 0x00100000. Select OK to exit the Config GUI.

Adding Reset GPIO IP:

We can use a Constant IP from the IP catalog set to (const width = 2, const val = 01) and connect this to the reset_mode pin on the MicroBlaze. Concat the GPIO_O pin from the Zynq PS and the Microblaze Dbg_Wakeup to the Wakeup input pin on the MicroBlaze.

Generate the Output Products (you will see a port mismatch warning, this is fine), and the HDL wrapper. Write Bitstream and export to SDK (File Export -> Export Hardware) and select include bitstream. Finally, export to SDK.

Open the Address editor and unmap (right click and select unmap segment) on the GP0_DDR_LOWOCM, GP0_QSPI_LINEAR and GP0_M_AXI_GP0:

Here, I have changed the base address to match my Microblaze boot vector address. The reason I don't have the Microblaze executable memory at 0x0 in DDR is because the FSBL may be using this. 

Tip: For ease of use in changing the DDR address. Change the range to 4K first, then change the base address to 0x0010_0000. Then, change the range to 256MB (or whatever size you need). 

Software Generation:

Create FSBL:

Select File -> New -> Application Project. Set the Project Name to "fsbl", and the Processor to "ps7_cortexa9_0" and select Next. Select the Zynq FSBL and Finish.

FSBL Modification:

We can add the debug to the FSBL (this is optional). To do this, right click on the fsbl in the Project explorer and select C/C++ Build Settings and add the FSBL_DEBUG_INFO to the compiler symbol:

Next, open the fsbl_hooks.c from fsbl/src in the Project Explorer, and add the code to toggle the GPIO that we added in the Hardware. You can add the register writes seen below to the FsblHookFallback function:

Right click on the FSBL, and select Generate Linker Script, and place all sections in ps7_ram_0 and Generate.

Create Microblaze Hello World Application:

Create the MicroBlaze Hello World Application. Select New -> Application Project. Set the Project Name to "hello", and the Processor to "microblaze_0" and select Next. Select the Hello World and Finish. This will automatically create the BSP. The BSP will use the PS7_UART_1 for STDIN/OUT as we have connected the DP interface on the MicroBlaze to the GP port which allows access to PS IP (including the UART). Generate the Linker script for this application and make sure all sections are in the DDR.

Note: Both the MicroBlaze app and the FSBL are sharing the same ps7_uart_1. Be aware that if both processors try to write at the same time, you might see issues.

Note: The linker script will automatically be created based on the memory settings detected in the XSA. In this case, the DDR i set to 0x0010_0000:

Boot Image Creation:

Here, we will be booting from the SD card. To create a BIN image for the SD card, use the Create Boot Image tool in the SDK. Right click on the FSBL, and select Create Boot Image. The FSBL and the BIT should be pre-populated. If not, then you can add these manually using the Add button in the GUI.

Note: the FSBL partition type is bootloader, all other partitions are datafile. Add the hello.elf (select Add, and browse to the hello.elf. The partition type is datafile):

Select Create Image to create the BOOT.BIN file.

Booting from SD Card:

Place this BOOT.bin file onto the SD card, and set the bootmode to boot from the SD card and power on the board. You will see the FSBL debug information, and the Hello World App:

Debugging in Vitis:

In typical systems containing a Microblaze the executable BRAM is populated with a bootloop that is automatically generated in Vivado based on the Microblaze BOOT_VECTOR. This bootloop ELF is then associated in Vivado. The reason for the bootloop is so the Microblaze has some valid instructions to execute once the Microblaze comes out of reset. This is not an issue if booting from SD Card. However, if we want to debug in Vitis, we can place this bootloop in our executable memory (PS DDR) and bring our Microblaze out of reset prior to debugging in Vitis. We can use an XSCT script to do this:
fpga -no-rev -f design_1_wrapper/hw/design_1_wrapper.bit
# Download FSBL to A9 #0
targets -set -nocase -filter {name =~ "APU"}
source design_1_wrapper/hw/ps7_init.tcl;ps7_post_config
targets -set -filter {name =~ "ARM Cortex-A9 MPCore #0"}
dow design_1_wrapper/zynq_fsbl/fsbl.elf
after 500
dow hello_world_mb/Debug/mb_bootloop_le.elf
# set stdin/out to mdm in BSP settings
#targets -set -filter {name =~ "MicroBlaze Debug Module at USER2"}
# Wake up Microblaze
targets -set -nocase -filter {name =~ "APU"}
mwr -force 0xE000A284 0x00000001
mwr -force 0xE000A048 0x00000001


The mb_bootloop_le.elf can be copied from your Vivado project; project_1.gen\sources_1\bd\design_1\ip\design_1_microblaze_0_0\data

I then launch Vitis, and created a Debug Configuration. In the Target setup and removed all the init (as this is done via the script):
The debugger should jump to the breakpoint at main():

© Copyright 2019 - 2022 Xilinx Inc. Privacy Policy