Explore Variable Names and Loop Rolling
timesN
Looping Tutorial Overview
Objective: This example shows how you can influence looping behavior of generated code.
Open the Example:
openExample('simulinkcoder/AdviceAboutTLCTutorialsExample') cd('tlctutorial/timesN')
Work with the model sfun_xN
in tlctutorial/timesN
.
It has one source (a Sine Wave generator block), a times N
gain block, an Out block, and a Scope block.
The tutorial guides you through following steps:
Getting Started — Set up the exercise and run the model
Modify the Model — Change the input width and see the results
Change the Loop Rolling Threshold — Change the threshold and see the results
More About TLC Loop Rolling — Parameterize loop behavior
Getting Started
Make
tlctutorial/timesN
your current folder, so that you can use the files provided.In the MATLAB® Command Window, create a MEX-file for the S-function:
mex timesN.c
This avoids picking up the version shipped with Simulink®.
Note
An error might occur if you have not previously run
mex -setup
.Open the model file
sfun_xN
.View the previously generated code in
sfun_xN_grt_rtw/sfun_xN.c
. Note that no loops exist in the code. This is because the input and output signals are scalar.
Modify the Model
Replace the Sine Wave block with a Constant block.
Set the parameter for the Constant block to 1:4, and change the top label,
model: sfun_xN
, tomodel: sfun_vec
.Save the edited model as
sfun_vec
(intlctutorial/timesN
). The model now looks like this.Because the Constant block generates a vector of values, this is a vectorized model. Generate code for the model and view the
/*Model output function */
section ofsfun_vec.c
in your editor to observe how variables andfor
loops are handled. This function appears as follows:/* Model output function */ static void sfun_vec_output(int_T tid) { /* S-Function Block: <Root>/S-Function */ /* Multiply input by 3.0 */ sfun_vec_B.timesN_output[0] = sfun_vec_P.Constant_Value[0] * 3.0; sfun_vec_B.timesN_output[1] = sfun_vec_P.Constant_Value[1] * 3.0; sfun_vec_B.timesN_output[2] = sfun_vec_P.Constant_Value[2] * 3.0; sfun_vec_B.timesN_output[3] = sfun_vec_P.Constant_Value[3] * 3.0; /* Outport: '<Root>/Out' */ sfun_vec_Y.Out[0] = sfun_vec_B.timesN_output[0]; sfun_vec_Y.Out[1] = sfun_vec_B.timesN_output[1]; sfun_vec_Y.Out[2] = sfun_vec_B.timesN_output[2]; sfun_vec_Y.Out[3] = sfun_vec_B.timesN_output[3]; UNUSED_PARAMETER(tid); }
Notice that there are four instances of the code that generates model outputs, corresponding to four iterations.
Set the parameter for the Constant block to 1:10, and save the model.
Generate code for the model and view the
/*Model output function */
section ofsfun_vec.c
in your editor to observe how variables andfor
loops are handled. This function appears as follows:/* Model output function */ static void sfun_vec_output(int_T tid) { /* S-Function Block: <Root>/S-Function */ /* Multiply input by 3.0 */ { int_T i1; const real_T *u0 = &sfun_vec_P.Constant_Value[0]; real_T *y0 = sfun_vec_B.timesN_output; for (i1=0; i1 < 10; i1++) { y0[i1] = u0[i1] * 3.0; } } { int32_T i; for (i = 0; i < 10; i++) { /* Outport: '<Root>/Out' */ sfun_vec_Y.Out[i] = sfun_vec_B.timesN_output[i]; } } UNUSED_PARAMETER(tid); }
Notice that:
The code that generates model outputs gets “rolled” into a loop. This occurs by default when the number of iterations exceeds 5.
Loop index
i1
runs from 0 to 9.Pointer
*y0
is used and initialized to the output signal array.
Change the Loop Rolling Threshold
The code generator creates iterations or loops depending on the current value of the Loop unrolling threshold parameter.
The default value of Loop unrolling threshold is
5
. To change looping behavior for blocks in a model:
On the Optimization pane of the Configuration Parameters dialog box, set Loop unrolling threshold to
12
and clickApply
.The parameter
RollThreshold
is now12
. Loops will be generated only when the width of signals passing through a block exceeds 12.Note
You cannot modify
RollThreshold
for specific blocks from the Configuration Parameters dialog box.Press Ctrl+B to regenerate the output.
Inspect
sfun_vec.c
. It will look like this:/* Model output function */ static void sfun_vec_output(int_T tid) { /* S-Function Block: <Root>/S-Function */ /* Multiply input by 3.0 */ sfun_vec_B.timesN_output[0] = sfun_vec_P.Constant_Value[0] * 3.0; sfun_vec_B.timesN_output[1] = sfun_vec_P.Constant_Value[1] * 3.0; sfun_vec_B.timesN_output[2] = sfun_vec_P.Constant_Value[2] * 3.0; sfun_vec_B.timesN_output[3] = sfun_vec_P.Constant_Value[3] * 3.0; sfun_vec_B.timesN_output[4] = sfun_vec_P.Constant_Value[4] * 3.0; sfun_vec_B.timesN_output[5] = sfun_vec_P.Constant_Value[5] * 3.0; sfun_vec_B.timesN_output[6] = sfun_vec_P.Constant_Value[6] * 3.0; sfun_vec_B.timesN_output[7] = sfun_vec_P.Constant_Value[7] * 3.0; sfun_vec_B.timesN_output[8] = sfun_vec_P.Constant_Value[8] * 3.0; sfun_vec_B.timesN_output[9] = sfun_vec_P.Constant_Value[9] * 3.0; /* Outport: '<Root>/Out' */ sfun_vec_Y.Out[0] = sfun_vec_B.timesN_output[0]; sfun_vec_Y.Out[1] = sfun_vec_B.timesN_output[1]; sfun_vec_Y.Out[2] = sfun_vec_B.timesN_output[2]; sfun_vec_Y.Out[3] = sfun_vec_B.timesN_output[3]; sfun_vec_Y.Out[4] = sfun_vec_B.timesN_output[4]; sfun_vec_Y.Out[5] = sfun_vec_B.timesN_output[5]; sfun_vec_Y.Out[6] = sfun_vec_B.timesN_output[6]; sfun_vec_Y.Out[7] = sfun_vec_B.timesN_output[7]; sfun_vec_Y.Out[8] = sfun_vec_B.timesN_output[8]; sfun_vec_Y.Out[9] = sfun_vec_B.timesN_output[9]; UNUSED_PARAMETER(tid); }
To activate loop rolling again, change the Loop unrolling threshold to 10 (or less) on the Optimization pane.
Loop rolling is an important TLC capability for optimizing generated code. Take some time to study and explore its implications before generating code for production requirements.
More About TLC Loop Rolling
The following TLC %roll
code is the Outputs
function of timesN.tlc
:
%function Outputs(block, system) Output /* %<Type> Block: %<Name> */ %% /* Multiply input by %<gain> */ %assign rollVars = ["U", "Y"] %roll idx = RollRegions, lcv = RollThreshold, block, "Roller", rollVars %<LibBlockOutputSignal(0, "", lcv, idx)> = \ %<LibBlockInputSignal(0, "", lcv, idx)> * %<gain>; %endroll %endfunction %% Outputs
Arguments for %roll
The lines between %roll
and %endroll
may be
either repeated or looped. The key to understanding the %roll
directive
is in its arguments:
%roll sigIdx = RollRegions, lcv = RollThreshold, block, "Roller", rollVars
Argument | Description |
---|---|
sigIdx | Specify the index into a (signal) vector that is used in the generated
code. If the signal is scalar, when analyzing that block of the
|
lcv | A control variable generally specified in the |
block | This tells TLC that it is operating on block objects. TLC code for S-functions use this argument. |
"Roller" | This, specified in |
rollVars | Tells TLC what types of items should be rolled: input signals, output
signals, and/or parameters. You do not have to use
all of them. In a previous line,
%assign rollVars = ["U", "Y"] U )
and output signals (Y ). In cases where blocks specify an
array of parameters instead of a scalar parameter, rollvars
is specified
as%assign rollVars = ["U", "Y", "P"] |
Input Signals, Output Signals, and Parameters
Look at the lines that appear between %roll
and
%endroll
:
%<LibBlockOutputSignal(0, "", lcv, idx)> = \ %<LibBlockInputSignal (0, "", lcv, idx)> * 2.0;
The TLC library functions LibBlockInputSignal
and
LibBlockOutputSignal
expand to produce scalar or vector identifiers
that are named and indexed. LibBlockInputSignal
,
LibBlockOutputSignal
, and a number of related TLC functions are
passed four canonical arguments:
Argument | Description |
---|---|
first argument — | Corresponds to the input port index for a given block. The first input port has index 0. The second input port has index 1, and so on. |
second argument — | An index variable reserved for advanced use. For now, specify the
second argument as an empty string. In advanced applications, you may define
your own variable name to be used as an index with |
third argument — | As described previously, |
fourth argument — | Enables TLC to handle special cases. In the event that the
|