HLASM Character Operations: MVC, MVZ, MVN, MVI, and TR

TT

HLASM Character Operations: MVC, MVZ, MVN, MVI, and TR

Character operations move and transform bytes in memory. Unlike arithmetic instructions that work on registers, these SS (Storage-to-Storage) and SI (Storage-Immediate) instructions operate directly on memory fields. They are essential for data formatting, conversion, and manipulation.

MVC — Move Characters

MVC destination(length),source copies length bytes from source to destination:

hlasm
         MVC   OUTPUT(80),INPUT    Copy 80 bytes from INPUT to OUTPUT
         MVC   HEADING(10),=CL10'REPORT    '  Move literal to field

MVC copies from left to right, one byte at a time. This means overlapping moves work predictably:

hlasm
* Propagate a single byte across a field (padding trick):
         MVI   FIELD,C' '          Move one space to byte 0
         MVC   FIELD+1(79),FIELD   Copy byte 0 to bytes 1-79 (propagate)
* After: FIELD is 80 spaces
FIELD    DS    CL80

The MVI+MVC propagation is a classic HLASM idiom for initialising a field.

MVC Length Limit

MVC can move up to 256 bytes in one instruction. For longer fields, use a loop or the MVCL instruction:

hlasm
* Move a 500-byte field using two MVC instructions
         MVC   TARGET(256),SOURCE         First 256 bytes
         MVC   TARGET+256(244),SOURCE+256 Remaining 244 bytes

MVCL — Move Characters Long

MVCL moves up to 16MB using register pairs:

hlasm
* Move 500 bytes with padding
         LA    2,TARGET        Destination address
         LA    3,500           Destination length
         LA    4,SOURCE        Source address
         LA    5,300           Source length (shorter than dest)
         ICM   3,8,=X'40'      Set pad character (space) in high byte of reg 3
         MVCL  2,4             Move: pads with space if source shorter than dest

MVI — Move Immediate

MVI storage,immediate moves a single byte constant to storage:

hlasm
         MVI   FLAG,X'01'      Set flag byte to 1
         MVI   OUTPUT,C'*'     Put asterisk in first byte of output
         MVI   SIGN,C'+'       Set sign indicator
FLAG     DS    X
OUTPUT   DS    CL80
SIGN     DS    C

MVZ — Move Zones

MVZ destination(length),source copies only the zone (high nibble) of each byte:

hlasm
* Set zone bits of 5 bytes to EBCDIC zone (X'F')
         MVZ   NUMFIELD(5),=X'FFFFFFFFFFFFFFFF'
NUMFIELD DS    ZL5

MVZ is used with PACK/UNPK operations and sign manipulation.

MVN — Move Numerics

MVN destination(length),source copies only the numeric (low nibble) of each byte:

hlasm
* Copy numeric portions only (useful for digit extraction)
         MVN   DEST(5),SOURCE

TR — Translate

TR field(length),table replaces each byte in the field with the byte at that position in the 256-byte translation table. This is the z/OS equivalent of a character-by-character lookup table:

hlasm
* Convert lowercase EBCDIC to uppercase
UPRTAB   DC    256X'00'        Start: identity table would be better; use proper init
* (In practice, use a pre-built EBCDIC upper-case translation table)

         TR    INDATA(80),UPRTAB   Translate 80 bytes using table
INDATA   DS    CL80

Building a Translation Table

hlasm
* EBCDIC to ASCII conversion table (256 bytes)
E2ATAB   DS    0XL256
         DC    X'0001020304'    ... first 5 bytes
*        (full 256-byte table needed for complete conversion)

TRT — Translate and Test

TRT field(length),table scans the field and stops at the first byte whose table entry is non-zero:

hlasm
* Find first non-space character in a field
SCANTAB  DC    256X'FF'        All bytes signal "found"
         ORG   SCANTAB+X'40'
         DC    X'00'           Space (X'40') = don't stop
         ORG
*
         LA    3,INDATA        Point to input field
         TRT   INDATA(80),SCANTAB
         BZ    ALLSPACE        Branch if no non-space found
* reg 1 = address of first non-space byte
* reg 2 = table value at that position
INDATA   DS    CL80

TRT is commonly used for scanning records, finding delimiters, and parsing data.

Frequently Asked Questions

Q: Why does MVC copy left-to-right and why does this matter for overlapping moves? MVC processes bytes sequentially from left (lowest address) to right. When the source and destination overlap and the source starts before the destination by exactly one byte, MVC propagates the first source byte across the entire destination — this is the classic initialisation idiom (MVI FIELD,C' ' followed by MVC FIELD+1(n-1),FIELD). If source and destination overlap with source starting after destination, some bytes might be overwritten before being read, giving unexpected results.

Q: What is the maximum length for SS instructions like MVC? Most SS instructions, including MVC, CLC, and TR, have a maximum length of 256 bytes (specified as a value from 1 to 256, encoded as 0 to 255 in the instruction). For fields longer than 256 bytes, use multiple instructions, the MVCL/CLCL long-form instructions, or a loop.

Q: When should I use TR vs a loop with CLI/MVI? TR is significantly faster than a byte-by-byte loop for translating long fields because the CPU can process multiple bytes per cycle. Use TR for format conversion (EBCDIC to ASCII, lowercase to uppercase), character class testing, and similar bulk byte transformations. Use CLI/MVI when translating single bytes or when the logic is too complex to fit in a 256-byte table.


Part of HLASM Mastery Course — Module 9 of 22.