Main Content

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 files

  • Global 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.

Model blocks named mWithTwoModelBlocks_Ref2 and mWithTwoModelBlocks_Ref1 that reference different models, which both have 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.

S-Function block connected to a Variant Source block

#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_ */