| Contents | Index |
| On this page… |
|---|
Reusable Code and Referenced Models Generate Reusable Code from Stateflow Charts Generate 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 Simulink Coder 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 Subsystems. However, the following restrictions apply to such builds:
A top model that uses single-tasking mode and that has a submodel that uses multi-tasking mode executes properly for blocks with the different rates that are not connected. However, you get an error if the blocks with different rates are connected by Rate Transition block (inserted either manually or by Simulink).
ERT S-functions do not support subsystems that contain a continuous sample time.
The Simulink Coder 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 Automate 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
Go to the Code Generation tab and set Function packaging 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 Simulink Coder 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 folder), 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 for 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 fixed-size 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 Write S-Functions That Support Code Reuse for the list of requirements.
When you select the Reusable function option, two additional options are enabled, Function name options and File name options. See 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 Simulink Coder software to be able to reuse the subsystem code.
Subsystem Reusable Function Code Generation Option

To request that the Simulink Coder 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 Subsystem parameters from the menu.
If the subsystem is virtual, select Treat as atomic unit. On the Code Generation tab, the Function packaging menu becomes enabled.
If the system is already nonvirtual, the Function packaging menu is already enabled.
Go to the Code Generation tab and select Reusable function from the Function packaging 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 Function name options parameter, as described in Function Name Options Menu.
If you do not choose Auto for the Function name options parameter, 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 File name options parameter value other than Auto (options are described in 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 Simulink Coder 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 Simulink Coder 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 Function packaging 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 (see Write S-Functions That Support Code Reuse)
To File blocks (with data logging enabled)
To Workspace blocks (with data logging enabled)
Due to the limitations noted in Code Reuse Limitations, the Simulink Coder 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 Simulink Coder 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 Generate an HTML Code Generation 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 Simulink Coder 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 Function packaging 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 folder 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 =
0In 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.
Fix the problem by changing the output data type mode for the subsystems such that they match.
![]() | Referenced Models | Combined Models | ![]() |

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