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.
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 offsetn. On the S5-135U/155U with R-processor,RS 34points 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 1uses 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 aLRWfrom 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.
// 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
.S5Dor.Z0container, 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.
- Read the 16-bit DB number from DW0 of the currently open source DB into a flag word (FW240).
- Convert the number to a pointer so it can be used with
OPN DB [MW ...]or build the pointer to DBW 0 directly withP#DBX 0.0. - 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
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
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;
"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
- 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.
- 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).
- Force MW 240 to a known valid DB number (e.g. 10) using the watch table. Verify that
MW 244tracksDB10.DBW0after the next OB 1 cycle. Use VAT 1 with format 'HEX' for MW 240 to confirm the pointer was read correctly. - 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. - 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 0is 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 / CLRor 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. S7L DBWdoes the same. No byte swap is required. -
Address arithmetic on the 135U. The
+Fin the source is 16-bit fixed-point. If you ever need to port the actualL RS 34 + L FW 240 + +F + LIR 1pointer add instead of the cleaned-up version, the S7-400 STL equivalents areLAR1 P#0.0 / L MW 240 / SLD 3 / +AR1 / L DBW [AR1, P#0.0]whereSLD 3converts the word offset to a byte pointer (multiply by 8). -
CPU 928B only.
LIR/TIRwith 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 |
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.