| Products & Services | Solutions | Academia | Support | User Community | Company |
| Download Product Updates | | | Get Pricing | | | Trial Software |
| Documentation → Real-Time Workshop |
| Contents | Index |
| Learn more about Real-Time Workshop |
| On this page… |
|---|
Reusable Code and Referenced Models Generating Reusable Code from Stateflow Charts Generating Reusable Code for Subsystems Containing S-Function Blocks |
The difference between functions and reusable functions is that the latter have data passed to them as arguments (enabling them to be reentrant), while the former communicate by using global data. Choosing the Reusable function option directs the Real-Time Workshop code generator to generate a single function (optionally in a separate file) for the subsystem, and to call that code for each identical subsystem in the model, if possible.
Note The Reusable function option yields code that is called from multiple sites (hence reused) only when the Auto option would also do so. The difference between these options' behavior is that when reuse is not possible, selecting Auto yields inlined code (or if circumstances prohibit inlining, creates a function without arguments), while choosing Reusable function yields a separate function (with arguments) that is called from only one site. |
For a summary of code reuse limitations, see Code Reuse Limitations.
Models that employ model referencing might require special treatment when generating and using reusable code. The following sections identify general restrictions and discuss how reusable functions with inputs or outputs connected to a referenced model's root Inport or Outport blocks can affect code reuse.
You can generate code for subsystems that contain referenced models using the same procedures and options described in Creating Subsystems. However, the following restrictions apply to such builds:
ERT S-functions do not support subsystems that contain a continuous sample time.
The Real-Time Workshop S-function target is not supported.
The Tunable parameters table (set by using the Model Parameter Configuration dialog box) is ignored; to make parameters tunable, you must define them as Simulink parameter objects in the base workspace.
All other parameters are inlined into the generated code and S-function.
Note You can generate subsystem code using any target configuration available in the System Target File Browser. However, if the S-function target is selected, Build Subsystem behaves identically to Generate S-function. (See Automated S-Function Generation.) |
Reusable functions with inputs or outputs connected to a referenced model's root Inport or Outport block can affect code reuse. This means that code for certain atomic subsystems cannot be reused in a model reference context the same way it is reused in a standalone model.
For example, suppose you create the following subsystem and make the following changes to the subsystem's block parameters:
Select Treat as an atomic unit
Set Real-Time Workshop system code to Reusable function

Suppose you then create the following model, which includes three instances of the preceding subsystem.

With the Inline parameters option enabled in this stand-alone model, the Real-Time Workshop code generator can optimize the code by generating a single copy of the function for the reused subsystem, as shown below.
void reuse_subsys1_Subsystem1(
real_T rtu_0,
rtB_reuse_subsys1_Subsystem1 *localB)
{
/* Gain: '<S1>/Gain' */
localB->Gain_k = rtu_0 * 3.0;
}
When generated as code for a Model block (into an slprj project directory), the subsystems have three different function signatures:
/* Output and update for atomic system: '<Root>/Subsystem1' */
void reuse_subsys1_Subsystem1(const real_T *rtu_0,
rtB_reuse_subsys1_Subsystem1
*localB)
{
/* Gain: '<S1>/Gain' */
localB->Gain_w = (*rtu_0) * 3.0;
}
/* Output and update for atomic system: '<Root>/Subsystem2' */
void reuse_subsys1_Subsystem2(real_T rtu_In1,
rtB_reuse_subsys1_Subsystem2
*localB)
{
/* Gain: '<S2>/Gain' */
localB->Gain_y = rtu_In1 * 3.0;
}
/* Output and update for atomic system: '<Root>/Subsystem3' */
void reuse_subsys1_Subsystem3(real_T rtu_In1, real_T *rty_0)
{
/* Gain: '<S3>/Gain' */
(*rty_0) = rtu_In1 * 3.0;
}
One way to make all the function signatures the same — and therefore assure code reuse — is to insert Signal Conversion blocks. Place one between the Inport and Subsystem1 and another between Subsystem3 and the Outport of the referenced model.

The result is a single reusable function:
void reuse_subsys2_Subsystem1(real_T rtu_In1,
rtB_reuse_subsys2_Subsystem1 *localB)
{
/* Gain: '<S1>/Gain' */
localB->Gain_g = rtu_In1 * 3.0;
}
You can achieve the same result (reusable code) with only one Signal Conversion block. You can omit the Signal Conversion block connected to the Inport block if you select the Pass scalar root inputs by value check box at the bottom of the Model Referencing pane of the Configuration Parameters dialog box. When you do this, you still need to insert a Signal Conversion block before the Outport block.
You can generate reusable code from a Stateflow chart, or from a subsystem containing a chart, except in the following cases:
The Stateflow chart contains exported graphical functions.
The Stateflow model contains machine parented events.
Regarding S-Function blocks, there are several requirements that need to be met in order for subsystems containing them to be reused. See Writing S-Functions That Support Code Reuse for the list of requirements.
When you select the Reusable function option, two additional options are enabled, Real-Time Workshop function name options and Real-Time Workshop file name options. See the explanation of Function Option for descriptions of these options and fields. If you use these fields to enter a function name and/or a file name, you must specify exactly the same function name and file name for each instance of identical subsystems for the Real-Time Workshop software to be able to reuse the subsystem code.
Subsystem Reusable Function Code Generation Option

To request that the Real-Time Workshop software generate reusable subsystem code,
Select the subsystem block. Then select Subsystem Parameters from the Simulink model editor Edit menu. The Block Parameters dialog box opens.
Alternatively, you can open the Block Parameters dialog box by:
Shift-double-clicking the subsystem block
Right-clicking the subsystem block and selecting Block parameters from the menu.
If the subsystem is virtual, select Treat as atomic unit. The Real-Time Workshop system code menu becomes enabled.
If the system is already nonvirtual, the Real-Time Workshop system code menu is already enabled.
Select Reusable function from the Real-Time Workshop system code menu as shown in Subsystem Reusable Function Code Generation Option.
If you want to give the function a specific name, set the function name, using the Real-Time Workshop function name options described in Real-Time Workshop Function Name Options Menu.
If you do not choose the Real-Time Workshop function name Auto option, and want code to be reused, you must assign exactly the same function name to all other subsystem blocks that you want to share this code.
If you want to direct the generated code to a specific file, set the file name using any Real-Time Workshop file name option other than Auto (options are described in Real-Time Workshop File Name Options Menu).
In order for code to be reused, you must repeat this step for all other subsystem blocks that you want to share this code, using the same file name.
The Real-Time Workshop software uses a checksum to determine whether subsystems are identical. You cannot reuse subsystem code if:
Multiple ports of a subsystem share the same source.
A port used by multiple instances of a subsystem has different sample times, data types, complexity, frame status, or dimensions across the instances.
The output of a subsystem is marked as a global signal.
Subsystems contain identical blocks with different names or parameter settings.
The output of a subsystem is connected to a Merge block, and the output of the Merge block is a custom storage class that is implemented in the C code as memory that is nonaddressable (for example, BitField).
The input of a subsystem is nonscalar and has a custom storage class that is implemented in the C code as memory that is nonaddressable.
A masked subsystem has a parameter that is nonscalar and has a custom storage class that is implemented in the C code as memory that is nonaddressable.
Some of these situations can arise even when you copy and paste subsystems within or between models or you construct them manually such that they are identical. If you select Reusable function and the Real-Time Workshop software determines that code for a subsystem cannot be reused, it generates a separate function that is not reused. The code generation report can show that the separate function is reusable, even if it is used by only one subsystem. If you prefer that subsystem code be inlined in such circumstances rather than deployed as functions, you choose Auto for the Real-Time Workshop system code option.
Use of the following blocks in a subsystem can also prevent its code from being reused:
Scope blocks (with data logging enabled)
S-Function blocks that fail to meet certain criteria
To File blocks (with data logging enabled)
To Workspace blocks (with data logging enabled)
Due to the limitations noted in Code Reuse Limitations, the Real-Time Workshop software might not reuse generated code as you expect. To determine why code generated for a subsystem is not reused,
Review the Subsystems section of the HTML code generation report
If you cannot determine why based on the report, compare subsystem checksum data
If you determine that the Real-Time Workshop code generator does not generate code for a subsystem as reusable code and you specified the subsystem as reusable, examine the Subsystems section of the HTML code generation report (see Generating a Report). The Subsystems section contains
A table that summarizes how nonvirtual subsystems were converted to generated code
Diagnostic information that explains why the contents of some subsystems were not generated as reusable code
In addition to diagnosing exceptions, the Subsections section also indicates the mapping of each noninlined subsystem in the model to functions or reused functions in the generated code. For an example, open and build the rtwdemo_atomic demo model.
If the HTML code generation report indicates that no code reuse exceptions occurred and code for a subsystem you expect to be reused is not reused, you can determine why by accessing and comparing subsystem checksum data. The Real-Time Workshop software determines whether subsystems are identical by comparing subsystem checksums, as noted in Code Reuse Limitations.
Consider the demo model, rtwdemo_ssreuse.

SS1 and SS2 are instances of the same subsystem, and in both instances the subsystem parameter Real-Time Workshop system code is set to Reusable function.
The following example demonstrates how to use the method Simulink.SubSystem.getChecksum to get the checksum for a subsystem and compare the results to determine why code is not reused.
Open the model rtwdemo_ssreuse and save a copy of the demo in a directory where you have write access.
Select subsystem SS1 in the model window and in the command window enter
SS1 = gcb;
Select subsystem SS2 in the model window and in the command window enter
SS2 = gcb;
Use the method Simulink.SubSystem.getChecksum to get the checksum for each subsystem. This method returns two output values: the checksum value and details on the input used to compute the checksum.
[chksum1, chksum1_details] = ... Simulink.SubSystem.getChecksum(SS1); [chksum2, chksum2_details] = ... Simulink.SubSystem.getChecksum(SS2);
Compare the two checksum values. They should be equal based on the subsystem configurations.
isequal(chksum1, chksum2)
ans =
1To see how you can use Simulink.SubSystem.getChecksum to determine why the checksums of two subsystems differ, change the data type mode of the output port of SS1 so that it differs from that of SS2.
Look under the mask of SS1 by right-clicking the subsystem and selecting Look Under Mask in the context menu. A block diagram of the subsystem appears.
Double-click the Lookup Table block to open the Block Parameters dialog box.
Click Signal Attributes.
Select int8 for Output data type and click OK.
Get the checksum for SS1 again and compare the checksums for the two subsystems again. This time, the checksums should not be equal.
[chksum1, chksum1_details] = ...
Simulink.SubSystem.getChecksum(SS1);
isequal(chksum1, chksum2)
ans =
0After you determine that the checksums are different, find out why. The Simulink engine uses information, such as signal data types, some block parameter values, and block connectivity information, to compute the checksums. To determine why checksums are different, you compare the data used to compute the checksum values. You can get this information from the second value returned by Simulink.SubSystem.getChecksum, which is a structure array with four fields.
Look at the structure chksum1_details.
chksum1_details
chksum1_details =
ContentsChecksum: [1x1 struct]
InterfaceChecksum: [1x1 struct]
ContentsChecksumItems: [221x1 struct]
InterfaceChecksumItems: [91x1 struct]ContentsChecksum and InterfaceChecksum are component checksums of the subsystem checksum. The remaining two fields ContentsChecksumItems and InterfaceChecksumItems contain the checksum details.
Determine whether a difference exists in the subsystem contents, interface, or both. For example:
isequal(chksum1_details.ContentsChecksum.Value,...
chksum2_details.ContentsChecksum.Value)
ans =
0
isequal(chksum1_details.InterfaceChecksum.Value,...
chksum2_details.InterfaceChecksum.Value)
ans =
0
In this case, differences exist in both the contents and interface.
Write a script like the following to find the differences.
idxForCDiffs=[];
for idx = 1:length(chksum1_details.ContentsChecksumItems)
if (~strcmp(chksum1_details.ContentsChecksumItems(idx).Identifier, ...
chksum2_details.ContentsChecksumItems(idx).Identifier))
disp(['Identifiers different for contents item ', num2str(idx)]);
idxForCDiffs=[idxForCDiffs, idx];
end
if (ischar(chksum1_details.ContentsChecksumItems(idx).Value))
if (~strcmp(chksum1_details.ContentsChecksumItems(idx).Value, ...
chksum2_details.ContentsChecksumItems(idx).Value))
disp(['String values different for contents item ', num2str(idx)]);
idxForCDiffs=[idxForCDiffs, idx];
end
end
if (isnumeric(chksum1_details.ContentsChecksumItems(idx).Value))
if (chksum1_details.ContentsChecksumItems(idx).Value ~= ...
chksum2_details.ContentsChecksumItems(idx).Value)
disp(['Numeric values different for contents item ', num2str(idx)]);
idxForCDiffs=[idxForCDiffs, idx];
end
end
end
idxForIDiffs=[];
for idx = 1:length(chksum1_details.InterfaceChecksumItems)
if (~strcmp(chksum1_details.InterfaceChecksumItems(idx).Identifier, ...
chksum2_details.InterfaceChecksumItems(idx).Identifier))
disp(['Identifiers different for interface item ', num2str(idx)]);
idxForIDiffs=[idxForIDiffs, idx];
end
if (ischar(chksum1_details.InterfaceChecksumItems(idx).Value))
if (~strcmp(chksum1_details.InterfaceChecksumItems(idx).Value, ...
chksum2_details.InterfaceChecksumItems(idx).Value))
disp(['String values different for interface item ', num2str(idx)]);
idxForIDiffs=[idxForIDiffs, idx];
end
end
if (isnumeric(chksum1_details.InterfaceChecksumItems(idx).Value))
if (chksum1_details.InterfaceChecksumItems(idx).Value ~= ...
chksum2_details.InterfaceChecksumItems(idx).Value)
disp(['Numeric values different for interface item ', num2str(idx)]);
idxForIDiffs=[idxForIDiffs, idx];
end
end
endRun the script. The following example assumes you named the script check_details.
check_details String values different for contents item 64 String values different for contents item 75 String values different for contents item 81 String values different for interface item 46
The results indicate that differences exist for index items 64, 75, and 81 in the subsystem contents and for item 46 in the subsystem interfaces.
Use the returned index values to get the handle , identifier, and value details for each difference found.
chksum1_details.ContentsChecksumItems(64)
ans =
Handle: 'my_ssreuse/SS1/Lookup Table Output1'
Identifier: 'CompiledPortAliasedThruDataType'
Value: 'int8'
chksum2_details.ContentsChecksumItems(64)
ans =
Handle: 'my_ssreuse/SS2/Lookup Table Output1'
Identifier: 'CompiledPortAliasedThruDataType'
Value: 'double'
chksum1_details.ContentsChecksumItems(75)
ans =
Handle: 'my_ssreuse/SS1/Lookup Table'
Identifier: 'RunTimeParameter{'OutputValues'}.DataType'
Value: 'int8'
chksum2_details.ContentsChecksumItems(75)
ans =
Handle: 'my_ssreuse/SS2/Lookup Table'
Identifier: 'RunTimeParameter{'OutputValues'}.DataType'
Value: 'double'
chksum1_details.ContentsChecksumItems(81)
ans =
Handle: 'my_ssreuse/SS1/Lookup Table'
Identifier: 'OutDataTypeMode'
Value: 'int8'
chksum2_details.ContentsChecksumItems(81)
ans =
Handle: 'my_ssreuse/SS2/Lookup Table'
Identifier: 'OutDataTypeMode'
Value: 'Same as input'
chksum1_details.InterfaceChecksumItems(46)
ans =
Handle: 'my_ssreuse/SS1'
Identifier: 'CanonicalParameter(1).DataType'
Value: 'int8'
chksum2_details.InterfaceChecksumItems(46)
ans =
Handle: 'my_ssreuse/SS2'
Identifier: 'CanonicalParameter(1).DataType'
Value: 'double'As expected, the details identify the Lookup Table block and data type parameters as areas on which to focus for debugging a subsystem reuse issue.
Correct the problem by changing the output data type mode for the subsystems such that they match.
![]() | Creating Model Components | Supporting Shared Utility Directories in the Build Process | ![]() |

Learn more about Simulink through this collection of videos, articles, technical literature and the Getting Started with Simulink Guide.
| © 1984-2009- The MathWorks, Inc. - Site Help - Patents - Trademarks - Privacy Policy - Preventing Piracy - RSS |