Converting Siemens STL to LAD: A() and O() Block Interpretation

David Krause15 min read
SiemensTIA PortalTutorial / How-to
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

STL to LAD Conversion: What STEP 7 and TIA Portal Actually Support

Engineers frequently ask why a piece of Statement List (STL) code cannot simply be opened as Ladder (LAD) inside the SIMATIC environment. The reason is architectural, not a missing feature flag: the SIMATIC editors treat STL, LAD, and FBD as source representations of the same MC7 code, but the conversion path is intentionally one-way in nearly every configuration.

Editor Pair Direction S7-300/400 (STEP 7 V5.x) S7-300/400 (TIA Portal) S7-1200/1500 (TIA Portal)
LAD → STL Forward Supported Supported Not supported
FBD → STL Forward Supported Supported Not supported
STL → LAD Reverse Not supported Not supported Not supported
STL → FBD Reverse Not supported Not supported Not supported
LAD ↔ FBD Bidirectional Supported Supported Supported

Siemens confirms the boundary in the SiePortal knowledge base: "LAD and FBD can be easily converted to STL, conversion from STL to LAD or FBD (and vice-versa) are not possible, the code must be re-written." For S7-1200/1500, TIA Portal drops STL entirely as an authoring language — only LAD and FBD remain, and the editor switches between them on a per-network basis. For S7-300/400 the legacy direction is the same: STL → LAD is not a supported menu action. The only historical exception is STEP 7 Micro/WIN, which can round-trip STL with the S7-200 family — that path is closed for S7-300/400/1200/1500 systems described in the source program.

This is why the request to "convert this STL to ladder" cannot be answered with a button click. What can be done is a manual interpretation: reading the STL exactly the way the CPU executes it, then redrawing the resulting Boolean expression as LAD networks. The remainder of this article covers that interpretation, using the source program as a worked example.

Compiler visibility: If the block was originally authored in LAD, compiled to STL, and then re-opened, the editor still shows the STL text. Switching the view back to LAD is not possible. The only supported recovery is to read the STL semantically and redraw it.

STL Instruction Set Used in the Source Program

The snippet references a small, well-defined subset of the MC7 instruction set. Each operator is documented in the SIMATIC S7-300/400 Statement List programming manual, but the field-proven semantics are:

Operator Operands Effect on RLO / State
A Bit AND; combines the addressed bit with the current RLO
AN Bit AND-NOT; combines the inverted bit with the current RLO
O Bit OR; combines the addressed bit with the current RLO
ON Bit OR-NOT; combines the inverted bit with the current RLO
A( Push current RLO onto the nesting stack, then evaluate the parenthesised expression independently
O( Push current RLO onto the nesting stack, then evaluate the parenthesised expression independently
) Pop saved RLO from the stack; combine with the just-completed inner RLO using the operator that opened the bracket
= Bit / L Assign the current RLO to the addressed bit (write 1 if RLO = 1, else write 0)
S Bit Set: latch the addressed bit if RLO = 1
R Bit Reset: unlatch the addressed bit if RLO = 1
FP Bit / M / L Rising-edge detect; produces RLO = 1 for one scan when the addressed bit transitions 0 → 1
FN Bit / M / L Falling-edge detect; produces RLO = 1 for one scan when the addressed bit transitions 1 → 0
BLD 102 Display instruction; no CPU effect. Inserted automatically when LAD is compiled to STL so the line aligns with the original ladder rung

The two edge bits and the local variable L 35.0 (later aliased by A L 35.0) act as glue between sequential statements — the RLO produced by one network is handed to the next through a temporary that the user cannot see in LAD.

How A( and O( Brackets Manipulate the RLO

Statement List is stack-based. Each A( or O( pushes the current Result of Logic Operation (RLO), the OR bit (OR), the Status bit (STA), and the First Check bit (FC) onto a seven-deep nesting stack, then clears the RLO so the inner expression is evaluated fresh. When the matching ) is reached, the inner RLO is combined with the popped RLO using the operator that opened the bracket:

  • A( ... ) → popped_RLO AND inner_RLO → new RLO
  • O( ... ) → popped_RLO OR inner_RLO → new RLO

Nested brackets stack on top of one another. Up to seven levels of nesting are permitted per network in S7-300/400; exceeding the stack raises OB121 (programming error, nesting depth exceeded) on the CPU. In the source program the deepest nesting is three levels (the Emergency_Release_Rolls / Function_Request / Near_Work_POS_FX cluster), well within budget.

A common misreading is to treat A( and O( as "function calls" that return a Boolean. They are not. They are brackets that change how the RLO combines with what comes next. This is why counting open and close parentheses, line by line, is the only safe way to verify which inner terms group together.

Brace-Counting Method for Mapping Nested Networks

Before drawing a single LAD contact, count the parentheses. The method is mechanical and removes interpretation error:

  1. Initialise a counter at zero.
  2. Walk down the network line by line.
  3. For every A( or O( increment the counter and note the operator at that level.
  4. For every ) decrement the counter. The decrement always pairs with the most recent unclosed A( or O(.
  5. When the counter returns to zero the inner expression is closed and its RLO is the current RLO.

Applied to the source network (line numbers added for reference):

01: A(
02:   ON  "=CRIMPER+CB12-2K1"
03:   ON  "=CRIMPER+CB12-2K3"
04:   O   "M661.3"
05:   O   "M663.3"
06:   O   DB50.DBX 10.0
07:   O(
08:     A   "Data Exchange MP277_PLC".FX_Auto_Functions.CrimperRolls_Positioning.StopPositioning_Request
09:     =   "Data Exchange MP277_PLC".FX_Auto_Functions.CrimperRolls_Positioning.Stop_Positioning_Touched
10:     A   "Data Exchange MP277_PLC".FX_Auto_Functions.CrimperRolls_Positioning.Stop_Positioning_Touched
11:     A(
12:       A   "M660.1"
13:       =   "Data Exchange MP277_PLC".FX_Auto_Functions.CrimperRolls_Positioning.StopPositioning_Possible
14:       A   "Data Exchange MP277_PLC".FX_Auto_Functions.CrimperRolls_Positioning.StopPositioning_Possible
15:     )
16:   )
17:   O(
18:     A   "Emergency_Release_Rolls"
19:     FP  M 667.0
20:   )
21:   O(
22:     A   "Emergency_Release_Rolls"
23:     FN  M 667.4
24:   )
25:   O(
26:     A(
27:       A   "Emergency_Release_Rolls"
28:       FN  M 667.1
29:       O(
30:         A   "Data Exchange MP277_PLC".FX_Auto_Functions.CrimperRolls_Positioning.Function_Request
31:         FP  M 667.2
32:         AN  #IN_POS
33:       )
34:       O(
35:         A   "Data Exchange MP277_PLC".Select_Lists_Unit.Near_Work_POS_FX
36:         FP  M 667.3
37:       )
38:     )
39:     A   "M2.1"
40:   )
41:   O
42:   (
43:     AN  "Open_Fx_Manual"
44:     AN  "Close_Fx_Manual"
45:     A   "M2.0"
46:     AN  "M660.5"
47:     A   "M660.7"
48:     AN  "Emergency_Release_Rolls"
49:   )
50: )   // closes line 01 A(
51: A   "M_System_Ready"
52: =   L 35.0
53: A   L 35.0
54: BLD 102
55: S   "M661.0"
56: A   L 35.0
57: A(
58:   O   "Faults Messages".Fault_Messages_1.OP_SM1
59:   O   "Faults Messages".Fault_Messages_1.OP_SM2
60: )
61: S   "M663.0"

The deepest stack depth reached is 3 (lines 25 → 26 → 29), the closing ) on line 38 unwinds to depth 1, and line 50 closes the original A( on line 01. The lone O on line 41 followed by ( on line 42 is a stylistic break; semantically the O binds the entire parenthesised block on lines 42–49 to the running OR-chain started inside line 01.

Walking Through the Example STL Network

With the parentheses pinned, the RLO evolution can be read top-down. The most useful way is to track which Boolean expression is the "current RLO" at each line.

After line Current RLO (informal)
01 RLO = (push 0, begin inner)
02–06 RLO = ON(=CRIMPER+CB12-2K1)  OR  ON(=CRIMPER+CB12-2K3)  OR  M661.3  OR  M663.3  OR  DB50.DBX10.0
07 RLO pushed; inner begins
08–15 RLO = StopPositioning_Request AND M660.1
16 close O( at 07: prior RLO = prior OR this inner
17 push; inner begins
18–19 RLO = FP(Emergency_Release_Rolls) via M667.0
20 close; OR the rising edge into the running RLO
21 push
22–23 RLO = FN(Emergency_Release_Rolls) via M667.4
24 close; OR the falling edge into the running RLO
25 push
26 push again (depth 2)
27–28 RLO_innermost = FN(Emergency_Release_Rolls) via M667.1
29 push (depth 3)
30–32 RLO = FP(Function_Request) via M667.2 OR AN(IN_POS)
33 close O( at 29; OR with line 27–28
34 push
35–36 RLO = FP(Near_Work_POS_FX) via M667.3
37 close O( at 34; OR with line 33
38 close A( at 26; AND with prior at 25
39 AND with M2.1
40 close O( at 25; OR the entire cluster into the running RLO
41–49 RLO = AN(Open_Fx_Manual) AND AN(Close_Fx_Manual) AND M2.0 AND AN(M660.5) AND M660.7 AND AN(Emergency_Release_Rolls)
50 close A( at 01; the entire network RLO is now defined
51–52 AND M_System_Ready; assign to L 35.0
53–55 Set M661.0 (latch)
56–60 Set M663.0 if L 35.0 AND (OP_SM1 OR OP_SM2)

The key observation: the original author never trusted a single network to drive two outputs. Line 52 parks the composite RLO in a temporary (L 35.0) so lines 55 and 61 can both reuse it. In LAD this temporary becomes a "flag coil" or a connector branch.

Reconstructing the Equivalent LAD Network

The semantic decomposition above can be redrawn as two LAD networks. The first network holds the composite condition in a connector (or, in TIA Portal, a multi-instance flag), the second and third latch the outputs. The result is functionally identical to the STL:

Network 1: Composite enable (stored in M_Helper_Stop_Req, equivalent of L 35.0)

| NOT (=CRIMPER+CB12-2K1) --- | NOT (=CRIMPER+CB12-2K3) ---+---( )---( )---( )---( )---( )---( M_Helper_Stop_Req ) | M661.3 ---| OR-cluster A | M663.3 ---| | DB50.DBX10.0 ---+ | StopPositioning_Request --- | M660.1 ---+---( )---( )--- OR-cluster B (line 07-16) | M_Helper_Stop_Touched ---| | Emergency_Release_Rolls --- | M667.0 (FP) ---+---(P)---( )--- OR-cluster C (line 17-20) | Emergency_Release_Rolls --- | M667.4 (FN) ---+---(N)---( )--- OR-cluster D (line 21-24) | Emergency_Release_Rolls --- | M667.1 (FN) ---+---( )---( )---( )---( )--- OR-cluster E (line 25-40) | Function_Request ---| | | | M667.2 (FP) ---+---(P)---( )--+ | | NOT IN_POS ---+---(/)---------+ | | Near_Work_POS_FX ---+---(P)---( )----+ | M2.1 ---( )--------------+ | NOT Open_Fx_Manual ---+---(/)---( )---( )---( )---( )---( )--- OR-cluster F (line 41-49) | NOT Close_Fx_Manual ---| | | M2.0 ---+---( )--------| | NOT M660.5 ---+---(/)--------| | M660.7 ---+---( )--------| | Emergency_Release_Rolls ---+---(/)--------+ | M_System_Ready ---( )---(

Network 2: Latch M661.0
| M_Helper_Stop_Req ---( )---( S M661.0 )

Network 3: Latch M663.0 (operator-panel stop)
| M_Helper_Stop_Req ---( )--- | OP_SM1 ---+---( )---( S M663.0 ) | OP_SM2 ---+

The OR-cluster letter labels map 1:1 to the source parentheses ranges. Each cluster becomes one parallel branch in LAD; the clusters are then placed in series between the bracket lines. The four edge bits (M667.0, M667.1, M667.2, M667.3) become LAD edge contacts (P for FP, N for FN) wired to the corresponding flag.

About BLD 102: The line BLD 102 on what was line 54 is a display instruction. It produces no MC7 code, has no effect on the RLO, and exists only so the original LAD rung lines up column-for-column with the auto-generated STL. It can be ignored during manual conversion; it is removed entirely when the author re-types the network in LAD.

Edge Detection (FP/FN) and Set (S) Behaviour in LAD

Each FP and FN in the source is implemented as a bit-addressed edge flag. In MC7, the FP/FN operator needs a bit operand that stores the previous-scan state of the input. The author used dedicated M flags (M667.0 … M667.4). When redrawing in LAD, three options exist:

  1. Wire a --( P )-- or --( N )-- contact directly to the input bit. TIA Portal automatically allocates a hidden edge bit per network — this is the most readable and is the preferred path on S7-1200/1500 where every network gets a fresh edge flag.
  2. Keep the dedicated M flag wiring: drive a normal contact, then place a --( P )-- contact addressed to the M flag. Functionally equivalent to the source but more verbose.
  3. Use the multi-instance DB approach for FB encapsulation: a static BOOL tag inside the instance DB replaces the global M flag and stays local to the block.

The two S operators (latch) translate directly to --( S )-- coils. The matching resets are not visible in the source network — they must be located elsewhere in the program (typically a separate stop-cancel or fault-clear network). Before deploying the reconstructed LAD, search the source block for R "M661.0" and R "M663.0" to ensure the unlatch path is preserved.

Address Translation: Symbols, DBs, and Local Variables

Three addressing styles appear in the source. Each needs handling during the redraw:

Address style Example from source Meaning
Symbolic (PLC tag table) "M_System_Ready", "Open_Fx_Manual" Tag-table symbol; resolves to a global bit
HMI / WinCC tag "=CRIMPER+CB12-2K1" Connection-prefixed name exported by WinCC flexible or TIA WinCC; the leading = is the connection prefix delimiter
Instance DB (multi-instance) "Data Exchange MP277_PLC".FX_Auto_Functions.CrimperRolls_Positioning.StopPositioning_Request Path into an instance DB opened against the data block named Data Exchange MP277_PLC
Global DB DB50.DBX 10.0 Global data block 50, byte 10, bit 0
Local (block parameter / temp) #IN_POS, L 35.0 Block-local static/FB input parameter or temporary variable
Bit-memory flag M 667.0 Global merker; addressable as %M667.0 in TIA Portal absolute syntax

The PLC tag table must contain every quoted symbol before TIA Portal will compile the rewritten block. The HMI-prefixed tags (=CRIMPER+CB12-2K1 etc.) are flagged by the compiler if no matching PLC tag exists; they must be declared in the HMI tag set of the WinCC project, not the PLC tag set, otherwise the rewritten network will produce unresolved-symbol warnings.

Manual Rewriting Strategy When No Tool Path Exists

For programs of this complexity, a structured rewrite beats a per-statement substitution. The procedure below is what experienced STEP 7 engineers apply:

  1. Print or export the STL. Use the STEP 7 / TIA Portal "Source files" export to generate a plain-text .AWL file. The text is searchable, line-numbered, and easy to mark up.
  2. Number every line. Add 1-based line numbers to the exported source. They are referenced in code review and in the test plan.
  3. Highlight every parenthesis. Mark A( and O( in one colour, ) in another. Draw a vertical line from each open bracket down to its matching close.
  4. Build the parse tree. For each A( / O( level, write down the simplified Boolean expression produced by the inner block. The leaf expressions are the lines that touch a real bit operand; the inner block is the OR/AND of those leaves.
  5. Map the tree to LAD. Each inner block becomes one parallel branch (for O) or one series sub-segment (for A). The root of the tree becomes the network contact chain.
  6. Re-insert the BLD 102 line as a no-op comment. Do not re-type it; LAD does not need it. If the original author used BLD 102 to label a section, convert it to a Network title in TIA Portal.
  7. Preserve execution order. STL is strictly sequential; LAD networks are not. When the STL uses the result of one statement as input to the next (as the source does with L 35.0), introduce a connector or a helper flag. The helper flag must be reset at the bottom of the chain to avoid stale RLOs from previous scans.
  8. Compile, then test on PLCSIM. TIA Portal's PLCSIM (S7-PLCSIM or PLCSIM Advanced) accepts the rebuilt block without needing physical hardware. Use the watch table to force every input bit and confirm the outputs latch and unlatch as expected.

Verification: Cross-Check and Online Testing

Manual conversion is not finished when the compile is green. A field-proven verification sequence:

  1. Static cross-check. Use a monitor with "Permit monitoring with "Process operation" — compare the rebuilt LAD RLO against the original STL RLO in a watch table, network by network, with all input forces held constant. RLO must match every scan.
  2. Path coverage. For each OR cluster in the network, force a single input true and the rest false, confirm the composite RLO. Repeat for the AND clusters. The Boolean truth table for the composite has 2n rows for n independent inputs; an MC7 simulation can compress this with a coverage script.
  3. Stack-depth check. Confirm no nested expression exceeds seven levels (S7-300/400 hard limit; S7-1500 raises this but the editor still warns).
  4. Watch for OB121. If the rebuilt block trips OB121 (programming error) at runtime, the most common cause in conversions of this kind is a stray BLD instruction, an unmatched parenthesis, or an attempt to write to a write-protected bit. Add an OB121 handler temporarily to log the block / offset pair.

FAQ

Can TIA Portal convert STL to LAD directly?

No. TIA Portal only supports LAD → STL and FBD → STL on S7-300/400; on S7-1200/1500 it does not support STL as an authoring language at all. The official Siemens guidance, restated in the SiePortal KB article convert ladder logic to STL/SCL, is that the code must be re-written. The only historical exception is STEP 7 Micro/WIN, which can round-trip STL on the S7-200 family.

What does the A( operator do in Siemens STL?

A( saves the current RLO, OR bit, status bit, and first-check bit on the seven-deep nesting stack, then clears the RLO so the parenthesised expression is evaluated independently. The matching ) pops the saved RLO and combines it with the inner RLO using AND. The O( variant combines with OR. Up to seven levels of nesting are permitted per network on S7-300/400; exceeding the limit raises OB121.

How do I read nested A( and O( blocks in a complex STL network?

Use brace counting. Number every open A( or O( and draw a vertical line down to its matching ). At each ) write the simplified Boolean expression produced by the inner block. The leaf expressions are the bit-operand lines; the inner block is the AND/OR of those leaves. The running RLO at the end of the network is the result.

What is the BLD 102 line in the source for?

BLD 102 is a display instruction that the CPU ignores. It is inserted automatically when a LAD network is compiled to STL so the generated statements line up with the original ladder rung. When you redraw the network in LAD, BLD 102 is removed entirely; if it labelled a section, convert it to a TIA Portal network title.

How do FP and FN map to LAD contacts?

FP (rising-edge) maps to a --( P )-- contact on the input bit; FN (falling-edge) maps to a --( N )-- contact. TIA Portal automatically allocates a hidden edge flag per network. If you need a global, named edge flag (for example to share an edge with another network), wire a normal contact and place the P/N contact against a dedicated M flag or a static BOOL in an instance DB. The source program in this article uses M667.0, M667.1, M667.2, M667.3, and M667.4 for that purpose.

Back to blog