The Snickerdoodle Book/DevelopmentEnvironment

From krtkl wiki
Jump to navigation Jump to search

Development Environment

11. Application Development (SDK)

Update: In 2019, Vitis replaced the SDK. Nevertheless, the brief coverage here applies to Vitis as well.

Xilinx provides a fully integrated Eclipse-based development environment for software development and deployment. The Xilinx SDK can be freely downloaded from Xilinx. The SDK uses Eclipse as it’s backbone and adds some convenient utilities for building applications and systems for Snickerdoodle’s application processor. Many aspects of the development cycle have been automated and integrated into the SDK. The SDK is hardware aware and is capable of automating significant portions of project creation, build and booting the application processor.

TODO: insert Figure 11.1

Project Workspace

To get started with application development, whether bare-metal or operating system based, a hardware aware workspace should be used. From within a hardware project directory, a .sdk directory is produced during the hardware export process. This directory contains the hardware specification to be used by the SDK for producing the required application board support packages. For more on developing producing custom hardware configurations, refer to Chapter ?? . For many applications, pre-defined hardware configurations can be used to get started with software layer development. Visit for example projects and 22 hardware configurations.

TODO: insert Figure 11.2

Figure 11.2 shows an example SDK workspace for a particular hardware configuration with a FSBL project and BSP (Board Support Package). The FSBL can be automatically generated by the SDK.

Create New Project

To create a new project, select File » New » Application Project as shown in Figure 11.3 .

TODO: insert Figure 11.3

12. Hardware Development (Vivado)

The versatility of Snickerdoodle is due to it’s software definable and reconfigurable hardware interface. The on-board Zynq-7000’s programmable logic allows for the hardware interface to be defined by a bitstream that can be generated in a way that is exceedingly similar to software and application development. The development environment, Vivado®, has been architected in such a way that the transition between developing for the programmable logic (PL) and processing subsystems (PS) is seamless.

InfoBox: Portions of this guide have been excerpted and adapted from the Xilinx® Wiki found at

This guide will get you started developing hardware definitions for Snickerdoodle. In this guide, it is assumed that you have an installation of Vivado (this guide uses the 2015.4 release) on a host computer. The process outlined in this guide was created using Windows 10 as the host computer operating system. While the process is similar for Windows users, those using Windows operating systems should consult the Windows version of this guide.

Install Snickerdoodle Board Files

To begin working with programmable logic on Snickerdoodle, a set of board files need to be installed onto the host computer for access by Vivado. The board files are a set of text files that are read by Vivado on startup and provide a set of constraints that define the board hardware.

Download Board Files

The board files can be downloaded directly from GitHub. The files can be downloaded as a .zip file from a web browser, downloaded directly using wget or cloned using git clone.

The archive (.zip) can be downloaded directly from a Linux terminal by invoking wget. The following command will download the board files repository archive:

$ wget

On a Windows host, the board files can be downloaded from GitHub by selecting "Clone or download" » "download ZIP" from the Github repository page.

Installing Board Files

CautionBox: Moving or copying files into the Vivado install directory will require root or administrator permissions just as installing any program would.

After downloading the board files archive, the files will need to be installed in the proper location so that they may be read by Vivado. The directory that Vivado uses to load board files when starting is relative to it’s install location. On a Windows host, typically Vivado is installed at C:/Xilinx/Vivado/<release>. On a Linux system, Vivado is usually installed into /opt/Xilinx/Vivado/<release>. The board files are located at <vivado_install_dir>/data/boards/board_files.

On a Linux system, the board files can be downloaded from the terminal using wget and extracting the archive to the board files directory.

The only files that should be installed are the Snickerdoodle and Snickerdoodle_black directories which contain the board files for the corresponding Snickerdoodle version. An exclusion file (EXCLUDE) is included in the archive to help with the copying process and prevent extraneous files (documentation, README, etc.) from being copied into the board files directory.

The following series of commands will extract the .zip archive and move the resulting board files into the board_files directory:

$ wget
$ cd snickerdoodle-board-files-master
$ rsync -av --exclude-from=EXCLUDE ./* /opt/Xilinx/Vivado/2015.4/data/boards/board_files/

Once the board files have been installed, Vivado will need to be restarted to load the files from the data directory.

Creating a New Project

Creating a new project can be done by selecting File » "New Project..." from the menubar or by selecting the Create New Project icon from the "Quick Start" menu, as shown in Figure 12.1 .

The first step to creating a new Vivado project is to select the project name and parent directory. By default, Vivado will create a new subdirectory for which to store the project files. It is highly recommended that this setting be left unchanged to keep the project files and directories organized and easily accessible for development (i. e., from the SDK). Figure 12.2 shows the input of the project name and parent directory when creating a new project.

TODO: insert Figure 12.1 and 12.2

Project Type and Sources

At this point in the project creation process, IP and design sources can be added to the project. If you would like to include existing sources, you will prompted to include those before choosing a project board. If you choose not to include any existing assets or constraints, the "Do no specify sources..." checkbox, shown in Figure 12.3 , can be selected to skip this step. Sources can be added to the project at any time after creation as outlined below.

TODO: insert Figure 12.3

Choosing a Project Board

If the board files have been copied and loaded properly, they will be listed in the table of boards. To view the available boards, choose "Boards" rather than "Parts" at the top of the window as shown in Figure 12.4 .

TODO: insert Figure 12.4

After selecting a board, the details of the project will be listed in the New Project Summary shown in Figure 12.5 . By clicking the "Finish" button, the project will be created and opened in the Vivado graphical user interface (GUI).

TODO: insert Figure 12.5

Working with Vivado

InfoBox: Additional information and resources on using Vivado to create and edit hardware designs can be found in the Vivado Design Suite User Guide: Getting Started or for a more in-depth guide at Vivado Design Suite User Guide: Using the Vivado IDE

Now that Vivado has been set up with the Snickerdoodle board files and a new project has been created, development can begin. The Vivado GUI is similar to many software development environments. Many project elements are contained within panes and editing of those elements can be done through the menubar or from the panes themselves. After creating an empty project, you are free to import existing assets or develop sources from scratch. To get started with development, a block design needs to be created.

Create Block Design

A block design is a visual representation of the hardware configuration. Hardware configurations can be defined by including or creating sources and assigning hardware I/O. Figure 12.7 shows an example block design with hardware definitions for fixed peripherals such as memory interfaces and a some GPIO ports defined in programmable logic.

TODO: Add the margin image

TODO: Add Figure 12.7

To create a block design for a new project, select Flow » Create Block Design from the menubar or from the "IP Integrator" section of the Flow Navigator pane as shown in Figure 12.6 .

Adding and integrating sources and IP into a block design can vary greatly depending on the design and application. For additional reading and information on integrating IP can be found at .

Getting Ports (get_ports)

After synthesizing and implementing the block design, the get_ports command can be used in the TCL console to view the ports available to be constrained. Before the synthesis and implementation is complete, the get_ports command will produce an error message as shown in Code Listing 12.2 .

Code Listing 12.2: Error When Getting Ports Before Synthesizing and Implementing Design

> get_ports
ERROR: [Common 17-53] User Exception: No open design. Please open
an elaborated, synthesized or implemented design before
executing this command.

Code Listing 12.3: Example TCL Console Output of get_ports Command

> get_ports
gpio0_tri_io[0] gpio0_tri_io[10] gpio0_tri_io[11]
Add Sources and IP

Adding sources can be done by right clicking inside the Sources pane or by selecting File » Add Sources... from themenubar. The Add SourcesWizard will appear and allow you to select existing sources, IP and constraints to add to the project.

TODO: add Figure 12.8

Create HDLWrapper

Before generating a bitstream for the project, an HDL wrapper must be generated for the design. To do this, right click on the design (in this case "base_design") from within the Sources pane and select "Create HDL Wrapper...".

Address Editor

The address editor can be used to configure and identify the register address values used to access the IP interfaces that have been used in the block design. These addresses will be used to specify configure the interfaces in the devicetree blob so that they are enumerated by Linux during the boot process and are made accessible from Linux. More information on devicetree usage, refer to Chapter 20 .

Generating Bitstreams

Bitstreams can be generated by selecting Flow » Generate Bitstream from the menubar or from within the "Program and Debug" section of the "Flow Navigator" pane as shown in Figure 12.12 . The bitstream contains all the information necessary to define the programmable logic and the associated hardware peripherals/interfaces.

TODO: add Figures 12.9 .. 12.11

Exporting Design with SDK

Export the Hardware Platform

add margin Figure 12.12

add Figure 12.13: Export Hardware Configuration from Vivado

Designs that are implemented using Vivado can be exported and opened in the SDK directly from Vivado. Before a design can be opened in the SDK, the hardware profile must be exported which can be done by selecting File » Export » ExportHardware... from the menubar as shown in Figure 12.13 .

add margin Figure 12.14

Figure 12.14 shows the options for hardware export. Select the "Include bitstream" checkbox to include the bitstream with the hardware definition files for use with the SDK. If you would like to use the hardware platformin a workspace other than the hardware project directory, change the selection of the "Export to:" input. This will be the workspace for the SDK.

InfoBox: If you choose an export location other than <Local to Project>, the SDK will need to be launched separately from Vivado to access the exported workspace location

Launching the SDK

The SDK can be launched directly from Vivado to use the exported hardware profile for software development. To launch the SDK from Vivado, select File » Launch SDK from the menubar, as shown in Figure 12.15 . If the hardware platform was exported to a directory within the Vivado project (by selecting <Local to Project> as export location), the hardware platform will be immediately available within the SDK workspace. If the hardware was exported to a different directory, you will need to change the workspace directory after the SDK has launched.

add margin Figure 12.15

13. First Stage Boot Loader (FSBL)

The first stage boot loader is used to initialize the processing subsystem and prepare it to load a user application or operating system. During the boot process, the BootROM loads the FSBL to the on chip memory. The FSBL can be made to load a bitstream to the programmable logic before loading additional programming to the processing subsystem.

Create FSBL Project

Within an exported hardware SDK workspace, an FSBL project can be automatically generated. The SDK uses the hardware definition files to determine the configuration data for the FSBL. The hardware definition files also contain initialization code that can be used to build make custom builds of U-Boot which, combined with the FSBL, can be used to generate a Snickerdoodle boot image.

FSBL Application Project Platform and BSP (Board Support Package)

As shown in Figure 13.1 , the FSBL can be created in the same way as a bare-metal application project by navigating to File » New » Application Project as shown in Figure 11.3 . From the New Project dialog, select a standalone platform. A project name can be entered from this interface.

FSBL Application Project Template

By clicking "Next>", a project template option dialog (Figure 13.2 ) will appear. Within this dialog window, an FSBL project template can be selected, which will use the hardware configuration to generate the initialization code for the FSBL. Clicking Finish will complete the project generation and build the FSBL code from the workspace hardware configuration.

Project Outputs (u-boot.elf)

By default, the FSBL project will automatically build a .elf output. After generating and building the FSBL project, the SDK workspace will look similar to Figure 13.3 . Additional projects can be added to the workspace and worked on from within the same environment to reuse the hardware configuration data.

TODO: insert Figures 13.1 .. 13.3

The FSBL project output can be accessed from within the SDK GUI to build boot images using prebuilt binaries or outputs from other projects within the workspace. The build output will be generated to <workspace_dir>/fsbl/Debug, by default and can be changed from within the project preferences. The process for generating these images is described in the upcoming chapter.

14. Boot Image (BOOT.bin)

Whether using a pre-built hardware configuration or working with a custom solution, a bootable image must be produced which initializes the processing subsystem and (optionally) the programmable logic. The specific components that are included in a boot image depend heavily on the requirements of the application. While a single boot image configuration cannot be made to suit all applications, a generic boot configuration can be used as a starting point for customization.

The boot image should contain, at least, all of the information required to initialize the processing subsystem, typically through a combination of FSBL and U-Boot boot loaders. A bitstream which defines the programmable logic configuration can be loaded upon boot by building the bitstream into the boot image or a minimal boot image can be used if the bitstream is to be loaded fromuser/application space.

Boot Information File (.bif)

The components of a boot image are defined by a boot information file (.bif). The structure of the .bif will depend on the specific application details of the system. Typical components for creating a boot image are as follows:

InfoBox: Chapter 6 in the Zynq-7000 All Programmable SoC Software Developers [ Guide] has more detailed information about the boot process and components of the boot image.

Ref: Xilinx, Inc. Zynq-7000 All Programmable SoC Technical Reference Manual, 1.10 edition, February 2015

  • FSBL - First stage boot loader (FSBL). Responsible for loading the bitstream (if one exists), loading into memory and handing off the boot process to the second stage bootloader. The FSBL should always be specified with the bootloader tag in the .bif.
  • U-Boot - Second stage boot loader. Responsible for loading Linux system components (devicetree, uImage, file system)
  • Bitstream - The bitstream to be built into the boot image.
  • Device Tree - The Linux devicetree to be loaded by FSBL or U-Boot.
  • Kernel - Linux kernel image to be loaded by FSBL or U-Boot.
Small Initialization Boot Image

A very small boot image can be built using FSBL and U-Boot. An image with this configuration can be used to load application or operating system images from a specified boot medium (i.e., microSD, QSPI). This boot image provides no application programming, on it’s own. An advantage of this approach is modularity and flexibility of the other system components and choice of boot medium. Code Listing 14.1 shows the .bif structure for producing a small boot image.

Code Listing 14.1: Minimal Boot Image with FSBL and U-Boot

image : {
Load Images Using FSBL

InfoBox: The uImage.bin file specified in the .bif is simply a uImage that has been renamed with .bin for compatibility with bootgen

An entire standalone image can be produced with all of the components required to boot Linux. The first configuration of such a boot image is specified to load the system components into memory using FSBL.With this specification, the Linux components will be loaded into memory before FSBL hands off execution to the second stage boot loader (U-Boot). The load=0xXXXX tag is added to any images that should be loaded by the FSBL during the boot process. This will place the image in the specified memory location, from which the system can be booted using bootm from U-Boot. Code Listing 14.2 shows an example .bif specification with the memory addresses to load the Linux components. With this configuration, the images are pre-loaded and thus the boot process is well-defined and inflexible but simple.

Code Listing 14.2: Load Linux Components

Using FSBL
image : {
Load Images Using U-Boot

CautionBox: To avoid creating a boot image of unnecessarily large size, the offsets for the system components should be carefully calculated using the file sizes of the components (including FSBL and U-Boot).

The third configuration, while not nearly exhausting the possible configurations, to consider is building a boot image with the system components at known offsets within the image. The offset=0xXXXX tag is added to the components to control their location within the boot image. This is a convenient architecture for building standalone images not dependent on outside sources while not pre-loading the components into memory. With this configuration, the system remains flexible to loading outside components from boot medium while keeping a known bootable set of components within a singular boot image.

Code Listing 14.3: Load Linux Components from Known Boot Image Offsets

image : {

Building Bitstream into BOOT.bin

Bitstreams can be built into the boot image and specified to be loaded when the boot image starts the boot process. This method can be useful for bitstreams that need to be loaded before the operating system is booted, especially in cases where the operating system expects PL devices to be available during or immediately after the boot process which includes cases where PL devices are defined in the devicetree blob. There are two methods for building the boot image (BOOT.bin): a GUI based method executed from the SDK environment and a command line method from which the GUI process is derived. The boot image can be used to load bare-metal applications as well as general purpose operating system (e. g., Linux, FreeRTOS).

Building Boot Images from SDK

TODO: insert Figure 14.1: Create Boot Image SDK Menu Selection

The SDK provides a graphical way to select the components/partitions for the boot image and generate a reusable boot image file (.bif). The graphical front-end provides the necessary interface for selecting existing boot partitions (typically pre-compiled and/or provided by Vivado project) and will generate the .bif file along with the boot image. Figure 14.2 shows the graphical interface for creating Zynq boot images from the SDK. To access the interface and begin generating images, select Xilinx Tools » Create Boot Image from the menubar in the SDK as shown in Figure 14.1 .

TODO: insert Figure 14.2: Create Boot Image Interface in Xilinx SDK

Prebuilt .bif files can be used by the SDK interface by selecting "Import from exisiting BIF file", shown at the top of the window in Figure 14.2 . Boot partitions are listed in the "Boot image partitions" table within the interface. To add boot partitions from the interface, selecting "Add" will open an "Add partition" dialog (shown in Figure 14.3 ) which will allow you to select and specify the partition file.

TODO: insert Figure 14.3: Create New Boot Image Parition

Import and Specify Boot Images Sources

The most typical boot image for a Linux based system includes a FSBL, bitstream and U-Boot which will be used to load Linux. The image sources should be added one-by-one by clicking Add from the Create Boot Image interface as shown in Figure 14.2 . FSBL should be specified as the bootloader by selecting bootloader as the parition type as shown in Figure 14.4 .

After adding the FSBL, add the bitstream and U-Boot images from the filesystem. Add the sources as a datafile as shown in Figure 14.5 . Prebuilt UBoot executables can be downloaded from and copied to the workspace directory for import into boot image generation. Additional system components can be added in the same way and Offset or Load locations can be specified in the Add partition dialog.

After importing the boot image sources, the boot image interface should look similar to Figure 14.6 .

After selecting Create Image, the SDK console should output the status of the bootgen command and the generated boot image location. The generated boot image can then be loaded onto amicroSD card and used as a boot source.

TODO: add Figure 14.4: FSBL Bootloader Boot Image Partition

TODO: add Figure 14.5: U-Boot Boot Image Partition Selection

TODO: add Figure 14.6: Boot Image Partition

Code Listing 14.4: SDK Create Boot Image Console Output

cmd /C bootgen -image boot.bif -arch zynq -o \

Building Boot Images with bootgen

CautionBox: When building boot images with bootgen, the boot partition files and .bif file should be isolated in a working directory from which bootgen is executed.

The GUI interface for building boot images from within the SDK is simply a wrapper for the command line executable that serves the same purpose. bootgen can be provided with a .bif file to specify the boot image partitions. Below is an example .bif file:

Code Listing 14.5: Boot Information File

image : {

After copying the boot partition file and the .bif file to a local working directory, the bootgen utility can be executed from that directory to output the boot image. Invoking the following command will create a boot image named BOOT.bin using the boot image file boot.bif:

Code Listing 14.6: Generate BOOT.bin with bootgen

$ bootgen -image boot.bif -o i BOOT.bin