Target Language Compiler    

A Complete Example

Suppose you have a simple S-function that mimics the Gain block with one input, one output, and a scalar gain. That is, y = u * p. If the Simulink block's name is foo and the name of the Level 2 S-function is foogain, the C MEX S-function must contain this code:

The following two sections show the difference in the code the Real-Time Workshop generates for model.c containing noninlined and inlined versions of S-function foogain. The model contained no other Simulink blocks.

For information about how to generate code with the Real-Time Workshop, see the Real-Time Workshop documentation.

Comparison of Noninlined and Inlined Versions of model.c

Without a TLC file to define the S-function specifics, the Real-Time Workshop must call the MEX-file S-function through the S-function API. The code below is the model.c file for the noninlined S-function (i.e., no corresponding TLC file).

Noninlined S-Function.   

Inlined S-Function.   

This code is model.c with the foogain S-function fully inlined:

By including this simple target file for this S-function block, the model.c code is generated as

Including a TLC file drastically decreased the code size and increased the execution efficiency of the generated code. These notes highlight some information about the TLC code and the generated output:

Comparison of Noninlined and Inlined Versions of model_reg.h

Inlining a Level 2 S-function significantly reduces the size of the model_reg.h code. Model registration functions are lengthy; much of the code has been eliminated in this example. The code below highlights the difference between the noninlined and inlined versions of model_reg.h; inlining eliminates all this code:

A TLC File to Inline S-Function foogain

To avoid unnecessary calls to the S-function and to generate the minimum code required for the S-function, the following TLC file, foogain.tlc, is provided as an example.

Managing Block Instance Data with an Eye Toward Code Generation

Instance data is extra data or working memory that is unique to each instance of a block in a Simulink model. This does not include parameter or state data (which is stored in the model parameter and state vectors, respectively), but rather is used for purposes such as caching intermediate results or derived representations of parameters and modes. One example of instance data is the buffer used by a transport delay block.

Allocating and using memory on an instance by instance basis can be done several ways in a Level 2 S-function: via ssSetUserData, work vectors (e.g., ssSetRWork, ssSetIWork), or data-typed work vectors known as DWorks. For the smallest effort in writing both the S-function and block target file and for automatic conformance to both static and malloc instance data on targets such as grt and grt_malloc, The MathWorks recommends using data-typed work vectors when writing S-functions with instance data, accessed with the ssSetDWork and ssGetDWork methods.

The advantages are twofold. In the first place, writing the S-function is more straightforward in that memory allocations and frees are handled for you by Simulink. Secondly, the DWork vectors are written to the model.rtw file for you automatically, including the DWork name, data type, and size. This makes writing the block target file a snap, since you have no TLC code to write for allocating and freeing the DWork memory -- Real-Time Workshop takes care of this for you.

Additionally, if you want to bundle up groups of DWorks into structures for passing to functions, you can populate the structure with pointers to DWork arrays in both your S-function's mdlStart function and the block target file's Start method, achieving consistency between the S-function and the generated code's handling of data.

Finally, using DWorks makes it straightforward to create a specific version of code (data types, scalar vs. vectorized, etc.) for each block instance that matches the implementation in the S-function, i.e., both implementations use DWorks in the same way so that the inlined code can be used with the Simulink Accelerator without any changes to the C MEX S-function or the block target file.

Using Inlined Code With the Simulink Accelerator

By default, the Simulink Accelerator will call your C MEX S-function as part of an accelerated model simulation. If you want to instead have the accelerator inline your S-function before running the accelerated model, tell the accelerator to use your block target file to inline the S-function with the SS_OPTION_USE_TLC_WITH_ACCELERATOR flag in the call to ssSetOptions() in the mdlInitializeSizes function of that S-function.

Note that memory and work vector size and usage must be the same for the TLC generated code and the C MEX S-function, or the Simulink Accelerator will not be able to execute the inlined code properly. This is because the C MEX S-function is called to initialize the block and its work vectors, calling the mdlInitializeSizes, mdlInitializeConditions, mdlCheckParameters, mdlProcessParameters, and mdlStart functions. In the case of constant signal propagation, mdlOutputs is called from the C MEX S-function during the initialization phase of model execution.

During the time-stepping phase of accelerated model execution, the code generated by the Output and Update block TLC methods will execute, plus the Derivatives and zero-crossing methods if they exist. The Start method of the block target file are not used in generating code for an accelerated model.


  S-Function Parameters Inlining M-File S-Functions