You can reduce the amount of code that the code generator produces for identical
atomic subsystems by configuring the subsystems as reusable functions that pass data
as arguments (for example, rtB_*
for block input and output,
rtDW_*
for continuous states, and
rtP_*
for parameters) . By default, the code generator
produces subsystem code that communicates with other code by sharing access to
global data structures that reside in shared memory. By passing data as arguments,
the code can be reentrant. Each instance of the code maintains its own unique
data.
To configure subsystems for reusability and reentrancy, configure mask and block parameters of the identical subsystems the same way. The code generator performs a checksum to determine whether subsystems are identical and whether the code is reusable. If the code is reusable, the code generator produces a single instance of reusable, reentrant function code.
To configure the subsystem block parameters:
If a subsystem is virtual, select block parameter Treat as atomic unit to enable function packaging parameters.
Set block parameter Function packaging to
Reusable function
. The code
generator produces a separate function with arguments for each
subsystem. Selecting Reusable function
also enables additional parameters that you can use to control the
names of the function and file that the code generator produces for
the subsystem code.
Select a value for block parameter Function name options. To generate reusable, reentrant code, specify the same setting for identical subsystems.
To let the code generator determine the function name,
select Auto
.
To use the subsystem name or, for a library block, the
name of the library block, select Use
subsystem name
.
To display block parameter Function name and enter
a unique, valid C/C++ function name, select
User specified
.
If multiple instances of an identical subsystem exist within a model
reference hierarchy, select Auto
.
If you are using Embedded Coder®, you can use identifier format controls. See Identifier Format Control.
Set File name options. To generate reusable, reentrant code, specify the same setting for identical subsystems.
To let the code generator determine file naming select
Auto
.
To use the subsystem name or, for a library block, the
name of the library block select Use
subsystem name
.
To use the function name, as specified by block
parameter Function name options
select Use function
name
.
To display block parameter File name (no extension) and enter
a file name, excluding the extension (for example,
.c
or .cpp
)
select User
specified
.
Other considerations:
If multiple instances of an identical subsystem exist
within a model reference hierarchy, select
Auto
.
If the code generator does not generate a separate
file for a subsystem, the function code is placed in
the file generated from the subsystem's parent
system. If the parent is the model itself, the code
generator places the function code in
or
model
.c
.model
.cpp
If your generated code is under source control,
specify a value other than
Auto
. This
specification prevents the generated file name from
changing when you modify and rebuild the
model.
If you select Use subsystem
name
, the code generator mangles the
subsystem file name if the model contains Model
blocks, or if a model reference target is being
generated for the model. In these situations, the
code generator uses the file name
model
subsystem
.c
.
If subsystem A has mask parameter b
and K
and
subsystem B has mask parameters c
and K
, code
reuse is not possible. The code generator produces separate functions for subsystems
A and B. If you set block parameters for subsystems A and B differently, code reuse
is not possible.
This example shows how to configure an atomic subsystem for generating reusable code. To specify that the code generated for a subsystem execute as an atomic unit, on the Block Parameters dialog box, select the Treat as atomic unit parameter . That parameter enables the Function Packaging parameter on the Code Generation tab. The Function Packaging parameter has these four settings:
Inline
: Inline the subsystem code
Nonreusable function
: Function with I/O passed as global data
Reusable function
: Function with I/O passed as function arguments
Auto
: Let Simulink Coder optimize based on context
The Reusable function
and Auto
settings permit the code generator to reuse subsystem code. The Reusable function
and Nonreusable function
settings enable the Function name options, Function name, and File name options parameters.
If you have an Embedded Coder license, you can configure a nonreusable subsystem to accept arguments.
Example Model
The rtwdemo_ssreuse
model contains two identical subsystems, SS1
and SS2
. For these subsystems, the Function packaging parameter is set to Reusable
function
, and the Function name parameter is myfun
. The subsystems are parameterized masked subsystems. To see the contents of the masked subsystems, right-click the subsystem blocks and select Mask > Look Under Mask.
model = 'rtwdemo_ssreuse';
open_system(model);
Generate and Inspect Code
Create a temporary folder for the build and inspection process. Open the Simulink Coder or Embedded Coder app. Then, generate and inspect the code.
currentDir=pwd; [~,cgDir]=rtwdemodir(); rtwbuild(model)
### Starting build procedure for: rtwdemo_ssreuse ### Successful completion of build procedure for: rtwdemo_ssreuse Build Summary Top model targets built: Model Action Rebuild Reason ================================================================================================ rtwdemo_ssreuse Code generated and compiled Code generation information file does not exist. 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 8.63s
cfile=fullfile(cgDir, 'rtwdemo_ssreuse_grt_rtw', 'rtwdemo_ssreuse.c'); rtwdemodbtype(cfile, '/* Model step', '/* Model initialize', 1, 0);
/* Model step function */ void rtwdemo_ssreuse_step(void) { /* Outputs for Atomic SubSystem: '<Root>/SS1' */ /* Inport: '<Root>/In1' incorporates: * Inport: '<Root>/In2' */ myfun(rtwdemo_ssreuse_U.In1, rtwdemo_ssreuse_U.In2, &rtwdemo_ssreuse_B.SS1, rtwdemo_ssreuse_P.T1Data, rtwdemo_ssreuse_P.T1Break); /* End of Outputs for SubSystem: '<Root>/SS1' */ /* Outport: '<Root>/Out1' */ rtwdemo_ssreuse_Y.Out1 = rtwdemo_ssreuse_B.SS1.LookupTable; /* Outputs for Atomic SubSystem: '<Root>/SS2' */ /* Inport: '<Root>/In1' incorporates: * Inport: '<Root>/In2' */ myfun(rtwdemo_ssreuse_U.In1, rtwdemo_ssreuse_U.In2, &rtwdemo_ssreuse_B.SS2, rtwdemo_ssreuse_P.T2Data, rtwdemo_ssreuse_P.T2Break); /* End of Outputs for SubSystem: '<Root>/SS2' */ /* Outport: '<Root>/Out2' */ rtwdemo_ssreuse_Y.Out2 = rtwdemo_ssreuse_B.SS2.LookupTable; }
In the model step function, there are two calls to the reusable function, myfun
. The mask parameters, T1Break
, T1Data
, T2Break
, and T2Data
, are function arguments.
Change the Function Packaging parameter to Inline
.
set_param('rtwdemo_ssreuse/SS1','RTWSystemCode','Inline') set_param('rtwdemo_ssreuse/SS2','RTWSystemCode','Inline')
Generate and inspect the code.
rtwbuild(model)
### Starting build procedure for: rtwdemo_ssreuse ### Successful completion of build procedure for: rtwdemo_ssreuse Build Summary Top model targets built: Model Action Rebuild Reason =============================================================================== rtwdemo_ssreuse Code generated and compiled Generated code was out of date. 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 5.4929s
cfile=fullfile(cgDir, 'rtwdemo_ssreuse_grt_rtw', 'rtwdemo_ssreuse.c'); rtwdemodbtype(cfile, '/* Model step', '/* Model initialize', 1, 0);
/* Model step function */ void rtwdemo_ssreuse_step(void) { real_T Out1_tmp; /* Outputs for Atomic SubSystem: '<Root>/SS2' */ /* Outputs for Atomic SubSystem: '<Root>/SS1' */ /* Sum: '<S1>/Sum' incorporates: * Inport: '<Root>/In1' * Inport: '<Root>/In2' * Sum: '<S2>/Sum' */ Out1_tmp = rtwdemo_ssreuse_U.In1 + rtwdemo_ssreuse_U.In2; /* End of Outputs for SubSystem: '<Root>/SS2' */ /* Outport: '<Root>/Out1' incorporates: * Lookup_n-D: '<S1>/Lookup Table' * Sum: '<S1>/Sum' */ rtwdemo_ssreuse_Y.Out1 = look1_binlx(Out1_tmp, rtwdemo_ssreuse_P.T1Break, rtwdemo_ssreuse_P.T1Data, 10U); /* End of Outputs for SubSystem: '<Root>/SS1' */ /* Outputs for Atomic SubSystem: '<Root>/SS2' */ /* Outport: '<Root>/Out2' incorporates: * Lookup_n-D: '<S2>/Lookup Table' */ rtwdemo_ssreuse_Y.Out2 = look1_binlx(Out1_tmp, rtwdemo_ssreuse_P.T2Break, rtwdemo_ssreuse_P.T2Data, 10U); /* End of Outputs for SubSystem: '<Root>/SS2' */ }
In the model step function, the subsystem code is inlined.
Change the Function Packaging parameter to Nonreusable function
. For SS2
, change the Function name parameter to myfun2
.
set_param('rtwdemo_ssreuse/SS1','RTWSystemCode','Nonreusable function') set_param('rtwdemo_ssreuse/SS2','RTWSystemCode','Nonreusable function') set_param('rtwdemo_ssreuse/SS2','RTWFcnName','myfun2')
Generate and inspect the code.
rtwbuild(model)
### Starting build procedure for: rtwdemo_ssreuse ### Successful completion of build procedure for: rtwdemo_ssreuse Build Summary Top model targets built: Model Action Rebuild Reason =============================================================================== rtwdemo_ssreuse Code generated and compiled Generated code was out of date. 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 5.5835s
cfile=fullfile(cgDir, 'rtwdemo_ssreuse_grt_rtw', 'rtwdemo_ssreuse.c'); rtwdemodbtype(cfile, '/* Model step', '/* Model initialize', 1, 0);
/* Model step function */ void rtwdemo_ssreuse_step(void) { /* Outputs for Atomic SubSystem: '<Root>/SS1' */ myfun(); /* End of Outputs for SubSystem: '<Root>/SS1' */ /* Outputs for Atomic SubSystem: '<Root>/SS2' */ myfun2(); /* End of Outputs for SubSystem: '<Root>/SS2' */ }
The model step function contains calls to the functions myfun
and myfun2
. These functions have a void-void interface.
Change the Function Packaging parameter to Auto
.
set_param('rtwdemo_ssreuse/SS1','RTWSystemCode','Auto') set_param('rtwdemo_ssreuse/SS2','RTWSystemCode','Auto')
For the auto
setting, Simulink Coder chooses the optimal format. For this model, the optimal format is a reusable function.
Close the model and clean up.
bdclose(model) rtwdemoclean; cd(currentDir)
The code generator uses a checksum to determine whether subsystems are identical and reusable. Subsystem code is not reused if:
In blocks and data objects, you use symbols to specify dimensions.
A port has different sample times, data types, complexity, frame status, or dimensions across subsystems.
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 configured with a
custom storage class that is implemented in the C
code as nonaddressable memory (for example,
BitField
).
The input of a subsystem is nonscalar and is configured with a custom storage class that is implemented in the C code as nonaddressable memory.
A masked subsystem has a parameter that is nonscalar and is configured with a custom storage class that is implemented in the C code as nonaddressable memory.
A function-call subsystem uses mask parameters
when you set the model configuration parameter
Default parameter behavior to
Tunable
. To reuse the
masked function-call subsystem, place it inside a
new atomic subsystem without a mask. Then move the
Trigger block from the masked subsystem into the
atomic subsystem.
A block in a subsystem uses a partially tunable expression. Some partially tunable expressions disable code reuse.
Partially tunable expressions are expressions
that contain one or more tunable variables and an
expression that is not tunable. For example,
suppose that you create the tunable variable
K
with value
15.23
and the tunable variable
P
with value
[5;7;9]
. The expression
K+P'
is a partially tunable
expression because the expression
P'
is not tunable. For more
information about tunable expression limitations,
see Tunable Expression Limitations.
For subsystems that contain S-function blocks that are reusable, the blocks must meet the requirements listed in S-Functions That Support Code Reuse.
If you select
Reusable function
, and
the code generator determines that you cannot reuse the code
for a subsystem, it generates a separate function that is
not reused. The code generation report might show that the
separate function is reusable, even if only one subsystem
uses it. If you prefer that the code generator inline
subsystem code in such cases (rather than deployed as
functions), set Function packaging to
Auto
.
If a reusable subsystem uses a shared local data store and you
configure default mapping for model data elements, leave the
default storage class mapping for category Shared
local data stores set to
Default
.
Use of these blocks in a subsystem can prevent the subsystem code from being reused:
Scope blocks (with data logging enabled)
S-Function blocks that fail to meet certain criteria (see S-Functions That Support Code Reuse)
To File blocks (with data logging enabled)
To Workspace blocks (with data logging enabled)
For reusable library subsystems (subsystems shared across
reference models), the code generator uses a checksum to
determine whether subsystems are identical. The code
generator places the reusable library subsystem code in the
shared utilities folder, and the reusable code is
independent of the generated code of the top model or the
reference model. For example, the reusable library subsystem
code does not include
or
model
.h
.model
_types.h
Reusable code that the code generator places in the shared utilities folder and is dependent on the model code does not compile. If the code generator determines that the reusable library subsystem code is dependent on the model code, the reusable subsystem code is not placed in the shared utilities folder. The code generator produces code that is dependent on the model code when the reusable library subsystem:
Contains a block that uses time-related functionality, such as a Step block, or continuous time or multirate blocks.
Contains one or more Model blocks.
Contains a subsystem that is not inlined or a reusable library subsystem.
Contains a signal that is not configured with
storage class Auto
. The code
generator places variables that are configured
with a non-Auto
storage class
in
.model
.h
Contains a parameter that is not configure
with storage class Auto
.
Contains a user-defined storage class like
Enumeration, Simulink.Signal, Simulink.Parameter,
and so on where Data Scope is
not set to Exported
.
The code generator might place the type definition
in
.model
_types.h
Is a variant subsystem that generates
preprocessor conditionals. The code generator
places preprocessor directives that define the
variant objects in
model
_types.h
The above limitations also apply for library-based code generation. For more information, see Library-Based Code Generation for Reusable Library Subsystems.