Execution of Code Generated from a Model
The code generator produces algorithmic code as defined by your model. You can include external (for example, custom or legacy) code in a model by using techniques explained in Choose an External Code Integration Workflow.
The code generator also provides an interface that executes the generated model code. The interface and model code are compiled together to create an executable program. The next figure shows a high-level object-oriented view of the executable.
The Object-Oriented View of a Real-Time Program
In general, the conceptual design of the model execution driver does not change between the rapid prototyping and embedded style of generated code. The following sections describe model execution for single-tasking and multitasking environments both for simulation (non-real-time) and for real time. For most model code, the multitasking environment provides the most efficient model execution (that is, fastest sample rate).
The following concepts are useful in describing how model code executes.
- Initialization: - model_initialize
- ModelOutputs: Calls blocks in your model that have a sample hit at the current time and has them produce their output. - model_output
- ModelUpdate: - model_update
- ModelDerivatives: Calls blocks in your model that have continuous states and has them update their derivatives. - model_derivatives
- ModelTerminate: - model_terminate
Program Execution
The code generated from a model executes in the context of a target environment. A real-time program cannot require 100% of a the target system CPU time. This requirement provides the system an opportunity to run background tasks during the time the CPU does not spend on the real-time program. Background tasks include operations such as writing data to a buffer or file, allowing access to program data by third-party data monitoring tools, or updating program parameters. For a program to execute in real time, it is important that the program be able to preempt background tasks to run as required.
The way that a program manages its tasks depends on capabilities of the target environment in which it runs. In a real-time system, execution of code generated from a model can be done with the aid of a real-time operating system or on bare-metal target hardware, where the generated code runs in the context of an interrupt service routine (ISR). Unlike general-purpose multitasking operating systems, which are unable to guarantee hard real-time performance, real-time operating systems and ISR solutions on bare-metal hardware provide capabilities for handling context switching and task scheduling necessary to avoid missed deadlines.
In systems where one process can exist at a time, an ISR must save the processor context, execute the model code, collect data, and restore the processor context. Operating systems, such as POSIX-compliant systems, provide automatic context switching and task scheduling. This simplifies the operations performed by the ISR. In this case, the ISR enables execution of the model code as a task, which is normally blocked.
This figure shows this difference between program execution on a bare-metal system that uses an ISR and program execution that uses a real-time operating system primitive.
Program Timing
Real-time programs require careful timing of the task invocations (either by using an interrupt or a real-time operating system tasking primitive) so that the model code executes to completion before another task invocation occurs. The timing includes time to read and write data to and from external hardware.
Consider these scenarios that demonstrate the significance of the time interval configuration.
- In one scenario, the time interval between consecutive invocations is sufficient for the code to complete the execution. 
- In the other scenario, the time interval between consecutive invocations is insufficient for the code to complete the execution. 
This figure illustrates the interrupt timing scenarios.
Task Timing
The sample interval must be long enough to allow model code execution between task invocations.
In the figure above, the time between two adjacent vertical arrows is the sample interval. The empty boxes in the upper diagram show an example of a program that can complete one step within the interval and still allow time for the background task. The gray box in the lower diagram indicates what happens if the sample interval is too short. Another task invocation occurs before the task is complete. Such timing results in an execution error.
If the real-time program is designed to run forever (that is, the final time is 0 or infinite
        so that the while loop never exits), then
        the shutdown code does not execute.
For more information on how the timing engine works, see Timer Representation and Computation.
External Mode Communication
External mode allows communication between the Simulink® block diagram and the standalone program that is built from the generated code. In this mode, the real-time program functions as an interprocess communication server, responding to requests from the Simulink engine.
Data Logging in Single-Tasking and Multitasking Model Execution
Configure Model for Debugging explains how you can save system states,
        output, and time to a MAT-file or MDF file at the completion of the model execution. The
          LogTXY function, which performs data logging, operates differently in
        single-tasking and multitasking environments.
If you examine how LogTXY is called in the single-tasking and
        multitasking environments, notice that for single-tasking LogTXY is
        called after ModelOutputs. During this ModelOutputs
        call, blocks that have a hit at time t execute, whereas in
        multitasking, LogTXY is called after
          ModelOutputs(tid=0), which executes only the blocks that have a hit at
        time t and that have a task identifier of 0. This results in
        differences in the logged values between single-tasking and multitasking logging.
        Specifically, consider a model with two sample times, the faster sample time having a period
        of 1.0 second and the slower sample time having a period of 10.0 seconds. At time t = k*10,
        k=0,1,2... both the fast (tid=0) and slow (tid=1)
        blocks execute. When executing in multitasking mode, when LogTXY is
        called, the slow blocks execute, but the previous value is logged, whereas in single-tasking
        the current value is logged. 
Another difference occurs when logging data in an enabled subsystem. Consider an enabled subsystem that has a slow signal driving the enable port and fast blocks within the enabled subsystem. In this case, the evaluation of the enable signal occurs in a slow task, and the fast blocks see a delay of one sample period; thus the logged values will show these differences.
To summarize differences in logged data between single-tasking and multitasking, differences will be seen when
- A root outport block has a sample time that is slower than the fastest sample time 
- A block with states has a sample time that is slower than the fastest sample time 
- A block in an enabled subsystem where the signal driving the enable port is slower than the rate of the blocks in the enabled subsystem 
For the first two cases, even though the logged values are different between single-tasking and multitasking, the model results are not different. The only real difference is where (at what point in time) the logging is done. The third (enabled subsystem) case results in a delay that can be seen in a real-time environment.
Non-Real-Time Single-Tasking Systems
This pseudocode shows the execution of a model for a non-real-time single-tasking system.
main()
{
    Initialization
    While (time < final time)
        ModelOutputs              -- Major time step.
        LogTXY                    -- Log time, states and root outports.
        ModelUpdate               -- Major time step.
        Integrate                 -- Integration in minor time step for 
                                  -- models with continuous states.
            ModelDerivatives
            Do 0 or more
                ModelOutputs
                ModelDerivatives
            EndDo                 -- Number of iterations depends upon the solver
            Integrate derivatives to update continuous states.
        EndIntegrate
    EndWhile
    Termination
}
The initialization phase begins first. This consists of initializing model states and
        setting up the execution engine. The model then executes, one step at a time. First
          ModelOutputs executes at time t, then the
        workspace I/O data is logged, and then ModelUpdate updates the discrete
        states. Next, if your model has continuous states,
          ModelDerivatives integrates the continuous states' derivatives
        to generate the states for time , where h is the step size. Time then moves forward to  and the process repeats.
During the ModelOutputs and ModelUpdate phases
of model execution, only blocks that reach the current point in time
execute.
Non-Real-Time Multitasking Systems
This pseudocode shows the execution of a model for a non-real-time multitasking system.
main()
{
    Initialization
    While (time < final time)
        ModelOutputs(tid=0)        -- Major time step.
        LogTXY                     -- Log time, states, and root 
                                   -- outports.
        ModelUpdate(tid=0)         -- Major time step.
        Integrate                  -- Integration in minor time step for 
                                   -- models with continuous states.
            ModelDerivatives
            Do 0 or more
                ModelOutputs(tid=0)
                ModelDerivatives
            EndDo (Number of iterations depends upon the solver.)
            Integrate derivatives to update continuous states.
        EndIntegrate
        For i=1:NumTids
            ModelOutputs(tid=i)    -- Major time step.
            ModelUpdate(tid=i)     -- Major time step.
        EndFor
    EndWhile
    Termination
}
Multitasking operation is more complex than single-tasking execution because the output and
        update functions are subdivided by the task identifier
          (tid) that is passed into these functions. This allows for multiple
        invocations of these functions with different task identifiers using overlapped interrupts,
        or for multiple tasks when using a real-time operating system. In simulation, multiple tasks
        are emulated by executing the code in the order that would occur if preemption did not exist
        in a real-time system.
Multitasking execution assumes that  task rates are multiples of the base rate. The
          Simulink product enforces this when you create a fixed-step multitasking model. The
        multitasking execution loop is very similar to that of single-tasking, except for the use of
        the task identifier (tid) argument to ModelOutputs
        and ModelUpdate.
You cannot use tid values from code generated by a target file and
        not by Simulink
            Coder™. Simulink
            Coder tracks the use of tid when generating code for a specific
        subsystem or function type. When you generate code in a target file, this argument cannot be
        tracked because the scope does not have subsystem or function type. Therefore,
          tid becomes an undefined variable and your target file fails to
        compile.
Real-Time Single-Tasking Systems
This pseudocode shows the execution of a model in a real-time single-tasking system where the model is run at interrupt level.
rtOneStep()
{
    Check for interrupt overflow
    Enable "rtOneStep" interrupt
    ModelOutputs              -- Major time step.
    LogTXY                    -- Log time, states and root outports.
    ModelUpdate               -- Major time step.
    Integrate                 -- Integration in minor time step for models 
                              -- with continuous states.
          ModelDerivatives
          Do 0 or more 
              ModelOutputs
              ModelDerivatives
          EndDo (Number of iterations depends upon the solver.)
          Integrate derivatives to update continuous states.
    EndIntegrate
}
main()
{
    Initialization (including installation of rtOneStep as an 
    interrupt service routine, ISR, for a real-time clock).
    While(time < final time)
        Background task.
    EndWhile
    Mask interrupts (Disable rtOneStep from executing.)
    Complete any background tasks.
    Shutdown
}
Real-time single-tasking execution is very similar to non-real-time
single-tasking execution, except that instead of free-running the
code, the rt_OneStep function is driven by a
periodic timer interrupt.
At the interval specified by the program's base sample rate, the interrupt service routine (ISR) preempts the background task to execute the model code. The base sample rate is the fastest in the model. If the model has continuous blocks, then the integration step size determines the base sample rate.
For example, if the model code is a controller operating at 100 Hz, then every 0.01 seconds the background task is interrupted. During this interrupt, the controller reads its inputs from the analog-to-digital converter (ADC), calculates its outputs, writes these outputs to the digital-to-analog converter (DAC), and updates its states. Program control then returns to the background task. These steps must occur before the next interrupt.
Real-Time Multitasking Systems
This pseudocode shows how a model executes in a real-time multitasking system where the model is run at interrupt level.
rtOneStep()
{
    Check for interrupt overflow
    Enable "rtOneStep" interrupt
    ModelOutputs(tid=0)         -- Major time step.
    LogTXY                      -- Log time, states and root outports.
    ModelUpdate(tid=0)          -- Major time step.
    Integrate                   -- Integration in minor time step for 
                                -- models with continuous states.
          ModelDerivatives
          Do 0 or more
              ModelOutputs(tid=0)
              ModelDerivatives
          EndDo (Number of iterations depends upon the solver.)
          Integrate derivatives and update continuous states.
    EndIntegrate
    For i=1:NumTasks
        If (hit in task i)
            ModelOutputs(tid=i)
            ModelUpdate(tid=i)
        EndIf
    EndFor
}
main()
{
    Initialization (including installation of rtOneStep as an 
        interrupt service routine, ISR, for a real-time clock).
    While(time < final time)
        Background task.
    EndWhile
    Mask interrupts (Disable rtOneStep from executing.) 
    Complete any background tasks.
    Shutdown
}
Running models at interrupt level in a real-time multitasking environment is very similar to the previous single-tasking environment, except that overlapped interrupts are employed for concurrent execution of the tasks.
The execution of a model in a single-tasking or multitasking environment when using real-time operating system tasking primitives is very similar to the interrupt-level examples discussed above. The pseudocode below is for a single-tasking model using real-time tasking primitives.
tSingleRate()
{
    MainLoop:
        If clockSem already "given", then error out due to overflow.
        Wait on clockSem
        ModelOutputs             -- Major time step.
        LogTXY                   -- Log time, states and root 
                                 -- outports
        ModelUpdate              -- Major time step
        Integrate                -- Integration in minor time step 
                                 -- for models with continuous 
                                 -- states.
            ModelDeriviatives
            Do 0 or more
                ModelOutputs
                ModelDerivatives
            EndDo (Number of iterations depends upon the solver.)
            Integrate derivatives to update continuous states.
        EndIntegrate
    EndMainLoop
}
main()
{
    Initialization
    Start/spawn task "tSingleRate".
    Start clock that does a "semGive" on a clockSem semaphore.
    Wait on "model-running" semaphore.
    Shutdown
}
In this single-tasking environment, the model executes as real-time
operating system tasking primitives. In this environment, create a
single task (tSingleRate) to run the model code.
This task is invoked when a clock tick occurs. The clock tick gives
a clockSem (clock semaphore) to the model task
(tSingleRate). The model task waits for the semaphore
before executing. The clock ticks occur at the fundamental step size
(base rate) for your model.
Multitasking Systems Using Real-Time Tasking Primitives
This pseudocode is for a multitasking model using real-time tasking primitives.
tSubRate(subTaskSem,i)
{
    Loop:
        Wait on semaphore subTaskSem.
        ModelOutputs(tid=i)
        ModelUpdate(tid=i)
    EndLoop
}
tBaseRate()
{
    MainLoop:
        If clockSem already "given", then error out due to overflow.
        Wait on clockSem
        For i=1:NumTasks
            If (hit in task i)
                If task i is currently executing, then error out due to 
                    overflow.
                Do a "semGive" on subTaskSem for task i.
            EndIf
        EndFor
        ModelOutputs(tid=0)        -- major time step.
        LogTXY                     -- Log time, states and root outports.
        ModelUpdate(tid=0)         -- major time step.
        Loop:                      -- Integration in minor time step for 
                                   -- models with continuous states.
            ModelDeriviatives
            Do 0 or more
                ModelOutputs(tid=0)
                ModelDerivatives
            EndDo (number of iterations depends upon the solver).
            Integrate derivatives to update continuous states.
        EndLoop
    EndMainLoop
}
main()
{
    Initialization
    Start/spawn task "tSubRate".
    Start/spawn task "tBaseRate".
    Start clock that does a "semGive" on a clockSem semaphore.
    Wait on "model-running" semaphore.
    Shutdown
}
In this multitasking environment, the model is executed using
real-time operating system tasking primitives. Such environments require
several model tasks (tBaseRate and several tSubRate tasks)
to run the model code. The base rate task (tBaseRate)
has a higher priority than the subrate tasks. The subrate task for tid=1 has
a higher priority than the subrate task for tid=2,
and so on. The base rate task is invoked when a clock tick occurs.
The clock tick gives a clockSem to tBaseRate.
The first thing tBaseRate does is give semaphores
to the subtasks that have a hit at the current point in time. Because
the base rate task has a higher priority, it continues to execute.
Next it executes the fastest task (tid=0), consisting
of blocks in your model that have the fastest sample time. After this
execution, it resumes waiting for the clock semaphore. The clock ticks
are configured to occur at the fundamental step size for your model.
Rapid Prototyping and Embedded Model Execution Differences
The rapid prototyping program framework provides a common application programming interface (API) that does not change between model definitions.
The Embedded Coder® product provides a different framework called the embedded program framework. The embedded program framework provides an optimized API that is tailored to your model. When you use the embedded style of generated code, you are modeling how you would like your code to execute in your embedded system. Therefore, the definitions defined in your model should be specific to your embedded targets. Items such as the model name, parameter, and signal storage class are included as part of the API for the embedded style of code.
One major difference between the rapid prototyping and embedded
style of generated code is that the latter contains fewer entry-point
functions. The embedded style of code can be configured to have only
one  function, model_step
Thus, model execution code eliminates Loop...EndLoop statements and groups
          ModelOutputs, LogTXY, and
          ModelUpdate into a single statement,
            model_step
For more information about how generated embedded code executes, see Configure Generated C Function Interface for Model Entry-Point Functions.