Main Content

SIL and PIL Simulations

What Are SIL and PIL Simulations?

With Embedded Coder®, you can run software-in-the-loop (SIL) and processor-in-the-loop (PIL) simulations of your model. These simulations generate source code for either the top model or part of the model. A SIL simulation compiles and runs the generated code on your development computer. A PIL simulation cross-compiles source code on your development computer, and then downloads and runs the object code on a target processor or an equivalent instruction set simulator.

With SIL and PIL simulations, you can:

  • Test whether your model and generated code are numerically equivalent.

  • Observe code coverage.

  • Perform code execution profiling.

Why Use SIL and PIL

Through SIL and PIL, you can early on test and fix defects. For example, you can model and test a system component in normal mode. Then, you can reuse your test suites in a SIL or PIL simulation that runs compiled generated code. To check numerical equivalence, you compare normal and SIL or PIL simulation results. You do not have to leave the Simulink® environment to test generated code on a separate infrastructure.

This table describes situations where you can use SIL and PIL.

SituationUse
Test numerical equivalence between model and generated code by reusing test vectors developed for normal mode simulation to verify numerical output of generated (or legacy) code. See SIL/PIL Manager Verification Workflow and Test Two Simulations for Equivalence (Simulink Test)SIL and PIL

Collect metrics for generated code:

SIL and PIL
Achieve IEC 61508, IEC 62304, ISO 26262, or DO-178 certification. See IEC Certification Kit Reference Workflow Overview (IEC Certification Kit) and Testing of Outputs of Integration Process (DO Qualification Kit).SIL and PIL
Without target hardware, get a convenient alternative to PIL.SIL

With target hardware, for example, an evaluation board or instruction set simulator:

  • Verify behavior of target-specific code, for example, code replacement optimizations, and legacy code. See What Is Code Replacement? and What Is Code Replacement Customization?.

  • Optimize the execution speed and memory footprint of your code. In this table, see the information about collecting execution profiling and stack profiling metrics.

  • Investigate effects of compiler settings and optimizations, for example, deviation from ANSI® C overflow behavior.

Normal simulation techniques do not account for restrictions and requirements that the hardware imposes, such as limited memory resources or behavior of target-specific optimized code.


For information about running PIL simulations on specific targets, see Sample Custom Targets.

PIL

Note

The SIL and PIL simulation modes are not designed for the reduction of model simulation times. If you want to speed up the simulation of your model, use the rapid accelerator mode. For more information, see What Is Acceleration?.

How SIL and PIL Simulations Work

In a SIL or PIL simulation, code is generated for either the top model or part of the model. With SIL, this code is compiled for and executed on your development computer. With PIL, the code is cross-compiled for the target hardware and runs on the target processor.

Through a communication channel, Simulink sends stimulus signals to the code on your computer or target processor for each sample interval of the simulation.

  • For a top model, Simulink uses stimulus signals from the base or model workspace.

  • If you have designated only part of the model to simulate in SIL or PIL mode, then a part of the model remains in Simulink and code is not generated for this part of the model. Typically, you configure this part of the model to provide test vectors for the software executing on the hardware. This part of the model can represent other parts of the algorithm or the environment in which the algorithm operates.

When your computer or target processor receives signals from Simulink, the processor executes the SIL or PIL algorithm for one sample step. The SIL or PIL algorithm returns output signals calculated during this step to Simulink through a communication channel. One sample cycle of the simulation is complete, and Simulink proceeds to the next sample interval. The process keeps repeating itself and the simulation progresses. SIL and PIL simulations do not run in real time. In each sample period, Simulink and the object code exchange I/O data.

Comparison of SIL and PIL Simulations

Type of SIL or PIL SimulationWhat Happens in SIL SimulationWhat Happens in PIL Simulation

Specify through:

  • Top-model simulation mode

  • Model block Simulation mode parameter

  • Test behavior of generated source code on development computer. Simulation does not test code compiled for target hardware because code is compiled for the development computer (different compiler and different processor architecture than the target).

  • Generated production code compiled and executed on development computer as separate process, independent of MATLAB® process.

  • Execution is host/host and nonreal time.

  • Test object code that you intend to deploy in production on either real target hardware or an instruction set simulator.

  • On development computer, generated production code cross-compiled for target. Object code downloaded and executed on target processor or instruction set simulator.

  • Execution is host/target and nonreal time.

Use SIL or PIL block created from subsystem.
  • Simulation runs compiled object code through S-function. S-function communicates with object code executing as standalone application on development computer. SIL block execution is independent of the MATLAB process.

  • Execution is host/host and nonreal time.

  • Simulation runs cross-compiled object code through S-function on development computer. S-function communicates with object code executing as standalone application on target processor or instruction set simulator.

  • Execution is host/target and nonreal time.

Code Interfaces for SIL and PIL

You generate standalone code when you perform, for example, a top-model or right-click subsystem build for a single deployable component. You can compile and link standalone code into a standalone executable or integrate it with other code. For more information on the standalone code interface, see Configure C Code Generation for Model Entry-Point Functions.

When you generate code for a referenced model hierarchy, the software generates standalone executable code for the top model and a library module called a model reference target for each referenced model. When the code executes, the standalone executable invokes the applicable model reference targets to compute the referenced model outputs. For more information, see Build Model Reference Targets.

To integrate generated code with legacy code, use standalone code because the standalone code interface is documented.

Note

SIL and PIL simulations do not provide direct support for custom code interfaces. You can incorporate these interfaces into Simulink as an S-function, for example, using the Legacy Code Tool, S-Function Builder, or handwritten code. Then, you can verify the custom code by using SIL and PIL simulations.

This table provides the interfaces that SIL and PIL simulations generate.

SIL/PIL SimulationCode Interface
Top-model

SIL/PIL simulation generates the standalone code interface. If code exists, simulation calls standalone code for the model . If code does not exist, simulation generates standalone code.

Model block

If you set Code interface block parameter to Top model, SIL/PIL simulation generates standalone code interface. Simulation calls standalone code for the model if it exists. Otherwise, simulation generates standalone code by using slbuild('model') command.

If you set Code interface block parameter to Model reference, SIL/PIL simulation generates model reference code interface. Simulation calls model reference target for Model block if it exists. Otherwise, simulation generates model reference target by using slbuild('model', 'ModelReferenceCoderTargetOnly') command.

SIL or PIL blockBlock uses standalone code interface.

Scheduling Considerations

ItemInformation
Algebraic loops

There are algebraic loops that occur in SIL and PIL simulations but not in normal mode simulations:

  • Single output/update function in code generation optimization can introduce algebraic loops because the option introduces direct feedthrough via a combined output and update function.

    Single output/update function is not compatible with Minimize algebraic loop occurrences (in the Subsystem Parameters dialog box and Configuration Parameters > Model Referencing pane). Minimize algebraic loop occurrences allows code generation to remove algebraic loops by partitioning generated code between output and update functions to avoid direct feedthrough.

  • If you generate code for a virtual subsystem, code generation treats the subsystem as atomic and generates the code accordingly. The resulting code can change the execution behavior of your model, for example, by applying algebraic loops, and introduce inconsistencies to the simulation behavior.

    To enable consistent simulation and execution behavior for your model, declare virtual subsystems as atomic subsystems.

For more information, see:

Exported functions in feedback loops

If your model has function-call subsystems and you export a subsystem that has context-dependent inputs (for example, feedback signals), the results of a SIL/PIL simulation with the generated code and the results of the normal mode simulation of your model can differ. One approach to make SIL/PIL and normal mode simulations yield identical results is to use Function-Call Feedback Latch blocks in your model. You can make context-dependent inputs become context-independent.

Embedded Coder generates a warning identifying context-dependent inputs of exported function-call subsystems if you set the Context-dependent inputsconfiguration parameter to one of the following:

  • Enable all as warnings

  • Use local settings

  • Disable all

For more information, see:

Imported Data and Function Definitions

Imported Data

In SIL and PIL simulations, you can use signals, parameters, and data stores that specify storage classes with imported data definitions. The simulations define storage for imported data associated with:

  • Signals at the root level of the component (on the I/O boundary).

  • Parameters in the base workspace or a data dictionary. For parameters in the model workspace:

    • Top-model SIL/PIL and SIL/PIL block simulations define storage.

    • Model block SIL/PIL simulations do not define storage. You must define storage and specify initial values that match MATLAB values.

  • Global data stores.

SIL and PIL simulations do not define storage for other imported data. For example, the simulations do not define storage for imported data associated with:

  • Internal signals (not on the I/O boundary)

  • Local data stores

In these cases, define the storage through custom code included by the component under test or through the PIL rtw.pil.RtIOStreamApplicationFramework API.

See also Tunable Parameters and SIL/PIL.

GetSet Custom Storage Class

SIL and PIL simulations support the GetSet custom storage class. The SIL/PIL test harness provides C definitions of the Get and Set functions that are used during simulations. For more information, see Access Data Through Functions with Storage Class GetSet.

Custom Storage Class of Type Other

To enable SIL and PIL support for the custom storage class where Type is set to Other , create a custom attributes class for the custom storage class and associate the custom attributes class with a Boolean property, SupportSILPIL, set to true.

classdef CSCOtherAttributes < Simulink.CustomStorageClassAttributes
  properties(PropertyType = 'logical scalar')
    SupportSILPIL = true;
  end
end

For more information about custom attributes, see Further Customize Generated Code by Writing TLC Code and Finely Control Data Representation by Writing TLC Code for a Storage Class.

To build the SIL or PIL application interface, the code generator calls the DataAccess and ClassAccess functions in the associated custom TLC file to get required information. The code generator stores the extracted information in build artifacts in the build folder.

For a custom storage class that is not grouped:

  • The code generator calls DataAccess with the request argument taking values of define, declare, layout, contents, address, or set.

  • The code generator uses the string returned by DataAccess(record, "define", "", "") to define the variable in the SIL or PIL application if one of these is true:

    • The signal or parameter has an Imported data scope.

    • The model uses a model reference code interface.

    • The model uses a top model code interface, EnableDataOwnership is on, and the Owner attribute for the custom storage class is not empty and not equal to the name of the current model

  • The code generator uses the string returned by DataAccess(record, "declare", "", "") to declare the variable in the SIL or PIL application if the following are true:

    • The model uses a top model code interface.

    • The signal or parameter uses an Exported storage class.

    • EnableDataOwnership is off, or EnableDataOwnership is on and the Owner attribute for the custom storage class is empty or equal to the model name.

    • Code packaging is configured so that the variable is not declared in model.h or a header file that is included by model.h

For a custom storage class that is grouped:

  • The code generator calls DataAccess with the request argument taking values of layout, address, or set.

  • The code generator calls ClassAccess with the request argument taking the value of groupTypeDeclDefn.

  • You must provide the grouped type (struct) definition and the extern declaration of the grouped variable if one of these is true:

    • The signal or parameter has an Imported data scope.

    • The model uses a model reference code interface.

    • The model uses a top model code interface, EnableDataOwnership is on, and the Owner attribute for the custom storage class is not empty and not equal to the name of the current model

    Provide the definition and declaration in a header file associated with the custom storage class by using the HeaderFile attribute or custom code that you include through the model.h file. To define the variable in the SIL or PIL application, the code generator uses the string returned by ClassAccess(record, "groupTypeDeclDefn").

  • Static initialization can assume an order of struct elements that is different from the order that is generated if the data scope is Exported. When the code generator queries ClassAccess(record, "groupTypeDeclDefn"), it temporarily overrides the data initialization attribute of the custom storage class with the value None.

To determine whether the SIL or PIL application can access the variable in the code by address, the code generator uses the elements returned by DataAccess(record, "layout", "", ""). To create the functionality in the application that transfers input or output port, tunable parameter, or global data store memory values between the development computer and target hardware, the code generator uses the output from:

  • DataAccess(record, "address", idx, reim) if the first returned element is scalar, vector, row-mat, or col-mat.

  • DataAccess(record, "contents", idx, reim) (or DataAccess(record, "set", idx, reim)) if the first returned element is other.

The code generator assumes that for row-mat and col-mat, matrices are stored in row-major format respectively. The assumption is independent of the array layout for the rest of the model. The code generator assumes that if the array layout of the storage implemented by the custom storage class differs from the rest of the model, the TLC file associated with the custom storage file performs the required transformations.

You can construct the custom TLC file associated with a custom storage class of type Other to perform other functions (in addition to returning the requested code fragments). For example, write directly to a custom file or call MATLAB functions that change the state of the base workspace. If you do not always want to execute these functions when DataAccess or ClassAccess are called, use the LibIsAccessingCustomDataForSILPIL(record) TLC function to distinguish between target code generation and requests for code fragments for the construction of the SIL or PIL application. For example:

...
%case "contents"
  %if !LibIsAccessingCustomDataForSILPIL(record)
    %matlab functionWithSideEffects()
  %endif
%return LibDefaultCustomStorageContents(record, idx, reim)
...

See also Other custom storage class limitations.

AUTOSAR Runtime Environment

You can use top-model and Model block SIL/PIL and SIL/PIL block simulations to perform model-based testing of an AUTOSAR software component. The software links generated code for the AUTOSAR software component with a basic component-specific AUTOSAR Runtime Environment (RTE) to create a test application. This application tests AUTOSAR API calls made by the AUTOSAR software component.

For a top-level AUTOSAR software component that contains referenced models, you can run top-model or Model block (Code interface set to Top model) SIL or PIL simulations. In the simulations, the software:

  • Before compilation of referenced models, generates AUTOSAR RTE header files.

  • Provides the RTE include path for referenced model compilation.

You can also run Model block (Code interface set to Model reference) SIL or PIL simulations for a referenced model within the top-level AUTOSAR SWC. In this case, before you run a simulation, you must build the parent component to generate the RTE header files. If you do not build the parent component, the SIL or PIL simulation fails.

Related Topics