Main Content

Target Language Compiler Directives

You control how code is generated from models largely through writing or modifying scripts that apply TLC directives and built-in functions. Use the following sections as your primary reference to the syntax and format of target language constructs, as well as the MATLAB® tlc command itself.

A target language directive must be the first non-blank character on a line and 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.

Syntax

A target language file consists of a series of statements of either form:

  • [text | %<expression>]* 

    The literal text is passed to the output stream unmodified, and expressions enclosed in %< > are evaluated before being written to output (stripped of %< >).

  • %keyword [argument1, argument2, ...]

    The %keyword represents one of the directives of Target Language Compiler, and [argument1, argument2, ...] represents expressions that define required parameters. For example, the statement

    %assign sysNumber = sysIdx + 1

    uses the %assign directive to define or change the value of the sysNumber parameter.

Directives

The rest of this section shows the complete set of Target Language Compiler directives, and describes each directive in detail.

%% text

Single-line comment where text is the comment.

/% text%/

Single (or multiline) 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 that are evaluated. For example, if you 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 need not be placed within the %<> syntax. Doing so causes 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 write %if x == 3. In MATLAB notation, this would equate to writing if eval('x') == 3 as opposed to if x = 3. The exception to this is during an %assign for format control, as in

 %assign str = "value is: %<var>"

Note: Nested evaluation expressions (e.g., %<foo(%<expr>)> ) are not supported.

There is not a speed penalty for evaluations inside strings, such as

%assign x = "%<expr>"

Avoid evaluations outside strings, such as the following example.

%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, you do not have 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 when the result is known).

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

The %switch directive is similar to the C language switch statement. The expression expr should be of a 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 can be nested as desired).

Note that on the left side of %assign statements contained within a %with / %endwith block, references to fields of records must be fully qualified (see Assign 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 issues an error message, a stack trace and exit; otherwise, the execution continues normally. To enable the evaluation of assertions outside the code generator environment, use the command-line option -da. When building from within the code generator, this flag is ignored, as it is superseded by the Enable TLC assertion check box on the TLC process section of the Code Generation > Debug 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. To see the current setting, use

get_param(model, 'TLCAssertion')

%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.

When reporting errors, use the following command if the error is produced by an incorrect configuration that the user needs to fix in the model.

%exit Error Message

If you are adding assert code (that is, 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 Assign 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 you can create and index arrays of subrecords 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 the %createrecord token, the record is created in the global scope.

Note

You should not create a record array by using %createrecord within a loop.

%addtorecord

Adds fields to an existing record. The new fields can 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 makes 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 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 duplicate fields exist in the records being merged, the original record’s fields are not 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.

The only valid value is C which enables support for C and C++ code generation as specified by the configuration parameter TargetLang (see Language for more information).

%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 or C++, this should be the first noncomment 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 variables in the file are visible only within that file. Note that this limitation also applies to files inserted, via the %include directive, into the file containing the %filescope directive.

You should not use the %filescope directive 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

Use %include "file.tlc"to insert the specified target file at the current point.

The %include directives behave as if they were in a global context. For example,

%addincludepath "./sub1"
%addincludepath "./sub2"

in a .tlc file enables either subfolder to be referenced implicitly:

%include "file_in_sub1.tlc"
%include "file_in_sub2.tlc"

Use forward slashes for folder names, as they work on both UNIX® and PC systems. However, if you do use back slashes in PC folder names, be sure to escape them, e.g., "C:\\mytlc". Alternatively, you can express a PC folder name as a literal using the L format specifier, as in L"C:\mytlc".

%addincludepath

Use %addincludepath "folder" to add additional paths to be searched. Multiple %addincludepath directives can appear. The compiler evaluates multiple %addincludepath directives from the bottom up.

Using %addincludepath directives establishes a global context. For example,

%addincludepath "./sub1"
%addincludepath "./sub2"

in a .tlc file enables either subfolder to be referenced implicitly:

%include "file_in_sub1.tlc"
%include "file_in_sub2.tlc"

Use forward slashes for folder names, as they work on both UNIX and PC systems. However, if you do use back slashes in PC folder names, be sure to escape them, e.g., "C:\\mytlc". Alternatively, you can express a PC folder name as a literal using the L format specifier, as in L"C:\mytlc".

%roll
%endroll

Multiple inclusion plus intrinsic loop rolling based upon a specified threshold. This directive can be used by most Simulink® blocks that have the concept of an overall block width that is usually the width of the signal passing through the block.

This 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 that 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 there are 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 in a loop. When the decision is made to place a given region in a loop, the loop control variable is a valid identifier (e.g., "i"); otherwise it is "".

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 roll structures. The defined loop variables relative to a block are

"U"

The 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. The "u" must be lowercase or it will be interpreted as "U" above.

"Y"

The 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. The "y" must be lowercase or it will be interpreted as "Y" above.

"P"

The 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

The 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

The 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

The 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

The 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.

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 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 are 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 is enabled. 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 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

Use this function if your block has derivatives.

%function ZeroCrossings(block,system) Output

Use 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 a filename is not 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 or "w" for writing.

Note that the special string streamIdNULL_FILE specifies no output. The special string streamIdSTDOUT 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 entire record array.

Comments

You can place comments anywhere within a target file. To include comments, use the /%...%/ or %% directives. For example:

/%
    Abstract:    Return the field with [width], if field is wide
%/

or

%endfunction %% Outputs function

Use the %% construct for line-based comments. Characters from %% to the end of the line become a comment.

Non-directive lines, that is, lines that do not have % as their first non-blank character, are copied into the output buffer verbatim. For example,

/* Initialize sysNumber */
int sysNumber = 3;

copies both lines to the output buffer.

To include comments on lines that do not begin with the % character, you can use the /%...%/ or %% comment directives. In these cases, the comments are not copied to the output buffer.

Note

If a non-directive line appears within a function, it is not copied to the output buffer unless the function is an output function or you specifically select an output file using the %selectfile directive. For more information about functions, see Target Language Functions.

Line Continuation

You can use the C language \ character or the MATLAB sequence ... to continue a line. If a directive is too long to fit conveniently on one line, this allows you to split the directive onto multiple lines. For example:

%roll sigIdx = RollRegions, lcv = RollThreshold, block,\ 
      "Roller", rollVars

or

%roll sigIdx = RollRegions, lcv = RollThreshold, block,... 
      "Roller", rollVars

Note

Use \ to suppress line feeds to the output and the ellipsis ... to indicate line continuation. Note that \ and the ellipsis ... cannot be used inside strings.

Target Language Value Types

This table shows the types of values you can use within the context of expressions in your target language files. Expressions in the Target Language Compiler must use these types.

Value Type StringExample Description

"Boolean"

1==1

Result of a comparison or other Boolean operator. The result will be TLC_TRUE or TLC_FALSE.

"Complex"

3.0+5.0i

64-bit double-precision complex number (double on the target machine).

"Complex32"

3.0F+5.0Fi

32-bit single-precision complex number (float on the target machine).

"File"

%openfile x

String buffer opened with %openfile.

"File"%openfile x = "out.c"

File opened with %openfile.

"Function"

%function foo...

User-defined function and TLC_FALSE otherwise.

"Gaussian"

3+5i

32-bit integer imaginary number (int on the target machine).

"Identifier"abc

Identifier values can appear only within the model.rtw file and cannot appear in expressions (within the context of an expression, identifiers are interpreted as values). To compare against an identifier value, use a string; the identifier will be converted to a string.

"Matrix"

Matrix (3,2) [ [ 1, 2]; [3 , 4]; [ 5, 6] ]

Matrices are simply lists of vectors. The individual elements of the matrix do not need to be the same type, and can be any supported type except vectors or matrices. The Matrix (3,2) text in the example is optional.

"Number"

15

Integer number (int on the target machine).

"Range"

[1:5]

Range of integers between 1 and 5, inclusive.

"Real"3.14159

Floating-point number (double on the target machine), including exponential notation.

"Real32"

3.14159F

32-bit single-precision floating-point number (float on the target machine).

"Scope"

Block { ... }

Block record.

"Special"

FILE_EXISTS

Special built-in function, such as FILE_EXISTS.

"String"

"Hello, World"

ASCII character strings. In all contexts, two strings in a row are concatenated to form the final value, as in "Hello, " "World", which is combined to form "Hello, World". These strings include the ANSI® C standard escape sequences such as \n, \r, \t, etc. Use of line continuation characters (i.e., \ and ...) inside strings is illegal.

"Subsystem"

<sub1>

Subsystem identifier. Within the context of an expansion, be careful to escape the delimiters on a subsystem identifier, as in %<x == <sub\>>.

"Unsigned"

15U

32-bit unsigned integer (unsigned int on the target machine).

"Unsigned Gaussian"

3U+5Ui

32-bit complex unsigned integer (unsigned int on the target machine).

"Vector"

[1, 2] or BR Vector(2) [1, 2]

Vectors are lists of values. The individual elements of a vector do not need to be the same type, and can be of any supported type except vectors or matrices.

Target Language Expressions

You can include an expression of the form %<expression> in a target file. The Target Language Compiler replaces %<expression> with a calculated replacement value based upon the type of the variables within the %<> operator. Integer constant expressions are folded and replaced with the resultant value; string constants are concatenated (e.g., two strings in a row "a" "b", are replaced with "ab").

%<expression>                /* Evaluates the expression.  
  * Operators include most standard C
  * operations on scalars. Array indexing
  * is required for certain parameters that 
  * are block-scoped within the .rtw file.*/

Within the context of an expression, each identifier must evaluate to an identifier or function argument currently in scope. You can use the %< > directive on a line to perform text substitution. To include the > character within a replacement, you must escape it with a \ character. For example:

%<x \> 1 ? "ABC" : "123">

Operators that need the > character to be escaped are the following:

OperatorDescriptionExample
>

greater than

y = %<x \> 2>;
>=

greater than or equal to

y = %<x \>= 3>;
>>

right shift

y = %<x \>\> 4>;

The table Target Language Expressions lists the operators that are allowed in expressions. In this table, expressions are listed in order from highest to lowest precedence. The horizontal lines distinguish the order of operations.

As in C expressions, conditional operators are short-circuited. If the expression includes a function call with effects, the effects are noticed as if the entire expression was not fully evaluated. For example:

%if EXISTS(foo) && foo == 3

If the first term of the expression evaluates to a Boolean false (i.e., foo does not exist), the second term (foo == 3) is not evaluated.

In the upcoming table, note that numeric is one of the following:

  • Boolean

  • Number

  • Unsigned

  • Real

  • Real32

  • Complex

  • Complex32

  • Gaussian

  • UnsignedGaussian

Also, note that integral is one of the following:

  • Number

  • Unsigned

  • Boolean

See TLC Data Promotions for information on the promotions that result when the Target Language Compiler operates on mixed types of expressions.

Target Language Expressions

Expression

Definition

constant

Constant parameter value. The value can be a vector or matrix.

variable-name

Valid in-scope variable name, including the local function scope, if any, and the global scope.

::variable-name

Used within a function to indicate that the function scope is ignored when the variable is looked up. This accesses the global scope.

expr[expr]

Index into an array parameter. Array indices range from 0 to N-1. This syntax is used to index into vectors, matrices, and repeated scope variables.

expr([expr[,expr]...])

Function call or macro expansion. The expression outside the parentheses is the function/macro name; the expressions inside are the arguments to the function or macro.

Note: Macros are text-based; they cannot be used within the same expression as other operators.

expr . expr

The first expression must have a valid scope; the second expression is a parameter name within that scope.

(expr)

Use () to override the precedence of operations.

!expr

Logical negation (generates TLC_TRUE or TLC_FALSE). The argument must be numeric or Boolean.

-expr

Unary minus negates the expression. The argument must be numeric.

+expr

No effect; the operand must be numeric.

~expr

Bit-wise negation of the operand. The argument must be an integer.

expr * expr

Multiplies the two expressions; the operands must be numeric.

expr / expr

Divides the two expressions; the operands must be numeric.

expr % expr

Takes the integer modulo of the expressions; the operands must be integers.

expr + expr

Works on numeric types, strings, vectors, matrices, and records as follows:

Numeric types: Add the two expressions; the operands must be numeric.

Strings: The strings are concatenated.

Vectors: If the first argument is a vector and the second is a scalar, the scalar is appended to the vector.

Matrices: If the first argument is a matrix and the second is a vector of the same column width as the matrix, the vector is appended as another row in the matrix.

Records: If the first argument is a record, the second argument is added as a parameter identifier (with its current value).

Note that the addition operator is associative.

expr - expr

Subtracts the two expressions; the operands must be numeric.

expr << expr

Left-shifts the left operand by an amount equal to the right operand; the arguments must be integers.

expr >> expr

Right-shifts the left operand by an amount equal to the right operand; the arguments must be integers.

expr > expr

Tests whether the first expression is greater than the second expression; the arguments must be numeric.

expr < expr

Tests whether the first expression is less than the second expression; the arguments must be numeric.

expr >= expr

Tests whether the first expression is greater than or equal to the second expression; the arguments must be numeric.

expr <= expr

Tests whether the first expression is less than or equal to the second expression; the arguments must be numeric.

expr == expr

Tests whether the two expressions are equal.

expr != expr

Tests whether the two expressions are not equal.

expr & expr

Performs the bit-wise AND of the two arguments; the arguments must be integers.

expr ^ expr

Performs the bit-wise XOR of the two arguments; the arguments must be integers.

expr | expr

Performs the bit-wise OR of the two arguments; the arguments must be integers.

expr && expr

Performs the logical AND of the two arguments and returns TLC_TRUE or TLC_FALSE. This can be used on either numeric or Boolean arguments.

expr || expr

Performs the logical OR of the two arguments and returns TLC_TRUE or TLC_FALSE. This can be used on either numeric or Boolean arguments.

expr ? expr : expr

Tests the first expression for TLC_TRUE. If true, the first expression is returned; otherwise, the second expression is returned.

expr , expr

Returns the value of the second expression.

Note

Relational operators ( <, =<, >, >=, !=, == ) can be used with nonfinite values.

You do not have to place expressions in the %< > eval format when they appear on directive lines. Doing so causes a double evaluation.

TLC Data Promotions

When the Target Language Compiler operates on mixed types of expressions, it promotes the results to the common types indicated in the following table.

The table uses the following abbreviations:

B

Boolean

N

Number

U

Unsigned

F

Real32

D

Real

G

Gaussian

UG

UnsignedGaussian

C32

Complex32

C

Complex

The top row (in bold) and first column (in bold) show the types of expression used in the operation. The intersection of the row and column shows the resulting type of expressions.

For example, if the operation involves a Boolean expression (B) and an unsigned expression (U), the result will be an unsigned expression (U).

Data Types Resulting from Expressions of Mixed Type

 BNUFDGUGC32C
BBNUFDGUGC32C
NNNUFDGUGC32C
UUUUFDUGUGC32C
FFFFFDC32C32C32C
DDDDDDCCCC
GGGUGC32CGUGC32C
UGUGUGUGC32CUGUGC32C
C32C32C32C32C32CC32C32C32C
CCCCCCCCCC

Formatting

By default, the Target Language Compiler outputs floating-point numbers in exponential notation with 16 digits of precision. To override the default, use the directive

%realformat string

If string is "EXPONENTIAL", the standard exponential notation with 16 digits of precision is used. If string is "CONCISE", the compiler uses internal heuristics to output the values in a more readable form while maintaining accuracy. The %realformat directive sets the default format for Real number output to the selected style for the remainder of processing or until it encounters another %realformat directive.

Conditional Inclusion

The conditional inclusion directives are

%if constant-expression
%else
%elseif constant-expression
%endif

%switch constant-expression
%case constant-expression
%break
%default
%endswitch

%if

The constant-expression must evaluate to an integer expression. It controls the inclusion of the following lines until it encounters an %else, %elseif, or %endif directive. If the constant-expression evaluates to 0, the lines following the directive are not included. If the constant-expression evaluates to an integer value other than 0, the lines following the %if directive are included until the %endif, %elseif, or %else directive.

When the compiler encounters an %elseif directive, and no prior %if or %elseif directive has evaluated to nonzero, the compiler evaluates the expression. If the value is 0, the lines following the %elseif directive are not included. If the value is nonzero, the lines following the %elseif directive are included until the subsequent %else, %elseif, or %endif directive.

The %else directive begins the inclusion of source text if the previous %elseif statements or the original %if statement evaluates to 0; otherwise, it prevents the inclusion of subsequent lines up to and including the following %endif.

The constant-expression can contain any expression specified in Target Language Expressions.

%switch

The %switch statement evaluates the constant expression and compares it to expressions appearing on %case selectors. If a match is found, the body of the %case is included; otherwise the %default is included.

%case ... %default bodies flow together, as in C, and %break must be used to exit the switch statement. %break exits the nearest enclosing %switch, %foreach, or %for loop in which it appears. For example,

%switch(type)
%case x         
	/* Matches variable x. */
	/* Note: Any valid TLC type is allowed. */
%case "Sin"
	/* Matches Sin or falls through from case x. */
   %break
	/* Exits the switch. */
%case "gain"
	/* Matches gain. */
   %break
%default
	/* Does not match x, "Sin," or "gain." */
%endswitch

In general, this is a more readable form for the %if/%elseif/%else construction.

Multiple Inclusion

%foreach

The syntax of the %foreach multiple inclusion directive is

%foreach identifier = constant-expression
   %break
   %continue
%endforeach

The constant-expression must evaluate to an integer expression, which then determines the number of times to execute the foreach loop. The identifier increments from 0 to one less than the specified number. Within the foreach loop, you can use x, where x is the identifier, to access the identifier variable. %break and %continue are optional directives that you can include in the %foreach directive:

  • Use %break to exit the nearest enclosing %for, %foreach, or %switch statement.

  • Use %continue to begin the next iteration of a loop.

%for

Note

The %for directive is functional, but it is not recommended. Instead, use %roll, which provides the same capability in a more open way. The code generator does not use the %for construct.

The syntax of the %for multiple inclusion directive is

%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 in that it causes a loop to execute from 0 to N-1 times over the body of the loop. In the normal case, it includes only the lines between %body and %endbody, and the lines between the %for and %body, and ignores the lines between %endbody and %endfor.

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. If const-exp2 is true, ident2 receives the value of const-exp3; otherwise it receives the null string. When the loop is rolled, the lines between the %for and the %endfor are included in the output exactly one time. ident2 specifies the identifier to be used for testing whether the loop was rolled within the body. For example,

%for Index = <NumNonVirtualSubsystems>3, rollvar="i"

    {
        int i;

        for (i=0; i< %<NumNonVirtualSubsystems>; i++)
        {
          %body
	x[%<rollvar>] = system_name[%<rollvar>];
          %endbody

        }
    }
%endfor

If the number of nonvirtual subsystems (NumNonVirtualSubsystems) is greater than or equal to 3, the loop is rolled, causing the code within the loop to be generated exactly once. In this case, Index = 0.

If the loop is not rolled, the text before and after the body of the loop is ignored and the body is generated NumNonVirtualSubsystems times.

This mechanism gives each individual loop control over whether or not it should be rolled.

%roll

The syntax of the %roll multiple inclusion directive is

%roll ident1 = roll-vector-exp, ident2 = threshold-exp, ... 
               block-exp [, type-string [,exp-list] ]
  %break
  %continue
%endroll

This statement uses the roll-vector-exp to expand the body of the %roll statement multiple times as in the %foreach statement. If a range is provided in the roll-vector-expand that range is larger than the threshold-exp expression, the loop will roll. When a loop rolls, the body of the loop is expanded once and the identifier (ident2) provided for the threshold expression is set to the name of the loop control variable. If no range is larger than the specified rolling threshold, this statement is identical to the %foreach statement. For example,

%roll Idx = [ 1 2 3:5, 6, 7:10 ], lcv = 10, ablock
%endroll

In this case, the body of the %roll statement expands 10 times, as in the %foreach statement, because there are no regions greater than or equal to 10. Idx counts from 1 to 10, and lcv is set to the null string, "".

When the Target Language Compiler determines that a given block will roll, it performs a GENERATE_TYPE function call to output the various pieces of the loop (other than the body). The default type used is Roller; you can override this type with a string that you specify. Extra arguments passed to the %roll statement are provided as arguments to these special-purpose functions. The called function is one of these four functions:

RollHeader(block, ...).  This function is called once on the first section of this roll vector that will actually roll. It should return a string that is assigned to the lcv within the body of the %roll statement.

LoopHeader(block, StartIdx, Niterations, Nrolled, ...).  This function is called once for each section that will roll prior to the body of the %roll statement.

LoopTrailer(block, Startidx, Niterations, Nrolled, ...).  This function is called once for each section that will roll after the body of the %roll statement.

RollTrailer(block, ...).  This function is called once at the end of the %roll statement if any of the ranges caused loop rolling.

These functions should output language-specific declarations, loop code, and so on as required to generate code for the loop.

An example of a Roller.tlc file is

%implements Roller "C"
%function RollHeader(block) Output
	{
		int i;
	%return ("i")
%endfunction
%function LoopHeader(block,StartIdx,Niterations,Nrolled) Output
 	for (i = %<StartIdx>; i < %<Niterations+StartIdx>; i++)
	{
%endfunction
%function LoopTrailer(block,StartIdx,Niterations,Nrolled) Output
	}
%endfunction
%function RollTrailer(block) Output
	}
%endfunction

Note

The Target Language Compiler function library provided with the code generator has the capability to extract references to the block I/O and other code generator vectors that vastly simplify the body of the %roll statement. These functions include LibBlockInputSignal, LibBlockOutputSignal, LibBlockParameter, LibBlockRWork, LibBlockIWork, LibBlockPWork, LibDeclareRollVars, LibBlockMatrixParameter, LibBlockParameterAddr, LibBlockContinuousState, and LibBlockDiscreteState. (See the function reference pages in Input Signal Functions, Output Signal Functions, Parameter Functions, and Block State and Work Vector Functions.) This library also includes a default implementation of Roller.tlc as a “flat” roller.

Extending the former example to a loop that rolls,

%language "C"
%assign ablock = BLOCK { Name "Hi" }
%roll Idx = [ 1:20, 21, 22, 23:25, 26:46], lcv = 10, ablock
	Block[%< lcv == "" ? Idx : lcv>] *= 3.0;
%endroll

This Target Language Compiler code produces this output:

{
	int             i;
	for (i = 1; i < 21; i++)
	{
	    Block[i] *= 3.0;
	}
	Block[21] *= 3.0;
	Block[22] *= 3.0;
	Block[23] *= 3.0;
	Block[24] *= 3.0;
	Block[25] *= 3.0;
	for (i = 26; i < 47; i++)
	{
	    Block[i] *= 3.0;
	}
}

Object-Oriented Facility for Generating Target Code

The Target Language Compiler provides a simple object-oriented facility. The language directives are

%language string
%generatefile
%implements

This facility was designed specifically for customizing the code for Simulink blocks, but can be used for other purposes as well.

%language

The %language directive specifies the target language being generated. It is required as a consistency check to verify the implementation files found for the language being generated. The %language directive must appear prior to the first GENERATE or GENERATE_TYPE built-in function call. %language specifies the language as a string. For example:

%language "C"

Simulink blocks have a Type parameter. This parameter is a string that specifies the type of the block, for example "Sin" or "Gain". The object-oriented facility uses this type to search the path for a file that implements the block. By default the name of the file is the Type of the block with .tlc appended, so for example, if the Type is "Sin" the Compiler would search for "Sin.tlc" along the path. You can override this default filename using the %generatefile directive to specify the filename that you want to use to replace the default filename. For example,

%generatefile "Sin" "sin_wave.tlc"

The files that implement the block-specific code must contain an %implements directive indicating both the type and the language being implemented. The Target Language Compiler will produce an error if the %implements directive does not match as expected. For example,

%implements "Sin" "Pascal"

causes an error if the initial language choice was C.

You can use a single file to implement more than one target language by specifying the desired languages in a vector. For example,

%implements "Sin" "C"

Finally, you can implement several types using the wildcard (*) for the type field:

%implements * "C"

Note

The use of the wildcard (*) is not recommended because it relaxes error checking for the %implements directive.

GENERATE and GENERATE_TYPE Functions

The Target Language Compiler has two built-in functions that dispatch object-oriented calls, GENERATE and GENERATE_TYPE. You can call a function appearing in an implementation file (from outside the specified file) only by using the GENERATE and GENERATE_TYPE special functions.

GENERATE.  The GENERATE function takes two or more input arguments. The first argument must be a valid scope and the second a string containing the name of the function to call. The GENERATE function passes the first block argument and any additional arguments specified to the function being called. The return argument is the value, if any, returned from the function being called. Note that the compiler automatically “scopes” or adds the first argument to the list of scopes searched as if it appears on a %with directive line. (See Variable Scoping.) This scope is removed when the function returns.

GENERATE_TYPE.  The GENERATE_TYPE function takes three or more input arguments. It handles the first two arguments identically to the GENERATE function call. The third argument is the type; the type specified in the Simulink block is ignored. This facility is used to handle S-function code generation by the build process. That is, the block type is S-function, but the Target Language Compiler generates it as the specific S-function specified by GENERATE_TYPE. For example,

GENERATE_TYPE(block, "Output", "dp_read")

specifies that S-function block is of type dp_read.

The block argument and any additional arguments are passed to the function being called. Like the GENERATE built-in function, the compiler automatically scopes the first argument before the GENERATE_TYPE function is entered and then removes the scope on return.

Within the file containing %implements, function calls are looked up first within the file and then in the global scope. This makes it possible to have hidden helper functions used exclusively by the current object.

Note

It is not an error for the GENERATE and GENERATE_TYPE directives to find no matching functions. This is to prevent requiring empty specifications for all aspects of block code generation. Use the GENERATE_FUNCTION_EXISTS or GENERATE_TYPE_FUNCTION_EXISTS directives to determine whether the specified function actually exists.

Output File Control

The structure of the output file control construct is

%openfile string optional-equal-string optional-mode
%closefile id
%selectfile id

%openfile

The %openfile directive opens a file or buffer for writing; the required string variable becomes a variable of type file. For example,

%openfile x               /% Opens and selects x for writing. %/
%openfile out = "out.h"   /% Opens "out.h" for writing. %/

%selectfile

The %selectfile directive selects the file specified by the variable as the current output stream. Output goes to that file until another file is selected using %selectfile. For example,

%selectfile x               /% Select file x for output. %/

%closefile

The %closefile directive closes the specified file or buffer. If the closed entity is the currently selected output stream, %closefile invokes %selectfile to reselect the previously selected output stream.

There are two possible cases that %closefile must handle:

  • If the stream is a file, the associated variable is removed as if by %undef.

  • If the stream is a buffer, the associated variable receives the text that has been output to the stream. For example,

    %assign x = ""                 /% Creates an empty string. %/
    %openfile x
    "hello, world"
    %closefile x		 /% x = "hello, world\n"%/

If desired, you can append to an output file or string by using the optional mode, a, as in

%openfile "foo.c", "a"             %% Opens foo.c for appending.

Input File Control

The input file control directives are

%include string
%addincludepath string

%include

The %include directive searches the path for the target file specified by string and includes the contents of the file inline at the point where the %include statement appears.

%addincludepath

The %addincludepath directive adds an additional include path to be searched when the Target Language Compiler references %include or block target files. The syntax is

%addincludepath string

The string can be an absolute path or an explicit relative path. For example, to specify an absolute path, use

%addincludepath "C:\\folder1\\folder2"     (PC)
%addincludepath "/folder1/folder2"         (UNIX)

To specify a relative path, the path must explicitly start with .. For example,

%addincludepath ".\\folder2"                  (PC)
%addincludepath "./folder2"                   (UNIX)

Note that for PC, the backslashes must be escaped (doubled).

When an explicit relative path is specified, the folder that is added to the Target Language Compiler search path is created by concatenating the location of the target file that contains the %addincludepath directive and the explicit relative path.

The Target Language Compiler searches the folders in the following order for target or include files:

  1. The current folder.

  2. Include paths specified in %addincludepath directives. The compiler evaluates multiple %addincludepath directives from the bottom up.

  3. Include paths specified at the command line via -I . The compiler evaluates multiple -I options from right to left.

Typically, %addincludepath directives should be specified in your system target file. Multiple %addincludepath directives will add multiple paths to the Target Language Compiler search path.

Note

The compiler does not search the MATLAB path, and will not find a file that is available only on that path. The compiler searches only the locations described above.

Asserts, Errors, Warnings, and Debug Messages

The related assert, error, warning, and debug message directives are

%assert expression
%error tokens
%warning tokens
%trace tokens
%exit tokens

These directives produce error, warning, or trace messages whenever a target file detects an error condition, or tracing is desired. The tokens following the directive on a line become part of the generated error or warning message.

The Target Language Compiler places messages generated by %trace onto stderr if and only if you specify the verbose mode switch (-v) to the Target Language Compiler. See Command-Line Arguments for additional information about switches.

The %assert directive evaluates the expression and produces a stack trace if the expression evaluates to a Boolean false.

Note

In order for %assert directives to be evaluated, Enable TLC assertion must be selected in the TLC process section of the Code Generation > Debug pane. The default action is for %assert directives not to be evaluated.

The %exit directive reports an error and stops further compilation.

Built-In Functions and Values

The following table lists the built-in functions and values that are added to the list of parameters that appear in the model.rtw file. These Target Language Compiler functions and values are defined in uppercase so that they are visually distinct from other parameters in the model.rtw file, and, by convention, from user-defined parameters.

TLC Built-In Functions and Values

Built-In Function NameExpansion

CAST(expr, expr)

The first expression must be a string that corresponds to one of the type names in the table Target Language Value Types, and the second expression will be cast to that type. A typical use might be to cast a variable to a real format as in

CAST("Real", variable-name) 

An example of this is in working with parameter values for S-functions. To use them within C or C++ code, you need to typecast them to real so that a value such as 1 will be formatted as 1.0 (see also %realformat).

EXISTS(var)

If the var identifier is not currently in scope, the result is TLC_FALSE. If the identifier is in scope, the result is TLC_TRUE. var can be a single identifier or an expression involving the . and [] operators.

FEVAL(matlab-command,
   TLC-expressions)

Performs an evaluation in MATLAB. For example,

%assign result = FEVAL("sin",3.14159)

The %matlab directive can be used to call a MATLAB function that does not return a result. For example,

%matlab disp(2.718)

Note: If the MATLAB function returns more than one value, TLC receives the first value only.

FILE_EXISTS(expr)

expr must be a string. If a file by the name expr does not exist on the path, the result is TLC_FALSE. If a file by that name exists on the path, the result is TLC_TRUE.

FORMAT(realvalue, format)

The first expression is a Real value to format. The second expression is either EXPONENTIAL or CONCISE. Outputs the Real value in the designated format, where EXPONENTIAL uses exponential notation with 16 digits of precision, and CONCISE outputs the number in a more readable format while maintaining numerical accuracy.

FIELDNAMES(record)

Returns an array of strings containing the record field names associated with the record. Because it returns a sorted list of strings, the function is O(n*log(n)).

GETFIELD(record,
   "fieldname"
)

Returns the contents of the specified field name, if the field name is associated with the record. The function uses hash lookup, and therefore executes in constant time.

GENERATE(record,
   function-name,  ...)

Executes function calls mapped to a specific record type (i.e., block record functions). For example, use this to execute the functions in the .tlc files for built-in blocks. Not that TLC automatically “scopes” or adds the first argument to the list of scopes searched as if it appears on a %with directive line.

GENERATE_FILENAME(type)

For the specified record type, does a .tlc file exist? Use this to see if the GENERATE_TYPE call will succeed.

GENERATE_FORMATTED_VALUE
   (expr, string, expand)

Returns a potentially multiline string that can be used to declare the value(s) of expr in the current target language. The second argument is a string that is used as the variable name in a descriptive comment on the first line of the return string. If the second argument is the empty string, "", then no descriptive comment is put into the output string. The third argument is a Boolean that when TRUE causes expr to be expanded into raw text before being output. expand = TRUE uses much more memory than the default (FALSE); set expand = TRUE only if the parameter text needs to be processed for some reason before being written to disk.

For example,

static const unsigned char contents[] =

%assign value = GENERATE_FORMATTED_VALUE(SFcnParamSettings.CONTENTS, "", TLC_FALSE)

;

yields this C code:

static const unsigned char contents[] = { 0U, 1U, 2U, 3U, 4U };

GENERATE_FUNCTION_EXISTS
   (record, function-name)

Determines whether a given block function exists. The first expression is the same as the first argument to GENERATE, namely a block scoped variable containing a Type. The second expression is a string that should match the function name.

GENERATE_TYPE
   (record, function-name,
   type, ...)

Similar to GENERATE, except that type overrides the Type field of the record. Use this when executing functions mapped to specific S-function block records based upon the S-function name (i.e., the name becomes the type).

GENERATE_TYPE_FUNCTION_EXISTS
   (record, function-name,
   type)

Same as GENERATE_FUNCTION_EXISTS except that it overrides the Type built into the record.

GET_COMMAND_SWITCH

Returns the values of command-line switches. Only the following switches are supported:

v, m, p, O, d, dr, r, I, a
See also Command-Line Arguments.

IDNUM(expr)

expr must be a string. The result is a vector where the first element is a leading string, if any, and the second element is a number appearing at the end of the input string. For example,

IDNUM("ABC123") yields ["ABC", 123]

IMAG(expr)

Returns the imaginary part of a complex number.

INT8MAX

127

INT8MIN

-128

INT16MAX

32767

INT16MIN

-32768

INT32MAX

2147483647

INT32MIN

-2147483648

INTMIN

Minimum integer value on host machine.

INTMAX

Maximum integer value on host machine.

ISALIAS(record)

Returns TLC_TRUE if the record is a reference (symbolic link) to a different record, and TLC_FALSE otherwise.

ISEQUAL(expr1, expr2)

Where the data types of both expressions are numeric: returns TLC_TRUE if the first expression contains the same value as the second expression; returns TLC_FALSE otherwise.

Where the data type of either expression is nonnumeric (e.g., string or record): returns TLC_TRUE if and only if both expressions have the same data type and contain the same value; returns TLC_FALSE otherwise.

ISEMPTY(expr)

Returns TLC_TRUE if the expression contains an empty string, vector, or record, and TLC_FALSE otherwise.

ISFIELD(record, "fieldname")

Returns TLC_TRUE if the field name is associated with the record, and TLC_FALSE otherwise.

ISINF(expr)

Returns TLC_TRUE if the value of the expression is inf, and TLC_FALSE otherwise.

ISNAN(expr)

Returns TLC_TRUE if the value of the expression is NAN, and TLC_FALSE otherwise.

ISFINITE(expr)

Returns TLC_TRUE if the value of the expression is not +/- inf or NAN, and TLC_FALSE otherwise.

ISSLPRMREF(param.value)

Returns a Boolean value indicating whether its argument is a reference to a Simulink parameter or not. This function supports parameter sharing with Simulink; using it can save memory and time during code generation. For example,

%if !ISSLPRMREF(param.Value) 
  assign param.Value = CAST("Real", param.Value) 
%endif

NULL_FILE

A predefined file for no output that you can use as an argument to %selectfile to prevent output.

NUMTLCFILES

The number of target files used thus far in expansion.

OUTPUT_LINES

Returns the number of lines that have been written to the currently selected file or buffer. Does not work for STDOUT or NULL_FILE.

REAL(expr)

Returns the real part of a complex number.

REMOVEFIELD(record, "fieldname")

Removes the specified field from the contents of the record. Returns TLC_TRUE if the field was removed; otherwise returns TLC_FALSE.

ROLL_ITERATIONS()

Returns the number of times the current roll regions are looping or NULL if not inside a %roll construct.

SETFIELD(record, "fieldname", value)

Sets the contents of the field name associated with the record. Returns TLC_TRUE if the field was added; otherwise returns TLC_FALSE.

SIZE(expr[,expr])

Calculates the size of the first expression and generates a two-element row vector. If the second operand is specified, it is used as an integer index into this row vector; otherwise the entire row vector is returned. SIZE(x) applied to a scalar returns [1 1]. SIZE(x) applied to a scope returns the number of repeated entries of that scope type. For example, SIZE(Block) returns

[1,<number of blocks>]

SPRINTF(format,var,...)

Formats the data in variable var (and in any additional variable arguments) under control of the specified format string, and returns a string variable containing the values. Operates like the C library sprintf(), except that output is the return value rather than contained in an argument to sprintf.

STDOUT

A predefined file for stdout output. You can use this as an argument to %selectfile to force output to stdout.

STRING(expr)

Expands the expression into a string; the characters \, \n, and " are escaped by preceding them with \ (backslash). The ANSI escape sequences are translated into string form. If %<> is in the expression, it is escaped so that the enclosed string is not subject to further TLC interpretation.

STRINGOF(expr)

Accepts a vector of ASCII values and returns a string that is constructed by treating each element as the ASCII code for a single character. Used primarily for S-function string parameters.

SYSNAME(expr)

Looks for specially formatted strings of the form <x>/y and returns x and y as a two-element string vector. This is used to resolve subsystem names. For example,

%<sysname("<sub>/Gain")>

returns

["sub","Gain"]

In Block records, the name of the block is written <sys/blockname>, where sys is S# or Root. You can obtain the full path name by calling LibGetBlockPath(block); this will include newlines and other troublesome characters that cause display difficulties. To obtain a full path name suitable for one-line comments but not identical to the Simulink path name, use LibGetFormattedBlockPath(block).

TLCFILES

Returns a vector containing the names of the target files included thus far in the expansion. Absolute paths are used. See also NUMTLCFILES.

TLC_FALSE

Boolean constant that equals a negative evaluated Boolean expression.

TLC_TRUE

Boolean constant that equals a positive evaluated Boolean expression.

TLC_TIME

Date and time of compilation.

TLC_VERSION

Version and date of the Target Language Compiler.

TYPE(expr)

Evaluates expr and determines the result type. The result of this function is a string that corresponds to the type of the given expression. See the Value Type String column in the table Target Language Value Types for possible values.

UINT8MAX

255U

UINT16MAX

65535U

UINT32MAX

4294967295U

UINTMAX

Maximum unsigned integer value on host machine.

WHITE_SPACE(expr)

Accepts a string and returns 1 if the string contains only white-space characters ( , \t, \n, \r); returns 0 otherwise.

WILL_ROLL(expr1, expr2)

The first expression is a roll vector and the second expression is a roll threshold. This function returns true if the vector contains a range that will roll.

FEVAL Function

The FEVAL built-in function calls MATLAB file functions and MEX-functions. The structure is

%assign result = FEVAL( matlab-function-name, rhs1, rhs2, ... 
	rhs3, ... );

Note

  • Only a single left-side argument is allowed when you use FEVAL.

  • If your MATLAB function evaluation leads to an error, the TLC compiler does not terminate but continues with the execution. The FEVAL directive returns an empty value to the TLC.

This table shows the conversions that are made when you use FEVAL.

MATLAB Conversions

TLC TypeMATLAB Type
"Boolean"Boolean (scalar or matrix)
"Number"Double (scalar or matrix)
"Real"Double (scalar or matrix)
"Real32"Double (scalar or matrix)
"Unsigned"Double (scalar or matrix)
"String"String
"Vector"If the vector is homogeneous, it is converted to a MATLAB vector. If the vector is heterogeneous, it is converted to a MATLAB cell array.
"Gaussian"Complex (scalar or matrix)
"UnsignedGaussian"Complex (scalar or matrix)
"Complex"Complex (scalar or matrix)
"Complex32"Complex (scalar or matrix)
"Identifier"String
"Subsystem"String
"Range"Expanded vector of Doubles
"Idrange"Expanded vector of Doubles
"Matrix"If the matrix is homogeneous, it is converted to a MATLAB matrix. If the matrix is heterogeneous, it is converted to a MATLAB cell array. (Cell arrays can be nested.)
"Scope" or "Record"Structure with elements
Scope or Record aliasString containing fully qualified alias name
Scope or Record arrayCell array of structures
Other type not listed aboveConversion not supported

When values are returned from MATLAB, they are converted as shown in this table. Note that conversion of matrices with more than two dimensions is not supported, nor is conversion or downcast of 64-bit integer values.

More Conversions

MATLAB TypeTLC Type
String String
Vector of Strings

Vector of Strings

Boolean (scalar or matrix)Boolean (scalar or matrix)
INT8,INT16,INT32
(scalar or matrix)
Number (scalar or matrix)
INT64Not supported
UINT64Not supported
Complex INT8,INT16,INT32
(scalar or matrix)
Gaussian (scalar or matrix)
UINT8,UINT16,UINT32
(scalar or matrix)
Unsigned (scalar or matrix)
Complex UINT8,UINT16,UINT32
(scalar or matrix)
UnsignedGaussian (scalar or matrix)
Single precisionReal32 (scalar or matrix)
Complex single precisionComplex32 (scalar or matrix)
Double precisionReal (scalar or matrix)
Complex double precisionComplex (scalar or matrix)
Sparse matrixExpanded to matrix of Doubles
Cell array of structuresRecord array
Cell array of non-structuresVector or matrix of types converted from the types of the elements
Cell array of structures and non-structuresConversion not supported
StructureRecord
ObjectConversion not supported

Other value types are not currently supported.

As an example, this statement uses the FEVAL built-in function to call MATLAB to take the sine of the input argument.

%assign result = FEVAL( "sin", 3.14159 )

Variables (identifiers) can take on the following constant values. Note the suffix on the value .

Constant FormTLC Type
1.0"Real"
1.0[F/f]"Real32"
1"Number"
1[U|u]"Unsigned"
1.0i"Complex"
1[Ui|ui]"UnsignedGaussian"
1i"Gaussian"
1.0[Fi|fi]"Complex32"

Note

The suffix controls the Target Language Compiler type obtained from the constant.

This table shows Target Language Compiler constants and their equivalent MATLAB values.

TLC ConstantsEquivalent MATLAB Value
rtInf, Inf, inf+inf
rtMinusInf-inf
rtNan, NaN, nannan
rtInfi, Infi, infiinf*i
rtMinusInfi-inf*i
rtNaNi, NaNi, naninan*i

TLC Reserved Constants

For double-precision values, the following are defined for infinite and not-a-number IEEE® values:

rtInf, inf, rtMinusInf, -inf, rtNaN, nan

For single-precision values, these constants apply:

rtInfF, InfF, rtMinusInfF, rtNaNF, NaNF

Their corresponding versions when complex are:

rtInfi, infi, rtMinusInfi, -infi, rtNaNi (for doubles)
rtInfFi, InfFi, rtMinusInfFi, rtNaNFi, NaNFi (for singles)

For integer values, the following are defined:

INT8MIN, INT8MAX, INT16MIN, INT16MAX, INT32MIN, INT32MAX, 
UINT8MAX, UINT16MAX, UINT32MAX, INTMAX, INTMIN, UINTMAX

Identifier Definition

To define or change identifiers (TLC variables), use the directive

%assign [::]expression = constant-expression

This directive introduces new identifiers (variables) or changes the values of existing ones. The left side can be a qualified reference to a variable using the . and [] operators, or it can be a single element of a vector or matrix. In the case of the matrix, only the single element is changed by the assignment.

The %assign directive inserts new identifiers into the local function scope, file function scope, generate file scope, or into the global scope. Identifiers introduced into the function scope are not available within functions being called, and are removed upon return from the function. Identifiers inserted into the global scope are persistent. You can change existing identifiers by completely respecifying them. The constant expressions can include legal identifiers from the .rtw files. You can use %undef to delete identifiers in the same way that you use it to remove macros.

Within the scope of a function, variable assignments create new local variables unless you use the :: scope resolution operator. In this example, the assignment creates a variable foo, local to the function, that will disappear when the function exits.

%function ...
...
%assign foo = 3
...
%endfunction

Note that foo is created even if a global foo already exists.

To create or change values in the global scope, you must use the scope resolution operator (::) to disambiguate, as in

%function ...
%assign foo = 3
%assign ::foo = foo
...
%endfunction

The scope resolution operator forces the compiler to assign the value of the local variable foo, 3, to the global variable foo.

Note

It is an error to change a value from the code generator file without qualifying it with the scope. This example does not generate an error:

	%assign CompiledModel.name = "newname"	%% No error 

This example generates an error:

%with CompiledModel
  %assign name = "newname"	   %% Error 	%endwith

Creating Records

Use the %createrecord directive to build new records in the current scope. For example, if you want to create a new record called Rec that contains two items (e.g., Name "Name" and Type "t"), use

%createrecord Rec {  Name "Name"; Type "t" }

Adding Records

Use the %addtorecord directive to add new records to existing records. For example, if you have a record called Rec1 that contains a record called Rec2, and you want to add an additional Rec2 to it, use

%addtorecord Rec1 Rec2 {  Name "Name1"; Type "t1" }

This figure shows the result of adding the record to the existing one.

If you want to access the new record, you can use

%assign myname = Rec1.Rec2[1].Name

In this same example, if you want to add two records to the existing record, use

%addtorecord Rec1 Rec2 {  Name "Name1"; Type "t1" }
%addtorecord Rec1 Rec2 {  Name "Name2"; Type "t2" }

This produces

Adding Parameters to an Existing Record

You can use the %assign directive to add a new parameter to an existing record. For example,

%addtorecord Block[Idx] N 500 /% Adds N with value 500 to Block %/
%assign myn = Block[Idx].N    /% Gets the value 500 %/

adds a new parameter, N, at the end of an existing block with the name and current value of an existing variable, as shown in this figure. It returns the block value.

Variable Scoping

This section discusses how the Target Language Compiler resolves references to variables (including records).

Scope, in this document, has two related meanings. First, scope is an attribute of a variable that defines its visibility and persistence. For example, a variable defined within the body of a function is visible only within that function, and it persists only as long as that function is executing. Such a variable has function (or local) scope. Each TLC variable has one (and only one) of the scopes described in Scopes.

The term scope also refers to a collection, or pool, of variables that have the same scope. At a given point in the execution of a TLC program, several scopes can exist. For example, during execution of a function, a function scope (the pool of variables local to the function) exists. In all cases, a global scope (the pool of global variables) also exists.

To resolve variable references, TLC maintains a search list of current scopes and searches them in a well-defined sequence. The search sequence is described in How TLC Resolves Variable References.

Dynamic scoping refers to the process by which TLC creates and deallocates variables and the scopes in which they exist. For example, variables in a function scope exist only while the defining function executes.

Scopes

The following sections describe the possible scopes that a TLC variable can have.

Global Scope.  By default, TLC variables have global scope. Global variables are visible to, and can be referenced by, code anywhere in a TLC program. Global variables persist throughout the execution of the TLC program. Global variables are said to belong to the global pool.

Note that the CompiledModel record of the model.rtw file has global scope. Therefore, you can access this structure from your TLC functions or files.

You can use the scope resolution operator (::) to explicitly reference or create global variables from within a function. See The Scope Resolution Operator for examples.

Note that you can use the %undef directive to free memory used by global variables.

File Scope.  Variables with file scope are visible only within the file in which they are created. To limit the scope of variables in this way, use the %filescope directive anywhere in the defining file.

In the following code fragment, the variables fs1 and fs2 have file scope. Note that the %filescope directive does not have to be positioned before the statements that create the variables.

%assign fs1 = 1
%filescope
%assign fs2 = 3

Variables whose scope is limited by %filescope go out of scope when execution of the file containing them completes. This lets you free memory allocated to such variables.

Function (Local) Scope.  Variables defined within the body of a function have function scope. That is, they are visible within and local to the defining function. For example, in the following code fragment, the variable localv is local to the function foo. The variable x is global.

%assign x = 3

%function foo(arg)
   %assign localv = 1
   %return x + localv
%endfunction

A local variable can have the same name as a global variable. To refer, within a function, to identically named local and global variables, you must use the scope resolution operator (::) to disambiguate the variable references. See The Scope Resolution Operator for examples.

Note

Functions themselves (as opposed to the variables defined within functions) have global scope. There is one exception: functions defined in generate scope are local to that scope. See Generate Scope.

%with Scope.  The %with directive adds a new scope, referred to as a %with scope, to the current list of scopes. This directive makes it easier to refer to block-scoped variables.

The structure of the %with directive is

%with expression
%endwith

For example, the directive

%with CompiledModel.System[sysidx]
   ...
%endwith

adds the CompiledModel.System[sysidx] scope to the search list. This scope is searched before anything else. You can then refer to the system name simply by

Name

instead of

CompiledModel.System[sysidx].Name

Generate Scope.  Generate scope is a special scope used by certain built-in functions that are designed to support code generation. These functions dispatch function calls that are mapped to a specific record type. This capability supports a type of polymorphism in which different record types are associated with functions (analogous to methods) of the same name. Typically, this feature is used to map Block records to functions that implement the functionality of different block types.

Functions that employ generate scope include GENERATE, GENERATE_TYPE, GENERATE_FUNCTION_EXISTS, and GENERATE_TYPE_FUNCTION_EXISTS. See GENERATE and GENERATE_TYPE Functions. This section discusses generate scope using the GENERATE built-in function as an example.

The syntax of the GENERATE function is

GENERATE(blk,fn)

The first argument (blk) to GENERATE is a valid record name. The second argument (fn) is the name of a function to be dispatched. When a function is dispatched through a GENERATE call, TLC automatically adds blk to the list of scopes that is searched when variable references are resolved. Thus the record (blk) is visible to the dispatched function as if an implicit %with <blk>... %endwith directive existed in the dispatched function.

In this context, the record named blk is said to be in generate scope.

Three TLC files, illustrating the use of generate scope, are listed below. The file polymorph.tlc creates two records representing two hypothetical block types, MyBlock and YourBlock. Each record type has an associated function named aFunc. The block-specific implementations of aFunc are contained in the files MyBlock.tlc and YourBlock.tlc.

Using GENERATE calls, polymorph.tlc dispatches to a function for each block type. Notice that the aFunc implementations can refer to the fields of MyBlock and YourBlock, because these records are in generate scope.

  • The following listing shows polymorph.tlc:

    %% polymorph.tlc
    
    %language "C"
    
    %%create records used as scopes within dispatched functions
    
    %createrecord MyRecord { Type "MyBlock"; data 123 }
    %createrecord YourRecord { Type "YourBlock"; theStuff 666 }
    
    %% dispatch the functions thru the GENERATE call.
    
    %% dispatch to MyBlock implementation
    %<GENERATE(MyRecord, "aFunc")> 
    
    %% dispatch to YourBlock implementation
    %<GENERATE(YourRecord, "aFunc")>
    
    %% end of polymorph.tlc
  • The following listing shows MyBlock.tlc:

    %%MyBlock.tlc
    
    %implements "MyBlock" "C"
    
    %% aFunc is invoked thru a GENERATE call in polymorph.tlc.
    %% MyRecord is in generate scope in this function.
    %% Therefore, fields of MyRecord can be referenced without
    %% qualification
    
    %function aFunc(r) Output
    %selectfile STDOUT
    The value of MyRecord.data is: %<data>
    %closefile STDOUT
    %endfunction
    
    %%end of MyBlock.tlc
  • The following listing shows YourBlock.tlc:

    %%YourBlock.tlc
    
    %implements "YourBlock" "C"
    
    %% aFunc is invoked thru a GENERATE call in polymorph.tlc.
    %% YourRecord is in generate scope in this function.
    %% Therefore, fields of YourRecord can be referenced without
    %% qualification
    
    %function aFunc(r) Output
    %selectfile STDOUT
    The value of YourRecord.theStuff is: %<theStuff>
    %closefile STDOUT
    %endfunction
    
    %%end of YourBlock.tlc

The invocation and output of polymorph.tlc, as displayed in the MATLAB Command Window, are shown below:

tlc -v polymorph.tlc

The value of MyRecord.data is: 123
The value of YourRecord.theStuff is: 666

Note

Functions defined in generate scope are local to that scope. This is an exception to the general rule that functions have global scope. In the above example, for instance, neither of the aFunc implementations has global scope.

The Scope Resolution Operator

The scope resolution operator (::) is used to indicate that the global scope should be searched when a TLC function looks up a variable reference. The scope resolution operator is often used to change the value of global variables (or even create global variables) from within functions.

By using the scope resolution operator, you can resolve ambiguities that arise when a function references identically named local and global variables. In the following example, a global variable foo is created. In addition, the function myfunc creates and initializes a local variable named foo. The function myfunc explicitly references the global variable foo by using the scope resolution operator.

%assign foo = 3   %% this variable has global scope
.
.
.
%function myfunc(arg)
   %assign foo = 3   %% this variable has local scope
   %assign ::foo = arg   %% this changes the global variable foo
%endfunction

You can also use the scope resolution operator within a function to create global variables. The following function creates and initializes a global variable:

%function sideffect(arg)
   %assign ::theglobal = arg   %% this creates a global variable
%endfunction

How TLC Resolves Variable References

This section discusses how the Target Language Compiler searches the existing scopes to resolve variable references.

Global Scope.  In the simplest case, the Target Language Compiler resolves a variable reference by searching the global pool (including the CompiledModel structure).

%with Scope.  You can modify the search list and search sequence by using the %with directive. For example, when you add the following construct,

%with CompiledModel.System[sysidx]
   ...
%endwith

the System[sysidx] scope is added to the search list. This scope is searched first, as shown by this picture.

This technique makes it simpler to access embedded definitions. Using the %with construct (as in the previous example), you can refer to the system name simply by

Name

instead of

CompiledModel.System[sysidx].Name

Function Scope.  A function has its own scope. That scope is added to the previously described search list, as shown in this diagram.

For example, in the following code fragment,

% with CompiledModel.System[sysidx]
...
   %assign a=foo(x,y)
...
%endwith
...
%function foo(a,b)
...
   assign myvar=Name
...
%endfunction
...
%<foo(1,2)>

If Name is not defined in foo, the assignment uses the value of Name from the previous scope, CompiledModel.System[SysIdx].Name.

In a nested function, only the innermost function scope is searched, together with the enclosing %with and global scopes, as shown in the following diagram:

File Scope.  File scopes are searched before the global scope, as shown in the following diagram.

The rule for nested file scopes is similar to that for nested function scopes. In the case of nested file scopes, only the innermost nested file scope is searched.

Target Language Functions

The target language function construct is

%function identifier ( optional-arguments ) [Output | void]
%return
%endfunction

Functions in the target language are recursive and have their own local variable space. Target language functions do not produce output unless they are output functions or explicitly use the %openfile, %selectfile, and %closefile directives.

A function optionally returns a value with the %return directive. The returned value can be a type defined in the table at Target Language Value Types.

In this example, a function, name, returns x if x and y are equal, or returns z if x and y are not equal:

%function name(x,y,z) void

%if x == y
   %return x
%else
   %return z
%endif

%endfunction

Function calls can appear in contexts where variables are allowed.

The %with statements that are in effect when a function is called are available to the function. Calls to other functions do not include the local scope of the function, but do include %with statements appearing within the function.

Assignments to variables within a function create new local variables and cannot change the value of global variables unless you use the scope resolution operator (::).

By default, a function returns a value and does not produce output. You can override this behavior by specifying the Output and void modifiers on the function declaration line, as in

%function foo() Output
...
%endfunction

In this case, the function continues to produce output to the currently open file, and is not required to return a value. You can use the void modifier to indicate that the function does not return a value and should not produce output, as in

%function foo() void
...
%endfunction

Variable Scoping Within Functions

Within a function, the left-hand member of an %assign statement defaults to creating a local variable. A new entry is created in the function’s block within the scope chain; it does not affect the other entries. An example appears in Function Scope.

You can override this default behavior by using %assign with the scope resolution operator (::).

When you introduce new scopes within a function, using %with, these new scopes are used during nested function calls, but the local scope for the function is not searched.

If a %with is included within a function, its associated scope is carried with nested function calls, as shown in the next figure.

%return

The %return statement closes all %with statements appearing within the current function. In this example, the %with statement is automatically closed when the %return statement is encountered, removing the scope from the list of searched scopes:

%function foo(s)
    %with s
        %return(name)
    %endwith
%endfunction

The %return statement does not require a value. You can use %return to return from a function without a return value.

Related Topics