Target Language Compiler    

Compiler Directives

Syntax

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

Statements of the first type cause all literal text to be passed to the output stream unmodified, and expressions enclosed in %< > are evaluated before being written to output (stripped of %< >).

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

uses the %assign directive to define or 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. Lines beginning with %% are TLC comments, and are not passed to the output stream. Lines beginning with /* are C comments, and are passed to the output stream.

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

Table 6-1: Target Language Compiler Directives  
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. For example, the following code checks whether a parameter, k, has the numeric value 0.0 by executing a TLC library function to check for equality.
%if ISEQUAL(k, 0.0)
  <text and directives to be processed if, k is 0.0>
%endif

In this and other directives, it is not necessary to expand variables or expressions using the %<expr> notation unless expr appears within a string. For example:
%if ISEQUAL(idx, "my_idx%<i>"), where idx and i are both strings.
As in other languages, logical evaluations do short circuit (are halted as soon as the result is known).
%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

%with recordName is a scoping operator. Use it to bring the named record into the current scope, to remain until the matching %endwith is encountered (%with directives may be nested as desired).

Note that on the left-hand side of %assign statements contained within a %with / %endwith block, references to fields of records must be fully qualified (see Assigning Values to Fields of Records), as in the following example.
    %with CompiledModel
      %assign oldName = name
      %assign CompiledModel.name = "newname"
    %endwith

%setcommandswitch
string

Changes the value of a command-line switch as specified by the argument string. Only the following switches are supported: v, m, p, O, d, r, I, a
The following example sets the verbosity level to 1.
  %setcommandswitch "-v1"
See also Command Line Arguments.
%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 outside the Real-Time Workshop environment, use the command line option "-da". When building from within RTW, this flag is not needed and will be ignored, as it is superseded by the Enable TLC Assertions check box on the TLC debugging section of the Real-Time Workshop dialog pane. To control assertion handling from the MATLAB command window, use:
 set_param(model, 'TLCAssertion', 'on|off') to set this flag on or off. Default is Off.
 get_param(model, 'TLCAssertion') to see the current setting.
%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 in memory. 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. The values themselves can be record specifications, as the following illustrates.

  • %createrecord NEW_RECORD { foo 1 ; SUB_RECORD {foo 2} }
    %assign x = NEW_RECORD.foo                  /* x = 1 */
    %assign y = NEW_RECORD.SUB_RECORD.foo       /* y = 2 */
    
If more than one record specification follows a given record name, the set of record specifications constitutes an array of records.
  • %createrecord RECORD_ARRAY   { foo 1 } ...
                                 { foo 2 } ...
                                 { bar 3 } 
    %assign x = RECORD_ARRAY[1].foo             /* x = 2 */
    %assign y = RECORD_ARRAY[2].bar             /* y = 3 */
    

Note that arrays of subrecords can be created and indexed by specifying %createrecord with identically named subrecords, as follows:

  • %createrecord RECORD_ARRAY { SUB_RECORD { foo 1 } ... 
                                 SUB_RECORD { foo 2 } ... 
                                 SUB_RECORD { foo 3 } }
    %assign x = RECORD_ARRAY.SUB_RECORD[1].foo  /* x = 2 */
    %assign y = RECORD_ARRAY.SUB_RECORD[2].foo  /* y = 3 */
    

If the scope resolution operator (::) 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. A %filescope directive, anywhere in a file declares that all variables in the file are visible only within that file. Note that this limitation also applies to any files inserted, via the %include directive, into the file containing the %filescope directive.
The %filescope directive should not be used within functions or GENERATE functions.
%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. We recommend UNIX-style forward slashes for directory names, as they will work on both UNIX and PC systems. However, if you do use backslashes in PC directory names, be sure to escape them, e.g., "C:\\mytlc". Alternatively, you can express a PC directory name as a literal using the L format specifier, as in L"C:\mytlc". All %include directives behave as if they were in a global context, such that
  • %addincludepath "./sub1"
    %addincludepath "./sub2"
    
in a .tlc file enables either subdirectory to be referenced implicitly:
  • %include "file_in_sub1.tlc"
    %include "file_in_sub2.tlc"
    
%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 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.

%breakpoint
Sets a breakpoint for the TLC debugger. See %breakpoint Directive.
%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 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 ZeroCrossings(block,system) Output
Used this function if your block does zero crossing detection and has actions to be performed in MdlZeroCrossings.

%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 no filename is specified, a variable (string buffer) named streamId 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.


  Directives and Built-in Functions Comments