Target Language Compiler    

Inlining M-File S-Functions

All of the functionality of M-file S-functions can be inlined in the generated code. Writing a block target file for an M-file S-function is essentially identical to the process for a C MEX S-function.

Note that while you can fully inline an M-file S-function to achieve top performance - even with Simulink Accelerator - the MATLAB Math Library is not included with Real-Time Workshop, so any high-level MATLAB commands and functions you use in the M-file S-function must be written by hand in the block target file.

A quick example will illustrate the equivalence of C MEX and M-file S-functions for code generation. The M-file S-function timestwo.m is equivalent to the C MEX S-function timestwo. In fact, the TLC file for the C MEX S-function timestwo will work for the M-file S-function timestwo.m as well! Since TLC only requires the `root' name of the S-function and not its type, it is independent of the type of S-function. In the case of timestwo, one line determines what the TLC file will be used for

To try this out for yourself, copy file timestwo.m from matlabroot/toolbox/simulink/blocks/ to a temporary directory, then copy the file timestwo.tlc from matlabroot/toolbox/simulink/blocks/tlc_c/ to the same temporary directory. In MATLAB, cd to the temporary directory and make a Simulink model with an S-function block that calls timestwo. Since the MATLAB search path will find timestwo.m in the current directory before finding the C MEX S-function timestwo in the matlabpath, Simulink will use the M-file S-function for simulation. Verify which S-function will be used by typing the MATLAB command

The answer you see will be the M-file S-function timestwo.m in the temporary directory. Here is the sample model.

Upon generating code, you will find that the timestwo.tlc file was used to inline the M-file S-function with code that looks like this (with an input signal width of 5 in this example).

As expected, each of the inputs, u0[i1], is multiplied by 2.0 to form the output value. The Outputs method in the block target file used to generate this code was

Alter these temporary copies of the M-file S-function and the TLC file to see how they interact -- start out by just changing the comments in the TLC file and see it show up in the generated code, then work up to algorithmic changes.

Inlining Fortran (FMEX) S-Functions

The capabilities of Fortran MEX S-functions can be fully inlined using a TLC block target file. With a simple F MEX S-function version of the ubiquitous "timestwo" function, this interface can be illustrated. Here is the sample Fortran S-function code

Copy the above code into file ftimestwo.for in a convenient working directory.

Putting this into an S-function block in a simple model will illustrate the interface for inlining the S-function. Once your Fortran MEX environment is set up, prepare the code for use by compiling the S-function in a working directory along with the file simulink.for from matlabroot/simulink/src/. This is done with the mex command at the MATLAB command prompt.

And now reference this block from a simple Simulink model set with a fixed step solver and the grt target.

The TLC code needed to inline this block is a modified form of the now familiar timestwo.tlc. In your working directory, create a file named ftimestwo.tlc and put this code into it.

Now you can generate code for the ftimestwo Fortran MEX S-function. The resulting code fragment specific to ftimestwo is

Inlining Ada-MEX S-Functions

Like all the other S-functions, Ada MEX S-functions directly support inlining in the generated code. As an example, copy the times_two Ada MEX S-function source code from directory matlabroot/simulink/ada/examples/times_two/ to a temporary directory -- make sure to get both the times_two.adb and times_two.ads files. Once your Ada MEX environment is set up, compile times_two from the MATLAB command line with

which makes a MEX file named ada_times_two.mexext. Use this MEX S-function in a model the same way as other S-functions.

To inline this function in C code, copy the timestwo.tlc file from the previous M-file S-function example into the temporary directory and name it ada_times_two.tlc. In the editor, modify the %implements line to match the name of the S-function, in this case it should read

After ensuring your model is set to use a fixed-step solver, generate C code for this model. The Ada Mex S-function code looks the same as it does for all the other S-function implementations

If, as is likely, you wish to generate inlined Ada code for your model and its Ada MEX S-function using the Real-Time Workshop Ada Coder, you use a different TLC file -- one that generates Ada code. To get started with this, copy the timestwo.tlc file from matlabroot/toolbox/simulink/blocks/tlc_ada/ into the temporary directory and name it ada_times_two.tlc. Once again, edit the %implements line to read

So the minimum necessary contents of the TLC file look like this.

Now select Ada Simulation Target for GNAT via the Tools -> Real-Time Workshop -> Options... menu using the Select... button. This target uses the rt_ada_sim.tlc system target file and does not support blocks with continuous states, so it will be necessary to alter the sine wave source block to have a discrete sample time (choose it to be the same as the value chosen for the fixed-step solver's time step, for instance).

Generate code with the Build button. The model.ads file that is generated will contain this inlined code for the ada_times_two S-function.

Notice that the TLC code is relatively independent of the target language in use (C or Ada) -- for instance, the %roll construct will create the correct C or Ada loop code based solely on whether the block target file implements "C" or "Ada". TLC constructs themselves are meant to be language-neutral; the only part that is language-specific are the operators, comments, and function name differences in the standard libraries.

TLC Coding Conventions

These guidelines help ensure that the programming style in each target file is consistent, and hence, more easily modifiable.

Begin Identifiers with Uppercase Letters

All identifiers in the Real-Time Workshop file begin with an uppercase letter. For example,

Block records that contain a Name identifier should start the name with an uppercase letter since the Name identifier is often promoted into the parent scope. For example, a block may contain

Since the Name identifier within the RWorkDefine record is promoted to PrevT in its parent scope, it must start with an uppercase letter. The promotion of the Name identifier into the parent block scope is currently done for the Parameter, RWorkDefine, IWorkDefine, and PWorkDefine block records.

The Target Language Compiler assignment directive (%assign) generates a warning if you assign a value to an "unqualified" Real-Time Workshop identifier. For example,

produces an error because TID identifier is not qualified by Block. However, a "qualified" assignment does not generate a warning.

does not generate a warning because the Target Language Compiler assumes the programmer is intentionally modifying an identifier since the assignment contains a qualifier.

Begin Global Variable Assignments with Uppercase Letters

Global TLC variable assignments should start with uppercase letters. A global variable is any variable declared in a system target file (grt.tlc, mdlwide.tlc, mdlhdr.tlc, mdlbody.tlc, mdlreg.tlc, or mdlparam.tlc), or within a function that uses the :: operator. In some sense, global assignments have the same scope as Real-Time Workshop variables. An example of a global TLC variable defined in mdlwide.tlc is

An example of a global reference in a function is

Begin Local Variable Assignments with Lowercase Letters

Local TLC variable assignments should start with lowercase letters. A local TLC variable is a variable assigned inside a function. For example,

Begin Functions Declared in block.tlc files with Fcn

When you declare a function inside a block.tlc file, it should start with Fcn. For example,

Do Not Hard Code Variables Defined in commonsetup.tlc

Since the Real-Time Workshop tracks use of variables and generates code based on usage, you should use access routines instead of directly using a variable. For example, you should not use the following in your TLC file.

You should use

Similarly, instead of using %<tTID>, use %<LibTID()>. For a complete list of functions, see Chapter 9, TLC Function Library Reference.

All Real-Time Workshop global variables start with rt and all Real-Time Workshop global functions start with rt_.

Avoid naming global variables in your run-time interface modules that start with rt or rt_ since they may conflict with Real-Time Workshop global variables and functions. These TLC variables are declared in commonsetup.tlc.

This convention creates consistent variables throughout the target files. For example, the Gain block contains the following Outputs function.

Notes about this TLC code:

    1. The code section for each block begins with a comment specifying the block type and name.
    2. Include a blank line immediately after the end of the function in order to create consistent spacing between blocks in the output code.
    3. Try to stay within 80 columns per line for the function banner. You might set up an 80 column comment line at the top of each function. As an example, see constant.tlc.
    4. For consistency, use the variables sysIdx and blkIdx for system index and block index, respectively.
    5. Use the variable rollVars when using the %roll construct.
    6. When naming loop control variables, use sigIdx and lcv when looping over RollRegions and xidx and xlcv when looping over the states.

Example: Output function in gain.tlc

Example: InitializeConditions function in linblock.tlc

Conditional Inclusion in Library Files

The Target Language Compiler function library files are conditionally included via guard code so that they may be referenced via %include multiple times without worrying if they have previously been included. It is recommended that you follow this same practice for any TLC library files that you yourself create.

The convention is to use a variable with the same name as the base filename, uppercased and with underscores attached at both ends. So, a file named customlib.tlc should have the variable _CUSTOMLIB_ guarding it.

As an example, the main Target Language Compiler function library, funclib.tlc, contains this TLC code to prevent multiple inclusion.


 A Complete Example Block Target File Methods