Target Language Compiler Quick Reference | Help Desk |
Code Architecture:
Sample of the generated code for a model with a sine, gain, and outport. Each block places code intoMdl
routines. Here we show MdlOutputs
:![]() |
![]() |
The model.rtw file and scopes:
TLC variables can be scalars, strings, vectors, matrices, and records. Themodel.
rtw
file is an ASCII file containing parameter-value pairs stored in a hierarchy of records defined by your model. In TLC, identifiers refer to parameters. Each record creates a new "scope". The format of model
.rtw
is:
CompiledModel {
Name "modelname" -- Example of a parameter-value
... pair (record field).
System { -- There is one system for each
nonvirtual subsystem.
Block { -- Block records for each
Type "S-Function" nonvirtual block in the system.
Name "<S3>/S-Function"
...
Parameter {
Name "P1"
Value Matrix(1,2) [[1, 2];]
}
...
Block {
}
}
...
System { -- The last system is for the root of
} your model.
}
Within TLC, to access parameter values of TLC variables, you need to specify a valid path to the parameter. Multiple records of the same name form a list where the index of the first record starts at 0. For example to access the above S-function block record, you would use CompiledModel.System[0].Block[0]
To access the name field of this block, you would use: CompiledModel.System[0].Block[0].Name
It is also possible to "scope" a given record. This is done via the %with
directive. When inlining S-function blocks, your S-function Block
record is scoped. In an inlined .tlc
file, you should access fields without a fully qualified path. For example, to access the name of your block, you would use: Name.
This accesses CompiledModel.System[i].Block[j].Name,
since CompiledModel.
System[i].Block[j]
is currently scoped.
nan
and their corresponding version when complex:
rtInfi, infi, rtMinusInfi, -infi, rtNaNi
For integer values, we define the following:
INT8MIN, INT8MAX, INT16MIN, INT16MAX, INT32MIN, INT32MAX,
UINT8MAX, UINT16MAX, UINT32MAX
TLC Values
Variables (identifiers) within TLC can be of the following value typeConstant Form |
TLC 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" |
TLC Expressions
In any place throughout a target file, you can include an expression of the form %<expression>
. TLC 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"
). Note, on directive lines it is not necessary to place the expression in the %< > format. Doing so causes a double evaluation.
Within the context of an expression, each identifier must evaluate to a identifier or function argument currently in scope. You can use the %< >
directive on any line to perform textual substitution. To include the >
character within a replacement, you must escape it with a "\
" character as in: %<x \> 1 ? "ABC" : "123"
>
In the following table, expressions are listed in order from highest to lowest precedence. The horizontal lines distinguish the order of operations.
As opposed to C expressions, conditional operators are not short-circuited. Therefore, if the expression includes a function call with side effects, the effects are noticed as if the entire expression were evaluated. In the following table, numeric refers to one of Boolean
, Number
, Unsigned
, Real
, Real32
, Complex
, Complex32
, Gaussian
, or UnsignedGaussian.
Also, integral refers to one of Number
, Unsigned
, or Boolean.
TLC Data Promotions
When the Target Language Compiler operates on mixed types of expressions, it promotes the result to the common types indicated in the following table, where the notation is (B) for Boolean, (N) for Number, (U) for Unsigned, (F) for Real32, (D) for Real, (G) for Gaussian, (UG) for UnsignedGaussian, (C32) for Complex32, and (C) for 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 expression. For example, if the operation involves a Boolean expression (B) and an unsigned expression (U), the result will be an unsigned expression (U).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 themodel
.rtw
file. These TLC 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.Commonly used functions in the TLC Function Library
The filefunclib.tlc
contains the RTW TLC function library. This file contains the necessary TLC functions required to write a block target file. In this section we give a description of the more common functions. The following table describes arguments to these functions.:
|
Refers to an input or output port index, starting at zero, for example the first input port of an S-function is 0. |
|
User control variable. This is an advanced feature and overrides the |
|
Loop control variable. This is generally generated by the % |
|
Signal index. Sometimes referred to as the signal element index. When accessing specific elements of a input or output signal directly, the call to the various library routines should have |
continued
|
sigIdx an overloaded argument. Specifically, the index when passed to a Lib function can be of the form:
|
paramIdx |
Parameter index. Sometimes referred to as the parameter element index. The handling of this parameter is very similar to |
stateIdx |
State index. Sometimes referred to as the state vector element index (it must evaluate to an integer where the first element starts at 0). |
LibBlockInputSignal(portIdx, ucv, lcv, sigIdx)
--portIdx
), the user control variable (ucv
), the loop control variable (lcv
), and the signal index (sigIdx
), this function returns a reference to the source signal. The text string returned can be decomposed into four parts: inputSignal = <vect><ioq><id><index>
.
The first part, <vect>
, depends on where this signal originates. This is derived from the attributes of the signal source. The possibilities are:
rtU
: External inputs vector (driven by a inport block in root window)
rtX
: States vector (output from the state port of driving block)
rtB
: Block I/O vector, declared globally
rtb_
: Block I/O vector, declared locally
rtC
: Const Block I/O vector (driven by an invariant block)
rtC_
: #define'd Const Block I/O (driven by an invariant block).
u
: Inside a rolled loop
<ioq>
, is the I/O qualifier (or the selection operator), which is largely determined by the code format. The possibilities are:
.
: RealTime
, Embedded-C
, and Ada
code formats
->
: RealTimeMalloc
and S-Function
code formats
<id>
, is the unique identifier assigned to this signal. This identifier is obtained from either the signal label specified in the Simulink diagram or, if a signal label is not present, the name of the block from which this signal originates.
For invariant block I/O signals, whose value is set by a #define
statement, an additional _
is appended between the <id>
and <index>
positions.
The final part, <index>
, is the index into the appropriate element and/or real/imaginary part of the input signal, if it is either wide and/or complex. This depends on ucv
, lcv
, and idx
.
If you combine all of them, you get strings such as rtB.s7_Gain1[2]
, where:
rtB
is the <vect>
part
s7_Gain1
is the <id>
part (s7
represents Subsystem 7 while Gain1
is the name of the block)
[2]
is the <index>
part.
Examples:roll
or directly). In the above example, case 1 occurs when an explicit call is made with the ucv set to "i"
. Cases 2 and 3 receive the same arguments, lcv
and sigIdx
however they produce different return values. Case 2 occurs when LibBlockInputSignal
is called within a %roll
directive and the current roll region is being rolled. Case 3 occurs when LibBlockInputSignal
is called within a %roll
directive and the current roll region is not being rolled.
When called within a %roll
directive, this function looks at ucv
, lcv
, and sigIdx
, the current roll region, and the current roll threshold to determine the return value. The variable ucv
has highest precedence, lcv
has the next highest precedence, and sigIdx
has the lowest precedence. That is, if ucv
is specified, it will be used (thus, when called in a %roll
directive it is usually ""
). If ucv
is not specified and lcv
and sigIdx
are specified, the returned value depends on whether or not the current roll region is being placed in a for loop or being expanded. If the roll region is being placed in a loop then, lcv
is used, otherwise sigIdx
is used.
A direct call to this function (inside or outside of a %roll
directive) will use sigIdx
when ucv
and lcv
are specified as "".
For an example of this function, see matlabroot
/toolbox/simulink/blocks/tlc_c/sfun_multiport.tlc
.
Related input signal functions:
LibBlockInputSignalWidth(portIdx)
-- Return the width of the input port specified by portIdx
.
LibBlockInputSignalAddr(portIdx, ucv, lcv, sigIdx)
-- Similar to LibBlockInputSignal
except the address is returned (e.g. &rtB.blockname[0]
). In Ada, this function returns the identifier and the caller must append the 'Address
attribute.
LibBlockInputSignalBufferDstPort(portIdx)
Þ-- Returns the output port corresponding to input port (portIdx
) which share the same memory, otherwise (-1
) is returned. You will need to use this function when you specify ssSetInputPortOverWritable(S,portIdx,TRUE)
in your S-function.
LibBlockSrcSignalBlock(portIdx, sigIdx)
-- Returns the signal source for specified input port element. Return values will be: [systemIdx, blockIdx]
if source is a block output or a block state, ExternalInput
if the source is a root inport, Ground
if the source is grounded or unconnected, or 0
if the source is not unique (i.e. connected to a Merge block or it is a reused signal due to block I/O optimizations).
LibBlockSrcSignalIsDiscrete(portIdx, sigIdx)
-- Returns 1 if source signal is discrete; otherwise 0 (or if the signal cannot be uniquely determined). The signal cannot be uniquely determined if it is a merged or reused signal (i.e., the source is a Merge
block or if the signal has been reused due to block I/O optimization).
LibBlockSrcSignalIsGlobalAndModifiable(portIdx, sigIdx)
-- Returns 1 if the block's specified source signal is in global memory, 0 otherwise. If the signal is in global memory: 1) it visible everywhere in the generated code, 2) it can be referenced by its address, and 3) its value can change (i.e., it is not declared as a constant).
LibBlockSrcSignalIsInvariant(portIdx, sigIdx)
-- Returns 1 if the specified block input signal element is invariant, 0 otherwise. An invariant signal source signal has a constant (purple sample time). In this case the value of the signal does not change during model execution.
LibBlockOutputSignal(portIdx, ucv, lcv, sigIdx)
--portIdx
), the user control variable (ucv), the loop-control variable (lcv
), the signal index (idx
), and the location of this output signal, LibBlockOutputSignal
returns the appropriate for a block output signal. Calling conventions, usage, and return values are similar to LibBlockInputSignal
.
Related output signal functions:
LibBlockOutputSignalWidth(portIdx)
-- Return the width of the output port specified by portIdx
.
LibBlockOutputSignalAddr(portIdx, ucv, lcv, sigIdx)
-- Similar to LibBlockOutputSignal
except the address is returned (e.g. &rtB.blockname[0]
). In Ada, this function returns the identifier and the caller must append the 'Address
attribute.
LibBlockOutputSignalIsInBlockIO(portIdx)
-- Check if the specified block output port exists in the global Block I/O data structure. You may need to use this if you specify ssSetOutputPortReusable(S,portIdx,TRUE)
in your S-function.
See matlabroot
/toolbox/simulink/blocks/tlc_c/sfun_multiport.tlc
.
LibBlockParameter(param, ucv, lcv, paramIdx)
--LibBlockInputSignal
(in the handling of ucv and lcv). This function returns the appropriate reference to a block's parameter. The function can only be used for parameters of type Scalar
or Vector
. The first argument, param
, is a reference to a block parameter (i.e. the value of Parameter[i].Name
). The last argument, paramIdx
identifies which element of the parameter we need to access. This is very similar to the sigIdx of the LibBlockInputSignal
function. For example,matlabroot
/toolbox/simulink/blocks/tlc_c/sfun_multiport.tlc.
LibBlockParameterAddr(param, ucv, lcv, paramIdx)
Þ-- Similar to LibBlockParameter
except it return the address of the parameter and guarantees that the parameter will be in the global parameter vector. In Ada, the caller must append a 'Address
attribute.
LibBlockParameterSize(param)
-- Returns the size of the parameter in a two element vector: [
nRows
,
nCols
]
.
LibBlockParameterValue(param, paramIdx)
-- Returns the numeric value of the specified parameter element.
LibBlockParameterFormattedValue(param, paramIdx)
-- Similar to LibBlockParameterValue
except it has been formatted into a string suitable for writing to the generated code file.
LibBlockMatrixParameter(param, rowUcv, rowLcv, rowParamIdx, colUcv, colLcv, colParamIdx)
-- Return the appropriate matrix parameter for a block given the row and column user control variables, loop control variables, and indices. Currently, rowLcv
and colLcv
must be ""
(i.e. loop rolling is not supported). The row and column index arguments are similar to the arguments for LibBlockParameter
. The column index (colParamIdx
) is overloaded to handle complex numbers.
LibBlockMatrixParameterAddr(param, rowUcv, rowLcv, rowParamIdx, colUcv, colLcv, colParamIdx)
-- This function returns the appropriate address of a block's matrix parameter. The function is similar to LibBlockParameterAddr
.
LibBlockMatrixParameterValue(param, rowParamIdx, colParamIdx)
-- Returns the numeric value of a matrix parameter.
LibBlockMatrixParameterFormattedValue(param, rowParamIdx, colParamIdx)
-- Similar to LibBlockMatrixParmaeterValue
except it has been formatted into a string suitable for writing to the generated code file.
Block State and Work Vector Functions
LibBlockContinuousState(ucv, lcv, stateIdx)
-- Used to access a block's continuous state vector from outside (ucv = "", lcv = "", stateIdx specified) of or within a %roll
directive (ucv= "", lcv, stateIdx specified).
LibBlockDiscreteState(ucv, lcv, stateIdx)
-- Used to access a block's discrete state vector from outside (ucv = "", lcv = "", stateIdx specified) of or within a %roll
directive (ucv= "", lcv, stateIdx specifed).
LibBlockRWork(rworkRef, ucv, lcv, workIdx)
LibBlockIWork(iworkRef, ucv, lcv, workIdx)
LibBlockPWork(pworkRef, ucv, lcv, workIdx)
-- The behavior of these functions is similar to LibBlockInputSignal
with respect to handling of ucv, lcv, and workIdx (sigIdx specified as integer). These functions return the appropriate reference to the block's RWork
, IWork
, and PWork
. The additional arguments, rworkRef
, iworkRef
, and pworkRef
, are references to the block internal records RWorkDefine
, IWorkDefine
, and PWorkDefine
, respectively.
If the block records RWorkDefine
, IWorkDefine
, and PWorkDefine
are not defined, then the reference to the work records is replaced with a reference to the block's vector identifier, RWork
, IWork
, and PWork
, respectively. Use the mdlRTW
S-function method to add [R|I|P]WorkDefine
records to the model.
rtw
file.
LibBlockMode(ucv, lcv, modeIdx)
-- The behavior of this function is similar to the LibBlockRWork
function.
LibBlockSampleTime(block)
-- Returns the block's sample time. The return value is the actual block's sample time (a real number greater than zero) if it is discrete. If the block is triggered, -1.0 is returned. If the block is constant then -2.0 is returned. If the block is continuous then 0.0 is returned.
LibIsSFcnSampleHit(sfcnTID)
-- Returns the code required to check for a sample hit. This function should only be used when your block has multiple sample times. For block-based sample times, specify sfcnTID
as an integer corresponding to the local sample time of the blockssIsSampleHit(S,sfcnTID)
). For port-based sample times, specify sfcnTID
as a string of the form InputPortIdx#
(e.g. InputPortIdx3
for the 4th input port) or OutputPortIdx#
. If a block is single rate, it doesn't need sample time checks (i.e, don't use LibIsSFcnSampleHit
).
LibGetNumSFcnSampleTimes(block)
-- Returns the integer number of sample times the S-function block has.
LibGetSFcnTIDType(sfcnTID)
-- Returns "continuous"
, "discrete"
, "triggered"
, or "constant"
. See LibIsSFcnSampleHit
for specification of the sfcnTid
argument.
LibIsContinuous(tid)
-- Returns 1 if the specified model task id (TID
field of a block) is continuous. Note that TIDs equal to "triggered"
or "constant"
are not continuous.
LibIsDiscrete(tid)
-- Returns 1 if the specified model task id (TID field of a block) is discrete. Note that TIDs equal to "triggered"
or "constant"
are not discrete.
LibIsSFcnSingleRate(block)
-- Returns 1 if an S-function is single rate (one sample time), 0 otherwise.
LibIsSampleHit(tid)
-- Returns the code required to check for a sample hit. The argument, tid
can be specified as an integer corresponding to a model sample time or a string variable used to index the sample hit array. In general, S-functions should use LibIsSFcnSampleHit
except when checking for sample hits in a loop, in this case LibIsSampleHit("
loopindex
")
should be used. This would typically be done for an advanced port-based sample time S-function.
LibTID()
-- Returns %<tTID>
, the task identifier needed when checking for sample hits. Note, in general only advanced S-functions should use this. S-functions should never directly access %<tTID>
since this may result in code that doesn't compile. LibTID
guarantees that %<tTID>
will exist.
LibGetGlobalTIDFromLocalTid(sfcnTid)
-- This function returns the integer model task id for a local S-function task id. Each S-function block has the concept of local task identifiers (TIDs). For example, if an S-function has two sample times, then the local TIDs are 0 for the first sample time and 1 for the second sample time. These local TIDs map one-to-one with the model task ids. For our example, local task id 0 could map to the 3rd model task id. See LibIsSFcnSampleHit
for specification of the sfcnTid
argument.
If your block accesses time, it must use one of the following functions; otherwise
the generated code may fail to compile.
LibGetT()
-- Returns a string giving access to the model time corresponding to task id 0. If your block accesses model time corresponding to task id 0, it must use this function.
LibGetTaskTimeFromTID(block)
-- Returns a string giving access to the time for the current task.
LibGetBlockPath(block)
-- Returns the full path name string for a block record. This includes carriage returns and other special characters. You use the full path name including special characters when accessing blocks from within MATLAB.
LibGetFormattedBlockPath(block)
Þ-- Returns the full path name string for a block record with special characters removed. This is useful when issuing information, warnings, or error messages from within TLC.
LibCacheDefine(buffer)
Þ-- Generally called from within a BlockTypeSetup
function to add #define
statements to model
.h
.
LibCacheExtern(buffer)
-- Generally called from within a BlockTypeSetup
function to add extern
definitions for variables to model
.h.
LibCacheFunctionPrototype(buffer)
-- Generally called from within a BlockTypeSetup
function to add extern
function prototypes to model
.h
.
LibCacheIncludes(buffer)
-- Generally called from within a BlockTypeSetup
function to add #include
statements to model
.h
.
LibCacheNonFiniteAssignment(buffer)
-- Generally called from within a BlockTypeSetup
function to add assignments for non-finite values which needed to be initialized in the model registration function model
.reg
.
LibCacheTypedefs(buffer)
-- Generally called from within a BlockTypeSetup
function to add typedef
statements to model
.h
.
LibIsEmpty(arg)
-- Returns 1 if arg
is empty (i.e. ""
, []
, etc.), 0 otherwise. This is useful to use when you aren't sure of arg
's type.
LibIsEqual(expr1,expr2)
-- Returns 1 if expr1
equals expr2
, 0 otherwise. This is useful when you aren't sure of the expr1
, expr2
types.
LibAddIdentifier(record, name, value)
-- Adds the name/value
pair to the specified scope (record
). An error is reported if the identifier (name
) already exists. This is generally called in a BlockTypeSetup
function for the block. To avoid name conflicts, choose a name that starts with a lowercase character. It is recommended that you prefix the name to be added with your company name or initials.
LibAddToCompiledModel(name, value)
Þ-- Adds a name
/value pair to the CompiledModel
scope. An error is reported if the identifier (name
) already exists. To avoid conflicts, you should choose names which do not start with an uppercase letter. In addition, prefixing with gbl
CompanyName
is recommended.
LibIsFinite(value)
-- Return 1 if value
is finite (e.g. not equal to NaN, Inf, etc.), 0 otherwise.
LibRealNonFinite(value)
-- Returns a text string suitable for placement in the generated code corresponding to the specified nonfinite value. The input argument, value
can be one of: inf
, -inf
, or nan
in the form of a string or number (i.e. quotes are optional).