Create a MicroBlaze, Test the UART in SDK, and Boot Linux using 2019.1 Vivado and PetaLinux Tools

This post contains everything needed to create a MicroBlaze design and boot Linux on it over JTAG. It also contains links to all the IP documentation and how to smoke-test a design before using it.

Versions Used

2019.1 Vivado, PetaLinux Tools, and XSDK

VMWare Workstation 14 Player running Ubuntu 16.04.5 LTS running on Windows 10

Update Vivado 2019.1


I needed this patch to build the bitstream.


Step #1: Download the patch at:,will%20not%20generate%20a%20response.

Step #2: Exit Vivado 2019.1

Note: commands assume Vivado is installed at:


Step #3: Run

mkdir /tools/Xilinx/Vivado/2019.1/patches
mkdir /tools/Xilinx/Vivado/2019.1/patches/AR72956
pushd /tools/Xilinx/Vivado/2019.1/patches/AR72956
unzip ~/Downloads/

Step #4: Restart Vivado 2019.1

Step #5: Check that the Patch Applied

Enter in the Design


For Linux to boot on MicroBlaze

Page 19 of lists the requirements to run Linux on a MicroBlaze. I've left out both the Non-volatile memory and Ethernet in this design. Also, I use an AXI Timer, not a Dual channel timer.


Step #1: Run Vivado 2019.1

Step #2: File > Project > New

Step #3: Click Next on the Create New Vivado Project window

Step # 3.1: Click Next in the Project Name window

Step #3.2: (A) Click RTL Project and (B) click Next

Step # 3.3: (A) Click Boards, (B) enter zcu102, (C) click on the line, and (D) click Next

Step #3.4: Click Finish

Create the Block Design


Step #1: Click Create Block Design

Step #1.1: Click OK

Step #2: (A) Click Board, (B) Pull DDR4 SDRAM to the Diagram, and (C) click OK

Step #3: Click Run Connection Automation

Step #3.1: (A) Check all checkboxes and (B) click OK

You should see:

Step #4: (A) Click +, (B) type micro, and (C) double-click MicroBlaze

Step #5: Click Run Block Automation

Step #6: (A) Check the Interrupt Controller checkbox and (B) click OK

Note: we select Linux with MMU later during IP customization

Note 2: this ^^^ step is how you get microblaze_0_local_memory

Step #7: Click Run Connection Automation

Step #7.1: (A) Select all checkboxes and (B) click OK

You should see:

Step #7.2: (A) Click Board, (B) click and drag UART, (C) click OK, and (D) click Run Connection Automation

Step #7.3: Click OK

You should see:

Step #8: (A) Click +, (B) Type AXI Timer, and (C) click AXI Timer

Step #8.1: Click Run Connection Automation

Step # 8.2: Click OK

You should see:

Step #9: Connect the axi_timer_0 interrupt and the axi_uartlite_0 interrupt pins to the microblaze_0_xlconcat

Note: you will still see the UART output in XSDK without this, and Linux will run, but you won't see any UART output.

Customize the MicroBlaze IP


Step #1: Double click on the microblaze_0 instance of the MicroBlaze

Step #1.1: (A) Select Linux with MMU and (B) click OK

You only need to set Linux with MMU. Here are the other pages as a reference.

Page 1

Page 2

Page 3

Page 4

Page 5

Page 6

Page 7

Get Ready to Create the Bitstream


Step #1: Check the Board

Step #2: Check the full design

Step #2.1: Zoom into the left side

Step #2.2: Zoom into the right side

Step #3: Check the Address Editor

Step #4: Check the Project Summary

Step #4.1: Click PROJECT MANAGER to get the Project Summary

You should see something like:

Create the Bitstream


Step #1: Create the HDL Wrapper

Step #1.1: (A) Click Sources, (B) right-click design_1 (design_1_hd), and (C) click Create HDL Wrapper...

Step #1.2: Leave Let Vivado manage wrapper and auto-update selected and click OK

You should see:

Step #2: Click Generate Bitstream

Step #2.1: Click Save

Step #2.2: Click Yes on the No Implementation Results Available notification box

Step #2.3: Select as many cores as you can and click OK

Note: this can take 1 to 2 hours to run

Note 2: You should see a status indicator in the upper right-hand corner

Program the Bitstream


Step #1: (A) Select Open Hardware Manager and (B) click OK

Step #2: Plug the UART and JTAG USB cables into the board...

Step #2.1: ...and into a hub...

Step #2.2: ...which is plugged into the computer

Important note: using a hub is a good way to connect the JTAG and UART USB devices to a VM. It has worked for VMWare and VirtualBox.

Step #3: Make sure the SW6 is set to JTAG boot the ZCU102

Step #4: Turn on the ZCU102

Step #5: Ensure that the Cygnal Integrated CP2108 Quad USB to UART Bridge Controller is enabled and Future Devices Digilent USB Device is enabled.

Step #6: Click Open target

Step #7: Click Auto Connect

Step #8: Click Program device

Step #9: Click Program

You should see:

Export the Design for UART Smoke Test with XSDK and Creating a Linux Build with PetaLinux


Step #1: (A) Click File, (B) Export, and (C) Export Hardware...

Step #1.1: Click OK

Create a Hello World test App to Test the UART Works Before Creating a Linux Build


Step #1: (A) Click File and (B) click Launch SDK

Step #1.1: Click OK

Step #2: (A) Click the drop-down and (B) click Application Project

Step #2.1: (A) Use Hello_world for the Project name: and (B) click Next

Important Note: never use spaces; the SDK cannot handle spaces

Step #2.2: (A) Click Hello World and (B) Finish

Step #3: Open a terminal and start screen using:

screen /dev/ttyUSB2 9600

Note 1: Type Ctrl-a d to detach, Ctrl-a k to kill

Note 2: After detaching, reattached with:

screen -r 

Note 3: if someone else has attached, reattach with:

screen -x

Note 4: to clear what's in a screen, type Ctrl-a C. To get more commands, type Ctrl-a ?

Step #4: (A) Right-click on Hello_world, (B) click Debug As, and (C) click Launch on Hardware (System Debugger)

Step #5: Click Yes to Confirm Perspective Switch

You will likely not see anything because the target is stuck at:

void XUartLite_SendByte(UINTPTR BaseAddress, u8 Data)
 while (XUartLite_IsTransmitFull(BaseAddress));   /* <<<<< stuck */

 XUartLite_WriteReg(BaseAddress, XUL_TX_FIFO_OFFSET, Data);

...and the memory load from the UART returned:

xsct% mrd 0x40600000

xsct% Memory read error at 0x40600000. Memory access exception


We'll fix that next by ensuring we click the Reset entire system check box in the Debug configuration.

Step #6: (A) Click the debug drop down and (B) click Debug Configurations....

Step #6.1: (A) Check the Reset entire system checkbox, (B) click Apply, and (C) click Debug

Step #6.2: Click OK

Step #7:Click Step Over

Step #7.1: Click Step Over again

Step #7.2: ...and one more time observing Hello World on your screen session

Note: To restart debugging, click the Bug...

...and click OK...

Create and Build MicroBlaze Linux


Step #1: Type the following to create a PetaLinux project and build it

cd plxprjs/
source ~/petalinux/2019.1/
petalinux-create --type project --template microblaze --name zcu102mb
cd zcu102mb
petalinux-config --get-hw-description=/home/demo/project_3/project_3.sdk
# Accept defaults and exit (just select Exit in the autoconfig)

Step #2: Reset the ZCU102

Step #3: Download the FPGA using xsct

cd /home/demo/petalinux/2019.1/tools/xsct/bin/
 connect -url tcp:localhost:3121
 # Select the PL
 targets 3
 fpga -no-revision-check /home/demo/plxprjs/zcu102mb/images/linux/system.bit

Note 1:

I needed to use xsct flow because I got a

WARNING: [Xicom 50-99] Incorrect bitstream assigned to device. Bitstream was generated for part xczu9eg-ffvb1156-2-e, target device (with IDCODE revision 1) is compatible with es2 revision bitstreams.

Note 2: You can download the bit file using HARDWARE MANAGER by running:

set_param xicom.use_bitstream_version_check false Vivado

Step #4: Back in PetaLinux type:

petalinux-boot --jtag --kernel -v

Note: Consider always using -v to see what the command actually does

Step #5: Examine build output:

INFO: sourcing build tools
XSDB Script:
INFO: Launching XSDB for file download and boot.
INFO: This may take a few minutes, depending on the size of your image.

targets -set -nocase -filter {name =~ "microblaze*#0"}
puts stderr "INFO: Downloading ELF file: /home/demo/plxprjs/zcu102mb/images/linux/image.elf to the target."
dow "/home/demo/plxprjs/zcu102mb/images/linux/image.elf"
after 2000
rlwrap: warning: your $TERM is 'xterm-256color' but rlwrap couldn't find it in the terminfo database. Expect some problems.: Inappropriate ioctl for device
INFO: Downloading ELF file: /home/demo/plxprjs/zcu102mb/images/linux/image.elf to the target.
Downloading Program -- /home/demo/plxprjs/zcu102mb/images/linux/image.elf
 section, .text: 0xc0000000 - 0xc043d427
 section, __fdt_blob: 0xc043d428 - 0xc044d427
 section, .rodata: 0xc044e000 - 0xc0565adf
 section, .pci_fixup: 0xc0565ae0 - 0xc056767f
 section, __ksymtab: 0xc0567680 - 0xc056ddbf
 section, __ksymtab_gpl: 0xc056ddc0 - 0xc0572717
 section, __ksymtab_strings: 0xc0572718 - 0xc058bf6c
 section, __param: 0xc058bf70 - 0xc058c537
 section, __modver: 0xc058c538 - 0xc058cfff
 section, __ex_table: 0xc058d000 - 0xc058e53f
 section, .notes: 0xc058e540 - 0xc058e57b
 section, .sdata2: 0xc058e57c - 0xc058efff
 section, .data: 0xc058f000 - 0xc05b557f
 section, .init.text: 0xc05b6000 - 0xc05d9c1f
 section, 0xc05d9c20 - 0xc05db6b3
 section, .init.ivt: 0xc05db6b4 - 0xc05db6db
 section, .init.setup: 0xc05db6dc - 0xc05dba8f
 section, .initcall.init: 0xc05dba90 - 0xc05dbe07
 section, .con_initcall.init: 0xc05dbe08 - 0xc05dbe0b
 section, .init.ramfs: 0xc05dbe0c - 0xc1283013
 section, .bss: 0xc1284000 - 0xc1310533
100% 18MB 0.2MB/s 01:52 
Setting PC to Program Start Address 0x80000000
Successfully downloaded /home/demo/plxprjs/zcu102mb/images/linux/image.elf

Step #6: Examine console output

Note 1: it looks like the console hangs, but it eventually came up (after a few minutes)

Note 2: Use root for the username and root for the password

Ramdisk addr 0x00000000,
Compiled-in FDT at (ptrval)
Linux version 4.19.0-xilinx-v2019.1 (oe-user@oe-host) (gcc version 8.2.0 (GCC)) #1 Sun Mar 7 18:29:2
2 UTC 2021
setup_memory: max_mapnr: 0x20000
setup_memory: min_low_pfn: 0x80000
setup_memory: max_low_pfn: 0xa0000
setup_memory: max_pfn: 0xa0000
Zone ranges:
 DMA [mem 0x0000000080000000-0x000000009fffffff]
 Normal empty
 HighMem empty
Movable zone start for each node
Early memory node ranges
 node 0: [mem 0x0000000080000000-0x000000009fffffff]
Initmem setup node 0 [mem 0x0000000080000000-0x000000009fffffff]
On node 0 totalpages: 131072
 DMA zone: 1024 pages used for memmap
 DMA zone: 0 pages reserved
 DMA zone: 131072 pages, LIFO batch:31
setup_cpuinfo: initialising
setup_cpuinfo: Using full CPU PVR support
pcpu-alloc: s0 r0 d32768 u32768 alloc=1*32768
pcpu-alloc: [0] 0
Built 1 zonelists, mobility grouping on. Total pages: 130048
Kernel command line: console=ttyUL0,9600 earlyprintk
Dentry cache hash table entries: 65536 (order: 6, 262144 bytes)
Inode-cache hash table entries: 32768 (order: 5, 131072 bytes)
Memory: 499716K/524288K available (4341K kernel code, 153K rwdata, 1276K rodata, 13108K init, 561K b
ss, 24572K reserved, 0K cma-reserved, 0K highmem)
Kernel virtual memory layout:
 * 0xfffea000..0xfffff000 : fixmap
 * 0xff800000..0xffc00000 : highmem PTEs
 * 0xff800000..0xff800000 : early ioremap
 * 0xf0000000..0xff800000 : vmalloc & ioremap
NR_IRQS: 64, nr_irqs: 64, preallocated irqs: 0
irq-xilinx: /amba_pl/interrupt-controller@41200000: num_irq=2, edge=0x1
/amba_pl/timer@41c00000: irq=1
clocksource: xilinx_clocksource: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 6370868154 ns
sched_clock: 32 bits at 300MHz, resolution 3ns, wraps every 7158278654ns
Calibrating delay loop... 49.35 BogoMIPS (lpj=246784)
pid_max: default: 4096 minimum: 301
Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
devtmpfs: initialized
random: get_random_u32 called from bucket_table_alloc+0xa0/0x23c with crng_init=0
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
futex hash table entries: 16 (order: -4, 448 bytes)
NET: Registered protocol family 16
audit: initializing netlink subsys (disabled)
PCI: Probing PCI hardware
audit: type=2000 audit(0.200:1): state=initialized audit_enabled=0 res=1
vgaarb: loaded
clocksource: Switched to clocksource xilinx_clocksource
NET: Registered protocol family 2
tcp_listen_portaddr_hash hash table entries: 256 (order: 0, 6144 bytes)
TCP established hash table entries: 4096 (order: 2, 16384 bytes)
TCP bind hash table entries: 4096 (order: 4, 81920 bytes)
TCP: Hash tables configured (established 4096 bind 4096)
UDP hash table entries: 256 (order: 1, 12288 bytes)
UDP-Lite hash table entries: 256 (order: 1, 12288 bytes)
NET: Registered protocol family 1
RPC: Registered named UNIX socket transport module.
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
RPC: Registered tcp NFSv4.1 backchannel transport module.
PCI: CLS 0 bytes, default 32
random: fast init done
Skipping unavailable RESET gpio -2 (reset)
workingset: timestamp_bits=30 max_order=17 bucket_order=0
romfs: ROMFS MTD (C) 2007 Red Hat, Inc.
io scheduler noop registered
io scheduler deadline registered
io scheduler cfq registered (default)
io scheduler mq-deadline registered
io scheduler kyber registered
Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
40600000.serial: ttyUL0 at MMIO 0x40600000 (irq = 2, base_baud = 0) is a uartlite
console [ttyUL0] enabled
brd: module loaded
libphy: Fixed MDIO Bus: probed
NET: Registered protocol family 17
Key type encrypted registered
Warning: unable to open an initial console.
Freeing unused kernel memory: 13108K
This architecture does not have kernel memory protection.
Run /init as init process
random: dd: uninitialized urandom read (512 bytes read)
random: dropbearkey: uninitialized urandom read (32 bytes read)
random: dropbearkey: uninitialized urandom read (32 bytes read)
random: crng init done
PetaLinux 2019.1 zcu102mb /dev/ttyUL0

zcu102mb login: