S5 to S7 Conversion: Resolving LIR and TIR Errors

David Krause15 min read
HMI ProgrammingSiemensTroubleshooting
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

S5 to S7 Conversion: Resolving LIR and TIR Errors

The Siemens S5-to-S7 converter is a powerful utility for migrating legacy STEP 5 programs into the STEP 7 / TIA Portal environment, but it cannot translate every instruction set 1:1. Two of the most common conversion blockers are the indirect register operations LIR (Load Register Indirectly) and TIR (Transfer Register Indirectly). These operations exploit the 16-bit, byte-addressed memory model of the S5 CPU, a model that no longer exists on S7-300, S7-400, S7-1200, or S7-1500 controllers. The converter surfaces them as blocking errors and aborts the migration. This reference describes exactly why the conversion fails, the underlying machine semantics, and how to re-implement the LIR/TIR pattern with portable S7 code.

Field reality: A clean S5 → S7 migration almost never completes with the converter alone. Expect 5% to 25% of FBs to require manual re-coding after the converter finishes. Plan the conversion as a two-stage project: (1) automated translation + log review, (2) manual rewrite of indirect-register blocks.

1. Problem Details

An S5 program is uploaded from a running S5-95U / S5-115U / S5-135U / S5-155U CPU and opened in the S5-S7 converter (shipped as part of STEP 7 V5.x under Start → SIMATIC → STEP 7 → S5-S7 Converter, or the standalone S5Conv tool). The converter produces an S7 source container (*.s7) plus a conversion log. Typical log entries for LIR/TIR blocks resemble:

ERROR  30010  FB 210  LIR  -- instruction not convertible (S5-specific)
ERROR  30010  FB 210  TIR  -- instruction not convertible (S5-specific)
ERROR  32001  FB 210  conversion aborted, see log
WARN   10021  DB  72  data-word remap suggestion (DW0 = MW100)

The errors block the affected FB from being written to the S7 program. Warnings (e.g. data-word remapping) do not abort the conversion but require manual review. The error count must be zero before STEP 7 / TIA Portal will accept the converted S7 source.

Symptoms in the S5 program that almost always predict LIR/TIR usage:

  • FBs that manipulate data words in an indexed manner (e.g. a sorting, scanning, or search routine).
  • Code that loads the address into ACCU 1 first, then issues LIR or TIR immediately after.
  • Any FB that reads/writes arbitrary memory words from a runtime-computed offset.

2. Root Cause: S5 Memory Architecture vs. S7 Addressing

To fix the conversion cleanly, the engineer must understand the instruction semantics, not just patch symbols. The S5-115U and similar CPUs expose the following machine model to STEP 5 code:

S5 Resource Width Addressing Notes
ACCU 1 / ACCU 2 32 bits Implicit Loaded/stored by LIR / TIR with parameter 0 or 2
Data Words (DW) 16 bits DB-relative, byte offset 0..255 Each DW is two consecutive bytes
Flags (M / F) 1 bit / 8 bits / 16 bits Byte address, e.g. MW 100 Same byte address as S7, but word alignment is implicit
Inputs / Outputs 1 bit / 8 bits / 16 bits Byte address, e.g. IW 0 Process image only
Timers / Counters 16 bits 0..255 (S5) vs. 0..511 (S7-300) Range differences must be audited

The LIR instruction reads two consecutive bytes from the memory location whose absolute byte address sits in ACCU 1's low word, then writes the 16-bit result into the target register:

STEP 5 syntax:    LIR  <register>
                  register = 0  (load into ACCU 1, low word)
                  register = 2  (load into ACCU 2)

Equivalently, TIR writes the contents of ACCU 1 (or ACCU 2) to the absolute byte address that was loaded into ACCU 1's low word before the TIR call. The addressing model is therefore flat, byte-absolute, and pointer-relative to ACCU 1.

S7 controllers do not support flat absolute byte addressing from the user program. S7-300/400 use 16-bit pointers in DB-relative or area-internal form, and S7-1200/1500 prefer 32-bit POINTER / VARIANT structures plus the P# pointer literal. There is no direct equivalent to the S5 "I have a byte address in a register, fetch two bytes" idiom; the engineer must re-architect the access using either:

  • Indexed DB access with an ANY pointer built at runtime, or
  • An ARRAY of WORD in a global DB and an integer index, or
  • Memory-area access via PEW / PAW / area-crossing pointer math.

This is why the S5-S7 converter cannot lift LIR/TIR mechanically. The reference manual STEP 7 - From S5 to S7 lists LIR/TIR under "operations requiring manual intervention" and provides the same guidance: understand the STEP 5 code first, then re-write the block in STEP 7.

3. Prerequisites

Before starting the conversion, assemble the following:

  1. Source S5 program, ideally as a *.s5d or unzipped S5DOS file set, including cross-reference and symbol tables. Without symbols, the LIR/TIR call sites are nearly unreadable.
  2. Original S5 documentation: FB printouts, signal lists, operator panel layouts.
  3. STEP 7 V5.5 SPx with the S5-S7 converter installed, or the standalone S5-S7 converter from the Siemens Industry Online Support portal.
  4. STEP 7 (TIA Portal) V13 or later target environment, depending on the chosen S7-300/400/1200/1500 hardware.
  5. An offline S7 simulator (PLCSIM V13+) for verifying the rewritten blocks before commissioning.
  6. A diff/merge tool (e.g. WinMerge) to compare converted FB shells against the S5 originals.
Tip: Always run the converter twice — once for the FB sources, once for the DB sources — and merge the result into a single S7 project. The converter creates CONV sub-folders; do not edit in place.

4. Step-by-Step Conversion Workflow

The recommended procedure for a clean migration of an LIR/TIR-bearing program is:

Step 1 - Backup and Inventory

Archive the S5 source and write a one-page inventory of every FB, DB, OB, PB, SB referenced. Note timers, counters, flags, and process image areas. Cross-check the inventory against the symbol table so the engineer knows which addresses are used as runtime pointers (these are the LIR/TIR candidates).

Step 2 - Run the S5-S7 Converter

Open the converter, select the S5 program folder, choose a destination S7 project. Use the default rules for DB remapping (DW0 → DBB0/DBW0 in the target DB). Capture the full *.log file; the error table below maps the most common messages to their fixes.

Step 3 - Triage the Conversion Log

Group errors by block. For every error in an LIR/TIR context, the engineer must:

  1. Open the S5 FB printout.
  2. Identify the absolute byte address being loaded into ACCU 1 prior to the LIR/TIR.
  3. Determine which area the address refers to (DB, M, I, Q, T, C) and the offset within that area.
  4. Decide the S7 representation: DBW + index, MW + index, PEW + index, or an ANY pointer for area-crossing access.

Step 4 - Rewrite the Affected FBs

Replace each LIR/TIR pair with the patterns in section 5 / 6. Keep the FB's interface (IN, OUT, STAT, TEMP) unchanged so the call sites do not break.

Step 5 - Re-import and Compile

Re-import the manually edited STL/SCL sources into the S7 project. Compile, download to PLCSIM, and exercise the rewritten logic with a representative I/O trace.

Step 6 - Commission on the Real CPU

Move the project to the target S7-300 / S7-400 / S7-1500 station. Verify with a live signal test that the rewritten indirect access produces bit-identical results to the S5 reference (where reference data exists).

5. Replacing LIR (Load Register Indirectly) in STEP 7

The S5 idiom below is typical for "read a data word at a runtime-computed address":

| STEP 5 (S5-115U, FB210, STL)             | Meaning                              |
|------------------------------------------|--------------------------------------|
| L   DB  72                                | Open DB 72                           |
| L   DW  10                                | Load pointer offset (e.g. 10)        |
| SLD  1                                    | Shift left 1 to get byte address    |
| LIR  0                                    | Load 2 bytes into ACCU 1 low word    |

The S7 equivalent depends on the memory target. For the common case where the destination is a DB:

// S7-300/400 STL replacement for the LIR pattern above
      L     DBW [DB_NO]                  // open the destination DB (was DB 72)
      L     #iIndex                       // runtime index, INT, was DW 10
      SLD   3                             // byte offset = index * 2 (word = 2 B)
      +AR1                                // add to AR1 (or use LAR1 + AR1 logic)
      L     DBW [AR1,P#0.0]               // load the word at the indexed offset
      T     #wValue                       // store in TEMP / STAT

For S7-1200/1500 (TIA Portal), the canonical pattern uses an explicit ARRAY of WORD in a global DB:

// SCL / S7-1500, TIA Portal V16+
IF #iIndex >= 0 AND #iIndex < "gDB_Scan".awData[#iIndex]  // bounds guard
   THEN
      #wValue := WORD_TO_INT("gDB_Scan".awBuffer[#iIndex]);
END_IF;

For memory-flag or process-image targets, the same pattern uses MW[#iIndex] or PEW[#iIndex] on S7-300/400, and indexed access through a tag array in TIA Portal on S7-1500.

Word-alignment caveat: The S5 LIR always reads two consecutive bytes starting at the byte address in ACCU 1. The S7 index must be halved (shift right 1) or multiplied by 2 (shift left 1) depending on whether the index is a word count or a byte count. Document the unit explicitly in the new FB header comment to avoid off-by-one bugs during commissioning.

6. Replacing TIR (Transfer Register Indirectly) in STEP 7

The S5 write idiom is the mirror of the read:

| STEP 5 (S5-115U, FB210, STL)             | Meaning                              |
|------------------------------------------|--------------------------------------|
| L   DB  72                                | Open DB 72                           |
| L   DW  10                                | Load pointer offset                  |
| SLD  1                                    | Shift left 1 to get byte address    |
| L   DW  50                                | Value to be written                  |
| TIR  0                                    | Store ACCU 1 low word to mem[addr]   |

The S7 replacement is the indexed-store equivalent:

// S7-300/400 STL replacement for the TIR pattern above
      L     #iIndex                       // runtime index, INT
      SLD   3                             // byte offset = index * 2
      +AR1
      L     #wValue                       // value to store
      T     DBW [AR1,P#0.0]               // write to the indexed offset

For S7-1500 in TIA Portal, use direct array-element assignment:

// SCL / S7-1500, TIA Portal V16+
IF #iIndex >= 0 AND #iIndex < "gDB_Scan".awData[0].#iIndex  // bounds guard
   THEN
      "gDB_Scan".awBuffer[#iIndex] := INT_TO_WORD(#wValue);
END_IF;

For area-crossing writes (e.g. writing into the flag area or process image), build an ANY pointer with BLD / LAR1 semantics on S7-300/400:

// S7-300/400 area-crossing write via ANY pointer
      LAR1  P##tAnyPointer                 // load address of ANY
      L     B#16#10                        // syntax ID: S7 area (MW / PEW / ...)
      T     LB [AR1,P#1.0]
      L     B#16#2                         // transport size: WORD
      T     LB [AR1,P#2.0]
      L     1                              // length = 1 WORD
      T     LW [AR1,P#4.0]
      L     #iIndex                        // byte offset (already word-multiplied)
      SLD   3
      T     LD [AR1,P#6.0]
      L     #wValue
      T     LW [AR1,P#10.0]

7. Pointer Construction and Boundary Checks

S7 indirect access crashes (CPU STOP, SF LED, entry in the diagnostic buffer) when the runtime index is out of range. The S5 platform tolerated many such edge cases silently because the entire memory map was reachable. The S7 platform protects itself, so the rewritten FB must include explicit bounds checks:

Target area Index unit Valid range (S7-300) Valid range (S7-1500) Recommended check
Global DB (WORD) Word index 0..DB length (words) - 1 0..Array upper bound iIndex >= 0 AND iIndex < DB_LEN
Merker (MW) Word index 0..255 n/a (use global DB) iIndex >= 0 AND iIndex <= 255
Process image (PEW / PAW) Byte index / 2 0..byte image size - 1 0..byte image size - 1 Use P# with RANGE input
Timers / Counters Word index 0..511 0..65535 (S7-1500) Check against CPU_RT configuration

The 32-bit S7 POINTER format is laid out as follows, and is the structure that the S5 LIR/TIR byte address must be re-encoded into:

Bits 31..24  | 23..16         | 15..8      | 7..0
DB number    | Area (B#16#84) | Byte offset high
                                              | Byte offset low (bit 7..0)

For area-internal pointers (no DB), bits 31..24 and 23..16 hold the area ID and a byte offset within a single area. Use P#DB100.DBX0.0 BYTE 2 as a literal template when building the pointer at runtime.

8. Common Converter Errors and Resolutions

Converter error / warning Typical cause Resolution
ERROR 30010 LIR / TIR not convertible Indirect register op Rewrite block per sections 5-7
ERROR 30011 DO / DO = on S5 file type DO/DO= loop on S5-135/155 Replace with FOR / WHILE in SCL or LOOP in STL
ERROR 30020 formal parameter type mismatch S5 BYTE/WORD/DWORD semantics differ from S7 Adjust the FB interface, retest call sites
ERROR 30030 unsupported operand area Access to AS/RS/extended flags Move data into M/DB and rewrite access
WARN 10021 data-word remap suggestion DBW 0 ↔ DBB 0 vs. DW 0 mapping Verify bit/byte orientation, swap if needed
WARN 10035 timer range extension S5 had 256 timers, S7-300 has 512 Reassign T 256..511 to match runtime needs
ERROR 32001 conversion aborted Fatal earlier error Fix the first non-warning error, re-run

9. When Re-Coding Is Faster Than Converting

For S5 programs dominated by indirect access (sort routines, ring-buffer management, scan logic, recipe tables), it is often faster to re-architect the FB in SCL using an explicit ARRAY OF WORD than to mechanically translate LIR/TIR call sites. The trade-off table below is field-proven on several mid-sized S5-115U projects:

Approach Effort (1 FBs) Risk of LIR/TIR bug Maintainability Best for
Converter only Low 100% (will fail) Poor Pure logic, no indirect access
Converter + manual LIR/TIR patch Medium Low Good Mixed programs with few LIR/TIR sites
Full re-coding in SCL / TIA Portal High None Excellent Programs with many indirect accesses, new S7-1500 target
Hybrid: convert structure, re-code hot blocks Medium-High Low Good Most realistic migrations

10. Verification and Commissioning

Once the manual re-coding is complete, the project must pass these checks before live commissioning:

  1. Compile clean — no warnings related to overlapping memory areas or unreachable code.
  2. PLCSIM unit tests — exercise every iIndex boundary (0, last valid, +1 past end, max INT, min INT) and confirm the FB returns the expected default / clamps / flags an error.
  3. Cross-reference parity — diff the S5 and S7 cross-reference tables. Every variable that was used in the S5 program should be present in the S7 project, even if the data type changed.
  4. Cycle-time budget — indexed S7 access is slower than direct symbolic access. Benchmark the rewritten FB in OB1 and confirm the overall OB1 time stays within the configured maximum cycle time.
  5. Diagnostic-buffer inspection — run the converted project for at least 8 hours in PLCSIM with full I/O toggling, then check the diagnostic buffer for STOPs, area-length errors, or DB-not-loaded errors.
  6. Side-by-side commissioning — when possible, run the S5 and S7 stations in parallel for a few production shifts, comparing outputs bit by bit before cutting over.
Safety-critical reminder: If the S5 program implements safety functions (e.g. ESTOP, light curtain, guard interlock), the converted S7 logic must be re-validated in a SIL/PL context. S5-to-S7 conversion alone is not a valid argument for preserving a SIL rating. Use the appropriate Siemens safety CPU (e.g. S7-1500F, ET 200SP F-CPU) and re-verify with the S7 F-Configuration Pack.

11. Toolchain Reference

Tool Version Use Source
STEP 7 V5.5 SPx V5.5 + latest HF Source project, S5-S7 converter host Siemens Industry Online Support
S5-S7 Converter shipped with STEP 7 V5.5 Automated translation Siemens (manual 45531547)
STEP 7 (TIA Portal) V13 .. V18 (target dependent) Target engineering Siemens Industry Online Support
PLCSIM V13+ Offline validation Siemens Industry Online Support
S7-SCL optional add-on High-level rewrite of indirect FBs Siemens Industry Online Support

The reference manual STEP 7 - From S5 to S7 (PDF, Siemens manual 6ES7810-4CA06-8CA0 / 45531547) remains the authoritative guide for the converter workflow and is the same document the converter itself consults for its built-in remapping rules. Pair that document with the TIA Portal help on indexed access and you have a complete, auditable migration path.

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

Because LIR (Load Register Indirectly) and TIR (Transfer Register Indirectly) read or write two bytes at a flat, byte-absolute address held in ACCU 1. S7 user programs cannot issue flat absolute byte addresses; they must use DB-relative or area-internal pointers. The converter has no general rule to translate the S5 idiom, so it logs ERROR 30010 and aborts the affected FB.

What is the direct S7 replacement for LIR 0?

If the absolute address pointed into a DB, open the DB and load the indexed word: L DBW [AR1,P#0.0] where AR1 has been loaded with the byte offset of the target word. If the address pointed at flag memory, use L MW[AR1,P#0.0]; for process-image access, L PEW[AR1,P#0.0] or L PAW[AR1,P#0.0] for output. Always add a bounds check before the indexed access to avoid CPU STOP.

What is the direct S7 replacement for TIR 0?

The mirror of the LIR replacement: T DBW[AR1,P#0.0] after pre-loading AR1 with the byte offset. For TIR that wrote into the flag area, use T MW[AR1,P#0.0]. The S5 parameter 0 (ACCU 1) and 2 (ACCU 2) are both collapsed onto ACCU 1 in S7 because S7 STL always operates on ACCU 1 by default.

How do I migrate a large S5 project with many LIR/TIR blocks?

Run the S5-S7 converter for the bulk of the project, then iterate over the conversion log. Group the failed FBs by the memory area they target. For DB-targeted FBs, refactor the DB into an ARRAY OF WORD and re-implement the FB in SCL using array indexing; this typically removes 80% of the LIR/TIR boilerplate. For flag- or PI-targeted FBs, build ANY pointers or use PEW / PAW indexed access. Always validate the rewritten FBs in PLCSIM before commissioning.

Can the S5-S7 converter preserve the original S5 semantics if I accept the warnings?

No. Warnings do not suppress errors. An FB that contains LIR or TIR is blocked from being written to the S7 program at all, regardless of warning acceptance. The only way to keep that FB is to manually rewrite the indirect access patterns as described in this article. Treat the S5-S7 converter as a translation accelerator, not a complete migration tool.

Are there any S5 instructions other than LIR/TIR that the converter cannot translate?

Yes. The converter also cannot translate DO / DO = (program loop), some S5-135/155-only instructions such as AS / AF / JU-to-PB branches, and any access to the S5 system data areas. The reference manual STEP 7 - From S5 to S7 lists the full set in its appendix; budget for manual intervention on each occurrence.

Back to blog