From RTSC-Pedia

Jump to: navigation, search
revision tip
—— LANDSCAPE orientation
[printable version]  [offline version]offline version generated on 04-Aug-2010 21:08 UTC

Creating Targets

How to create a new target

Contents

Introduction

Targets are RTSC modules that implement the xdc.bld.ITarget interface and are an essential part of the RTSC build and configuration models. Targets are used to generate makefiles that can compile and link portable C/C++ code and are used by packages during configuration to select appropriate libraries to link into the end application. Targets also serve to enable compatibility checks between packages built with different toolchains.

Adding a new target from scratch involves three major steps.

  1. Create a module that extends the xdc.bld.ITarget interface; i.e., you must implement the methods and supply the configuration parameters declared in the xdc.bld.ITarget interface.
  2. Define the "base" types required from all targets; i.e., create a C header (named by the module created above) that defines the target-specific "base" types (Int8, Int16, Int32, etc.).
  3. Provide a runtime support package for the target. This package contains the startup boot sequence (if necessary) plus a pre-built library of all of the xdc.runtime package's modules.

However, if the target you want to add is a simple variation of an existing target, these steps can be greatly simplified by simply "inheriting" from an existing target. For example, the local.targets package illustrates how to create a package of targets that inherits the xdc.bld.ITarget implementation from ti.targets.ITarget. In this case, each new target is nothing more than a relatively short .xdc module specification that defines a few constants. Also, in Inheriting from an Existing Target, we describe the steps required to create a new target based on an existing target.

Creating an ITarget Module

Since targets are RTSC modules, they are developed and delivered in a package. In addition, it is common for several targets to be delivered together; e.g., a big endian and little endian variation of a target. Object files that should not be combined in a single application must be created with different targets.

Since the implementation of the xdc.bld.ITarget interface is strongly influenced by the compiler toolchain that it "wraps", it is usually best to create separate target packages for each compiler vendor; e.g., GNU gcc compiler targets are in a package separate from the Microsoft Windows compiler targets. While is common for multiple packages to support the same compiler tool chain, it is best not to have a single package support multiple tool chains.

Implementing the xdc.bld.ITarget interface

Different targets in a package often only differ by a small set of required options; e.g., options that select a runtime model, structure packing conventions, or a specific Instruction Set Architecture (ISA). As a result, most target packages first define common interface that both inherits from xdc.bld.ITarget and defines properties that are common to the target modules in the package.

In RTSC, metaonly interfaces can provide "default" implementations of their declared methods. This allows a form of implementation inheritance that often allows new target modules that inherit a common interface to simply declare unique compiler options and rely on the default method implementation in the common interface to do the "heavy lifting" required to implement xdc.bld.ITarget.

For example, the targets package gnu.targets contains an interface gnu.targets.ITarget that inherits xdc.bld.ITarget, defines default values for the targets in this package, and provides default implementations for these targets (in gnu/targets/ITarget.xs).

The local.targets example package illustrates how to create a package of targets that inherits the xdc.bld.ITarget implementation from ti.targets.ITarget. In this case, each new target is nothing more than a relatively short .xdc module specification that defines a few constants.

Defining target-specific "base" types

All targets name a target-specific C header that defines a "base" set of types; see xdc.bld.ITarget.stdInclude. Client source code, on the other hand, always includes the target-independent header xdc/std.h to access these definitions. The xdc/std.h header indirectly includes target-specific definitions of these types based on the value of the symbol xdc_target_types__ defined on the command line. This bit of indirection eliminates target-specific references from sources and makes them trivially portable to any target.

In fact, two symbols are always defined when compiling any code that references a RTSC module: xdc_target_types__ and xdc_target_name__. These symbols are defined on the compiler's command line either explicitly by the end-user or implicitly by the makefile generated from the target module. The first symbol, xdc_target_types__, is used by xdc/std.h to include a target-specific header. The second symbol, xdc_target_name__, is optionally used by the target-specific header to conditionally define base types. For more information about how code that references RTSC modules is compiled, see Integrating RTSC Modules.

Example of a Base Types Header

The following command line sets these symbols for the TI C6x compiler when using the ti.targets.C64 target.

 
cl6x -Dxdc_target_types__=ti/targets/std.h -Dxdc_target_name__=C64 ... client.c

The client sources include xdc/std.h which, in turn, uses the definition of xdc_target_types__ to include the target-specific header. To make it possible to this target-specific header to easily include automatically generated definitions (from the ITarget interface), most target-specific headers include a header whose name is simply derived from adding ".h" to the end of value of xdc_target_name__.

In summary,

  1. client code includes <xdc/std.h>
  2. xdc/std.h includes a target-specific header, say <ti/targets/std.h>, and finally
  3. this target-specific header includes a machine-generated header whose name is derived from xdc_target_name__, say "C64.h".

The following fragment shows the basic structure of the header used for all targets supplied by the ti.targets package.

ti/targets/std.h
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
#ifndef ti_targets_STD_  /* prevent multiple includes of this header */
#define ti_targets_STD_
 
/*  Include target-specific "portable" macros
 *
 *  The build command-line defines xdc_target_name__ to be the value
 *  of the target's name config parameter.  We use this to include the
 *  target-specific definitions for the required target-independent
 *  xdc_target* macros.
 *
 *  xdc__local_include is a macro that expands into a #include of
 *  "<name>.h", where <name> is the argument to the macro. This macro
 *  is defined in xdc/std.h.
 *
 *  This header is machine generated from the template xdc/bld/stddefs.xdt
 *  and includes many definitions that are specified in the xdc.bld.ITarget
 *  interface.
 */
#if defined(xdc_target_name__) & !defined(xdc_target_macros_include__)
#include xdc__local_include(xdc_target_name__)
#endif
 
/* include the C99 standard integer types supported by TI */
#include <stdint.h> 
 
/* use compiler specific macros to guide definitions within xdc/std.h */   
#if defined(_TMS320C6X) /* defined by cl6x for all C6x CPUs */
       :
    #define xdc__BITS64__     /* has a precise 64-bit type */
    #define xdc__INT64__      /* has a 64-bit integer type */
#elif ...
    :
#else
    /* generate an error if this header is used with an unknown target */
    #error <ti/targets/std.h> is not supported for this target
#endif
 
/* define the RTSC base types in terms the TI compiler understands */
typedef int_least8_t    xdc_Int8;
typedef uint_least8_t   xdc_UInt8;
typedef int_least16_t   xdc_Int16;
typedef uint_least16_t  xdc_UInt16;
typedef int_least32_t   xdc_Int32;
typedef uint_least32_t  xdc_UInt32;
 
#ifdef xdc__INT64__
    typedef int_least64_t   xdc_Int64;
    typedef int_least64_t   xdc_UInt64;
#endif
 
#endif /* ti_targets_STD_ */

In most cases, it is unnecessary to create the file above from scratch. In fact, most new targets are simple variations of existing target. In these cases, the new targets can "inherit" the definitions above by simply #include'ing the header and redefining as necessary. For example, a new package of targets, say local.targets, can define local/targets/std.h as shown below.

local/targets/std.h
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
#ifndef local_targets_STD_  /* prevent multiple includes of this header */
#define local_targets_STD_
 
/* include my target-specific "portable" macros (which will
 * override the ones included by ti/targets/std.h because  
 * xdc_target_macros_include__ is defined by my target's
 * header)
 */
#if defined(xdc_target_name__) & !defined(xdc_target_macros_include__)
#include xdc__local_include(xdc_target_name__)
#endif
 
/* include the existing TI RTSC base definitions */
#include <ti/targets/std.h> 
 
#endif /* local_targets_STD_ */

Providing a runtime support package

The xdc.bld.ITarget interface names a package that contains pre-built libraries of the modules contained in the xdc.runtime package; see xdc.bld.ITargets.rts. The xdc.runtime package contains target-independent C sources and files to simplify the creation of target-specific packages that contain pre-built versions of these sources. This architecture ensures that new targets can be added and used without requiring any re-release of the xdc.runtime package itself.

Although it is not required, it is natural to "nest" the runtime support package under the package of targets that reference it. Suppose, for example, that the targets package is named local.targets, the runtime support package might be named local.targets.rts. The files below are the only source files required to create this package.

package.xdc
 
 
package local.targets.rts { 
}
package.bld
 
 
 
 
 
 
 
 
 
 
 
 
 
var RtsBuild = xdc.loadCapsule('xdc/runtime/build.xs');
 
Pkg.makePrologue = RtsBuild.makePrologue;
Pkg.attrs.exportAll = true;
 
for (var i = 0; i < Build.targets.length; i++) {
    var targ = Build.targets[i];
    if (targ.rts == Pkg.name) {
        var lib = Pkg.addLibrary("lib/" + Pkg.name,
            targ);
        lib.addObjects(RtsBuild.objs);
    }
}

To build and release this package you must add your newly created targets to your config.bld script and run the "xdc release" command from the base of the local.targets.rts package. The resulting package archive contains all the libraries necessary for clients to take full advantage of the xdc.runtime modules without any additional build steps.

Inheriting from an Existing Target

An easy way to create a new target is to find an existing target similar to the new target, copy the existing target's files, and make the changes required for the new target. This section demonstrates a simple scenario where the target producer plans to create only one target named local.targets.Arm9e and this target is a simple variation of the preexisting ti.targets.arm.Arm9 target.

In this example, the target producer creates a target similar to ti.targets.arm.Arm9 target, with the difference that new target uses the big endian code model.

1. Create a package local.targets by creating a directory local/targets, and create the files config.bld, package.bld and package.xdc. The content of these three files is shown below.

config.bld
 
Build.useTargets = null;
package.xdc
 
 
 
 
 
requires ti.targets.arm;
 
package local.targets {
    module Arm9e; 
}
package.bld
 
Pkg.attrs.exportAll = true;

The purpose of config.bld in this package is to prevent an accidental usage of another config.bld, which might have a reference to the target being built in this package.

In package.xdc, we declare that this package contains the module Arm9e. This module, described in the following steps, defines the new target. Also, since the new target relies on the ti.targets.arm.IArm interface to define most of the new target's configuration, the package ti.targets.arm must be available on the package path.

Finally, package.bld ensures that all files required to use this target are available in the package's releases.

2. Copy the Arm9.xdc file from the ti.targets.arm package to Arm9e.xdc in the local.targets package.

3. Make the changes in Arm9e.xdc that differentiate the local.targets.Arm9e target from ti.targets.arm.Arm9. The extent of the changes that must be made in this step greatly depends on the differences between the existing and the new target. In this case, besides the obvious changes related to the name of the new target, we changed the build options for both the compiler and assembler, the name of the target-specific header (stdInclude), the target's runtime support library (rts, which will be built using this target), and the default toolchain runtime library (linkLib).

The content of the new file is shown below with the lines with changes marked by >.

Arm9e.xdc
 
 
 
>
>
>
 
>
 
 
 
 
>
 
 
>
 
 
 
>
 
 
 
 
>
 
 
 
 
 
 
 
>
 
/*!
 *  ======== Arm9e.xdc ========
 */
metaonly module Arm9e inherits ti.targets.arm.IArm {
    override readonly config string name = "Arm9e";
    override readonly config string suffix = "9e";
    override readonly config string isa = "v5T";    
    override readonly config string rts = "local.targets.rts";
 
    override readonly config xdc.bld.ITarget.Module base = ti.targets.TMS470;
 
    override readonly config xdc.bld.ITarget.Model model = {
        endian: "big"
    };
 
    override config String stdInclude = "local/targets/std.h";
 
    override readonly config ti.targets.ITarget.Command cc = {
        cmd:  "cl470 -c",
        opts: "-mv5e --abi=ti_arm9_abi"
    };
 
    override readonly config ti.targets.ITarget.Command asm = {
        cmd:  "cl470 -c",
        opts: "-mv5e --abi=ti_arm9_abi"
    };
 
    /*!
     *  ======== linkLib ========
     *  Default TMS470 cgtools runtime library to link with executable
     *  (comes from $rootDir/lib)
     */
    config string linkLib = "rts32.lib";
}

4. Add the std.h file, shown below, whose purpose and content are described in Defining target-specific "base" types.

local/targets/std.h
 
 
 
 
 
 
 
 
 
 
 
 
#ifndef local_targets_STD_  /* prevent multiple includes of this header */
#define local_targets_STD_
 
/* include my target-specific "portable" macros */
#if defined(xdc_target_name__) & !defined(xdc_target_macros_include__)
#include xdc__local_include(xdc_target_name__)
#endif
 
/* include the existing TI Arm RTSC base definitions */
#include <ti/targets/arm/std.h> 
 
#endif /* local_targets_STD_ */

5. Create the package local.targets.rts that will contain a pre-compiled version of the runtime support package for your new target. Follow the steps from Providing a runtime support package to add files and build the support package. Once the target package and this runtime support package are successfully built, the new target can be configured in a config.bld file and used to build executables.

config.bld
 
 
 
var Arm9e = xdc.useModule('local.targets.Arm9e');
Arm9e.rootDir = "C:/CCStudio_v3.3/tms470/cgtools";
Build.targets = [Arm9e];

The result of building this package should look something like the following:

% xdc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
making package.mak (because of package.bld) ...
generating interfaces for package ti.targets.rts6000 (because package/pack\
 
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/SysMin.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/Startup.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/Memory.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/Core_params.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/Diags.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/System.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/Assert.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/Core_mem.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/SysStd.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/LoggerSys.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/Core_label.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/Timestamp.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/Error.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/Text.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/Gate.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/HeapMin.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/GateNull.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/LoggerBuf.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/Log.c ...
cl9e package/package_ti.targets.rts6000.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/HeapStd.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/xdc_noinit.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/TimestampNull.c ...
cl9e /db/ztree/dr/xdc-s18x/src/packages/xdc/runtime/TimestampStd.c ...
archiving package/lib/lib/ti.targets.rts6000/xdc/runtime/SysMin.o9e  ...
all files complete.
[printable version]  [offline version]offline version generated on 04-Aug-2010 21:08 UTC
Copyright © 2008 The Eclipse Foundation. All Rights Reserved
Views
Personal tools
package reference