C-Callable IP Libraries
This section describes how to create a C-Callable IP library for IP blocks written in a hardware description language like VHDL or Verilog. User applications can statically link with such libraries using the SDSoC™ system compiler, and the IP blocks are instantiated into the generated hardware system. Using the SDx™ IDE and its command line equivalents are shown.
SDSoC applications can use C-Callable IP libraries to access packaged IP blocks written in a hardware description language (HDL) such as VHDL or Verilog or with a high-level synthesis (HLS) tool like Vivado® HLS. At times, hardware specific optimizations or micro-architectures are easier to implement through an HDL and can be delivered encapsulated within a C-Callable library.
Using a C-Callable IP library provides both the design reuse flexibility of a software library and the performance gain of optimized hardware IP blocks. With a bottom-up approach individual IP blocks can be designed, implemented, and tested prior to being placed into a C-callable library for broader use. The library of hardware-accelerated functions allows a means to insulate hardware and software development teams from low-level implementation details while still ensuring that both teams are cognizant of the functional interfaces.
Creating C-Callable IP Libraries
The SDx™ installation contains examples of C-Callable IP in the <SDx_Install_Dir>/samples/rtl directory. These examples show single-function as well as multi-function accelerator libraries where function arguments are passed as registers, memory references, or AXI streams, which are highlighted (axilite_arraycopy, aximm_arraycopy, axis_arraycopy). The multi-function examples (mfa_fir, mfa_scalar128_none, mfa_scalar_axi) highlight single accelerators with multiple software entry points.
The SDx IDE's Library Project flow is used to create a C-Callable IP library with foundational support from the sdx_pack utility. A description of the sdx_pack command line arguments can be found in the SDx Command and Utility Reference Guide (UG1279). For inspecting interfaces within Vivado-packaged IP, sdx_pack provides the capability to query IP settings including their hardware interfaces. The SDx IDE uses this feature to populate menu selections with interfaces and pull-down choices relevant to the IP being transformed into a C-Callable IP library.
A procedure for creating a C-Callable IP library using the axis_arraycopy example for a zcu102 platform is
described below. The axis_arraycopy example
contains the Vivado-packaged IP and the files used
to create the libarraycopy.a library. The
arraycopy.hpp header file contains the
software function declarations associated with the hardware functionality provided in
the packaged IP. The component.xml contains the
meta-data used by the SDx IDE and the underlying
sdx_pack
tool to build the library.
The following steps are necessary to create the C-Callable IP library with the SDx IDE:
- Create a C-Callable IP Library project.
- Each library is created for a specific
device_family
,cpu_type
, andOS_type
tuple.
- Each library is created for a specific
- Import source files from the <SDx_Install_Dir>/samples/rtl directory.
- Import both the header file and the packaged IP.
- Identify the header file (.hpp) and the IP meta-data file (component.xml) to use as inputs to build the C-Callable IP library.
- Show how to customize the IP.
- Indicate how the arguments of each function in the C-Callable IP library maps to the hardware IP.
The following tables guide you on how to complete the SDx dialogs.
- The top row of each table contains the SDx IDE menu selection to begin each task.
- The Dialog column lists the names of the subsequent dialog boxes that open.
- Selection and Action columns indicate how to fill out the dialog boxes to complete the task.
SDx Library Project
Begin by launching the SDx IDE and specifying a workspace (for example, sdx_workspace) to create a Library project ( ).
The project name becomes the name of the library created by concatenating the prefix lib and the .a suffix (lib<project_name>.a).
Dialog | Selection or Field Name | Action |
---|---|---|
Project Type | Application | Click Next |
Create a New SDx Project | Project name: | arraycopy |
Use default location | Check-mark | |
Click Next | ||
Accelerated Library Type | Type: | C-Callable Library |
Platform | Name | zcu102 |
Click Next | ||
System Configuration | System configuration: | A53_Linux |
Runtime: | C/C++ | |
Domain: | a53_linux | |
(pre-set) | CPU: | cortex-a53 |
(pre-set) | OS: | linux |
Linux Root File System: | Leave unchecked | |
Click Next | ||
Templates | Empty Application | Click Finish |
Import Sources Dialog Options
The following table shows the menu selection for importing sources.
Dialog | Selection or Field Name | Action |
---|---|---|
File system | From directory: | Browse to axis_arraycopy directory in samples/rtl |
Click OK | ||
Files: src/arraycopy.hpp | Check-marked | |
Directory: ip | Check-marked | |
Into folder: | arraycopy/src | |
Click Finish |
Add IP Customizations
In the IP Customizations window, click Add IP Customizations (file icon with stylized "h"). The following figure and table show how to add IP customization.
Dialog | Selection or Field Name | Action |
---|---|---|
Add IP Customizations | Header File: | Click Select |
Files: | Select arraycopy.hpp | |
Qualifier: | Select src/src/arraycopy.hpp | |
Click OK | ||
IP Path: | Click Select | |
Files: | Select component.xml | |
Qualifier: | Select src/ip/component.xml | |
Click OK | ||
Accelerator control: | Protocol: ap_ctrl_hs | |
Port: s_axi_lite | ||
Offset: 0 | ||
Primary Clock: ap_clk |
10.0 | |
Derived Clock: | (no change) | |
IP Parameters | (no change) | |
Click OK |
Add Function Mapping
This axis_arraycopy example uses the contents of the provided samples/rtl/axis_arraycopy/src/Makefile to complete the dialog box option.
The component.xml and, if provided, the register_map.txt files associated with the IP block can also be queried for information on the how the function arguments map to the hardware.
In the IP Customizations window, click Add Function Mapping ("+" icon) shown in the figure and table.
Dialog | Selection or Field Name | Action |
---|---|---|
Add Function Mapping | Function name: | Click "+" icon on the right-side |
Select arraycopy | ||
Click OK | ||
Arguments and Function Return mapped to AXILite Interface |
Click Add Function Argument Map ("+" icon) above the table for this interface type | |
Argument (Click within field to expose pull-down menu) | M | |
AXILite Interface
(Click within field to expose pull-down menu) |
s_axi_lite | |
Direction (Click within field to expose pull-down menu) | IN | |
Register Info (Click within field to expose pull-down menu) | M, at offset 16 | |
Array Arguments mapped to AXIS Interface |
Click Add Function Argument Map ("+" icon) above the table for this interface type | |
Argument (Click within field to expose pull-down menu) | A | |
AXIS Interface
(Click within field to expose pull-down menu) |
A | |
Direction (Click within field to expose pull-down menu) | IN | |
Array Arguments mapped to AXIS interface |
Click Add Function Argument Map ("+" icon) above the table for this interface type | |
Argument (Click within field to expose pull-down menu) | B | |
AXIS Interface
(Click within field to expose pull-down menu) |
B | |
Direction (Click within field to expose pull-down menu) | OUT | |
Complete the Add Function Mapping dialog box | Click OK |
Building the C-Callable IP Project
To build the project, the C-Callable IP library is generated and placed in the build output directory of the application (for example, the Release directory) with the name lib<application>.a (libarraycopy.a for this example).
In addition to the SDx IDE method
of creating a C-Callable IP library, a command line method that directly invokes the
sdx_pack
tool is available. The equivalent sdx_pack
command to match the actions taken with the
SDx IDE for the axis_arraycopy
example is:
sdx_pack -header arraycopy.hpp -lib libarraycopy.a \
-func arraycopy -map A=A:in -map B=B:out -map M=s_axi_lite:in:16 -func-end \
-ip ../ip/component.xml -control ap_ctrl_hs=s_axi_lite:0 \
-primary-clk ap_clk=10.0 -target-family zynquplus \
-target-cpu cortex-a53 -target-os linux \
-verbose
-func
and
-func-end
options of the sdx_pack
call.Multi-Function Accelerator Libraries
The axis_arraycopy example is a
library with a single accelerator function. Other examples, in particular the ones that
begin with the mfa_ prefix are multi-function
accelerator (MFA) libraries where more than one function is mapped onto one IP block.
Below is the sdx_pack
command for the mfa_scalar_128_none example that generates the libmfa.a.
The C-Callable IP library contains eight functions and is shown in the
following code example. This accelerator library uses control protocol none
, indicating that the user explicitly controls the IP.
This MFA example also demonstrates 128-bit scalar function arguments that map to
AXI4-Lite interfaces as well as 128-bit array
arguments that map to master AXI4-Stream
interfaces.
sdx_pack -header mfa.hpp -I inc -lib libmfa.a \
-func mfa_reset -map inst=s_axi_AXILiteS:in:0x40 -func-end \
-func mfa_init -map inA=inA:in -map inst=s_axi_AXILiteS:in:0x40 -func-end \
-func mfa_copy -map outB=outB:out -map inst=s_axi_AXILiteS:in:0x40 -func-end \
-func mfa_sum -map result=axi_AXILiteS:out:0x2c -map inst=s_axi_AXILiteS:in:0x40 -func-end \
-func mfa_status -map return=axi_AXILiteS:out:0x10 -map inst=s_axi_AXILiteS:in:0x40 -func-end \
-func mfa_status2 -map status=s_axi_AXILiteS:out:0x10 -map inst=s_axi_AXILiteS:in:0x40 -func-end \
-func mfa_result -map result=s_axi_AXILiteS:out:0x2c -func-end \
-func mfa_stop -map inst=s_axi_AXILiteS:in:0x40 -func-end \
-ip ../ip/component.xml -control none \
-add-ip-repo ../dummy_ip \
-add-ip-repo ../dummy_ip_repo \
-primary-clk ap_clk=10.0 \
-target-family zynquplus -target-cpu cortex-a53 -target-os linux -verbose
Another example of an MFA type of C-Callable library is the mfa_scalar_axi accelerator. This accelerator library
uses an ap_ctrl_hs
control protocol and shows the use
of scalar function arguments that map to AXI4-Lite
interfaces as well as array arguments that map to master AXI4 interfaces.
sdx_pack -header mfa.hpp -I inc -lib libmfa.a \
-func mfa_reset -map status=s_axi_AXILiteS:out:0x20 -map inst=s_axi_AXILiteS:in:0x34 -func-end \
-func mfa_init -map inA=s_axi_AXILiteS:in:0x10,m_axi_inA:in -map status=s_axi_AXILiteS:out:0x20 \
-map inst=s_axi_AXILiteS:in:0x34 -func-end \
-func mfa_copy -map outB=s_axi_AXILiteS:in:0x18,m_axi_outB:out -map status=s_axi_AXILiteS:out:0x20 \
-map inst=s_axi_AXILiteS:in:0x34 -func-end \
-func mfa_sum -map result=s_axi_AXILiteS:out:0x28 -map status=s_axi_AXILiteS:out:0x20 \
-map inst=s_axi_AXILiteS:in:0x34 -func-end \
-func mfa_status -map status=s_axi_AXILiteS:out:0x20 -func-end \
-func mfa_stop -map status=s_axi_AXILiteS:out:0x20 -map inst=s_axi_AXILiteS:in:0x34 -func-end \
-ip ../ip/component.xml -control AXI=s_axi_AXILiteS:0x0 \
-primary-clk ap_clk=10.0 \
-target-family zynquplus -target-cpu cortex-a53 -target-os linux -verbose
A register map showing the bit-level definition of the AXI4-Lite control protocol signals used in the mfa_scalar_axi example is provided in the mfa_scalar_axi/ip/register_map.txt file and excerpted below. In general, IP register mapping information is provided by the IP developer.
// ==============================================================
// File generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2018.3
// Copyright (C) 1986-2018 Xilinx, Inc. All Rights Reserved.
//
// ==============================================================
// AXILiteS
// 0x00 : Control signals
// bit 0 - ap_start (Read/Write/COH)
// bit 1 - ap_done (Read/COR)
// bit 2 - ap_idle (Read)
// bit 3 - ap_ready (Read)
// bit 7 - auto_restart (Read/Write)
// others - reserved
// 0x04 : Global Interrupt Enable Register
// bit 0 - Global Interrupt Enable (Read/Write)
// others - reserved
// 0x08 : IP Interrupt Enable Register (Read/Write)
// bit 0 - Channel 0 (ap_done)
// bit 1 - Channel 1 (ap_ready)
// others - reserved
// 0x0c : IP Interrupt Status Register (Read/TOW)
// bit 0 - Channel 0 (ap_done)
// bit 1 - Channel 1 (ap_ready)
// others - reserved
// 0x10 : Data signal of inA_offset
// bit 31~0 - inA_offset[31:0] (Read/Write)
// 0x14 : reserved
// 0x18 : Data signal of outB_offset
// bit 31~0 - outB_offset[31:0] (Read/Write)
// 0x1c : reserved
// 0x20 : Data signal of status
// bit 31~0 - status[31:0] (Read)
// 0x24 : Control signal of status
// bit 0 - status_ap_vld (Read/COR)
// others - reserved
// 0x28 : Data signal of result
// bit 31~0 - result[31:0] (Read)
// 0x2c : Data signal of result
// bit 31~0 - result[63:32] (Read)
// 0x30 : Control signal of result
// bit 0 - result_ap_vld (Read/COR)
// others - reserved
// 0x34 : Data signal of inst
// bit 31~0 - inst[31:0] (Read/Write)
// 0x38 : reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)
The mfa_fir C-Callable IP library example highlights instantiating IP parameters, using AXI4-Stream interfaces, a 24-bit data type, and a control protocol selection of none.
ibfir.a: fir.hpp
sdx_pack -header fir.hpp -lib libfir.a \
-func fir -map X=S_AXIS_DATA:in -map Y=M_AXIS_DATA:out -func-end \
-func fir_reload -map H=S_AXIS_RELOAD:in -func-end \
-func fir_config -map H=S_AXIS_CONFIG:in -func-end \
-ip ../ip/fir_compiler_v7_2/component.xml -control none \
-param DATA_Has_TLAST="Packet_Framing" \
-param M_DATA_Has_TREADY="true" \
-param Coefficient_Width="8" \
-param Data_Width="8" \
-param Quantization="Integer_Coefficients" \
-param Output_Rounding_Mode="Full_Precision" \
-param Coefficient_Reload="true" \
-param Coefficient_Structure=Non_Symmetric \
-primary-clk aclk_intf=10.0 \
-target-family zynquplus -target-cpu cortex-a53 -target-os linux -verbose
Considerations for C-Callable IP Libraries
- Function arguments of
TYPE *a
orTYPE &a
are interpreted as anOUTPUT
scalar. - Arrays must be declared as
TYPE a[N]
orTYPE a[]
. - Function return type can only be a scalar in the format of
TYPE: TYPE*
orTYPE&
are not allowed. - C-Callable IP library header files cannot have SDS pragmas that use
MACRO
as parameters:#pragma sds data copy (A[0:SIZE])
is not allowed whenSIZE
is a macro (for example,#define SIZE 16
). - Overlapped function calls of multi-function accelerators (MFAs) are not allowed,
as there is only one IP instance in the hardware; therefore,
async
pragmas around MFA functions are very risky and not recommended unless there is no chance of overlapping during runtime. - Argument sizes must match between the software declared argument and the hardware port pair: <project_name>/Release/reports/sdx_pack.html report file can be used to double-check if the library implemented the expected argument sizes, offsets, and bus interfaces.
- This supports up to one AXI4-Lite interface per top-level IP.
- For C-Callable functions, all pragmas must be applied when building the library
using
sdx_pack
. Any pragmas added into the header file after the library is already built are ignored by the tool.
sdx_pack Command
The following are examples of the sdx_pack
command:
sdx_pack -header <header.h/pp>-ip <component.xml>
[-param <name>="value"] [configuration options]
The following table provides further details on the sdx_pack
tool.
Option | Description |
---|---|
-header
header.h/.hpp |
(required) Header file (.h, .hpp) with function prototypes.sdx_pack generates C++
style library for a .hpp file and
a C-style library for a .h file.
Only one top-level header file is allowed per library. The top-level header can include other header files, using the-I option. |
-ip
component.xml |
(required) Path to Vivado packaged IP. Only one top-level IP per library. The top-level IP can invoke other IP blocks, using the-add-ip-repo option. |
-control protocol [=port
[:offset]] |
(required) IP control protocol options:
|
-func function_name -map
swName= hwNAME:direction[:offset[aximm_name:direction]]
-func-end |
(required) Specify a list of
C-Callable IP functions. Each function is listed between a The
|
-param
name="value" |
IP parameter name-value pairs to instantiate IP
parameters. Use one -param option per
pair. |
-lib
libname |
Use specified libname for naming the generated library. By default
lib header.a is used. |
-I path |
If the file named with the -header option includes other files, this option specifies
the path to the additionally included files. Multiple -I options can be used. For easier library
distribution, place all include files into a single directory. |
-add-ip-repo
path |
Add all IP found in the listed repository into the library. Although
multiple -add-ip-repo options can be
used to specify multiple paths.Xilinx recommends to place all required IP into a
single directory and use a single |
-primary-clk
clk_interface=min_clk_period |
Specify the primary clock interface and its minimum clock period in nanoseconds. |
-derived-clk
clk_interface=multiplier:divisor |
Specify a phase-aligned derived clock interface and its multiplier and divisor in units of integers. Only two phase-aligned clocks are supported. |
-target-family
device_family |
The target device family supported by the IP (for
example, zynq (default), zynquplus ). |
-target-cpu
cpu_type |
Specify target CPU:
|
-target-os
name |
Specify target OS:
|
-query-target
type |
Query one of: supported device families, cpu types,
or OS type for the IP [family, cpu,
os ] |
-query-interface
type |
Query interfaces and parameters of the IP. Multiple
query types supported [all, aximm, axilite,
axis, clock, control, param, misc ]Note: This requires that the IP has packaged all
necessary information needed by the query.
|
-o
output.json |
User-specified JSON file to save query results. |
-verbose |
Print verbose output to STDOUT. |
-version |
Print the sdx_pack
version information to STDOUT. |
-h, -help,
--help |
Display sdx_pack
option usage and descriptions. |
Here is an example of the code:
sdx_pack -header arraycopy.hpp -lib libarraycopy.a \
-func arraycopy -map A=A:in -map B=B:out \
-map M=s_axi_lite:in:16 -func-end \
-ip ../ip/component.xml -control AXI=s_axi_lite:0 \
-target-family zynquplus -target-cpu cortex-a53 -target-os standalone \
-verbose
Where:
- arraycopy.hpp specifies the
header file defining the function prototype for the
arraycopy
function. - component.xml of the IP generates the packaged Vivado IP for SDx.
-control
specifies the IP control protocol.–map
specifies the mapping of an argument from the software function to a port on the Vivado IP. Notice the option is used three times in the example above to map function argumentsA
,B
, andM
to IP ports.- The
–target-os
option specifies the target operating system.
The sdx_pack
utility generates a
C-Callable IP library to match the name in the -lib
option, libarraycopy.a in this case.
Using C-Callable IP Libraries
After generating the C-Callable library, create a new SDx Application project to use the library. Continuing
with the example of the axis_arraycopy
C-Callable IP
library built in the previous section, use the generated library (libarraycopy.a) from the library build's Release
directory. The result of building the Application project is an executable file
(ELF) that is linked with the C-Callable IP
Library.
- Create an SDx application
project to output an executable file. Click .Note: The tuple consisting of
device_family
,cpu_type
, andos_type
must match that of the C-Callable IP library.Table 6. SDx Application Project Dialog Box Selection or Field Name Action Project Type Application Click Next Create a New SDx Project Project name: app_arraycopy Use default location Check-marked Click Next Platform Name zcu102
Click Next System Configuration System configuration: A53_Linux Runtime: C/C++ Domain: a53_linux (pre-set) CPU: cortex-a53 (pre-set) OS: linux Linux Root File System: Unchecked Click Next Templates Empty Application Click Finish - Import the function declarations header file (.hpp) common to both the library and the
application. In the Project Explorer window, right-click app_arraycopy and select Import
Sources.
Table 7. Select Import Sources Dialog Selection or Field Name Action File system From directory: Browse to axis_arraycopy/src directory in <SDx_Install_Dir>/samples/rtl. Click OK Files: arraycopy.hpp Check-marked Into folder: app_arraycopy/src Click Finish - Open the Importing Sources dialog box again to get the example main
application code from the <SDx_Install_Dir>/samples/rtl directory. In the Project
Explorer window, right-click app_arraycopy
and select Import Sources.
Now that the source files for the
Table 8. Select Import Sources Dialog Selection or Field Name Action File system From directory: Browse to the axis_arraycopy/app directory in <SDx_Install_Dir>/samples/rtl Click OK Files: main.cpp Check-marked Into folder: app_arraycopy/src Click Finish app_arraycopy
application have been imported, update the C/C++ Build Settings to have thesds++
linker use the arraycopy.a C-Callable IP library when building the application. - Update the C/C++ Build
Settings in the Project Explorer window, right-click app_arraycopy and select C/C++ Build Settings as shown in the table.
Table 9. C/C++ Build Settings Dialog Selection or Field Name Action SDS++ Linker Select Libraries Click Add symbol (with "+" icon) in the Libraries (-l) window Libraries(-l) arraycopy Click OK Click Add symbol (with "+" icon) in the Library search path (-L) window Click Workspace Folder: Navigate to and select arraycopy/Release Click OK (pre-set) Directory: ${workspace_loc:/arraycopy/Release} Click OK Click Apply and Close
To create the application, you can use the Assistant window to build the app_arraycopy application.
- In the Assistant window under app_arraycopy[SDSoC], right-click Debug[Hardware] and select Build. The Console window shows the build progression including the
sds++
system compiler invocation. - After the application successfully builds the target executable file (app_arraycopy.elf), the Assistant window populates with a Data Motion Network Report, the Compilation Log, and an SD Card Image menu. Through the SD Card Image menu, the contents of the generated (sd_card) files directory is available to view using the Project Explorer, a file browser, or a command shell window.
- When the build completes, you can write the contents of the generated sd_card directory to the root of a FAT32-formatted SD card and boot and run the app_arraycopy.elf application on a ZCU102 board. The sd_card directory includes a README.txt for boot setup instructions, a bootable BOOT.BIN file, and the image.ub file used to boot Linux.
The SDx IDE builds the application
with the sds++
system compiler using the C-callable
library and the application code. The main application is compiled to produce an object
file and then it is linked with the C-callable library (arraycopy).
The following examples show the issued commands.
Compilation of main.cpp:
sds++ -Wall -O0 -g -I../src -c -fmessage-length=0 -MTsrc/main.o -MMD -MP -MFsrc/main.d \
-MTsrc/main.o -o src/main.o ../src/main.cpp \
-sds-sys-config a53_linux -sds-proc a53_linux -sds-pf zcu102
Linking main.o with arraycopy library to produce executable application app_arraycopy.elf:
sds++ -L<path_to_arraycopy/Release> --remote_ip_cache ../ip_cache \
-o app_arraycopy.elf ./src/main.o -larraycopy -dmclkid 1 \
-sds-sys-config a53_linux -sds-proc a53_linux -sds-pf zcu102