Overview: Why the Compiled AWL Looks the Way It Does
When a STEP 7 V5.x project is delivered without the original SCL source file, only the compiled AWL (German Anweisungsliste, English STL) is left inside the FB/FC/OB block. The SCL compiler translates high-level expressions into a sequence of bit, byte, word, and double-word operations against the accumulator, address register AR1/AR2, and the local stack (L stack). The transformation is lossy for line-by-line correspondence but deterministic: the same SCL constructs produce predictable AWL patterns across compiler versions.
Reconstructing the SCL is a three-step process:
- Decode the block header and interface description to recover the symbol list, data types, and IN/OUT/IN_OUT/STAT/TEMP layout.
- Translate each AWL instruction into a symbolic expression, paying close attention to the AR1 register and L stack.
- Re-group the resulting expressions into SCL statements that produce the same accumulator state at the same code position.
Prerequisites
| Item | Why it is needed |
|---|---|
| STEP 7 V5.5 or V5.6 (SIMATIC Manager) | Hosts the S7-SCL compiler and the AWL/STL editor required to open and inspect compiled blocks. |
| S7-SCL option package, V5.3 SP5 or later | Minimum version that allows TIA Portal migration; the same package is required to recompile the recovered SCL on classic STEP 7. See the official Siemens migration guide for SCL programs (S7-300/S7-400). |
| The offline block container (S7-Program/Blocks) | Contains the FB, its instance DB, and any referenced global DBs. |
| Symbol table (Symbols) | The only way to map absolute addresses such as DB500.DBX 205.1 back to meaningful names like status_bit. |
| Cross-reference list (Reference Data → Display) | Shows every location that writes or reads each operand, which is essential for finding the source of part-qualified DB accesses. |
Decoding the SCL Block Header and Interface
Every FB carries a block header that records the compiler version, the interface (formal parameters and static data), and the size of the L stack. The interface is the most valuable source of information when the original SCL is lost. Open the block in the LAD/FBD/STL editor and select File → Properties → Interface (or use the SCL editor with the block opened as SCL). The interface fields translate to SCL declarations as follows:
| STEP 7 interface column | SCL declaration | Storage |
|---|---|---|
| IN | VAR_INPUT |
Block stack (L stack) at block call |
| OUT | VAR_OUTPUT |
Block stack at block call |
| IN_OUT | VAR_IN_OUT |
Pointer to actual in TEMP area |
| STAT |
VAR (static) |
Instance DB (DI) |
| TEMP | VAR_TEMP |
L stack (local data) |
| RETURN (FC only) | RET_VAL |
ACCU 1 / L stack word 0 |
Record the offset of every parameter; that offset is the literal you will see in the compiled AWL. For an FB called FB1000 with OUT : BOOL; declared as the first OUT, the compiled AWL will write to #OUT at offset 0.0 of the L stack, which is rendered as L 0.0 or as the symbolic name #OUT if the symbol table is populated.
AWL Opcodes Generated by the SCL Compiler
The SCL compiler emits a small, well-defined subset of AWL. Familiarize yourself with these opcodes before reading any compiled block:
| AWL opcode | Meaning | SCL idiom |
|---|---|---|
SET |
Set RLO = 1 | Compiler prologue; loads a constant TRUE into the logic bit |
CLR |
Clear RLO = 0 | Compiler prologue for FALSE
|
SAVE |
Copy RLO into BR | Block epilogue (and any ENO := assignment) |
= |
Assign RLO to operand | Right-hand side assignment |
U / O / X
|
AND / OR / XOR | Boolean operator |
UN / ON / XN
|
AND/OR/XOR with negation | Boolean operator with NOT
|
L |
Load into ACCU 1 | Right-hand side of expression |
T |
Transfer from ACCU 1 | Assignment to word/dword/int/real |
AUF / OPN
|
Open DB | Loads DB number into AR1 (and AR2 for DI) |
UC / CC
|
Unconditional / conditional call | FC/FB/SFB/SFC call |
BE / BEA
|
Block end / block end absolute | Compiler epilogue |
AUF is the standard mnemonic for opening a DB. In English locales, the editor displays OPN instead. Both are identical in the generated MC7 code.The AR1 Register and Part-Qualified DB Access
The address registers AR1 and AR2 are central to understanding SCL-generated AWL. After any full-qualified DB access, the CPU stores the DB number in AR1. After an AUF (or OPN) instruction, the target DB is loaded into AR1 (and for AUF DI into AR2 as well). Subsequent part-qualified accesses (DBX, DBB, DBW, DBD) implicitly use whatever DB is currently held in AR1.
Consider the example from the field report:
SET
SAVE
= L 0.1 // copy RLO=1 to local bit L 0.1 (TEMP area)
U DB500.DBX 205.1 // full-qualified: AR1 := 500, then read DBX 205.1
= #OUT // assign to OUT parameter (offset 0.0 of L stack)
= DBX 288.0 // part-qualified: writes to DB500.DBX 288.0
The line = DBX 288.0 contains no DB number because the previous instruction U DB500.DBX 205.1 already loaded 500 into AR1. To verify which DB is implied, search the block upward for the most recent AUF or full-qualified DB access. The cross-reference list (Options → Cross-reference in SIMATIC Manager) is the fastest way to confirm the DB number, because it shows every address that the DB occupies in this block.
For an FB, the instance DB is opened implicitly by the call mechanism. The CPU loads the DI number into AR2 and uses AR1 for the most recently accessed global DB. As a result, the AWL inside an FB will frequently mix DIX / DIW accesses (instance data) with DBX / DBW accesses (global data).
Interpreting Multi-Assignment Chains
A SCL statement such as:
OUT := DB500.DBX 0.0;
DB500.DBX 0.1 := OUT;
is compiled in two distinct ways depending on the SCL compiler version and the CreateDebugInfo setting.
Form A (debug info on, modern compilers):
U DB500.DBX 0.0
= #OUT // write the result to the OUT parameter
U #OUT // re-read it for the second assignment
= DBX 0.1 // write to DB500.DBX 0.1
Form B (debug info off, older or optimized compilers):
U DB500.DBX 0.0
= #OUT // write to the OUT parameter
= DBX 0.1 // write to DB500.DBX 0.1 in the same RLO
Both forms are functionally identical when the source operand is a single bit. Form B is shorter and is preferred when the SCL compiler can prove that the source operand has no side effects. The block in the field report produces Form A because the OUT parameter is read back before the second assignment.
Reconstruct the SCL by reading the first = after a load or boolean operation as the primary assignment, then treat any subsequent = on the next lines that target the same RLO-producing operand as additional assignment targets of the same expression. For example:
U #start_command
O #auto_start
= #motor_enable // primary assignment
= DB500.DBX 100.0 // secondary assignment of the same RLO
= DB500.DBX 101.0 // tertiary assignment
translates to:
motor_enable := start_command OR auto_start;
DB500.mirror_bit_1 := motor_enable;
DB500.mirror_bit_2 := motor_enable;
TEMP Variables and the L Stack
Compiled SCL frequently uses L 0.1, LW 4, LD 6, and so on. These are offsets into the block's local-data area (L stack), which is reserved at block call time. The mapping is:
| AWL operand | Data type | SCL declaration |
|---|---|---|
L 0.0 ... L x.7
|
BOOL (bit) | VAR_TEMP x : BOOL; |
LB 0 ... LB x
|
BYTE | Multi-bit BOOL cluster or BYTE
|
LW 0 ... LW x
|
WORD / INT |
WORD / INT / BOOL cluster |
LD 0 ... LD x
|
DWORD / DINT / REAL |
DWORD / DINT / REAL
|
The compiler allocates VAR_TEMP starting at offset 0.0 of the L stack. The first VAR_TEMP of BOOL type is L 0.0, the second is L 0.1, and so on. Bits within a single byte (LB 0) are referenced as L 0.0 through L 0.7; the next bit is L 1.0. The compiler prologue often starts with:
SET
SAVE
= L 0.1
This is a placeholder to initialize the first TEMP bit before the first real operation. If your interface does not list a VAR_TEMP at offset 0.1, the bit is an internal scratch flag generated by the compiler to manage expression evaluation, and you do not need to declare it in the rebuilt SCL.
The SAVE / BE Block Epilogue
Every FB/FC compiled by SCL ends with a fixed epilogue:
U L 0.1
SAVE
BE
The line U L 0.1 reads the BR mirror bit, and SAVE writes the current RLO into BR. BE returns to the calling block. This pattern means that the ENO output of the block reflects the value of the first TEMP bit at the end of execution. If the SCL source did not assign ENO explicitly, the compiler still emits the epilogue to satisfy the ENO contract.
Step-by-Step Reverse Engineering Procedure
- Open the block in the STL/FBD/LAD editor (double-click the FB in SIMATIC Manager). Switch the view to STL using View → STL.
- Enable symbolic representation with View → Display → Symbolic. Every address that has a symbol will now show the symbol name, which is the closest you can get to the original SCL identifier.
- Record the interface by opening the SCL view of the same block (View → SCL if the S7-SCL package is installed; otherwise use File → Properties → Interface). Export the interface to a text file.
- Generate the cross-reference list for the program folder (Options → Cross-reference → Display). For every global DBX/DBB/DBW/DBD used in the block, write down the symbol and the data type.
-
Annotate the AWL with AR1 state. Walk through the code top-to-bottom; whenever you see an
AUFinstruction or a full-qualified DB access, note the new AR1 value in the right margin. Every part-qualified access below it inherits that DB until the nextAUFor full-qualified access. -
Group assignments. For each
=instruction, identify the most recent RLO-producing load (U,O,L, or boolean expression). Consecutive=lines that share the same RLO source are a multi-assignment in SCL. -
Convert expression fragments to SCL.
L/Tpairs become right-hand-side expressions;Uchains become boolean expressions; arithmetic with+I,-D,*R,/Rbecomes integer or real arithmetic in SCL. - Reconstruct the block in SCL. Create a new SCL source file with the same FB number, paste the interface, and translate the annotated AWL into SCL statements. Keep the order of statements identical to the AWL to preserve evaluation order.
-
Compile the new SCL source and diff the generated AWL against the original. Functional equivalence is sufficient; minor differences in TEMP layout, multi-assignment grouping, and the use of
SET/CLRare expected. - Validate on the target CPU using a watch table, a test program, or PLCSIM. Run all branches of the block, including the error paths, and compare the output with the original block on a second instance of the CPU.
Compiler Settings That Affect Generated AWL
The SCL compiler exposes a small set of options that change the generated AWL. The most relevant ones for reverse engineering are:
| Option | Effect on AWL | Reverse-engineering impact |
|---|---|---|
| CreateDebugInfo | Embeds the line numbers and variable map required to step through SCL source. The original block in the field report was compiled with this flag off, which is why the multi-assignment collapses to a single RLO. | Blocks with debug info map cleanly back to SCL lines. Blocks without it require manual expression grouping. |
| Optimize object code | Removes redundant U / = pairs and re-uses temporaries. |
Statements can disappear; a single SCL line can produce zero AWL if the compiler proves it is a no-op. |
| Set ENO automatically | Emits the SAVE epilogue. |
If the option is off, the epilogue is omitted and the ENO is left at its previous value. |
| Recommended SCL header | { SCL_FB := 'true' ; SCL_CreateDebugInfo := 'true' } |
|
{ SCL_... pragma line in the SCL source forces the compiler options regardless of the editor settings. Always add it to new SCL source files so that the generated AWL is predictable across different workstations.Migration to TIA Portal: S7-SCL Version Requirements
If the recovered SCL is intended for a TIA Portal project, the original S7-SCL version on the source CPU must be V5.3 SP5 or later. Earlier V5.3 service packs produce SCL that the TIA Portal migration tool refuses to import. The official procedure is documented in the Siemens TIA Portal migration guide for SCL programs on S7-300/S7-400. Key points:
- The S7-SCL option package must be installed on the source device, not just on the target.
- Blocks compiled with debug info can be opened directly as SCL in TIA Portal; blocks compiled without debug info must be reverse-engineered by hand before migration.
- Symbolic names that reference deleted or renamed DBs are lost and must be re-mapped in the TIA Portal symbol table.
- TIA Portal V20 is the first version that supports migration of SCL from STEP 7 V5.7 with S7-SCL V5.4; for older STEP 7 V5.5 projects, S7-SCL V5.3 SP5 is the minimum.
Verification and Functional Equivalence Testing
Functional equivalence between the original AWL and the reconstructed SCL is the only safe completion criterion. Use the following checks:
-
Static checks: compile the new SCL with CreateDebugInfo = on and Optimize object code = off. The generated AWL should be nearly identical to the original line by line. Differences in
SET/CLRplacement and TEMP bit numbering are acceptable. - Cross-reference diff: generate the cross-reference list for both blocks and confirm that the set of read and write operations on every operand is identical.
- Online test in PLCSIM: instantiate the original FB in an OB1 call and capture every input combination into a watch table with force values. Repeat with the reconstructed FB. The instance DB contents must match after every test case.
-
Cycle-time check: use the CPU diagnostic buffer or the S7-PCTIME tool to compare OB1 cycle time before and after the swap. A change larger than 5% usually indicates that the reconstruction has introduced additional
U/=chains that should have been grouped. - EN/ENO behaviour: check the BR bit after the call. If the original block leaves BR = 0 on certain error paths, the reconstructed block must do the same.
Troubleshooting Matrix
| Symptom | Likely cause | Remedy |
|---|---|---|
| Compiled AWL uses an unknown DB number | Part-qualified DBX with no recent AUF visible in the same network |
Search the entire block, not just the current network; an earlier full-qualified access sets AR1 |
| Reconstructed SCL compiles to longer AWL | Optimize object code was off during the original compilation | Re-enable optimization; regroup multi-assignments manually |
| TIA Portal rejects the migrated SCL | S7-SCL version is below V5.3 SP5 | Reinstall S7-SCL on the source system, re-export the SCL, then migrate |
| Cyclic interrupt OB timeouts after reconstruction | Implicit SET at the top of the block is missing |
Add an explicit SET; at the start of the SCL source, or accept the implicit one |
| ENO stays TRUE in the reconstructed block but FALSE in the original | The compiler epilogue is missing or inverted | Add ENO := TRUE; at the end of the SCL source to force the SAVE epilogue |
| Different instance DB layout after re-compilation | Optimize object code reordered the STAT declarations | Re-create the instance DB with the original offsets before downloading |
Field-Proven Tips and Caveats
- Always export the original interface to a separate text file before you start touching the FB. The interface is the only piece of information that the SCL compiler never modifies between two recompilations of the same source.
- If the FB calls other FBs, the called block numbers are preserved in the AWL as direct
UC FBxxxcalls. Use the cross-reference list to walk the call tree before starting the reconstruction. - Multi-instance FBs (one FB used as a STAT inside another FB) appear in the AWL as accesses to the parent instance DB at fixed offsets. The offset of the multi-instance is the sum of all preceding STAT sizes; compute it by hand if the symbol table is missing.
- The SCL compiler does not emit comments. Once the SCL is recompiled, add comments for every non-obvious assignment to preserve the intent of the original programmer.
- If the project is from a third party and the original SCL cannot be reconstructed with full confidence, request the source from the machine builder before doing the migration. Reverse engineering is a last resort, not a routine task.
How do I find which DB is referenced by a part-qualified DBX in compiled AWL?
Walk upward in the same network until you find either an AUF (or OPN) instruction or a full-qualified DB access such as U DB500.DBX 205.1. The CPU loads that DB number into AR1, and every part-qualified DBX / DBB / DBW / DBD below it uses the same DB until the next AUF or full-qualified access. Confirm with the cross-reference list in SIMATIC Manager.
What is the L 0.1 in compiled SCL code?
L 0.1 is a TEMP bit at offset 0.1 in the block's local-data area. It is allocated by the SCL compiler as a scratch flag for expression evaluation, especially for the BR mirror at block end. It does not need to be declared in the rebuilt SCL; the compiler regenerates it automatically.
Can I decompile SCL back to source automatically?
No. STEP 7 V5.x does not ship an SCL decompiler. The SCL source can be opened directly only if the original block was compiled with CreateDebugInfo = on. Otherwise the only available workflow is manual reverse engineering from the compiled AWL, supported by the cross-reference list, the symbol table, and a hand-built SCL file recompiled in a sandbox project.
How does the CreateDebugInfo option affect SCL compilation?
With CreateDebugInfo = on, the compiler stores the SCL line numbers, the variable map, and intermediate RLO values inside the block, so that the SCL editor can step through the source. With CreateDebugInfo = off, the compiler omits that information, collapses multi-assignments into a single RLO, and may reorder or eliminate redundant statements. The original block in the field report was compiled with the option off.
What is the minimum S7-SCL version to migrate SCL blocks to TIA Portal?
S7-SCL V5.3 SP5 or later is the documented minimum. Earlier V5.3 service packs produce SCL that the TIA Portal migration tool refuses to import. The complete procedure and the version matrix are described in the Siemens TIA Portal migration guide for SCL programs on S7-300/S7-400.