> Agent-readable docs index: /llms.txt. Download /docs.zip to grep all markdown files locally.

---
$schema: https://holocron.so/frontmatter.json
title: Execution Model
description: How RoboC++ schedules PLC scan cycles, configurations, tasks, and simulation traces.
icon: lucide:repeat
---

RoboC++ executes a **deterministic scan-cycle interpreter** for **Structured Text**, **Instruction List**, **textual SFC**, **native LD/FBD**, and programs lowered from **PLCopen XML**. Execution always runs after a successful `check` when invoked through the CLI.

## Program execution

When a file contains one or more **`PROGRAM`** POUs and no configuration is selected, `run` executes a single program:

```bash
cargo run -p rbcpp_cli -- run examples/counter.st --cycles 3
```

Use **`--program <name>`** when multiple programs exist in one project.

Each cycle runs the program body once, then snapshots variables for the trace. Trace variable names are **uppercased** from the internal canonical identifier form.

## Configuration execution

When a project defines **`CONFIGURATION`** elements, `run` can schedule program instances attached to tasks inside resources:

```bash
cargo run -p rbcpp_cli -- run examples/configuration.st --configuration Plant --cycles 2
```

If the project has configurations and you omit `--program`, the CLI prefers **configuration execution**.

Scheduling behavior:

* Instances are ordered by task **priority** (lower number runs first among instances due in the same cycle).
* A task **interval** (`T#10ms` or integer ms) skips cycles where `elapsed_ms % interval != 0`.
* A task **`SINGLE := <bool_expr>`** fires on the **rising edge** of a BOOL expression (event task). The expression must type-check as BOOL.
* Each scheduled instance maintains its own variable environment.
* **Program instance output bindings** copy POU outputs after a scan, for example `Producer(Count => ResourceObserved)` or `Producer(Count => Values[2])`.
* **Program instance initializers** can set inputs at bind time, for example `Demo(Count := 5)`.

See `examples/configuration.st` for `VAR_GLOBAL`, `VAR_CONFIG`, `VAR_ACCESS`, and task wiring.

### Shared direct locations

In configuration runs, **direct locations** such as **`%QX0.0`** use **configuration-level direct state**. One scheduled program can write a located output in its scan, and another program scheduled later in the same cycle (by task priority) can read that value. Globals, resource variables, access-path writes, and program-instance output bindings also persist across cycles within the same **`run`** invocation.

## Simulator timing (`RuntimeOptions`)

The CLI **`run`** command uses default **`RuntimeOptions`**:

| Field                        | Default | Role                                                        |
| ---------------------------- | ------- | ----------------------------------------------------------- |
| `max_scan_cycles`            | 10,000  | Hard stop per invocation (also an implementation parameter) |
| `max_loop_iterations`        | 10,000  | Cap on `FOR`/`WHILE`/`REPEAT`/`SFC` inner loops             |
| `cycle_time_ms`              | **1**   | Simulated milliseconds per scan cycle                       |
| `warm_restart_before_cycles` | `[]`    | Library-only warm restart hook points                       |

**`cycle_time_ms`** drives timer FB elapsed time, SFC timed qualifiers, and configuration task interval math (`elapsed_ms = cycle * cycle_time_ms`). The default is **1 ms per cycle**, not wall-clock time.

Generated C defines **`#define RBCPP_CYCLE_MS 1`** for timer and SFC elapsed increments unless your target overrides time through the **`time_ms`** hook. See [Targets and Generated C](/targets).

Library embedders can pass custom **`RuntimeOptions`** to **`run_program`** / **`run_configuration`** and their access-write or communication-hook variants.

## VAR\_ACCESS injection

**`VAR_ACCESS`** paths appear in simulator traces. Use **`--access`** on **`run`** to inject **`READ_WRITE`** writes during simulation:

```bash
cargo run -p rbcpp_cli -- run examples/configuration.st --configuration Plant --cycles 2 --access StartAccess=TRUE
cargo run -p rbcpp_cli -- run controller.st --cycles 2 --access PublicInput=TRUE --access 1:PublicSetpoint=42
```

| Form               | Meaning                           |
| ------------------ | --------------------------------- |
| `NAME=VALUE`       | Write on cycle 0 (default)        |
| `CYCLE:NAME=VALUE` | Write before the named scan cycle |

Supported value forms: **`TRUE`** / **`FALSE`**, integers, reals, `'STRING'`, and `"WSTRING"`.

Configuration **`READ_WRITE`** injection persists globals and resource state across scan cycles in the simulator. See [Types and variables](/types-and-variables) and [Targets and Generated C](/targets) for generated C and target-side bindings.

## Scan cycle limits

The default maximum cycle count is **10,000** per run (`iec_profile` implementation parameters). Exceeding it produces a `RBCPP-COMPLIANCE` diagnostic.

## JSON traces

Pass **`--json`** to `run` for machine-readable output.

**Program trace shape:**

```json
{
  "program": "CounterDemo",
  "cycles": [
    {
      "cycle": 0,
      "variables": [{ "name": "COUNT", "value": 1 }],
      "accessPaths": [
        {
          "name": "StartAccess",
          "target": "%MX0.0",
          "direction": "READ_WRITE",
          "value": true
        }
      ]
    }
  ]
}
```

**Configuration trace shape:**

```json
{
  "configuration": "Plant",
  "cycles": [
    {
      "cycle": 0,
      "programs": [
        {
          "resource": "Cpu",
          "instance": "Main",
          "program": "ConfiguredProgram",
          "variables": [{ "name": "COUNT", "value": 1 }],
          "accessPaths": []
        }
      ],
      "accessPaths": []
    }
  ]
}
```

Values serialize as JSON numbers, booleans, strings, arrays, or objects depending on the runtime **`Value`** representation. **`accessPaths`** mirror resolved **`VAR_ACCESS`** values when storage exists.

## Warm restart (runtime API)

The runtime supports re-initializing state before selected cycles (`warm_restart_before_cycles` in `RuntimeOptions`). **`RETAIN`** variables keep values across warm restart; `NON_RETAIN` and plain locals reset to initial values. Library callers can pass custom `RuntimeOptions`; the CLI always uses defaults and does not expose a warm-restart flag.

## Communication hooks (runtime API)

Standard communication FBs need a **`CommunicationHooks`** implementation at runtime. The CLI **`run`** command does not install hooks. Semantic checking warns that comm FB instances require a target runtime hook. Generated C exposes **`_set_comm_hook`** for deployment. See [Standard library](/standard-library).

## Related pages

* [CLI reference](/cli): `run` flags
* [Types and variables](/types-and-variables): `RETAIN` / `NON_RETAIN`
* [Examples](/examples): `configuration.st`, `counter.st`


---

*Powered by [holocron.so](https://holocron.so)*
