Target Language Compiler    

Chapter 5
Directives and Built-in Functions


Compiler Directives

Syntax

A target language file consists of a series of statements of the form

where keyword represents one of the Target Language Compiler's directives, and [argument1, argument2, ...] represents expressions that define any required parameters. For example,

uses the %assign directive to change the value of the sysNumber parameter.
A target language directive must be the first nonblank character on a line and always begins with the % character. Beginning a line with %% lets you include a comment on a line.

This table shows the complete set of Target Language Compiler directives. The remainder of this chapter describes each directive in detail.

Directive
Description
%% text
Single line comment where text is the comment
/% text %/
Single (or multi-line) comment where text is the comment
%matlab
Calls a MATLAB function that does not return a result. For example, %matlab disp(2.718)
%<expr>
Target language expressions which are evaluated. For example, if we have a TLC variable that was created via: %assign varName = "foo", then %<varName> would expand to foo. Expressions can also be function calls as in %<FcnName(param1,param2)>. On directive lines, TLC expressions do not need to be placed within the %<> syntax. Doing so will cause a double evaluation. For example, %if %<x> == 3 is processed by creating a hidden variable for the evaluated value of the variable x. The %if statement then evaluates this hidden variable and compares it against 3. The efficient way to do this operation is to do: %if x == 3. In MATLAB notation, this would equate to doing
if eval('x') == 3 as opposed to if x = 3. The exception to this is during a %assign for format control as in
  %assign str = "value is: %<var>"
Note: Nested evaluation expressions (e.g., %<foo(%<expr>)> ) are not supported.
Note: There is no speed penalty for evals inside strings, such as
    %assign x = "%<expr>" 
    
Evals outside of strings, such as the following example, should be avoided whenever possible.
    %assign x = %<expr> 
    

%if expr
%elseif expr
%else
%endif

Conditional inclusion, where the constant-expression expr must evaluate to an integer. It is not necessary to expand variables or expressions using the %<expr> notation. Expanding the expression may be necessary when the expression needs to be re-evaluated. For example, assume k represents the value of a the gain block parameter which may be a number or a string variable. The following code will check if k is the numeric value 0.0 by executing a TLC library function to check for equality. Notice that the %<expr> syntax isn't used since we are operating on a directive line. Like other languages, expression evaluation do short circuit.
%if ISEQUAL(k, 0.0)
  <text and directives to be processed if, k is 0.0>
%endif


%switch expr
  %case expr
  %break
  %default
  %break
%endswitch

The switch directive is very similar to the C language switch statement. The expression, expr, can be of any type that can be compared for equality using the == operator. If the %break is not included after a %case statement, then it will fall through to the next statement.
%with
%endwith

model.rtw is organized as a hierarchy of records. The   
  %with
recordName
  %endwith
directives let you make a given record the current scope.

%setcommandswitch
Changes the value of a command-line switch as in
  %setcommandswitch "-v1"
%assert expr
Tests a value of a Boolean expression. If the expression evaluates to false TLC will issue an error message, a stack trace and exit, and otherwise the execution will be continued as normal. To enable the evaluation of asserts the command line option "-da" has to be added.
%error
%warning
%trace
%exit

Flow control directives:

    %error tokens -- The tokens are expanded and displayed.

    %warning tokens -- The tokens are expanded and displayed.

    %trace tokens -- The tokens are expanded and displayed only when the "verbose output" command line option -v or -v1 is specified.

    %exit tokens -- The tokens are expanded, displayed, and TLC exits.

Note, when reporting errors, you should use

    %exit Error Message

if the error is produced by an incorrect configuration that the user needs to correct in the model. If you are adding assert code (i.e., code that should never be reached), use

    %setcommandswitch "-v1" %% force TLC stack trace
    %exit Assert message

%assign
Creates identifiers (variables). The general form is

    %assign [::]variable = expression

The :: specifies that the variable being created is a global variable, otherwise, it is a local variable in the current scope (i.e., a local variable in the function).
If you need to format the variable, say, within a string based upon other TLC variables, then you should perform a double evaluation as in

    %assign nameInfo = "The name of this is %<Name>"

or alternately

    %assign nameInfo = "The name of this is " + Name

To assign a value to a field of a record you must use a qualified variable expression. See Assigning Values to Fields of Records.

%createrecord

Creates records. This command accepts a list of one or more record specifications (e.g., { foo 27 }). Each record specification contains a list of zero or more name-value pairs (e.g, foo 27) that become the members of the record being created, where the values it selves can be record specifications.

    %createrecord NEW_RECORD { foo 1 ; SUB_RECORD {foo 2} }
    %assign x = NEW_RECORD.SUB_RECORD.foo
    
If more than one record specification appears, these additional record specifications construct an array of records.
    %createrecord RECORD_ARRAY   { NEW_RECORD { foo 1 } } ...
                                 { NEW_RECORD { foo 2 } } ...
                                 { NEW_RECORD { foo 3 } }
    %assign x = RECORD_ARRAY[1].NEW_RECORD.foo
    

If :: is the first token after he %createrecord token, the record is created in the global scope.

%addtorecord

Adds fields to an existing record. The new fields may be name-value pairs or aliases to already existing records.

    %addtorecord OLD_RECORD foo 1
    

If the new field being added is a record, then %addtorecord will make an alias to that record instead of a deep copy. To make a deep copy, use %copyrecord.

    %createrecord NEW_RECORD { foo 1 }
    %addtorecord OLD_RECORD NEW_RECORD_ALIAS NEW_RECORD
    
%mergerecord
Adds (or merges) one or more records into another. The first record will contain the results of the merge of the first record plus the contents of all the other records specified by the command. The contents of the second (and subsequent) records are deep copied into the first (i.e., they are not references).
    %mergerecord OLD_RECORD NEW_RECORD
    
If there are duplicate fields in the records being merged the original record's fields will not be overwritten.
%copyrecord
Makes a deep copy of an existing record. It creates a new record in a similar fashion to %createrecord except the components of the record are deep copied from the existing record. Aliases are replaced by copies.
    %copyrecord NEW_RECORD OLD_RECORD
    
%realformat
Specifies how to format real variables. To format in exponential notation with 16 digits of precision, use

    %realformat "EXPONENTIAL"

To format without loss of precision and minimal number of characters, use

    %realformat "CONCISE"

When inlining S-functions, the format is set to concise. You can switch to exponential, but should switch it back to concise when done.
%language
This must appear before the first GENERATE or GENERATE_TYPE function call. This specifies the name of the language as a string, which is being generated as in %language "C". Generally, this is added to your system target file.
%implements
Placed within the .tlc file for a specific record type, when mapped via %generatefile. The syntax is: %implements "Type" "Language". When inlining an S-function in C, this should be the first non-comment line in the file as in

    %implements "s_function_name" "C"

The next noncomment lines will be %function directives specifying the functionality of the S-function.
See the %language and GENERATE function descriptions for further information.
%generatefile
Provides a mapping between a record Type and functions contained in a file. Each record can have functions of the same name, but different contents mapped to it (i.e., polymorphism). Generally, this is used to map a Block record Type to the .tlc file that implements the functionality of the block as in

    %generatefile "Sin" "sin_wave.tlc"

%filescope
Limits the scope of variables to the file in which they are defined. All variables defined after the appearance of %filescope in a file have this property, otherwise they default to global variables.
%filescope is useful in conserving memory. Variables whose scope is limited by %filescope go out of scope when execution of the file containing them completes. This frees memory allocated to such variables. By contrast, global variables persist in memory throughout execution of the program.
%include
%addincludepath

%include "file.tlc" -- insert specified target file at the current point. Use %addincludepath "directory" to add additional paths to be searched. Be sure to escape backslashes in PC directory names as in "C:\\mytlc". Note that %include directives behave as if they were in a global context.
%roll
%endroll

Multiple inclusion plus intrinsic loop rolling based upon a specified threshold. This directive can be used by most Simulink blocks which have the concept of an overall block width that is usually the width of the signal passing through the block. An example of the %roll directive is for a gain operation, y=u*k
    %function Outputs(block, system) Output
      /* %<Type> Block: %<Name> */
      %assign rollVars = ["U", "Y", "P"]
      %roll sigIdx = RollRegions, lcv = RollThreshold, block,...
            "Roller", rollVars
        %assign y = LibBlockOutputSignal(0, "", lcv, sigIdx)
        %assign u = LibBlockInputSignal(0, "", lcv, sigIdx)
        %assign k = LibBlockParameter(Gain, "", lcv, sigIdx)
          %<y> = %<u> * %<k>;
      %endroll
    %endfunction
    
The %roll directive is similar to %foreach, except it iterates the identifier (sigIdx in this example) over roll regions. Roll regions are computed by looking at the input signals and generating regions where the inputs are contiguous. For blocks, the variable RollRegions is automatically computed and placed in the Block record. An example of a roll regions vector is [0:19, 20:39], where we have two contiguous ranges of signals passing through the block. The first is 0:19 and the second is 20:39. Each roll region is either placed in a loop body (e.g., the C Language for statement), or inlined depending upon whether or not the length of the region is less than the roll threshold.
Each time through the %roll loop, sigIdx is an integer for the start of the current roll region or an offset relative to the overall block width when the current roll region is less than the roll threshold. The TLC global variable RollThreshold is the general model wide value used to decide when to place a given roll region into a loop. When the decision is made to place a given region into a loop, the loop control variable will be a valid identifier (e.g., "i"), otherwise it will be "".

%roll
(continued)


The block parameter is the current block that is being rolled. The "Roller" parameter specifies the name for an internal GENERATE_TYPE calls made by %roll. The default %roll handler is "Roller", which is responsible for setting up the default block loop rolling structures (e.g., a C for loop).
The rollVars (roll variables) are passed to "Roller" functions to create the correct roll structures. The defined loop variables relative to a block are

"U"         All inputs to the block. It assumes you use LibBlockInputSignal(portIdx, "", lcv, sigIdx) to access each input, where portIdx starts at 0 for the first input port.

"Ui"       Similar to "U", except only for specific input, i.

"Y"         All outputs of the block. It assumes you use LibBlockOutputSignal(portIdx, "", lcv, sigIdx) to access each output, where portIdx starts at 0 for the first output port.

"Yi"       Similar to "Y", except only for specific output, i.

"P"         All parameters of the block. It assumes you use LibBlockParameter(name, "", lcv, sigIdx) to access them.

"<param>/name" Similar to "P", except specific for a specific name.

RWork      All RWork vectors of the block. It assumes you use LibBlockRWork(name, "", lcv, sigIdx) to access them.

"<RWork>/name" Similar to RWork, except for a specific name.

DWork      All DWork vectors of the block. It assumes you use LibBlockDWork(name, "", lcv, sigIdx) to access them.

"<DWork>/name" Similar to DWork, except for a specific name.

IWork      All IWork vectors of the block. It assumes you use LibBlockIWork(name, "", lcv, sigIdx) to access them.

"<IWork>/name" Similar to IWork, except for a specific name.

PWork      All PWork vectors of the block. It assumes you use LibBlockPWork(name, "", lcv, sigIdx) to access them.

"<PWork>/name" Similar to PWork, except for a specific name.

"Mode"    The mode vector. It assumes you use LibBlockMode("",lcv,sigIdx) to access it.

"PZC"      Previous zero crossing state. It assumes you use LibPrevZCState("",lcv, sigIdx) to access it.

%roll
(continued)

To roll your own vector based upon the block's roll regions, you need to walk a pointer to your vector. Assuming your vector is pointed to by the first PWork, called name,

    datatype *buf = (datatype*)%<LibBlockPWork(name,"","",0)

    %roll sigIdx = RollRegions, lcv = RollThreshold, block, ...

          "Roller", rollVars

      *buf++ = whatever;

    %endroll

Note: in the above example, sigIdx and lcv are local to the body of the loop.

%function
%return
%endfunction











A function that returns a value is defined as
  %function name(optional-arguments)
    %return
value
  %endfunction
A void function does not produce any output and is not required to return a value. It is defined as
  %function name(optional-arguments) void
  %endfunction

A function that produces outputs to the current stream and is not required to return a value is defined as
  %function name(optional-arguments) Output
  %endfunction

For block target files, you can add to your inlined .tlc file the following functions that will get called by the model wide target files during code generation

%function BlockInstanceSetup(block, system) void
Called for each instance of the block within the model.

%function BlockTypeSetup(block, system) void
Called once for each block type that exists in the model.

%function BlockInstanceData(block, system) Output
Called once during model initialization to place code in the registration function (model_reg.h) to allocate persistent data.

%function Enable(block, system) Output
Use this if the block is placed within an enabled subsystem and has to take specific actions when the subsystem enables. Place within a subsystem enable routine.

%function Disable(block, system) Output
Use this if the block is placed within a disabled subsystem and has to take specific actions when the subsystem is disabled. Place within a subsystem disable routine.

%function Start(block, system) Output
Include this function if your block has startup initialization code that needs to be placed within MdlStart.

%function
%return
%endfunction
(continued)

%function InitializeConditions(block, system) Output
Use this function if your block has state that needs to be initialized at the start of execution and when an enabled subsystem resets states. Place in MdlStart and/or subsystem initialization routines.

%function Outputs(block, system) Output
The primary function of your block. Place in MdlOutputs.

%function Update(block, system) Output
Use this function if your block has actions to be performed once per simulation loop, such as updating discrete states. Place in MdlUpdate

%function Derivatives(block,system) Output
Used this function if your block has derivatives for MdlDerivatives.

%function Terminate(block, system) Output
Use this function if your block has actions that need to be in MdlTerminate.

%foreach
%endforeach

Multiple inclusion that iterates from 0 to the upperLimit-1 constant integer expression. Each time through the loop, the loopIdentifier, (e.g., x) is assigned the current iteration value.
  %foreach loopIdentifier = upperLimit
     %break    
-- use this to exit the loop
     %continue -- use this to skip the following code and
                 continue to the next iteration
  %endforeach


Note: The upperLimit expression is cast to a TLC integer value. The loopIdentifier is local to the loop body.
%for
Multiple inclusion directive with syntax
    %for ident1 = const-exp1, const-exp2, ident2 = const-exp3
      %body
        %break
        %continue
      %endbody
    %endfor
    

The first portion of the %for directive is identical to the %foreach statement. The %break and %continue directives act the same as they do in the %foreach directive. const-exp2 is a Boolean expression that indicates whether the loop should be rolled (see %roll above).

If const-exp2 evaluates to TRUE, ident2 is assigned the value of const-exp3. Otherwise, ident2 is assigned an empty string.

Note: ident1 and ident2 above are local to the loop body.

%openfile
%selectfile
%closefile

These are used to manage the files that are created. The syntax is
%openfile streamId="filename.ext" mode  {open for writing}
%selectfile streamId                    {select an open file}
%closefile streamId                     {close an open file}
Note that the "filename.ext" is optional. If not specified, streamId and filename will be the same and a variable (string buffer) is created containing the output. The mode argument is optional. If specified, it can be "a" for appending, "r" for reading, or "w" for writing.
Note that the special streamId NULL_FILE specifies that no output occur. The special streamId STDOUT specifies output to the terminal.
To create a buffer of text, use:
%openfile buffer
text to be placed in the 'buffer' variable.
%closefile buffer
Now buffer contains the expanded text specified between the %openfile and %closefile directives.
%generate

%generate blk fn is equivalent to GENERATE(blk,fn).
%generate blk fn type is equivalent to GENERATE(blk,fn,type).
See GENERATE and GENERATE_TYPE Functions.
%undef

%undef var removes the variable var from scope. If var is a field in a record, %undef removes that field from the record. If var is a record array, %undef removes the first element of the array.


 Exception to Using the Library Functions Comments