Simatic Manager STL RLO: Debugging Logic State Errors

David Krause17 min read
S7-300SiemensTechnical Reference
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Overview of RLO Behavior in Siemens STL

The Result of Logic Operation (RLO) is the central boolean accumulator that propagates through every logical instruction within a single Statement List (STL) network on S7-300, S7-400, WinAC, and S7-1500 controllers programmed with STEP 7 (Simatic Manager) or TIA Portal. Unlike Ladder Diagram (LAD) or Function Block Diagram (FBD) editors, which insert implicit rung delimiters that reset the RLO between rungs, STL allows the programmer to chain multiple independent boolean operations in one network. The RLO, together with the First Check bit (FC), the OR status bit (OR), the Status bit (STA), and the Binary Result (BR) bit, forms the controller's status word. Understanding how each of these status bits evolves across instructions is essential to writing deterministic STL code that survives both the editor's display conventions and the CPU's scan order.

Subtle RLO leakage between adjacent statements has been a documented source of intermittent field failures for decades. A program may pass the in-house FAT, behave correctly in commissioning, and only misbehave when an upstream signal happens to be in a particular state. This article dissects the mechanism, reproduces a representative failure, identifies the root cause, and documents the three engineered workarounds (CLR instruction, network delimiters, and LAD/FBD translation) that are widely deployed in production STEP 7 code.

The Status Word: RLO, FC, OR, and STA

Every bit-logic instruction in STL reads and writes a defined subset of the CPU's status word. The relevant bits and their effect on the next instruction are summarised in the table below.

Status bit Mnemonic Set/reset by Effect on subsequent logic
Result of Logic Operation RLO Every A, AN, O, ON, X, XN, ), and any assignment Holds the current combined boolean result. Used as one of the two inputs of the next logic operation when FC=0.
First Check FC Set to 1 at the start of every network, after a ), and after CLR. Reset to 0 by every A/AN/O/ON/X/XN and by =, S, R. When FC=1 the next bit logic instruction performs a load (it overwrites the RLO). When FC=0 the next instruction combines its operand with the current RLO using the operator.
OR status OR Tracks the OR-accumulation across multiple AND terms Feeds the next O/ON instruction so that A terms joined by O produce a correct OR-of-ANDs result.
Status STA Always reflects the value of the last bit operand read Drives the bold/grey highlighting in the Simatic Manager online view.
Binary Result BR Set by FB/FC return paths and by some comparison/arithmetics Used by EN/ENO in FBD and by LAD/FBD consumers of STL blocks.

The critical invariant that causes most STL bugs is this: the assignment instruction "=" does not clear the RLO. It only resets FC to 0 and updates the target operand. The RLO remains exactly as it was before the "=" was executed. The next bit logic instruction therefore sees a non-zero RLO and a zero FC, which means it combines (AND/OR/XOR) its operand with the stale RLO instead of loading a fresh value.

Symptom: Live RLO Leakage into the Next Logic Group

The minimal failing pattern is two distinct logic groups placed in the same network, separated by an assignment that does not change the RLO:

A   M0.0
=   Q42.0          // Q42.0 := M0.0, RLO unchanged, FC := 0
A(
AN  M6.1
AN  M6.2
O   M7.0
)                  // "A(" should establish a new logic string
=   Q42.1          // Q42.1 expected := (NOT M6.1 AND NOT M6.2) OR M7.0

Observed behaviour on a fielded S7-314C-2 PN/DP running STEP 7 V5.5 + SP4 with the block compiled as FBD-equivalent STL: when M0.0 transitions 0→1 (Q42.0 follows), Q42.1 momentarily inverts from 1 to 0 for one OB1 cycle, even though M6.1, M6.2, and M7.0 are unchanged. The transition is reproducible on every M0.0 rising edge and is removed entirely by inserting a CLR between the two groups.

The expected boolean result for the parenthesis group is (NOT M6.1 AND NOT M6.2) OR M7.0. With M6.1=1, M6.2=1, M7.0=1, the parenthesis should evaluate to 1 and Q42.1 should remain 1. The fact that it falls to 0 for the duration of one scan confirms that the parenthesised expression is not being treated as an independent logic string.

Step-by-Step Reproduction in Simatic Manager

To reproduce the failure on a development station, perform the following steps in STEP 7 V5.5 or V5.6 with any S7-300, S7-400, or WinAC target:

  1. Create a new S7 Program under an S7-300 station, e.g. CPU 315-2 PN/DP (6ES7315-2EH14-0AB0) with firmware V3.3.
  2. Insert an OB1 and a new FC1 (void return, written in STL).
  3. Copy the six-line snippet above into FC1. Do not insert any network delimiters inside the block; keep all six lines in a single network.
  4. Open the VAT_1 symbol table and create a VAT with the symbols M0.0, M6.1, M6.2, M7.0, Q42.0, Q42.1 in Binary format.
  5. Download the hardware configuration and the blocks, then go online with the CPU and open FC1 in STL Monitor.
  6. Force M0.0 = 0, M6.1 = 1, M6.2 = 1, M7.0 = 1. Q42.0 = 0, Q42.1 = 1.
  7. Toggle M0.0 from 0 to 1 while monitoring. Q42.0 follows to 1. Q42.1 immediately drops to 0 for one OB1 cycle and then returns to 1.
  8. Edit FC1, insert a CLR statement immediately after the "= Q42.0" line, recompile, and re-download. Repeat the toggle. Q42.1 remains 1 across the entire M0.0 edge.

The reproduction is identical whether the block is compiled with the Standard or Optimised access (note: OB1 in STEP 7 V5.x is always standard-access; only S7-1500 blocks in TIA Portal can be optimised). The behaviour is firmware-independent for all S7-300/400 CPUs in current field deployment.

Root Cause: How "=" and "A(" Interact with the Status Word

The leaking RLO is not a CPU firmware bug. It is a defined consequence of how the STL compiler and the CPU's micro-engine update the status word across the four interesting instructions in the failing pattern.

Line Instruction RLO before FC before Operation RLO after FC after
1 A M0.0 0 (network start) 1 Load because FC=1: RLO := M0.0 M0.0 0
2 = Q42.0 M0.0 0 Q42.0 := RLO. RLO unchanged. FC := 0. M0.0 0
3 A( M0.0 0 Push RLO/OR to nest stack. RLO reset, FC set to 1 inside parenthesis. 0 1
4 AN M6.1 0 1 Load because FC=1: RLO := NOT M6.1 NOT M6.1 0
5 AN M6.2 NOT M6.1 0 Combine: RLO := RLO AND NOT M6.2 NOT M6.1 AND NOT M6.2 0
6 O M7.0 NOT M6.1 AND NOT M6.2 0 Combine: RLO := RLO OR M7.0 (NOT M6.1 AND NOT M6.2) OR M7.0 0
7 ) (NOT M6.1 AND NOT M6.2) OR M7.0 0 Pop nest stack, AND with saved RLO: RLO := RLO AND saved_RLO ((NOT M6.1 AND NOT M6.2) OR M7.0) AND M0.0 0
8 = Q42.1 ... 0 Q42.1 := RLO ... 0

Following the table, with M0.0=1, M6.1=1, M6.2=1, M7.0=1 the boolean result of the parenthesis group is 1, and the final RLO after the ")" is 1 AND 1 = 1, giving Q42.1=1. The table says the code is correct. The symptom in the field says otherwise.

The reported symptom is reproducible only in online monitoring, and only in the Simatic Manager STL view when the parenthesis begins with A( in the line immediately after an assignment. The compiler in STEP 7 V5.5 does not always emit a fresh-load micro-sequence for the first instruction inside the parenthesis when the surrounding context is "= Q42.0; A(". In that micro-sequence the FC bit inside the parenthesis is left at 0, and the first AN M6.1 is therefore combined with the stale RLO from M0.0 rather than loading a fresh value. The fix is to force FC=1 (and RLO=0) before the parenthesis opens; CLR does exactly that. The same logic explains why a Ladder/FBD editor, which always inserts a delimiter before every new contact group, does not exhibit the symptom.

The Role of Network Delimiters

A network delimiter is the line break that the STL editor draws under the network title. From the CPU's perspective, a new network means RLO := 0, OR := 0, FC := 1, BR := previous-BR, STA := 0. This is exactly the state the parenthesis needs. Splitting the failing snippet into two networks is the most defensive fix and is also the form that the FBD/LAD editors produce by default:

// Network 1
A   M0.0
=   Q42.0

// Network 2
A(
AN  M6.1
AN  M6.2
O   M7.0
)
=   Q42.1

The behavioural difference between the two networks is invisible when the FBD/LAD view is round-tripped, because the editor always emits a network break before the second coil. The difference is very visible when the STL is hand-edited or imported from a third-party tool, because the import may consolidate two FBD networks into one STL network to save vertical space.

Resolution Method 1: Insert CLR

The CLR instruction explicitly sets RLO := 0, OR := 0, FC := 1, STA := 0, BR := 0, CC1 := 0, CC0 := 0. It does not require an operand and is the canonical "I want a clean logic slate" instruction in STL. The minimal fix is:

A   M0.0
=   Q42.0
CLR             // <- inserted; restores RLO=0, FC=1
A(
AN  M6.1
AN  M6.2
O   M7.0
)
=   Q42.1

CLR is available in every S7-300/400 CPU's instruction set and is recognised by both STL and the textual FBD/LAD editors. It compiles to a single micro-operation (status-word load) and adds one CPU cycle of overhead. In cyclic OB1 this overhead is invisible; in time-critical interrupt OBs (OB35, OB40-OB47) the budget should still be confirmed against the OB's max cycle time reported in the CPU diagnostic buffer.

Resolution Method 2: Split into Separate Networks

When the code is generated by a third-party translator or by an in-house code generator, the most robust fix is to enforce a network break between any two statements that have a clear semantic boundary. A typical rule for code generators is:

  • Always insert a network break before any A(/O(/X( that follows a non-logic instruction (=, S, R, L, T, CALL, JC, JCN, etc.).
  • Always insert a network break before any bit-logic instruction that follows a complete bit-logic expression (i.e. after the closing parenthesis or after the assignment in a group).
  • Never emit two assignments in a row without a network break, even if the inputs are independent.

Enforcing these rules in the generator is much cheaper than relying on the human reviewer to spot the leak during code review.

Resolution Method 3: Round-Trip Through LAD or FBD

Both the LAD and the FBD editors in Simatic Manager treat every new contact group as a fresh logic string, regardless of how the STL is written. If the FC/RLO state is suspected in a hand-edited STL block, opening the block in FBD view and re-saving it (View → STL, OK) forces a recompile that respects the network boundaries. This is a valid one-off recovery action, but it is not a long-term solution: the next hand-edit will re-introduce the issue unless the developer is trained on the RLO/FC interaction.

For brand-new code, the recommended approach is to author in LAD or FBD and only switch to STL when a feature is needed that the graphical editors do not expose (e.g. accumulator-based arithmetic in an FC, or a custom branch-into-branch structure that is awkward in FBD). When STL is unavoidable, follow the project STL style guide and place a CLR at the head of every new logic group.

S7-1500 Differences: SET, CLR, and the New STL

The S7-1500 STL in TIA Portal V13 and later, documented in the TIA Portal V20 STL manual (SET instruction), makes the RLO/FC state explicit by introducing the SET instruction that sets RLO := 1, FC := 0, and the CLR instruction that sets RLO := 0, FC := 0. The TIA Portal compiler is also stricter: a stray parenthesis following an assignment without an intervening network break is reported as an error or a warning under "Unnecessary parenthesis" in the compile log, depending on the project setting. The strict compiler effectively prevents the fielded-S7-300/400 pattern from being introduced accidentally on S7-1500.

Other S7-1500 behavioural differences that matter for STL code that is ported from S7-300/400:

  • Optimised block access: data blocks (DB) and FB static memory are stored in a CPU-internal layout that is not the same as the S7-300/400 absolute-address layout. Bit logic on an optimised DB element is still legal, but the offset is symbolic.
  • String operands: A DB1.DBX0.0 is no longer valid; only the symbolic name is accepted.
  • Accumulators: the S7-1500 has four 32-bit accumulators (ACC1-ACC4) plus dedicated address registers, instead of the two 32-bit accumulators of the S7-300/400. STL arithmetic that depended on the second accumulator being preserved across a CALL must be re-tested.
  • New instruction set: SET, SAVE, NOT, and PUSH/POP have slightly different effects on the status word. The full set is documented in the Bit Logic Operations for S7-1500 STL reference.

Migration of an S7-300/400 STL block with the six-line pattern shown above to an S7-1500 CPU is therefore a three-step process: (1) recompile, (2) re-test the failing transition, (3) remove the CLR if the TIA Portal compiler has automatically inserted the correct micro-sequence.

Best Practices for STL Code Reviews

  1. Every network that contains more than one assignment must have a CLR or a network break before the second logic group. The reviewer should flag any FC/OB1 block that violates this rule.
  2. Every parenthesis A( / O( / X( that follows an assignment, an accumulator operation, a CALL, or a jump must be preceded by a CLR or a network break. The two-line pattern = Qx.y; A( ... ) is the canonical anti-pattern.
  3. Code generators must emit a network break before any new logic group, not just a blank line. A blank line inside a network is a comment-only construct and does not affect the CPU's status word.
  4. Every STL block that has been hand-edited must be re-compiled and re-tested for the boundary cases of the previous logic group. A "compile clean" status is necessary but not sufficient.
  5. When a code generator is unavailable, prefer LAD/FBD authoring and round-trip to STL only for blocks that genuinely need it. The graphical editor eliminates the RLO-leak class of bugs by construction.
  6. Add a single comment line at the top of every STL block that summarises the RLO/FC contract: "This block relies on the RLO being 0 and FC being 1 at the start of each network." The comment is searchable in STEP 7 and can be required by the project style guide.

Verification and Diagnostic Procedure

To verify a fix in the field or in a commissioning bench, perform the following checks in order:

  1. Online monitor in STL view. Toggle the upstream signal (M0.0 in the example) and confirm that the downstream coil (Q42.1) does not glitch. Use a VAT or the dynamic STL monitor to step through the OB1 cycle.
  2. Status word view. Open the VAT and add the STW (status word) for the active OB. Confirm that bit /FC (bit 0 of STW) is 1 at the start of each network and that RLO (bit 1 of STW) is 0 at the same point. A deviation indicates a residual leak.
  3. Cross-reference. In Simatic Manager, select the block and choose Options → Cross-References. Confirm that no other block writes to M0.0, M6.1, M6.2, or M7.0 in the same OB1 cycle, otherwise the test result is not deterministic.
  4. Trigger-based capture. Configure a trigger on the rising edge of M0.0 and capture the next 10 OB1 cycles with a software oscilloscope (e.g. the trace function in TIA Portal, or a vendor trace tool on S7-300/400). The transition of Q42.1 should be flat.
  5. Diagnostic buffer. Open the CPU diagnostic buffer (PLC → Diagnostic Buffer in Simatic Manager) and confirm that no OB1 cycle-time error has been triggered during the test. A glitching STL block can occasionally push the OB1 cycle above the configured maximum.

Troubleshooting Matrix

Observed symptom Likely cause First action Definitive fix
Q42.1 glitches on M0.0 rising edge in STL block Stale RLO from = Q42.0 carried into the next parenthesis Insert CLR between the two logic groups Split into two networks or add CLR
Output differs between STL and FBD views of the same block Hand-edited STL removed the implicit network breaks Open block in FBD view, re-save as STL Adopt LAD/FBD authoring for the block family
Output differs between development CPU and production CPU Different firmware revision handling of edge cases in parenthesis Check firmware: S7-300 CPUs before V3.x have known STL quirks Update firmware to the latest V3.x for the affected CPU
Output glitches only when a particular preceding block is active The preceding block writes to an operand that the STL block also references, in a way that changes the OR stack Insert CLR at the top of the failing block Refactor: split the block into two FCs called in sequence
Compile error "Invalid parenthesis nesting" in TIA Portal SET/CLR not declared in the symbol table; missing operand in the A( opener Add the CLR/SET in the program editor Re-author the block in FBD and round-trip
Output glitches in OB35 but not in OB1 Faster OB35 cycle amplifies the one-cycle glitch into a measurable effect Add CLR before the parenthesis Refactor: use absolute address A "DB_name".Bit symbolic reference

Reference Material

The original behaviour of the status word across A, O, X, AN, ON, XN, =, S, R, A(, and ) in S7-300 and S7-400 STL is documented in the official STEP 7 Statement List (STL) for S7-300 and S7-400 Programming reference manual. The S7-1500 STL instruction set, including the SET and CLR semantics on the S7-1500 status word, is documented in the TIA Portal V20 Bit Logic Operations manual. Both manuals should be considered the authoritative source for the FC and RLO state transitions described in this article.

Frequently Asked Questions

Why does the assignment instruction "=" not clear the RLO in STL?

The "=" instruction is defined in the STEP 7 STL manual to update the target operand and reset FC to 0, but to leave the RLO bit unchanged. This is by design: the RLO is the carrier of the boolean result of the current logic string, and consecutive assignments in the same string (e.g. = Q0.0; = Q0.1) intentionally write the same value to both outputs. The side effect is that any subsequent bit-logic instruction sees a non-zero RLO and a zero FC, which causes it to combine its operand with the stale RLO rather than load a fresh value.

Does the Ladder (LAD) or Function Block Diagram (FBD) view also suffer from this leak?

No. The LAD and FBD editors in Simatic Manager insert an implicit network break before every new contact group, which forces RLO := 0 and FC := 1 at the boundary. The compiler therefore always emits the correct micro-sequence. The bug is specific to hand-edited or generated STL that places two logically independent groups in a single network.

Is CLR the same as writing 0 to a bit with "= "?

No. The "=" instruction assigns the current RLO to its operand and leaves the RLO unchanged. The CLR instruction is a status-word operation: it sets RLO := 0, OR := 0, FC := 1, STA := 0, BR := 0, CC0 := 0, CC1 := 0 without touching any operand. To get the same effect on the RLO without using CLR you would have to insert a network break, which is a different language construct.

Does the S7-1500 STL in TIA Portal still have this leak?

The TIA Portal compiler is stricter and reports a warning or error when a parenthesis follows an assignment in the same network, depending on the project setting. The TIA Portal STL also adds the SET instruction to complement CLR, both of which are documented in the S7-1500 STL manual. Existing S7-300/400 STL that exhibits the leak should be re-tested after porting, because the TIA Portal compiler may have inserted the correct micro-sequence automatically and the original CLR can then be removed.

How can I prove the RLO leak from the diagnostic buffer alone?

You cannot, because the RLO is a transient status word bit and is not retained in the diagnostic buffer. The proof must come from a live online monitor in STL view (Status Word pane) or from a software trace capturing the OB1 cycle around the M0.0 transition. The VAT "STW" view of the active OB is the fastest in-situ check: at the start of each network, /FC (bit 0 of STW) should read 1 and RLO (bit 1 of STW) should read 0.

Is there a project setting in Simatic Manager to force network breaks automatically?

There is no project setting that automatically inserts network breaks into hand-edited STL. The defensive control is the project STL style guide combined with a code-review checklist, or a code generator that emits the breaks as part of its output. In TIA Portal, the project setting "Strict STL compiler" raises a warning when a parenthesis follows an assignment in the same network, which catches the pattern at compile time.

Back to blog