Code Generation for Variant Blocks
The code generator produces code from a Simulink® model containing one or more Variant Subsystem, Variant Model, Variant Source, and Variant Sink blocks. To learn how to create a model containing variant blocks, see Create a Simple Variant Model. To learn how to create a custom Model Advisor check that evaluates the generated code from active and inactive variant paths in a variant system model, see Create Custom Check to Evaluate Active and Inactive Variant Paths from a Model (Simulink Check).
Note
During code generation, a warning related to 'Code generation function packaging' for
the Variant block might be displayed. In the block parameters dialog of the Variant block,
click Code Generation and then select Reusable
function
from the Function packaging drop-down list
to solve this issue.
Code is generated for different variant choices, the active variant, and the default variant. To generate code for variants, set the following conditions in the Variant Subsystem, Variant Source, or Variant Sink block:
Select
Expression
as Variant control mode.Select
code compile
as Variant activation time.
Code generated for Variant Subsystem blocks is surrounded by
C preprocessor conditionals #if
, #else
, #elif
,
and #endif
. Code generated for Variant Source and
Variant Sink blocks is surrounded by C preprocessor conditionals #if
and #endif
.
Therefore, the active variant is selected at compile time and the
preprocessor conditionals determine which sections of the code to
execute.
To construct variant models and generate preprocessor directives in the generated code, see the example Use Variant Models to Generate Code That Uses C Preprocessor Conditionals.
To construct variant subsystems and generate preprocessor directives in the generated code, see the example Use Variant Subsystem to Generate Code That Uses C Preprocessor Conditionals.
To construct models with variant sources and sinks and generate preprocessor directives in the generated code, see the example Represent Variant Source and Sink Blocks in Generated Code.
Restrictions on Variant Subsystem Code Generation
To generate preprocessor conditionals, the types of blocks that
you can place within the child subsystems of a Variant Subsystem block
are limited. Connections are not allowed in the Variant Subsystem
block diagram. However, during the code generation process, one VariantMerge
block
is placed at the input of each Outport block within
the Variant Subsystem block diagram. All
of the child subsystems connect to each of the VariantMerge
blocks.
In the figure below, the code generation process makes the following connections and adds
VariantMerge
blocks to the sldemo_variant_subsystems
model.
When compared to a generic Merge block the VariantMerge
block
can have only one parameter which is the number of Inputs. The VariantMerge
block
is used for code generation in variant subsystems internally, and
is not available externally to be used in models. The number of inputs
for VariantMerge
is determined and wired as shown
in the figure below.
The child subsystems of the Variant Subsystem block must be
atomic subsystems. Select Treat as atomic unit parameter
in the Subsystem block parameters dialog, to make the subsystems atomic.
The VariantMerge
blocks are inserted at the outport
of the subsystems if more than one child subsystems are present. If
the source block of a VariantMerge
block input
is nonvirtual, an error message will be displayed during code generation. You
must make the source block contiguous, by inserting Signal Conversion
blocks inside the variant choices. The signals that enter a Variant
Subsystem block must have the same signal properties (for example,
signal dimensions, port width, and storage class). The VariantMerge
block
does not support different signal properties because the input ports
and output ports share the same memory. You can use symbolic dimensions
to generate code for a variant subsystem with child subsystems of
different output signal dimensions.
Generated Code Components Not Compiled Conditionally
The following components are not conditionally compiled even if only code for variant subsystems or models that are conditionally compiled reference them.
rtModel
data structure fields#include
's of utility filesGlobal constant parameter structure fields that are referenced by multiple subsystems activated by different variants
Parameters that are configured to use an imported, exported, or custom code generation storage class, and are referenced by multiple subsystems that are activated by different variants
Parameters that are configured to use an imported, exported, or custom code generation storage class, and are used by variant model blocks
Code Generation for Variant Blocks with One Variant Choice
For modeling patterns in which a Root Inport block connects
to a Variant block with one variant choice, Simulink inserts a hidden
block combination of a Ground block, Signal Conversion block, and
a Variant Merge block. If the variant choice evaluates to false, this
block combination produces an output of 0.0
.
For example, the model Varianttoground
contains
a Variant Source block with one variant choice. When the Variant Control SYSCONST_A==6
evaluates
to true, the input to Subsystem
is a sine wave.
When SYSCONST_A==6
evaluates to false, the input
to Subsystem
is 0.0
.
The varianttoground.c
file contains this
code:
* Sin: '<Root>/Sine Wave' incorporates: * SignalConversion generated from: '<Root>/Subsystem' */ #if SYSCONST_A == 6 Varianttoground_B.VM_Conditional_Signal_Subsystem_0 = sin (Varianttoground_M->Timing.t[0]); #else /* SignalConversion generated from: '<Root>/Subsystem' */ Varianttoground_B.VM_Conditional_Signal_Subsystem_0 = 0.0; #endif /* End of Sin: '<Root>/Sine Wave' */
The comments in the generated code indicate the presence of the hidden signal conversion block. In the hyperlinked comments, you can trace to the original block in the model that triggered the insertion of the hidden block. The code does not contain a comment for the Variant Merge block because this block does not have associated generated code. The Variant Merge block is used internally and is not in the Simulink library.
Global Data Guarding: Signals and States
When a model has variant blocks, the global signals and states are guarded in the generated code with their corresponding variant condition.
Consider a model containing a Variant Source block. The Variant
Source block has conditions V==1
and
V==2
.
In the generated code, global signals are guarded in declaration, model initialization, and definition of data as shown below.
Signals guarding:
Declaration:
/* Exported block signals */ #if V == 1 || V == 2 real_T myOutput; /* '<Root>/Gain3' */ #endif
Model initialization:
/* exported global signals */ #if V == 1 || V == 2 myOutput = 0.0; #endif
Definition of data:
* Exported Global Signals * * Note: Exported global signals are block signals with an exported global * storage class designation. Code generation will declare the memory for * these signals and export their symbols. * */ #if V == 1 || V == 2 extern real_T myOutput; /* '<Root>/Gain3' */ #endif
Global Data Guarding: Parameters
When you generate code for a model containing variant blocks, the parameters are guarded in the generated code.
Consider a model with Constant block attached to a Variant Source block.
In the generated code, the parameter of the Constant block is guarded in header file as shown below.
/* Exported data definition */ /* Const memory section */ /* Definition for custom storage class: Const */ #if V == 2 const int32_T Parameter2 = 1; #endif
Guarding Reference Model Headers
When a model has Model Reference blocks that are conditional due to inline variants, the header file and the instances referring to the Model Reference blocks are guarded.
Consider this model with two Model References blocks that are conditional due to inline variants.
When you generate code for this model, the header file and instances referring to the Model Reference blocks are guarded as shown in the code below.
#include "mWithTwoModelBlocks_Top_types.h" #include "multiword_types.h" #if (A == 1) //Guarding #define mWithTwoModelBlocks_Ref2_MDLREF_HIDE_CHILD_ #include "mWithTwoModelBlocks_Ref2.h" #endif #if (B == 1) //Guarding #include "mWithTwoModelBlocks_Ref1.h" #endif
Guarding S-Function Block Headers
When a model has an S-Function block that is conditional due to any connected variant blocks, Simulink guards the header files associated with the S-Function block with the corresponding variant condition in the generated code.
Consider a model with an S-Function block connected to a Variant Source block. In the generated code, the header file is guarded with the variant condition.
#ifndef mSFunctionInclude_COMMON_INCLUDES_ #define mSFunctionInclude_COMMON_INCLUDES_ #include "rtwtypes.h" #include "rt_logging.h" #if V == 1 //Guarding #include "myHeader.h" #endif #endif /* mSFunctionInclude_COMMON_INCLUDES_ */