Please note as of Wednesday, August 15th, 2018 this wiki has been set to read only. If you are a TI Employee and require Edit ability please contact x0211426 from the company directory.

C6000 Linux Support

From Texas Instruments Wiki
Jump to: navigation, search

Content is no longer maintained or considered up to date and is being kept for reference only!'

C6x Linux Project

The C6000 Code Generation Tools (CGT), v7.3.0 or higher, can be used to create C6000 Linux ABI compliant object files and dynamic object modules. These object files are intended for use in the context of a Linux environment.

The linux-c6x project is a collaborative effort involving Texas Instruments Incorporated, CodeSourcery, and the Linux development community. It is focused on promoting support for the Linux ecosystem on the TI C64x family of digital signal processors and multi-core SOCs.

For more details about getting started with a Linux system for C6x and access to CodeSourcery GCC tools that generate code for C6x processors, please see the linux-c6x project wiki site: linux-c6x

TI/GCC Linux Interoperability

The TI/GCC interoperability scenarios described in this wiki page assume that the user has access to the CodeSourcery GCC tools that generate code for the C6x processors. Any Linux ABI application or dynamic modules that are created using a combination of TI and GCC tools will assume that they are going to be loaded and run on a Linux platform that has a Linux environment already running on it.

For more details about getting started with a Linux system for C6x and access to CodeSourcery GCC tools that generate code for C6x processors, please see the linux-c6x project wiki site:

http://www.linux-c6x.org

The Linux support in the C6000 Code Generation Tools (CGT) is designed to facilitate two primary development scenarios:

  • Using the TI compiler to build Linux object files that can be linked into a dynamic object module using the GCC linker and runtime libraries
  • Using the TI compiler and linker with GCC runtime libraries to build a dynamic shared object (DSO) that can be incorporated into a Linux process system

Before embarking on a more detailed discussion of these use cases, it is first necessary to set up a development environment for TI/GCC interoperability ...

Setting Up an Interoperability Development Environment

Before you get started, you should have these tools in your path:

  • cl6x: C6000 Code Generation Tools (CGT) version 7.3.0 or later
  • c6x-uclinux-gcc: Sourcery CodeBench Lite version 4.5-117 or later

Interlinking ToolKit (ITK)

To help you get started with setting up and using a TI/GCC interoperability development environment, you can unpack the C6x Interlinking Toolkit (ITK).

The ITK contains:

  • README - Documentation about how to install the ITK
  • setup.sh - Shell script to be run as part of installation instructions in README after proper modifications have been made to tell setup.sh where the development area is and where to find the TI and GCC tools
  • Makefile.itk - Makefile providing details about what options are to be used in the various supported platforms (to be included by parent Makefile); this Makefile is modified during installation when setup.sh is run
  • example/ - a subdirectory containing a simple "Hello World" example of how to use the ITK

Setup

Let's assume that your TI/GCC interoperability development area is in:

/home/ti_gcc_user/ti_gcc_interop

Let's also assume that you have the C6000 Code Generation Tools (CGT) installed in:

/db/ti_gcc_installations/ti_cgtools

Finally, assume also that you have the C6x GCC Sourcery CodeBench Lite tools installed in:

/db/ti_gcc_installations/c6x-gcc-4.5/c6x-4.5

You will need to modify the definition of both ILK_INSTALL_DIR and CL6X_PRODUCT_DIR and C6X_GCC_INSTALL_DIR in the setup.sh file as follows:

 #!/bin/sh

 # setup.sh
 #
 # Shell script to setup environment for interlinking code generated
 # by C6x GCC and TI toolchains.
 #
 # Usage:
 #   $ setup.sh

 # Destination directory for installing interlinking kit
 '''ITK_INSTALL_DIR=/home/ti_gcc_user/ti_gcc_interop'''

 # Path to cl6x toolchain distribution
 '''CL6X_PRODUCT_DIR=/db/ti_gcc_installations/ti_cgtools'''

 # Path to GCC toolchain distribution
 '''C6X_GCC_INSTALL_DIR=/db/ti_gcc_installations/c6x-gcc-4.5/c6x-4.5'''
 C6X_GCC_VERSION=4.5.1

 # -----------------------------------------------------------------------
 # Build the ITK
 mkdir -p ${ITK_INSTALL_DIR}

 # Include files needed by cl6x regardless of the library being used
 CL6X_TOOLCHAIN_INCLUDES="access.h assert.h c6x.h cpy_tbl.h
      elf_linkage.h elfnames.h float.h gsm.h iso646.h limits.h
      linkage.h pprof.h stdarg.h stdbool.h stddef.h stdint.h vect.h"

 mkdir -p ${ITK_INSTALL_DIR}/include/cl6x
 rm -f ${ITK_INSTALL_DIR}/include/cl6x/*
 for ifile in ${CL6X_TOOLCHAIN_INCLUDES}; do
   cp ${CL6X_PRODUCT_INCLUDE_DIR}/${ifile} ${ITK_INSTALL_DIR}/include/cl6x
 done

 # Include files used only when using the TI standard C library
 CL6X_LIBC_INCLUDES="access.h elfnames.h errno.h linkage.h math.h mathf.h
     mathl.h new.h setjmp.h signal.h stdio.h stdiostream.h stdlib.h stl.h
     string.h strstream.h time.h unaccess.h wchar.h wctype.h xlocinfo.h
     xwcc.h ymath.h yvals.h"

 mkdir -p ${ITK_INSTALL_DIR}/include/lib
 rm -f ${ITK_INSTALL_DIR}/include/lib/*
 for ifile in ${CL6X_LIBC_INCLUDES}; do
   cp ${CL6X_PRODUCT_INCLUDE_DIR}/${ifile} ${ITK_INSTALL_DIR}/include/lib
 done

 # If not installing in-place, copy Makefile.ilk and other original files from
 # ITK.
 if [ ${ITK_INSTALL_DIR} != $(pwd) ] ; then
   cp Makefile.cl6x ${ITK_INSTALL_DIR}
   mkdir -p ${ITK_INSTALL_DIR}/lib
 fi

The next step is to run the setup.sh script:

 ./setup.sh

When the setup.sh script is complete, there will be a new sub-directory in the ti_gcc_interop area:

 /home/ti_gcc_user/ti_gcc_interop/include

Which contains two sub-directories:

 cl6x
 lib

The cl6x sub-directory contains TI header files that must be used when using the cl6x compiler to compile a source module. This includes all of the header files listed in the definition of CL6X_TOOLCHAIN_INCLUDES in the setup.sh script above. The lib sub-directory contains TI header files that should be used when compiling an object file with c6x-uclinux-gcc, but linking with TI runtime support libraries (not a typical TI/GCC interoperability scenario).

The final step in the setup process is to edit the Makefile.itk in the ti_gcc_interop area to update the definition of CL6X_ITK_DIR to point to the TI/GCC interoperability development area (/home/ti_gcc_user/ti_gcc_interop) and the definition of C6X_GCC_INSTALL_DIR to point to the GCC tools installation (/db/ti_gcc_installations/c6x-gcc-4.5/c6x-4.5).

Using cl6x Compiled Objects in a Linux Dynamic Module Linked via GCC Linker and Libraries

The first TI/GCC interoperability use case we will consider is using the TI cl6x compiler to generate a C6000 Linux ABI compliant object file in which the compiler uses a combination of TI and GCC standard C header files. The object file can then be combined with other cl6x and/or GCC generated Linux object files in the static link step which uses the GCC linker and runtime libraries that are provided in the CodeSourcery GCC package.

Here is a picture of what this development flow looks like:

TI GCC Interoperability Use Case 1.jpg

Building a Linux ABI Compliant Object File with cl6x - "Hello World" Example

The Interlinking ToolKit (ITK) that was described earlier contains a sub-directory example/ which is a simple "Hello World" application which we will now use to illustrate the first use case and demonstrate the use of the ITK.

The example/ sub-directory contains a Makefile and a source file, hello.c:

#include <stdio.h>
void main()
{
   printf("Hello World\n");
}

To build the "Hello World" application, invoke the following gmake command from the example/ sub-directory:

 %> gmake PLATFORM=uclinux COMPILER=cl6x LINKER=gcc

The definitions of the PLATFORM, COMPILER, and LINKER variables will dictate which compiler, linker, and runtime libraries are used during the build. In the above gmake invocation:

  • PLATFORM=uclinux - specifies that a dynamic object module for a Linux platform is to be built. The ITK also supports a platform configuration of elf which can be used to build bare-metal static ELF executables.
  • COMPILER=cl6x - specifies that the TI compiler (cl6x) is to be used during the compilation steps of the build. The ITK also supports a configuration where the user can specify COMPILER=gcc.
  • LINKER=gcc - specifies that the GCC linker and runtime libraries are to be used during the static link step of the build. The ITK also supports a configuration of LINKER=cl6x in combination with PLATFORM=uclinux which is typically used when building a dynamic shared object with the TI compiler and linker, and the GCC runtime libraries.

Note: the ITK does not currently support the configuration PLATFORM=elf COMPILER=gcc LINKER=cl6x.

Compile hello.c

The first step in the build of the "Hello World" application is compilation of the hello.c source module. This is the cl6x command that is invoked from the Makefile for the compile step:

 %> cl6x --abi=eabi -mv64p --linux  --gcc -D__GNUC_MINOR__=3 \
    -I/home/ti_gcc_user/ti_gcc_interop/include/cl6x \
    -I/db/ti_gcc_installations/c6x-gcc-4.5/c6x-4.5/c6x-uclinux/libc/usr/include \
    -I/db/ti_gcc_installations/c6x-gcc-4.5/c6x-4.5/lib/gcc/c6x-uclinux/4.5.1/include \
    -D__extension__= -D__nothrow__= -D__STDC__ -D__SIZE_TYPE__="unsigned int" \
    -D__WINT_TYPE__="unsigned int" -D__WCHAR_TYPE__="unsigned int" \
    -D__gnuc_va_list=va_list -eo=o hello.c

Notes:

  • --linux is the compiler option that is required for building C6000 Linux ABI compliant object files. For more details on the --linux option please see The --linux Compiler Option below.
  • --gcc compiler option enables GCC C language extensions that are supported in the TI compiler in case some of these extensions are used in the source code.
  • -mv64p selects the C64+ version of the C6000 processor family. This is compatible with the C6x CodeSourcery GCC package which also supports C64+ by default.
  • --abi=eabi selects the C6000 EABI runtime model which utilizes the ELF object format. The EABI runtime model uses ELF mechanisms that have been designed to support dynamic linking.
  • -I options specify an include file directory search path. This ensures that the subset of TI header files that the TI compiler depends on will be searched first for a requested header file. The GCC header file directories are then searched to find header files that are compatible with the GCC runtime libraries.
  • -D options provide compile time symbol definitions that are needed to help the TI compiler work properly with the GCC linker and runtime libraries.
The --linux Compiler Option

The C6000 Code Generation Tools (CGT) now support the capability to create C6000 Linux ABI compliant object files that can be incorporated into a dynamic executable object or a dynamic shared object (DSO).

To compile a C6000 Linux ABI compliant object file with the TI compiler (cl6x), the --linux option must be used.

  • --linux
To create an object file that can be linked into a Linux executable object, use the '--linux' option, i.e.:
 cl6x --abi=eabi --linux -mv64p ... exe_source_file.c
The '--linux' option causes the compiler to generate position independent code. This significantly reduces the number of relocation entries that need to be processed when an object is dynamically loaded.


Implicit Compiler Options

The following compiler options are implied when the --linux option is specified on the command line:

  • --abi=eabi
Support for Linux is only available when using ELF object format since ELF contains mechanisms for the support of dynamic linking. Therefore, specifying --linux on the compiler command line will implicitly pass the the --abi=eabi option to the compiler.
  • --dsbt
The --dsbt option specifies that the compiler will assume the presence of a Data Segment Base Table (DSBT) and will load the data page register (DP) from the DSBT table for every function that is marked exported.
The DSBT model is a mechanism used by the code generation tools to facilitate sharing of a dynamic shared object (DSO) in the Linux dynamic linking model. It also can be used to reduce the number of dynamic relocations that need to be processed at load time when using the Bare-Metal dynamic linking model (please see C6000 EABI Dynamic Linking wiki for more details about dynamic linking support in the C6000 Code Generation Tools.
  • --wchar_t
The --wchar_t option is used to indicate the size (in bits) to be assumed for the wchar_t basic type (wide character). C/C++ supports the type wchar_t to represent wider characters. The C99 and C++ standards leave the size of wchar_t "implementation defined". The language standards require that the underlying type be an integer type that can represent the distinct codes for all members of the largest extended character set from the supported locale. Hence the platform which implements the locale influences the size of whcar_t.
By default, the compiler will assume that the wchar_t basic type is 16-bits wide. However, Linux uses 32-bit extended characters and hence requires that the wchar_t type is 32-bits wide. Therefore, when building an application to run on C6x Linux (--linux option), the --wchar_t=32 option will also be implicitly passed to the compiler.
The --wchar_t=32 option is allowed only in EABI mode. If the --wchar_t option is specified in COFF ABI mode, then the compiler will emit a warning:
 warning: Option --wchar_t=32 is not valid without --abi=eabi (ignored)
Note that an object created with --wchar_t=16 will not be compatible with an object file that is created with --wchar_t=32. If 32-bit wchar_t objects are mixed with 16-bit wchar_t objects, then the linker will emit an error indicating the object incompatibility and fail the link step.

Linking with GCC Linker and Runtime Libraries

Getting back to the "Hello World" application in the example/ subdirectory of the TI/GCC interoperability development area, we will now consider the link step.

After compiling the hello.c source file, the Makefile will trigger the following link step:

 %> c6x-uclinux-gcc  ./hello.o -o a.out -lc

which invokes the GCC linker, using the hello.o object file generated from the TI compiler as input and linking it with the GCC runtime libraries to produce a C6000 Linux ABI dynamic executable which can be loaded and run in a C6x Linux environment.

For more details on what happens during the link step, you can add the -v option to the above link step command. This can be done by running the following command from the example/ sub-directory:

 %> c6x-uclinux-gcc -v ./hello.o -o a.out -lc

or you can add -v to the GCC linker command in Makefile of the example/ sub-directory (look for -lc option).


Please refer back to the linux-c6x web site for details on how to load and run a C6000 Linux ABI dynamic executable in a C6x Linux environment.

Using the TI Compiler and Linker with GCC Runtime Libraries to Build a Dynamic Shared Object (DSO) For Use in a Linux Process System

The TI cl6x compiler and linker can be used to build a C6000 Linux ABI compliant dynamic shared object (DSO) that can be used by GCC-built Linux executables that are being run in a dynamic process system.

This is a picture of what this development flow looks like:

TI GCC Interoperability Use Case 2.jpg

Building a Linux Dynamic Shared Object with cl6x - CRC DSO Example

To demonstrate how the TI compiler and linker can be used to create a C6000 Linux ABI compliant dynamic shared object (DSO), we will build up a CRC application in the previously created TI/GCC interoperability development area.

The CRC Application

The CRC application that we are going to build utilizes two source files:

  • crc.c - contains two exported CRC routines written in C, one of which has been hand-optimized.
 #define N 16

 /****************************************************************************/
 /* CRC - Natural version of C code.                                         */
 /****************************************************************************/
 unsigned short crc_cn(unsigned short a, unsigned short g)
 {
    int i;
    unsigned short  s = 0;

    for (i = 0; i < N; i++)
    {
        if ((a ^ s) & 1) s ^= g;
        a >>= 1;
        s >>= 1;
    }
    return s;
 }

 /****************************************************************************/
 /* CRC_C - Hand optimized version.                                          */
 /****************************************************************************/
 unsigned short crc_c(unsigned short a, unsigned short g)
 {
    int i;
    unsigned int  s  = 0;
    unsigned int  ta = a;
    unsigned int  tg = g;

    for (i = 0; i < N; i++, ta >>= 1, s >>= 1)
        if ((ta ^ s) & 1) s ^= tg;

    return s;
 }
  • main.c - entry point and driver function which calls the two imported CRC routines, timing the execution of each over the same data.
 #include <stdio.h>
 #include <time.h>

 unsigned short crc_c (unsigned short, unsigned short);
 unsigned short crc_cn(unsigned short, unsigned short);

 typedef unsigned short ushort;

 ushort a = 0x47d1;
 ushort g = 0x3cf3;

 ushort ret_c, ret_cn;

 clock_t time_c    (ushort *i);
 clock_t time_cn   (ushort *i);

 void main()
 {
    clock_t t_overhead, t_start, t_stop, t_c, t_cn;

    /************************************************************************/
    /* COMPUTE THE OVERHEAD OF CALLING CLOCK TWICE TO GET TIMING INFO.      */
    /************************************************************************/
    t_start    = clock();
    t_stop     = clock();
    t_overhead = t_stop - t_start;

    /************************************************************************/
    /* CALL THE INDIVIDIUAL TIMING ROUTINES.                                */
    /************************************************************************/
    t_c    = time_c(&ret_c)       - t_overhead;
    t_cn   = time_cn(&ret_cn)     - t_overhead;

    /************************************************************************/
    /* PRINT TIMING RESULTS                                                 */
    /************************************************************************/
    printf("X_CRC: C: %d, natC: %d\n", t_c, t_cn);

    /************************************************************************/
    /* CHECK THE RETURN VALUE                                               */
    /************************************************************************/
    if (ret_cn != ret_c)
       printf ("Return value failure: cn (%08x) != c (%08x)\n", ret_cn,ret_c);
 }

 /****************************************************************************/
 /* COMPUTE THE ELAPSED TIME OF THE COMPILED C ROUTINE                       */
 /****************************************************************************/
 clock_t time_c(ushort *i)
 {
    clock_t t_start, t_stop;

    t_start = clock();
    *i      = crc_c (a, g);
    t_stop  = clock();
    return  t_stop - t_start;
 }

 /****************************************************************************/
 /* COMPUTE THE ELAPSED TIME OF THE COMPILED NATURAL C ROUTINE               */
 /****************************************************************************/
 clock_t time_cn(ushort *i)
 {
    clock_t t_start, t_stop;

    t_start = clock();
    *i      = crc_cn (a, g);
    t_stop  = clock();
    return  t_stop - t_start;
 }

The crc.c source file will be compiled and linked into a DSO, crc.dso, using the TI compiler and linker. The main.c source file will be compiled with the GCC compiler and then a C6000 Linux ABI dynamic executable will be created by the GCC linker using the resulting main.o object file and the crc.dso dynamic shared object as inputs.

Compile crc.c

%> cl6x --abi=eabi -mv64p --linux --pic --gcc -z -D__GNUC_MINOR__=3 \
   -I/home/ti_gcc_user/ti_gcc_interop/include/cl6x \
   -I/db/ti_gcc_installations/c6x-gcc-4.5/c6x-4.5/c6x-uclinux/libc/usr/include \
   -I/db/ti_gcc_installations/c6x-gcc-4.5/c6x-4.5/lib/gcc/c6x-uclinux/4.5.1/include  \
   -D__extension__=  -D__nothrow__=  -D__STDC__  \
   -D__SIZE_TYPE__="unsigned int"  -D__WINT_TYPE__="unsigned int" \
   -D__WCHAR_TYPE__="unsigned int"  -D__gnuc_va_list=va_list  -eo=o crc.c
The --linux and --pic Compiler Options
  • --linux and --pic
To create an object file that can be linked into a Linux DSO, the --linux option must be combined with the --pic option:
 %> cl6x --abi=eabi --linux --pic -mv64p ... so_source_file.c
As explained above, the --linux option causes the compiler to generate position independent code. The --pic option causes the compiler make all data accesses position independent. This makes the Read-Only (RO) segment of a DSO shareable. A separate copy of a DSO's Read-Write (RW) segment is made for each dynamic executable in the system that uses the DSO.

Linking crc.dso

 %> cl6x --abi=eabi -mv64p --linux --pic -z crc.o --sysv --shared --dsbt_index=21 -o crc.dso
 
The --sysv and --shared Linker Options

The C6000 Code Generation Tools (CGT) now support the creation of dynamic executables and dynamic shared objects (DSO) that are C6000 Linux ABI compliant.

  • --sysv and --shared
To create a Linux dynamic object, the --sysv option must be used in the linker command line. When used without the --shared option, the --sysv option instructs the linker to create a Linux dynamic object module.
 %> cl6x --abi=eabi --linux -mv64p ... hello.c -z --sysv ... -o hello.exe
Note that use of the --linux option in a cl6x command line which compiles and links will automatically pass the --sysv option to the linker (--sysv linker option does not need to be explicitly specified in the above example).
When the --sysv option is combined with the --shared option on the linker command line, the linker will create a dynamic shared object (DSO):
 %> cl6x --abi=eabi --linux --pic -mv64p ... a.c b.c -z --sysv --shared ... -o an.so

If you choose to build a Linux dynamic object file using separate compile and link steps, then the linker will enforce that the compile options used to build the constituent object files are compatible.

For example, if you choose to build a Linux dynamic shared object which uses pre-compiled object files, the linker will enforce that each object file that is input into the link step was built using both the --linux and --pic options.

Managing DSBT Parameters

When the --sysv option is specified during the static link step, the DSBT model is implied. The following options can be used to adjust the DSBT model parameters during the build of a Linux dynamic object file:

  • --dsbt_size
By default, the linker will reserve 64 slots for use in a DSBT. This default size can be adjusted on the linker command line if the --dsbt_size option is explicitly specified. For example,
 %> cl6x --abi=eabi --linux -mv64+ hello.c -z --sysv --dsbt_size=32 ... -o hello.exe
will reserve only 32 slots for use by the DSBT in the dynamic application, hello.exe.
For more detailed information about the DSBT model, please see Link title
  • --dsbt_index
When building a dynamic shared object (use --sysv and --shared during the link step), by default, the static linker will leave the dynamic shared object's (DSO) DSBT index unassigned. The responsibility for assigning a DSBT index to a DSO is often left to a downstream tool or in many cases, the dynamic loader. However, you can explicitly assign the DSO's DSBT index using the --dsbt_index option. For example,
 %> cl6x --abi=eabi --linux --pic -mv64+ a.c b.c c.c \
                    -z --sysv --shared --dsbt_index=4 ... -o an.so
will assign a DSBT index of '4' to the DSO, an.so. When this DSO is dynamically loaded, the dynamic loader should honor the pre-assigned DSBT index and ensure that no other DSOs that are used in a dynamic system have the same DSBT index.

Compile and Link Linux Dynamic Executable with TI Built DSO

Returning to the CRC DSO example, we will now build a C6000 Linux ABI dynamic executable with the GCC compiler, linker, and runtime libraries which takes a TI-built DSO as input.

 %> c6x-uclinux-gcc -fpic -c main.c
 %> c6x-uclinux-gcc  main.o crc.dso -o a.out -lc

NOTE: When loading and running this executable, you will need to:

  • Have the crc.dso file present as well as the a.out file. The dynamic loader will begin loading a.out and discover a dependency on crc.dso at which point it will load the DSO.
  • Have the directory containing crc.dso in the definition of the LD_LIBRARY_PATH environment variable. The dynamic loader will use the LD_LIBRARY_PATH (as well as its default search areas - like '/lib') to find shared objects that need to be loaded. You can set the LD_LIBRARY_PATH on the target via # export LD_LIBRARY_PATH=., for example.

Useful Links

E2e.jpg
  • For technical support on MultiCore devices, please post your questions in the C6000 MultiCore Forum
  • For questions related to the BIOS MultiCore SDK (MCSDK), please use the BIOS Forum

Please post only comments related to the article C6000 Linux Support here.

Hyperlink blue.png Links

Amplifiers & Linear
Audio
Broadband RF/IF & Digital Radio
Clocks & Timers
Data Converters

DLP & MEMS
High-Reliability
Interface
Logic
Power Management

Processors

Switches & Multiplexers
Temperature Sensors & Control ICs
Wireless Connectivity