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 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 box, 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, the software inserts a hidden block combination of a
Ground block, Signal Conversion block, and 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 the header file.
/* Exported data definition */ /* Const memory section */ /* Definition for custom storage class: Const */ #if V == 2 const int32_T Parameter2 = 1; #endif
Guarding Referenced Model Headers
When a model has Model blocks that are conditional due to inline variants, the header file and the instances referring to the Model blocks are guarded.
Consider this model with two Model blocks that are conditional due to inline variants.
When you generate code for this model, the header file and instances referring to the Model blocks are guarded.
#include "mWithTwoModelBlocks_Top_types.h" #include "multiword_types.h" #if (A == 1) //Guarding #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, the software 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_ */