From RTSC-Pedia

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

Extending xdc.runtime System/Example 1

A minimal System support module for tiny systems

Contents

A Minimal ISystemSupport Module

In this section we show the complete implementation of a package that includes a module, named SysBuf, that provides the "backend" services required by the xdc.runtime.System module. This example serves two purposes:

  1. illustrate how to create a simple "system support" module, and
  2. provide a small footprint System support module appropriate for deeply embedded multi-threaded systems.

System support modules are responsible for handling character output (generated from say System_printf()) as well as providing extensions to the System_exit() and System_abort() application termination process. The SysBuf module simply records each output character into a circular buffer (which is sized and placed at configuration time), and extends System_abort() by copying a termination message into the output buffer just prior to termination.

Using SysBuf

To illustrate the use of the ISystemSupport module SysBuf, we start with the "hello world" example from Using xdc.runtime System/Example 1 and add two lines to the application's configuration script. These statements (denoted by + below) simply declare that we want to use SysBuf as the System module's "support proxy" in lieu of the default, SysMin.

hello.c
 
 
 
 
 
 
 
 
 
 
#include <xdc/std.h>
 
#include <xdc/runtime/System.h>
 
/*  ======== main ======== */
Int main(Int argc, String argv[])
{
    System_printf("hello world\n");
    return (0);
}
hello.cfg
 
+
+
var System = xdc.useModule("xdc.runtime.System");
var SysBuf = xdc.useModule("xdc.runtime.SysBuf");
System.SupportProxy = SysBuf;

When we run this application no output is displayed; the output from the call to System_printf is simply written to the buffer managed by SysBuf. The only way to view the output is to examine the contents of this buffer. While this is ridiculously onerous when developing applications for platforms with a high-level operating system (such as Linux or WinCE), it can be a life saver when developing low-level bootstrap code for these platforms, code targeted for platforms without character output facilities, or device driver code for character output peripherals.

As we'll see in the implementation of SysBuf below, this module defines a global variable that makes it relatively easy to display the contents of the buffer from a modern graphical debugger. By default, SysBuf defines a global variable named SYSBUF that contains a pointer to the character output buffer.

Image:SysBuf.PNG

You can configure the name of the global variable containing the pointer to the output buffer, the size of the output buffer, and even the output section where the output buffer is placed. For example, by adding more two lines to the configuration script (indicated by +), the configuration script below defines the global variable name to be STDOUT and sets the output buffer size to be just 256 characters.

hello.cfg
 
 
 
+
+
var System = xdc.useModule("xdc.runtime.System");
var SysBuf = xdc.useModule("xdc.runtime.SysBuf");
System.SupportProxy = SysBuf;
SysBuf.bufName = "STDOUT";
SysBuf.bufSize = 256;

Implementation of SysBuf

In this section we show the entire implementation of the SysBuf module as well as all package files necessary to build and deliver the SysBuf module to anyone wishing to use it.

The SysBuf Module

The SysBuf module implements the ISystemSupport interface but makes minimal assumptions about underlying platform capabilities. In particular, it handles all character output by simply writing all output to a "global" buffer managed by SysBuf.

SysBuf.xdc
 
 
 
 
 
 
1
 
 
 
 
 
2
 
 
 
 
 
3
 
 
4
 
 
 
 
module SysBuf inherits xdc.runtime.ISystemSupport {
 
    /*!
     *  ======== bufName =========
     *  The name of a variable that points to the buffer
     */
    metaonly config bufName = "SYSBUF";
 
    /*!
     *  ======== bufSize ========
     *  Size (in MAUs) of the internal buffer where all output is stored
     */
    config SizeT bufSize = 1024;
 
    /*!
     *  ======== sectionName ========
     *  Section where the internal buffer managed by SysBuf is placed.
     */
    metaonly config String sectionName = null;
 
internal:
    struct Module_State {
        Char outbuf[];  /* output buffer */
        UInt outidx;    /* index of next available output character */
    }
}

As you can see from SysBufs specification, the size and placement of the output buffer can be configured by the end-user; 2 and 3 respectively. The bufName metaonly configuration parameter 1 allows you control the name of a global variable used to hold the pointer to the output buffer. This global variable's only purpose is to make it easy to display this buffer from an attached debugger. By making it a configuration parameter, the system integrator can control the name of this global variable without having to modify the sources of the SysBuf module; different applications can use different names (e.g., to avoid clashes with other global variables) and still use exactly the same pre-compiled SysBuf module.

SysBuf.c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
#include <xdc/std.h>
 
#include <xdc/runtime/Gate.h>
#include "package/internal/SysBuf.xdc.h"
 
/* ======== SysBuf_abort ======== */
Void SysBuf_abort(String str)
{
    if (SysBuf_bufSize != 0 && str != NULL) {
        Char ch;
        while ((ch = *str++) != '\0') {
            SysBuf_putch(ch);
        }
    }
}
 
/* ======== SysBuf_exit ======== */
Void SysBuf_exit(Int stat) {/* do nothing */}
 
/* ======== SysBuf_flush ======== */
Void SysBuf_flush() {/* nothing to do */}
 
/* ======== SysBuf_putch ======== */
Void SysBuf_putch(Char ch)
{
    if (SysBuf_bufSize != 0) {
        IArg key = Gate_enterSystem();
        if (module->outidx >= SysBuf_bufSize) {
            module->outidx = 0;
        }
        module->outbuf[module->outidx++] = ch;
        Gate_leaveSystem(key);
    }
}
 
/* ======== SysBuf_ready ======== */
Bool SysBuf_ready()
{
    return (SysBuf_bufSize != 0 ? TRUE : FALSE);
}
SysBuf.xs
 
 
 
 
 
 
a
 
 
b
 
 
 
 
 
 
c
 
 
 
 
 
d
 
 
 
 
 
 
 
 
 
var Memory = null;
 
/* ======== module$static$init ======== */
function module$static$init(obj, mod)
{
    /* set size of SysBuf's output buffer, outbuf */
    obj.outbuf.length = mod.bufSize;
 
    /* specify alignment and placement of outbuf */
    Memory.staticPlace(obj.outbuf, 
        0, mod.sectionName);
 
    /* initialize output index state */
    obj.outidx = 0;
 
    /* initialize output buffer */
    for (var i = 0; i < obj.outbuf.length; i++) {
        obj.outbuf[i] = 0;
    }
 
    /* optionally define variable to easily read buf */
    if (mod.bufName != null) {
        Program.global[mod.bufName] = obj.buf;
    }
}
 
/* ======== module$use ======== */
function module$use(obj, mod)
{
    Memory = xdc.module('xdc.runtime.Memory');
    xdc.module('xdc.runtime.Gate');
}

The C implementation of the ISystemSupport interface, SysBuf.c, is fairly straight forward. Perhaps the only comment worth making is about the implementation of the putch function, a function that handles every character output by the System module's methods. This implementation, although 100% portable ANSI C and thread-safe, is somewhat heavyweight for the output of a single character. In most cases it is possible (and easy) to greatly reduce the overhead of this function by taking advantage of device-specific instructions to "atomically" update the circular output buffer.

What makes the implementation of SysBuf interesting is not so much the code that's in SysBuf.c, rather it's the code that's not in SysBuf.c. Since RTSC modules can declare a "state" structure that is initialized by the module's meta-domain function module$static$init() and accessible by target code, there is no need to allocate or initialize the output buffer in SysBuf.c, no need to declare the global variable SYSBUF, nor is it necessary to recompile SysBuf.c to support different buffer sizes; RTSC Module Primer Lesson 7 contains another example leveraging Module_State and a complete discussion of this aspect of RTSC modules.

In this case, module$static$init() is passed two parameters: obj - an object that corresponds to the Module_State declaration in SysBuf.xdc 4, and mod - a reference to the current module object that in turn contains all of the module-wide configuration parameters. By initializing obj in this method, corresponding values will be used to initialize the SysBuf module's state data on the target before the target code even begins to run. In outline, this function

a allocates a static buffer by setting the length of the outbuf array declared by SysBuf.xdc;
b uses Memory.staticPlace() to identify the section where this buffer should be placed and how it should be aligned by the linker;
c initializes the buffer with values that will be seen by the initial code running on the target; and finally
d uses Program.global to define the global variable, whose name is declared at 1 in the specification of SysBuf, that makes it easy to view this output buffer from a debugger. The name is configurable to allow the user to either change the name to avoid clashes with existing code or to optionally not define any variable (by setting bufName to null).

The Package Files

Since all modules must live in a package we also need to create a two other files:

  1. package.xdc - a file that define the package's name and identifies the modules it contains, and
  2. package.bld - a file that specifies which targets should be used to build the sources contained in this package.

package.xdc
 
 
 
package examples.runtime.system { 
    module SysBuf; 
}
package.bld
 
 
 
 
 
 
for (var i = 0; i < Build.targets.length; i++) {
    var targ = Build.targets[i];
 
    var lib = Pkg.addLibrary("lib/" + Pkg.name, targ);
    lib.addObjects(["SysBuf.c"]);
}

The package.xdc file is largely self explanatory; it defines the name of the package, examples.runtime.system, and it specifies the modules contained in the package, SysBuf.

The package.bld file, on the other hand, requires some explanation. This package.bld file specifies that the package contains a library in the lib/ sub-directory containing the compiled version of SysBuf.c for every target supported by the producer's build environment. Remarkably, this package.bld file is sufficient to compile SysBuf.c for every target, archive it into a library, and a binary release of this package that supports all targets supported by the producer's build environment.

[printable version]  offline version generated on 04-Aug-2010 21:08 UTC
Copyright © 2008 The Eclipse Foundation. All Rights Reserved
Views
Personal tools
package reference