Exporting a Library for GCC

This chapter demonstrates how to use thesds++compiler to build a library of software functions with entry points into hardware functions implemented in programmable logic. This library can be linked into applications using the standard GCC linker forZynq®-7000 SoCandZynq® UltraScale+™ MPSoCdevices.

In addition to the library,sds++generates a complete boot image for the hardware functions and data motion network, including an FPGA bitstream. Using this library, you can develop software applications that call the hardware functions (and fixed hardware) using standard GCC toolchains. You are still targeting the same hardware system and using thesds++-generated boot environment, but you are free to develop your software application using the GNU toolchain in the software development environment of your choice.

IMPORTANT:In the current SDSoC™release, libraries are not thread-safe, so they must be called into from a single thread within an application, which could consist of many threads and processes.

Building a Shared Library

TIP:Shared libraries can be only created for application projects targeting Linux OS.

To build a shared library,sds++requires at least one accelerator. The following example provides three entry points into two hardware accelerators: a matrix multiplier and a matrix adder. You can find these files in thesamples/libmatrix/builddirectory.

  • mmult_accel.cpp: Accelerator code for the matrix multiplier
  • mmult_accel.h: Header file for the matrix multiplier
  • madd_accel.cpp: Accelerator code for the matrix adder
  • madd_accel.h: Header file for the matrix adder
  • matrix.cpp: Code that calls the accelerators and determines the data motion network
  • matrix.h: Header file for the library

Thematrix.cppfile contains functions that define the accelerator interfaces as well as how the hardware functions communicate with the platform (that is, the data motion networks between platform and accelerators). The functionmaddcalls a single matrix adder accelerator, and the functionmmultcalls a single matrix multiplier accelerator. Another functionmmultaddis implemented using two hardware functions, with the output of the matrix multiplier connected directly to the input of the matrix adder.

/* matrix.cpp */ #include "madd_accel.h" #include "mmult_accel.h" void madd(float in_A[MSIZE*MSIZE], float in_B[MSIZE*MSIZE], float out_C[MSIZE*MSIZE]) { madd_accel(in_A, in_B, out_C); } void mmult(float in_A[MSIZE*MSIZE], float in_B[MSIZE*MSIZE], float out_C[MSIZE*MSIZE]) { mmult_accel(in_A, in_B, out_C); } void mmultadd(float in_A[MSIZE*MSIZE], float in_B[MSIZE*MSIZE], float in_C[MSIZE*MSIZE], float out_D[MSIZE*MSIZE]) { float tmp[MSIZE * MSIZE]; mmult_accel(in_A, in_B, tmp); madd_accel(tmp, in_C, out_D); }

Thematrix.hfile defines the function interfaces to the shared library and is included in the application source code.

/* matrix.h */ #ifndef MATRIX_H_ #define MATRIX_H_ #define MSIZE 16 void madd(float in_A[MSIZE*MSIZE], float in_B[MSIZE*MSIZE], float out_C[MSIZE*MSIZE]); void mmult(float in_A[MSIZE*MSIZE], float in_B[MSIZE*MSIZE], float out_C[MSIZE*MSIZE]); void mmultadd(float in_A[MSIZE*MSIZE], float in_B[MSIZE*MSIZE], float in_C[MSIZE*MSIZE], float out_D[MSIZE*MSIZE]); #endif /* MATRIX_H_ */

In thesamples/libmatrix/build/sharedfolder, theMakefileshows how the project is built by specifying that the functionsmmult_accel,madd, andmmult_addmust be implemented in programmable logic.

SDSFLAGS = \ -sds-pf ${PLATFORM} \ -sds-hw mmult_accel mmult_accel.cpp -sds-end \ -sds-hw madd_accel madd_accel.cpp -sds-end

Object files are generated with position independent code (PIC), like standard shared libraries, using the GCC standard-fpicoption:

sds++ ${SDSFLAGS} -c -fpic –o mmult_accel.o mmult_accel.cpp sds++ ${SDSFLAGS} -c -fpic –o madd_accel.o madd_accel.cpp sds++ ${SDSFLAGS} -c -fpic –o matrix.o matrix.cpp

Link the objects files by using the using the GCC standard–sharedswitch:

sds++ ${SDSFLAGS} -shared -o libmatrix.so mmult_accel.o madd_accel.o matrix.o

After building the project, the following files are generated:

  • libmatrix.so: Shared library suitable for linking using GCC and for runtime use
  • sd_card: Directory containing an SD card image for booting the board

Delivering a Library

The following structure allows compiling and linking into applications using GCC in standard ways.

/include/matrix.h /lib/libmatrix.so /sd_card
IMPORTANT:The sd_cardfolder is to be copied into an SD card and used to boot the board. This image includes a copy of the libmatrix.sofile that is used at runtime.

Compiling and Linking Against a Library

The following is an example of using the library with a GCC compiler. The library is used by including the header filematrix.hand then calling the necessary library functions.

/* main.cpp (pseudocode) */ #include "matrix.h" int main(int argc, char* argv[]) { float *A, *B, *C, *D; float *J, *K, *L; float *X, *Y, *Z; ... mmultadd(A, B, C, D); ... mmult(J, K, L); ... madd(X, Y, Z); ... }

To compile against a library, the compiler needs the header file. The path to the header file is specified using the-Iswitch. You can find example files in thesamples/libmatrix/usedirectory.

TIP:For explanation purposes, the code above is only pseudocode and not the same as the main.cppfile in the directory. The file has more code that allows full compilation and execution.
gcc –I /include –o main.o main.c

To link against the library, the linker needs the library. The path to the library is specified using the-Lswitch. Also, ask the linker to link against the library using the-lswitch.

gcc –I /lib –o main.elf main.o -lmatrix

For detailed information on using the GCC compiler and linker switches see the GCC documentation.

Use a Library at Runtime

At runtime, the loader looks for the shared library when loading the executable. After booting the board into a Linux prompt and before executing the ELF file, add the path to the library to theLD_LIBRARY_PATHenvironment variable. Thesd_cardcreated when building the library already has the library, so the path to the mount point for thesd_cardmust be specified.

For example, if thesd_cardis mounted at/mnt, use this command:

export LD_LIBRARY_PATH=/mnt

Exporting a Shared Library

The following steps demonstrate how to export anSDSoCenvironment shared library with the corresponding SD card boot image using theSDSoCenvironment GUI.

  1. SelectFile>New>SDx Library Projectto bring up theNew SDx Library Projectdialog box.
  2. Create a new SDx Library project.
    1. Typelibmatrixin theProject namefield.
    2. Specify theLocation.
    3. ClickNext.
    4. Check theShared Librarycheckbox in theAccelerated Library Typewindow.
    5. ClickNext.
    6. SelectPlatformto bezc102.
    7. ClickNext.
  3. Provide the system configuration and software details of your project.
    1. Accept the default values in theSystem Configurationdialog box.
      Note:Ensure that Sysroot pathis unchecked.
    2. ClickNext.
  4. In theTemplatesdialog box, selectMatrix Shared Libraryfrom the Available Templates, and clickFinishto create the project.
  5. In theProject Explorer, right-clicklibmatrixand selectImport Sources.
  6. In theImport Sourcedialog box, selectBrowseandsamples/libmatrixand selectbuildand clickOK.
  7. In theImport Sourcesdialog box, checkbuildand clickFinish.

    A newSDSoCshared library application project calledlibmatrixis created in theProject Explorerview. The project includes two hardware functionsmmult_accelandmadd_accelthat are visible in theSDSoC Project Overview.

  8. Build the library.
    1. In theProject Explorerview, select thelibmatrixproject.
    2. SelectProject>Build Project.

      After the build completes, there is a boot SD card image under the Debug (or current configuration) folder.