MYIR Lite Zynq 7z007s

If like me, you’re a newbie to FPGAs, and SoC FPGAs from Xilinx, the complexity of running an application talking to your IP from Linux can be quite daunting. I started by using petalinux from Xilinx to try and use an IP that I made using Vivado HLS (C to HDL). I sort of got it working, but the iteration cycle was too long and I was not making much progress, and I was spending time on issues I didn’t really want to deal with. Petalinux is a little bit opaque, and it also uses Yocto behind the scenes. It is the right choice for many cases, but it may be too complex when you’re just starting off on a project. This blog post is an attempt to consolidate information that is spread across many web pages, and make the whole process easy to understand in a single sitting.

Note: this post assumes basic familiarity with Vivado, and Vivado SDK usage.

Step 1 – Create your Vivado project

Create or open your existing Vivado project, with whatever IP(s) you want in the block diagram. There are a few prerequisites that you do need to follow, to be able to run Linux: you will probably want serial console, so enable one uart on the correct pins, enable at least one TTC (triple timer counter). The board I’m using is MYIR Zturn-lite with the Zynq 7z007s chip. Here is what my block diagram looks like:

Vivado

Generate your bitstream, and export your hardware description file “.hdf“.

Step 2 – generate device tree for your project

You need to do the following step only once, for this and for the next few steps. We need to clone these three repos:

$ cd /opt/Xilinx/xil-sources
$ git clone https://github.com/Xilinx/u-boot-xlnx.git
$ git clone https://github.com/Xilinx/linux-xlnx.git
$ git clone https://github.com/Xilinx/device-tree-xlnx

For all three repositories, cd into the directory, and do ‘git checkout xilinx-v2018.3‘ revision, that’s the version of Vivado I’m using.

Next, launch Vivado SDK from your Vivado window, in the menu bar, go to Window -> Preferences -> Repositories, and add a local repository. Use the path for the ‘device-tree-xlnx’ directory.

Vivado SDK preferences

Generating the .dtb file

Go to SDK window’s menu, File -> New -> Board support project. It will open a window for “New Board Support Package”. Earlier, it used to have two options for OS, freertos10_xilinx, and standalone, now it will have a device_tree option also, that’s the one we need right now.

Vivado SDK new project window

Once you finish creating that, SDK will have created the required device tree files.

Project explorer

Now, the file “system-top.dts” is our main file, but it needs to be passed through a C preprocessor, to include the “.dtsi” dependencies, and then we’ll use dtc, the device-tree compiler to compile our device-tree blob file (.dtb). Make sure you have sourced the SDK’s settings64.sh file so that you have dtc in your path.

$ cd /mnt/shared/video_linux/video_linux.sdk/device_tree_bsp_0
$ cpp -nostdinc -I include -I arch  -undef -x assembler-with-cpp  system-top.dts system-top.dts.preprocessed
$ dtc -I dts -O dtb -i . -o devicetree.dtb system-top.dts.preprocessed

The above command generates the devicetree.dtb file, which will be used later with the Linux kernel.

Step 3 – Compile U-boot

$ cd /opt/Xilinx/xil-sources/u-boot-xlnx
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zynq_zc702_defconfig
or 
$ export ARCH=arm
$ export CROSS_COMPILE=arm-linux-gnueabihf-
$ make

You can customize u-boot as needed with “make menuconfig,” once you are done, a file named u-boot will be created in the directory, which is an ELF file. We’ll use this to create our BOOT.BIN file (along with FSBL – first stage bootloader).

Step 4 – Compile FSBL – first stage bootloader

We’ll use SDK to create this from Xilinx’s template code. Petalinux also generates this for you automatically.

Using the SDK, create a new Application project, and use “Zynq FSBL template“.

Vivado SDK new project
vivado SDK project templates

For the above screenshot, I had to go back and in my (already generated) “Standalone” BSP for the project, and enable the “xilffs“, i.e. the FAT file system driver, which is required by the FSBL template. Compiling this project will give you a “.elf” file, “fslbl.elf” for me. This also will be used in the next step to create the “BOOT.BIN” file.

Step 5 – Generate BOOT.BIN

From SDK window’s menu, Xilinx -> Create Boot Image. This will open a window like following image, and we will add our two “.elf” files to it. First the FSBL file, which we’ll mark as the bootloader, and then the u-boot file. FOr clarity, I renamed the “u-boot” file to “u-boot.elf“.

Create boot image window

The tool creates a boot.bif file, which is description of partitions in the BOOT.BIN file; and then it generated the BOOT.BIN. If you see the output in the console, you will see:

bootgen -image boot.bif -arch zynq -o \
/home/tavish/vivado/video_linux/video_linux.sdk/BOOT.bin -w on 

And here the contents of boot.bif, which we can use to bypass the SDK tool the next time:

//arch = zynq; split = false; format = BIN
the_ROM_image:
{
	[bootloader]/home/tavish/vivado/video_linux/video_linux.sdk/fsbl/Debug/fsbl.elf
	/opt/Xilinx/xil-sources/u-boot-xlnx/u-boot.elf
}

If you run the bootgen command from above, it generates the BOOT.BIN file, and we’ll use this from now on instead of the SDK window.

NOTE: in the above example we did not include the bitstream. We can include that also, and if you read the source of the FSBL project, you will see that if the bitstream is present in any partition in the BOOT.BIN file, then it takes care of loading the bitstream into the FPGA.

Tweaking the FSBL

We built the FSBL from the Xilinx template, but it doesn’t print anything right now, and we want to make sure, that it is doing what we think it is doing. To do that, go to the FSBL project properties in the SDK, and add “FSBL_DEBUG_INFO” to the C preprocessor defines section. Now if you regenerate the BOOT.BIN as before, and try to boot, you should see the output from FSBL.

To boot from microsd card, make sure the board is set to boot from SD card, and your SD card has the first partition formatted as FAT (you can make two partitions, the second one larger and formatted ext4, for the filesystem).

Now copy BOOT.BIN to the microsd card, and boot. Here is my console output:

Xilinx First Stage Boot Loader
Release 2018.3  Sep 12 2019-14:57:57
Devcfg driver initialized
Silicon Version 3.1
Boot mode is SD     
SD: rc= 0        
SD Init Done  
Flash Base Address: 0xE0100000
Reboot status register: 0x60680000
Multiboot Register: 0x0000C000
Image Start Address: 0x00000000
Partition Header Offset:0x00000C80
Partition Count: 2                  
Partition Number: 1             
Header Dump                      
Image Word Len: 0x0001748A
Data Word Len: 0x0001748A      
Partition Word Len:0x0001748A
Load Addr: 0x04000000
Exec Addr: 0x04000000
Partition Start: 0x000065D0
Partition Attr: 0x00000010
Partition Checksum Offset: 0x00000000
Section Count: 0x00000001
Checksum: 0xF7FB3A30
Application      
Handoff Address: 0x04000000
In FsblHookBeforeHandoff function
SUCCESSFUL_HANDOFF
FSBL Status = 0x1


U-Boot 2018.01 (Sep 11 2019 - 14:37:48 +0530) Xilinx Zynq ZC702

Model: Zynq ZC702 Development Board
Board: Xilinx Zynq
Silicon: v3.1
I2C:   ready
DRAM:  ECC disabled 1 GiB
MMC:   sdhci@e0100000: 0 (SD)
reading uEnv.txt
...
...

As I mentioned before, if the BOOT.BIN contains a partition with the PL bitstream, it automatically loads it. If we have debug prints turned on, it should show some messages about that also. This time we’ll directly edit the boot.bif file, and run bootgen. Add the path to the bitstream for your project to the boot.bif file, so that it looks like this:

//arch = zynq; split = false; format = BIN
the_ROM_image:
{
        [bootloader]/home/tavish/vivado/video_linux/video_linux.sdk/fsbl/Debug/fsbl.elf
        /home/tavish/vivado/video_linux/video_linux.sdk/top_wrapper_hw_platform_0/top_wrapper.bit
        /opt/Xilinx/xil-sources/u-boot-xlnx/u-boot.elf
}

Again, as before, run the bootgen command to generate the BOOT.BIN file:

bootgen -image boot.bif -arch zynq -o \
/home/tavish/vivado/video_linux/video_linux.sdk/BOOT.bin -w on 

If you copy over this file, the boot logs should look like:

Xilinx First Stage Boot Loader
Release 2018.3  Sep 12 2019-14:57:57                                                                                                                                                                               
Devcfg driver initialized                                                                                                                                                                                          
Silicon Version 3.1                                                                                                                                                                                                
Boot mode is SD                                                                                                                                                                                                    
SD: rc= 0                                                                                                                                                                                                          
SD Init Done                                                                                                                                                                                                       
Flash Base Address: 0xE0100000                                                                                                                                                                                     
Reboot status register: 0x60680000                                                                                                                                                                                 
Multiboot Register: 0x0000C000
Image Start Address: 0x00000000
Partition Header Offset:0x00000C80
Partition Count: 3
Partition Number: 1
Header Dump
Image Word Len: 0x0007F2E8
Data Word Len: 0x0007F2E8
Partition Word Len:0x0007F2E8
Load Addr: 0x00000000
Exec Addr: 0x00000000
Partition Start: 0x000065D0
Partition Attr: 0x00000020
Partition Checksum Offset: 0x00000000
Section Count: 0x00000001
Checksum: 0xFFE7BF06
Bitstream
In FsblHookBeforeBitstreamDload function
PCAP:StatusReg = 0x40000A30
PCAP:device ready
PCAP:Clear done
Level Shifter Value = 0xA
Devcfg Status register = 0x40000A30
PCAP:Fabric is Initialized done
PCAP register dump:
PCAP CTRL 0xF8007000: 0x4C00E07F
PCAP LOCK 0xF8007004: 0x0000001A
PCAP CONFIG 0xF8007008: 0x00000508
PCAP ISR 0xF800700C: 0x0802000B
PCAP IMR 0xF8007010: 0xFFFFFFFF
PCAP STATUS 0xF8007014: 0x50000F30
PCAP DMA SRC ADDR 0xF8007018: 0x00100001
PCAP DMA DEST ADDR 0xF800701C: 0xFFFFFFFF
PCAP DMA SRC LEN 0xF8007020: 0x0007F2E8
PCAP DMA DEST LEN 0xF8007024: 0x0007F2E8
PCAP ROM SHADOW CTRL 0xF8007028: 0xFFFFFFFF
PCAP MBOOT 0xF800702C: 0x0000C000
PCAP SW ID 0xF8007030: 0x00000000
PCAP UNLOCK 0xF8007034: 0x757BDF0D
PCAP MCTRL 0xF8007080: 0x30800100
DMA Done !
FPGA Done !
In FsblHookAfterBitstreamDload function
Partition Number: 2
Header Dump
Image Word Len: 0x0001748A
Data Word Len: 0x0001748A
Partition Word Len:0x0001748A
Load Addr: 0x04000000
Exec Addr: 0x04000000
Partition Start: 0x000858C0
Partition Attr: 0x00000010
Partition Checksum Offset: 0x00000000
Section Count: 0x00000001
Checksum: 0xF7F34730
Application
Handoff Address: 0x04000000
In FsblHookBeforeHandoff function
SUCCESSFUL_HANDOFF
FSBL Status = 0x1
U-Boot 2018.01 (Sep 11 2019 - 14:37:48 +0530) Xilinx Zynq ZC702
...

You can see that the bitstream was loaded this time! I think u-boot and Linux also can load the bitstream, but this is the easiest way that just-works, so we’ll use this.

Step 6 – Build the Linux kernel

cd into the linux-xlnx directory that you cloned earlier. Make sure you have the SDK’s environment file sourced (. settings64.sh). We have the kernel, but we should look for a sane starting config for our board, which is usually a defconfig file.

$ find . -name *defconfig | grep zynq
./arch/arm/configs/xilinx_zynq_defconfig
./arch/arm64/configs/xilinx_zynqmp_defconfig

Now we’ll run:

$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- xilinx_zynq_defconfig
#
# configuration written to .config
#

You can now customize the kernel’s configuration if you want using “make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig“.

Linux kernel menuconfig

To compile the kernel, run “make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4“. U-boot will expect kernel as a uImage file, which it will load into memory at a particular address and boot it. That address will be 0x8000. If you generate uImage now using “make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- uImage“, it will give you an error that says “Specify LOADADDR on the commandline to build an uImage”. To fix this, run:

$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- UIMAGE_LOADADDR=0x8000 uImage
...
...
Kernel: arch/arm/boot/Image is ready
Kernel: arch/arm/boot/zImage is ready
UIMAGE  arch/arm/boot/uImage
Image Name:   Linux-4.14.0-xilinx
Created:      Thu Sep 12 15:51:37 2019
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    3965568 Bytes = 3872.62 KiB = 3.78 MiB
Load Address: 00008000
Entry Point:  00008000
Kernel: arch/arm/boot/uImage is ready

Let’s try to boot the kernel this time, copy the uImage file to the boot partition in the microsd card, also copy the devicetree.dtb file. Also, we did not create it earlier, but we will also need a “uEnv.txt” file for u-boot, to tell it how to load the kernel and the devicetree file and what parameters to pass to it.

Note: the filenames uEnv.txt, and devicetree.dtb might be different for you, I may have changed this in the u-boot config using menuconfig.

Create uEnv.txt file in the boot partition with the contents:

bootargs=console=ttyPS0,115200 root=/dev/mmcblk0p2 rw earlyprintk rootfstype=ext4 rootwait
load_image=fatload mmc 0 ${kernel_load_address} ${kernel_image} && fatload mmc 0 ${devicetree_load_address} ${devicetree_image}
uenvcmd=echo Copying Linux from SD to RAM... && mmcinfo &&  run load_image && bootm ${kernel_load_address} - ${devicetree_load_address}

Once that is done, let’s try booting our kernel:

U-Boot 2018.01 (Sep 11 2019 - 14:37:48 +0530) Xilinx Zynq ZC702
Model: Zynq ZC702 Development Board
Board: Xilinx Zynq
Silicon: v3.1
I2C:   ready
DRAM:  ECC disabled 1 GiB
MMC:   sdhci@e0100000: 0 (SD)
reading uEnv.txt
...
...
reading uImage
3965632 bytes read in 254 ms (14.9 MiB/s)
reading devicetree.dtb
9226 bytes read in 17 ms (529.3 KiB/s)
## Booting kernel from Legacy Image at 02080000 ...
Image Name:   Linux-4.14.0-xilinx
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    3965568 Bytes = 3.8 MiB
Load Address: 00008000
Entry Point:  00008000
Verifying Checksum ... OK
## Flattened Device Tree blob at 02000000
Booting using the fdt blob at 0x2000000
Loading Kernel Image ... OK
Loading Device Tree to 1fffa000, end 1ffff409 ... OK
Starting kernel ...
Booting Linux on physical CPU 0x0
Linux version 4.14.0-xilinx (tavish@resurgam) (gcc version 7.3.1 20180314 (Linaro GCC 7.3-2018.04-rc3)) #1 SMP PREEMPT Wed Sep 11 15:01:56 IST 2019
CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=18c5387d
Waiting for root device /dev/mmcblk0p2...
mmc0: new high speed SDHC card at address 1388
mmcblk0: mmc0:1388 USD00 7.32 GiB 
mmcblk0: p1 p2
EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)
VFS: Mounted root (ext4 filesystem) on device 179:2.
Freeing unused kernel memory: 1024K
init_stage2: hwclock main process (731) terminated with status 1
Ubuntu 12.04 LTS localhost.localdomain ttyPS0
localhost login: root (automatic login)
Last login: Thu Jan  1 00:00:06 UTC 1970 on ttyPS0
Welcome to the Xillinux distribution for Zynq-7000 EPP.
You may communicate data with standard FPGA FIFOs in the logic fabric by
writing to or reading from the /dev/xillybus_* device files. Additional
pipe files of that sort can be set up by configuring and downloading a
custom IP core from Xillybus' web site (at the IP Core Factory).
For more information: http://www.xillybus.com.
To start a graphical X-Windows session, type "startx" at shell prompt.
root@localhost:~# 

It boots! It booted into Ubuntu for me, which will not happen in your case (because I had content from the demo CD which came with my board in the microsd card). More on the Linux root file system in the next section (rootfs). Here are my microsd card’s contents:

--- Partition 1 - FAT32 formatted boot partition
$ ll /media/tavish/boot/
total 6400
drwxr-xr-x  4 tavish tavish    1536 Jan  1  1970 ./
drwxr-x---+ 4 root   root      4096 Sep 12 16:07 ../
-rw-r--r--  1 tavish tavish 2569512 Sep 12 15:35 BOOT.BIN
-rw-r--r--  1 tavish tavish    9226 Sep 12 15:57 devicetree.dtb
-rw-r--r--  1 tavish tavish     372 Sep 11 14:47 uEnv.txt
-rw-r--r--  1 tavish tavish 3965632 Sep 12 15:56 uImage
--- Parition 2 - ext4 formatted - contains the rootfs - from demo image of Zturn lite
$ l /media/tavish/rootfs/
bin/  boot/  dev/  etc/  home/  lib/  lost+found/  media/  mnt/  opt/  proc/  root/  run/  sbin/  selinux/  srv/  sys/  tmp/  usr/ var/

How Linux was able to boot and run Ubuntu, was because of the ‘kernel cmdline/bootargs’ that we passed to it, through u-boot. It told the kernel to mount the root filesystem from first SD card’s second partition: This is from the uEnv.txt file:

bootargs=console=ttyPS0,115200 root=/dev/mmcblk0p2 rw earlyprintk rootfstype=ext4 rootwait devtmpfs.mount=0

Note: if your kernel has loadable modules, those need to be packed in the rootfs also, for that you need to do “make modules” and “make INSTALL_MOD_PATH=/media/tavish/rootfs modules_install” for example.

Note: uImage is necessary for u-boot bootm command, which we are using right now. uImage is a kernel image with a u-boot wrapper, created with mkimage utility. Newer u-boot (ours too) supports booting kernel zImage (which was also generated when we built our kernel) directly also.

Step 7 – Rootfs – Linux root filesystem

You have multiple options for how to obtain or create a root filesystem, for Linux. You can use a distribution like Debian, or Ubuntu if you can find a “armhf” port of it. Generally for Debian for example, you can use debootstrap or netinstall image with qemu or chroot to generate a filesystem image. Petalinux uses Yocto, which can also be used separately, or with petalinux. Right now we will use Buildroot, to generate a very minimal and basic rootfs, which is sufficient for our needs at the moment.

Buildroot

Here’s a XIlinx article about this – https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842369/Build+Linux+for+Zynq-7000+AP+SoC+using+Buildroot

  • Download Buildroot – “wget https://buildroot.org/downloads/buildroot-2019.02.5.tar.gz
  • Run “make menuconfig“, the settings you need to put for the correct architecture are:
    • Target options:
      Architecture: ARM (little endian)
      Architecture variant: cortex-A9
      [*] Enable NEON SIMD
      [*] Enable VFP extensions
      Target ABI – EABIhf
      Easy workflow for using UIO (Linux) to access IP on Xilinx Zynq 1
    • Go to “System configuration > Run a getty (login prompt) after boot > TTY port” and set to “ttyPS0
  • Run make

Once it is done building, the rootfs will be available in output/images/rootfs.tar. To copy to the microsd card, you can do: cd /media/tavish/rootfs/ (second partition on the card, ext4 formatted), then tar xvf /opt/Xilinx/buildroot/buildroot-2019.02.5/output/images/rootfs.tar. If you have kernel modules that need to be installed do that also as explained above with modules_install from the kernel directory.

This is the output from the serial now:

Waiting for root device /dev/mmcblk0p2...
mmc0: new high speed SDHC card at address 1388
mmcblk0: mmc0:1388 USD00 7.32 GiB 
mmcblk0: p1 p2
EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)
VFS: Mounted root (ext4 filesystem) on device 179:2.
devtmpfs: mounted
Freeing unused kernel memory: 1024K
EXT4-fs (mmcblk0p2): re-mounted. Opts: data=ordered
Starting syslogd: OK
Starting klogd: OK
Initializing random number generator... done.
Starting network: OK
Welcome to Buildroot
buildroot login: root
# 

Using UIO driver for your IP on Xilinx Zynq

UIO – (userspace I/O) is a Linux kernel feature which allows you to write driver for a memory mapped device. Candidates for UIO are devices that do not really need other kernel services, and which are not handled better by some other kernel driver. This includes many kinds of FPGA IPs.

Xilinx article on device tree and UIO – https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842482/Device+Tree+Tips#DeviceTreeTips-8UsingUIO

UIO howto from the kernel docs – https://www.kernel.org/doc/html/v4.17/driver-api/uio-howto.html

In the example that I am building, I have my custom IP (which I generated using Vivado HLS), attached to the AXI Bus. The goal of all of this was to access this IP from my Linux application. In the device tree project’s folder, SDK generated the file pl.dtsi, which contains this for me:

/ {
amba_pl: amba_pl {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
ranges ;
fir_filter_0: fir_filter@43c00000 {
/* This is a place holder node for a custom IP, user may need to update the entries */
clock-names = "ap_clk";
clocks = <&clkc 15>;
compatible = "xlnx,fir-filter-0.0";
reg = <0x43c00000 0x10000>;
xlnx,s-axi-axilites-addr-width = <0xa>;
xlnx,s-axi-axilites-data-width = <0x20>;
};
};
};

Although it is an auto-generated file, we will modify it for now (couldn’t find a way to not modify it, there is no system-user.dtsi for me as it is present for some people in forums). We’ll modify compatible = “xlnx,fir-filter-0.0”; to compatible = “generic-uio”; – this is so that we are able to use generic UIO driver to talk to this peripheral/IP. We’ll also pass uio_pdrv_genirq.of_id=generic-uio to kernel bootargs in uEnv.txt.

After making these two changes, i.e. – 1. edit uEnv.txt 2. edit pl.dtsi and re-generate devicetree.dtb, we will see if we can see our uio peripherals:

# ls /sys/class/uio/
uio0
# ls /dev/uio*
/dev/uio0

Using Buildroot SDK to cross-compile an application

See https://buildroot.org/downloads/manual/manual.html#_advanced_usage

We simply need to add the Buildroot toolchain to out path, and simply use it. You can do the following:

export PATH=/opt/Xilinx/buildroot/buildroot-2019.02.5/output/host/bin:$PATH
export CC=arm-buildroot-linux-uclibcgnueabihf-gcc
export CXX=arm-buildroot-linux-uclibcgnueabihf-g++
export LD=arm-buildroot-linux-uclibcgnueabihf-ld
export AR=arm-buildroot-linux-uclibcgnueabihf-ar
export OBJCOPY=arm-buildroot-linux-uclibcgnueabihf-objcopy
export SIZE=arm-buildroot-linux-uclibcgnueabihf-size

For the IP that I am testing (named fir_filter generated using HLS, but it does not matter if it is from an AXI memory mapped IP made with verilog/VHDL), there is driver code in the SDK project list’s BSP project, which I had created. Code is for both baremetal, and for Linux. For me it is located in “/home/tavish/vivado/video_linux/video_linux.sdk/standalone_bsp_0/ps7_cortexa9_0/libsrc/fir_filter_v0_0/src”. My project name was “video_linux”.

The application that I want to run is the following file (which doesn’t do much) – test.c:

#include "xfir_filter.h"
int main()
{
XFir_filter fir0;
int rc;
if ((rc = XFir_filter_Initialize(&fir0, "fir_filter")) != XST_SUCCESS) {
fprintf(stderr, "Initialization failed. Return code: %d\n", rc);
exit(EXIT_FAILURE);
}
if ((rc = XFir_filter_Release(&fir0)) != XST_SUCCESS) {
fprintf(stderr, "Release failed. Return code: %d\n", rc);
exit(EXIT_FAILURE);
}
return 0;
}

There is also a Makefile in the directory, which I modified slightly for my needs:

# ==============================================================
# File generated on Thu Aug 22 19:21:04 IST 2019
# Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC v2018.3 (64-bit)
# SW Build 2405991 on Thu Dec  6 23:36:41 MST 2018
# IP Build 2404404 on Fri Dec  7 01:43:56 MST 2018
# Copyright 1986-2018 Xilinx, Inc. All Rights Reserved.
# ==============================================================
COMPILER=$(CC)
ARCHIVER=$(AR)
CP=cp
COMPILER_FLAGS=
EXTRA_COMPILER_FLAGS=
LIB=libxil.a
RELEASEDIR=../../../lib
INCLUDEDIR=../../../include
INCLUDES=-I./. -I${INCLUDEDIR}
INCLUDEFILES=*.h
LIBSOURCES=*.c
OUTS = *.o 
app:
$(COMPILER) $(COMPILER_FLAGS) $(EXTRA_COMPILER_FLAGS) $(INCLUDES) $(LIBSOURCES) test_app/test.c -o test_fir
libs:
echo "Compiling fir_filter"
$(COMPILER) -c $(COMPILER_FLAGS) $(EXTRA_COMPILER_FLAGS) $(INCLUDES) $(LIBSOURCES)
$(ARCHIVER) -rv ${RELEASEDIR}/${LIB} $(OUTS)
make clean
include: 
${CP} $(INCLUDEFILES) $(INCLUDEDIR)
clean:
rm -rf ${OUTS}

Run make app, to build the file test_fir. This application doesn’t do anything, but it doesn’t give an error, which means initialization and release work. To test this, copy this file to the rootfs, say the /root folder.

When you run it you should see:

buildroot login: root
# ./test_fir 
#

No output! Which means our application was able to initialize and release the uio driver without any issue.

Conclusion

In this article, we were able to see the complete workflow of utilizing an IP in the FPGA, by building u-boot, FSBL, kernel, device tree, rootfs, and application. Writing this helped me remember all the parts involved in the whole process.