Converting SIMATIC S5 L RS and LIR Instructions to S7 STL

David Krause14 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

Overview

The classic SIMATIC S5 instruction pair L RS <n> followed by LIR <r> is a runtime indirection that the STEP 7 converter cannot translate. The converter flags the segment as an error and stops. You must rewrite the segment manually using STEP 7 STL (or SCL) pointer arithmetic on LAR1 / LAR2, the OPN DB / OPN DI block call, and the area-internal pointer format P#DBx.DBXy.z. This reference walks through the original S5 semantics, identifies the exact bit of the S5 R-processor memory model the code is touching, and shows a working S7-300/400 STL replacement that compiles in STEP 7 V5.x and TIA Portal V13+ for S7-300/S7-400 CPUs.

The two instructions are CPU-specific. They belong to the S5-135U and S5-155U with R-processor (RAG/RPG) firmware and to the CPU 928B. The S5-95U, S5-100U, and S5-115U do not implement LIR / L RS in the same way. Before porting, confirm the source CPU with the S5 program header (block OB 1 or DB 1 'CPU parameters').

The Source Segment, Annotated

The source S5 STL block (typical OB 1 cycle) reads:

L   FW 242        // load flag word FW242 into ACCU 1
I   1             // increment ACCU 1-L by 1
T   FW 242        // transfer back, rolling counter
DO  FW 242        // decrement FW242 (wraps 0 to 65535 on 135U)
L   DW 0          // load data word DW0 of the currently opened DB
T   FW 240        // store it in FW240 (the indirect index)
L   RS 34         // load the base address of the DB address list (RS 34)
L   FW 240        // add the offset stored in FW240
+F                // 16-bit fixed-point addition, result in ACCU 1
LIR 1             // load the word at the calculated address into ACCU 1
T   FW 244        // store result in flag word FW244

The semantic meaning of the two flagged instructions is documented in the SIMATIC S5 CPU 928B manual (Siemens entry ID 19397726) and the S5-135U R-processor operating instructions (entry 27833137):

  • L RS <n> loads the absolute word address of the start of the DB address list (Register Stack / Registersatz) at offset n. On the S5-135U/155U with R-processor, RS 34 points to the first byte of the runtime DB address list, i.e. the location where the base addresses of all opened DBs are kept.
  • LIR <r> performs an indirect read. LIR 1 uses register 1 of the R-processor as the address source. The 16-bit word at the address in ACCU 1-L is copied into ACCU 1-L. The CPU first reads the low word, then increments the address and reads the high word, exactly like a LRW from a memory-mapped pointer.

In the example, the S5 code resolves to: load the first word of DB whose number is stored in FW240 (which was just populated from DW0 of the currently open DB) into FW244. This is a classic table-lookup pattern: a DB number is read from a header word, then the corresponding DB is opened by number and its first data word is read.

Why the STEP 7 Converter Fails

The S5-to-S7 converter that ships with STEP 7 V5.x and the older S7-300 Migration Tool generates STL by pattern matching. LIR and TIR are not part of the S7-300/400 instruction set. The converter tries to map the operand to a memory area symbol, fails to find a 1:1 match, and raises a conversion error E32 'Cannot convert statement'. The R-processor register stack is also not available on S7 CPUs, so even the operand RS 34 has no S7 equivalent.

Do not attempt to silence the converter by adding manual // CONV comments or by suppressing errors with the 'Accept error' flag. The error must be fixed in the STL; the converter only converts syntax it understands.

Prerequisites

  • STEP 7 V5.5 or later (or TIA Portal V13 SP1+ with S7-300/S7-400 target). The SCL compiler is optional but recommended for clarity.
  • Source S5 project in .S5D or .Z0 container, with the S5 program converted to an S7 source.
  • Target CPU known: S7-314, S7-315-2 DP, S7-416, S7-317, or S7-319. All support the STL instructions below.
  • Siemens manual SIMATIC S5 Operating Instructions for the S5-135U with R-Processor (PDF, entry 27833137) for cross-reference of the source semantics.
  • Siemens manual CPU 928B Manual (S5-135U/155U) (entry 19397726), chapter 9 'Indirect addressing with the R-processor'.
  • Siemens STEP 7 STL Programming Manual for the address, pointer and area-crossing instruction set on S7-300/400.

S5 to S7 Instruction Mapping

S5 Instruction Meaning on S5-135U R-processor S7-300/400 Equivalent Notes
L RS 34 Load base address of DB address list (registersatz 34) LAR1 P#DBX 0.0 plus OPN DB[number] S7 has no RS list; use the block number directly
LIR 1 Indirect load using R-processor register 1 L DBW [AR1,P#0.0] after LAR1 Use AR1 (or AR2) and area-internal / area-crossing pointer
DO FW 242 Decrement 16-bit flag word (modulo 65536) DEC FW 242 not available; use L FW 242 / INC 1 / T FW 242 pattern (already used above) and explicit DEC via L FW 242 / + -1 / T FW 242 No dedicated decrement instruction in S7 STL
I 1 Increment ACCU 1-L by 1 (16 bit) + 1 or INC 1 on S7-400 INC is not in S7-300 instruction set; use + 1
TIR 1 Indirect store using R-processor register 1 T DBW [AR1,P#0.0] Same addressing scheme as LIR
L DW 0 Load data word 0 of opened DB L DBW 0 after OPN DB[number] Direct 1:1 match

Manual Conversion Strategy

The strategy is to split the original indirect DB-access into two deterministic S7 steps: (1) compute the DB number from the header word, (2) open that DB by number and read DBW 0. The intermediate pointer arithmetic disappears entirely on S7 because the CPU has a dedicated OPN DB[n] opcode that takes a 16-bit DB number from ACCU 1-L and resolves the DB base address in hardware. You no longer need to load the address-list base and add an offset by hand.

  1. Read the 16-bit DB number from DW0 of the currently open source DB into a flag word (FW240).
  2. Convert the number to a pointer so it can be used with OPN DB [MW ...] or build the pointer to DBW 0 directly with P#DBX 0.0.
  3. Open the destination DB and load DBW 0 into a flag word (FW244).

Step-by-Step Conversion

Step 1 - Replicate the source roll-counter

The lines before L RS 34 are a 16-bit rolling counter on FW242. On the S7-300, the INC opcode is not part of the instruction set; replace with explicit + 1:

L     MW 242            // S7 flag word (FW -> MW)
L     1
+I                     // 16-bit integer add
T     MW 242            // unsigned 16-bit wrap at 65536
If your original S5 code uses DO FW 242 as an independent decrement (separate from the increment above), port it as its own pair of L MW 242 / L -1 / +I / T MW 242 lines. Keep the two operations in the same order they appeared in the S5 source, because the S5 executes top-to-bottom without preemption only inside a single OB 1 cycle.

Step 2 - Load the DB number from DW0

The original code reads DW0 of the currently open DB. In S7, after OPN DB[x] the active DB is referenced by the DBW operand. The 1:1 mapping is:

OPN   DB   [the currently open DB in S5]
L     DBW  0
T     MW   240

You must have opened the source DB earlier in the same block with OPN DB <symbol> or OPN DI <symbol>. In STEP 7 the symbolic name (e.g. DB100) is required; the S5 'DW 0' implicit reference to the most-recently opened DB is no longer implicit.

Step 3 - Open the target DB by number and read DBW 0

This is the direct replacement for L RS 34 + L FW 240 + +F + LIR 1:

L     MW   240            // DB number, e.g. 10
OPN   DB   [MW 240]       // open DB whose number is in MW 240
L     DBW  0              // load DBW 0 of the now-open DB
T     MW   244            // write result into the flag word

The OPN DB [MW 240] operand expects a 16-bit word operand. MW 240 works directly. The CPU reads the number, validates that the DB exists in the work memory (loadable by SFC 12 'D_ACT_DP' if not resident), and updates the DB register. The next L DBW 0 reads word 0 of that DB.

Step 4 - Assemble the full STL segment

// --- rolling counter on MW 242 ---
L     MW   242
L     1
+I
T     MW   242

// --- optional decrement, mirrors original DO FW 242 ---
L     MW   242
L     -1
+I
T     MW   242

// --- read DB number from currently open source DB ---
OPN   DB   "src_db"           // symbolic name of the source DB
L     DBW  0
T     MW   240

// --- open target DB by number and read DBW 0 ---
L     MW   240
OPN   DB   [MW 240]           // open DB # = MW 240
L     DBW  0
T     MW   244

Alternative: Area-Internal Pointer Without OPN

If you want to keep the exact 'compute pointer, dereference' style of the S5 code, you can build a P# pointer in AR1 and use area-internal indirect addressing. This is closer to a line-by-line translation but adds no value on S7 and uses more CPU time. It is shown for completeness:

OPN   DB   "src_db"
L     DBW  0
T     MW   240                 // MW240 = DB number of target

L     MW   240                 // load target DB number
ITD                           // ACCU 1 -> 32-bit integer
LAR1                           // AR1 is not usable as DB number
L     P#0.0
LAR2                           // AR2 will hold the data offset
You cannot open a DB by number with a P# pointer. The OPN DB opcode always needs the DB number, never an address. Stick with the OPN DB [MW n] form for a 1:1 functional port.

Alternative in SCL

If you prefer a higher-level expression, the same logic in SCL for S7-300/400 (SCL V5.3+):

// SCL
src_db_word0 := "src_db".DBW0;
FOR n := 0 TO 0 DO
    MW240 := src_db_word0;
END_FOR;
IF (MW240 <> 0) AND (MW240 <= 65535) THEN
    "db_target".DB[MW240].DBW0 := MW244;
    MW244 := WORD_TO_INT("db_target".DB[MW240].DBW0);
END_IF;
SCL array indexing into a multi-instance DB ("db_target".DB[MW240]) is only legal in TIA Portal V15+ for S7-300/400 with an AREA-POINTER-aware compiler. On STEP 7 V5.5 use the OPN DB [MW n] STL pattern above.

Verification

  1. Compile the STL block in STEP 7 with 'Check Block Consistency' (menu: Edit → Check Block Consistency → All). The compiler must report zero errors and zero warnings.
  2. Download the block to the target CPU. The CPU must reach 'RUN' and the diagnostic buffer must show no startup OB errors (OB 100 / OB 101 / OB 102).
  3. Force MW 240 to a known valid DB number (e.g. 10) using the watch table. Verify that MW 244 tracks DB10.DBW0 after the next OB 1 cycle. Use VAT 1 with format 'HEX' for MW 240 to confirm the pointer was read correctly.
  4. Force MW 240 to 0. The CPU must NOT enter STOP. Add an explicit range check (L MW 240 / L 1 / <I / JC ERR / L 0 / T MW 244) if your application must reject DB number 0.
  5. Force a non-existent DB number (e.g. 9999). The CPU will raise OB 121 'Programming error' with BIE/STW bit pattern 'DB not loaded'. Catch the error in OB 121 or pre-validate with SFC 12 'D_ACT_DP' before opening.

Edge Cases and Field-Proven Caveats

  • DB number 0. OPN DB 0 is legal on S5 (closes the DB) and illegal on S7 (raises OB 121). Always guard against DB number 0 in the input word.
  • Unloaded DB. The S5 R-processor keeps the DB base address in the register stack. The S7 CPU must have the DB loaded in work memory. If the destination DB is RAM-only and not currently loaded, use SFC 12 'D_ACT_DP' to link it from passive to active before opening.
  • Data-consistency. The original S5 pattern has a 2-cycle race: an OB 1 cycle increments FW 242, then reads the DB number, then opens the DB. On S7, if OB 1 is interrupted by an OB 35 that also writes MW 242, the lookup can return the new value. Lock the critical section with SET / SAVE / CLR or move the data into a temp variable in the OB 1 priority class.
  • Byte order on 16-bit LIR. The S5-135U R-processor stores the low word at the lower address. S7 L DBW does the same. No byte swap is required.
  • Address arithmetic on the 135U. The +F in the source is 16-bit fixed-point. If you ever need to port the actual L RS 34 + L FW 240 + +F + LIR 1 pointer add instead of the cleaned-up version, the S7-400 STL equivalents are LAR1 P#0.0 / L MW 240 / SLD 3 / +AR1 / L DBW [AR1, P#0.0] where SLD 3 converts the word offset to a byte pointer (multiply by 8).
  • CPU 928B only. LIR / TIR with register 1/2 are CPU 928B and CPU 948B opcodes. The 928A has a different (limited) addressing scheme and does not implement the full register-stack indirection. Verify the source CPU before porting.
  • STEP 7 V5.5 deprecation. STEP 7 V5.5 is the last release for S7-300/400. Newer projects should be moved to TIA Portal V16+; the STL syntax above is identical between STEP 7 V5.5 and TIA Portal, but the conversion tool is removed in TIA Portal V18.

Cross-Platform Notes

Source CPU Target CPU Conversion Compiler
S5-135U R-processor S7-315-2 DP / S7-317 Manual STL rewrite with OPN DB [MW n] STEP 7 V5.5 / TIA V13-V17
S5-155U R-processor S7-416 / S7-417 Same as above, plus use of AR2 for multi-instance STEP 7 V5.5 / TIA V13-V17
CPU 928B (S5-135U/155U) S7-315-2 PN Same as above STEP 7 V5.5 / TIA V13-V17
S5-95U / 100U / 115U S7-314 No LIR in source; standard auto-conversion works STEP 7 V5.5 / TIA V13-V17
Any S5 S7-1200 / S7-1500 Not supported; S7-1200/1500 use optimized DBs and have no STL indirect OPN DB [MW] TIA Portal V16+ only
S7-1200 and S7-1500 do not support the OPN DB [MW n] form with a variable DB number on optimized DBs. If the target is S7-1500, you must declare the destination DB as a non-optimized (standard) DB and access it via %DB[n] in SCL. The STL technique in this article is for S7-300/400 only.

Troubleshooting Matrix

Symptom Likely Cause Fix
Converter stops with 'Cannot convert statement LIR' No S7 equivalent exists Rewrite segment manually as shown
CPU goes to STOP with OB 121 'DB not loaded' Target DB is in passive state, not in work memory Use SFC 12 'D_ACT_DP' to link DB before OPN
MW 244 holds garbage MW 240 is a DB number that is not yet loaded; OPN succeeds but DBW 0 is uninitialized Initialize the target DB or pre-validate with SFC 12
OB 1 cycle time increased by ~20% Pointer arithmetic in STL is slower than direct OPN DB Replace with the cleaned-up OPN DB [MW n] form
DB number changes between the increment and the OPN Higher-priority OB is writing MW 242 Move counter and lookup to a single OB, or lock with SET/SAVE/CLR

FAQ

What does L RS 34 mean in a SIMATIC S5 program?

On the S5-135U and S5-155U with R-processor (or CPU 928B), L RS 34 loads the absolute word address of the base of the DB address list (registersatz, offset 34) into ACCU 1-L. The DB address list is a system area that holds the base addresses of every opened DB; the runtime LIR / TIR instructions add a word offset to this base and dereference the result. See the CPU 928B Manual, chapter 9.

What does LIR 1 do on the S5?

LIR 1 reads a 16-bit word from the absolute address contained in ACCU 1-L, using R-processor register 1 as the addressing register. The CPU first reads the low word, then auto-increments the address and reads the high word, producing a full 32-bit result in ACCU 1. It is the S5 equivalent of L DBW [AR1, P#0.0] on S7, but at the absolute-memory level rather than the DB level.

Why does the S5-to-S7 converter fail on LIR and LIR/TIR pairs?

The S7-300/400 instruction set does not include absolute-memory LIR / TIR and does not expose the R-processor register stack. The converter has no 1:1 mapping and raises error E32 'Cannot convert statement'. You must rewrite the segment manually using OPN DB [MW n] or area-internal pointers on AR1 / AR2.

What is the S7-300/400 equivalent of the original S5 code in this article?

The clean replacement is: L MW 240 / OPN DB [MW 240] / L DBW 0 / T MW 244. The L RS 34 + L FW 240 + +F + LIR 1 chain collapses to a single OPN DB [MW 240] because the S7 CPU resolves the DB base in hardware from the DB number, eliminating the manual pointer add.

Can I use the same STL pattern on S7-1500 or TIA Portal V18+?

No. S7-1200 and S7-1500 with optimized DBs do not support OPN DB [MW n]. On S7-1500 you must use SCL with a non-optimized (standard) DB and the %DB[n] slice, or refactor the lookup into an ARRAY in a single DB. The STL pattern in this article targets S7-300 and S7-400 with STEP 7 V5.5 or TIA Portal V13-V17.

Back to blog