Friday, March 15, 2019

MVS/370 Assembler - Like Building with Lego Blocks


Here's another MVS/370 Assembler relic from the past... I've always found writing machine code to be, in an artistic sense, like assembling Lego blocks. The instructions are arranged in 2, 4 or 6-byte "blocks" - each with their own format & attributes - but still blocks nonetheless. This post showcases an Assembler "Building Block" experiment I conducted almost 30 years ago...


Below shows the IBM 370 instruction formats - each half-word takes up 2 bytes. You can see the RR format instructions take up 2 bytes. RX, RS, & SI are 4-bytes (a Full Word) and the SS series takes 6 bytes. So these are your Lego "blocks"...



There are strict rules that must be adhered to when "assembling your blocks". All instructions must be aligned at a minimum on a half-word boundary. That means an instruction (or "block") must be placed on an even offset (See my PC/370 Object Code Translator for an example in motion). That means offsets ending in an even hexadecimal number - 0,2,4,6,8,A,C,E. Some instructions require fullword alignment - hex offsets ending in 0, 4, 8 and C. When your source code is assembled (similar to a compile) the alignments & many other rules are adhered to.


If you took an Assembler course the instructor would probably have you map out the instruction values (in assembled object form) by hand so you can understand how the source code assembler operates. The result would be a string of hexadecimal numbers that would be difficult if not impossible to effectively interpret. A hex string x'90ECD00C' can be coded as a constant instead of the command: STM   R14,R12,12(R13) - that was a fairly easy one compared to others. When an instruction contains storage displacements it is futile to code the value in hex. If another instruction is added somewhere in the program your hard-coded offsets are no longer valid.

Here's an exercise that uses the "Lego Building Block" method to write a complete assembler program - it does not use any assembler source code instructions - it only uses define constants, equates & assembler directives such as USING, CNOP, LTORG, EJECT - none of these are actual machine code instructions. The key feature is that all the address values are relocatable - the program can be modified without having to make any adjustments - the offsets are adjusted automatically. The full source code for TESTASM.ASM is at the bottom of this post.

Here's some sample code with the traditional source code mnemonics & operands:

         DC    F'0'
REPORT   EQU   *
         ST    6,REPORT-4
*
         MVC   PRT,PRT-1

         MVC   PRT(L'DATE),DATE
*
         LA    3,CRE
         LA    4,PRT+8

         CP    CRE,ZERO
         BNE   EDAMT
         LA    3,DEB
         LA    4,PRT+18
EDAMT    EQU   *


And here is the same resulting object code - without a single source code mnemonic. I've built all instructions manually albeit a very clever way of doing so. There are no hard coded hexadecimal values to maintain (or waste time calculating).

         DC    F'0'
REPORT   EQU   *
         DC    AL1(ST),AL1(6*16),S(REPORT-4)
*
         DC    AL1(MVC),AL1(L'PRT-1),S(PRT,PRT-1)
         DC    AL1(MVC),AL1(L'DATE-1),S(PRT,DATE)
*
         DC    AL1(LA),AL1(3*16),S(CRE)
         DC    AL1(LA),AL1(4*16),S(PRT+8)
         DC    AL1(CP),AL1((L'CRE-1)*16+L'ZERO-1),S(CRE,ZERO)
         DC    AL2(BNE),S(EDAMT)
         DC    AL1(LA),AL1(3*16),S(DEB)
         DC    AL1(LA),AL1(4*16),S(PRT+18)
EDAMT    EQU   *


I defined each instruction opcode with equates that are assigned with their hex values. For example, the first instruction block is replicating the STORE command:

         ST    6,REPORT-4

 This is the replacement - it defines the opcode, register & address location:

         DC    AL1(ST),AL1(6*16),S(REPORT-4)

I defined the hex value x'50' for the ST opcode near the bottom of the program.

ST       EQU   X'50'

The next byte of the block is defined as AL1(6*16) - this designates register 6 (R6) and pushes it into the first 4 bits of the byte. This is a format requirement for the instruction. The S(REPORT-4) defines 2 bytes which contain the address of the Fullword Save area appearing 4 bytes before the label REPORT. The S-Constant directive puts the address in Base/Displacement form - this is a key component in building with this approach. I'm using a symbolic directive that adjusts at time of assembly. All the remaining instructions are built the same way...



The "Lego Guy" has moved on to building servers & circuit boards... he's a clever fellow... reminds me of... me! Same hair at least...



Below is the full working source code - the comments contain the JCL & sample data. I didn't bother restructuring the DCB (Data Control Block) macros for I/O - it wasn't necessary for this "proof of concept". I did replace the File Control Area for the PC/370 version.

         TITLE 'TESTASM - ASSEMBLER // TONY DELIA'
***********************************************************************
*                                                                     *
*        MODULE:  TESTASM.                                            *
*        AUTHOR:  TONY DELIA.                                         *
*          DATE:  04/17/90.                                           *
*          DESC:  TEST PGM USING ONLY ASSEMBLER COMMANDS AND DC'S.    *
*          NOTE:  JCL REQUIREMENTS AT BOTTOM OF MEMBER.               *
*                                                                     *
***********************************************************************
*        JCL REQUIREMENTS                                             *
***********************************************************************
*                                                                     *
*        //RUNNIT    EXEC PGM=TESTASM                                 *
*        //STEPLIB   DD   DSN=GF.LOAD.LIB,DISP=SHR                    *
*        //SYSOUT    DD   SYSOUT=*                                    *
*        //SYSUDUMP  DD   SYSOUT=*                                    *
*        //SYSPRINT  DD   SYSOUT=*                                    *
*        //FILOT     DD   SYSOUT=*,DCB=BLKSIZE=80                     *
*        //FILEA     DD   *                                           *
*        ******** **,***.** **,***.** ******************************* *
       05/29/90    500.00           CREDIT AMOUNT                   *
*        05/30/90              300.00 DEBIT  AMOUNT                   *
*        05/31/90  1,500.00           CREDIT AMOUNT                   *
*        06/01/90            1,100.00 DEBIT  AMOUNT                   *
*        ******** **,***.** **,***.** ******************************* *
*        /*                                                           *
*                                                                     *
***********************************************************************
*                                                                     *
*        PROGRAM KEEPS RUNNING TOTAL - ENDING WITH $600.00            *
*                                                                     *
***********************************************************************
         EJECT
***********************************************************************
*        T  E  S  T  A  S  M        P  R  O  G  R  A  M               *
***********************************************************************
TESTASM  START 0
         DC    AL1(STM),AL1(14*16+12),AL2(13*4096+12)
         DC    AL1(LR),AL1(12*16+15)
         USING TESTASM,12
         DC    AL1(L),AL1(11*16),S(BASE2)
         USING TESTASM+4096,11
         DC    AL1(ST),AL1(13*16),S(SAVE+4)
         DC    AL1(LR),AL1(14*16+13)
         DC    AL1(LA),AL1(13*16),S(SAVE)
         DC    AL1(ST),AL1(13*16),AL2(14*4096+8)
         DC    AL2(B),S(GO)
RETURN   EQU   *
         DC    AL1(L),AL1(13*16),S(SAVE+4)
         DC    AL1(LM),AL1(14*16+12),AL2(13*4096+12)
         DC    AL1(SR),AL1(15*16+15)
         DC    AL2(BR+14)
***********************************************************************
SAVE     DC    18F'0'
BASE2    DC    A(TESTASM+4096)
***********************************************************************
         EJECT
***********************************************************************
*        MAINLINE SECTION                                             *
***********************************************************************
         PRINT NOGEN
GO       EQU   *
         CNOP  0,4
         DC    AL1(BAL),AL1(1*16),S(*+6)
         DC    AL1(#INPUT),AL3(FILEA)
         DC    AL1(SVC),AL1(#OPEN)
         CNOP  0,4
         DC    AL1(BAL),AL1(1*16),S(*+6)
         DC    AL1(#OUTPUT),AL3(FILOT)
         DC    AL1(SVC),AL1(#OPEN)
***********************************************************************
READ     EQU   *
         DC    AL1(LA),AL1(1*16),S(FILEA)
         DC    AL1(LA),AL1(0*16),S(RECORD)
         DC    AL1(L),AL1(15*16),AL2(#IORTN)
         DC    AL1(BALR),AL1(14*16+15)
*
         DC    AL1(CLI),C'*',S(RECORD)
         DC    AL2(BE),S(READ)
*
         DC    AL1(BAL),AL1(6*16),S(HEADING)
         DC    AL1(BAL),AL1(6*16),S(FORMAT)
         DC    AL1(BAL),AL1(6*16),S(REPORT)
*
         DC    AL2(B),S(READ)
***********************************************************************
EOF      EQU   *
         DC    AL1(MVC),AL1(L'TOTLIT-1),S(TOTLIT,FINTOT)
         DC    AL1(BAL),AL1(6*16),S(TOTALS)
*
         CNOP  0,4
         DC    AL1(BAL),AL1(1*16),S(*+6)
         DC    AL1(#INPUT),AL3(FILEA)
         DC    AL1(SVC),AL1(#CLOSE)
*
         CNOP  0,4
         DC    AL1(BAL),AL1(1*16),S(*+6)
         DC    AL1(#INPUT),AL3(FILOT)
         DC    AL1(SVC),AL1(#CLOSE)
*
         DC    AL2(B),S(RETURN)
***********************************************************************
         EJECT
***********************************************************************
*        FORMAT INPUT                                                 *
***********************************************************************
         DC    F'0'
FORMAT   EQU   *
         DC    AL1(ST),AL1(6*16),S(FORMAT-4)
*
         DC    AL1(ZAP),AL1((L'CRE-1)*16+L'ZERO-1),S(CRE,ZERO)
         DC    AL1(ZAP),AL1((L'DEB-1)*16+L'ZERO-1),S(DEB,ZERO)
         DC    AL1(LA),AL1(3*16),S(CREDIT)
         DC    AL1(LA),AL1(4*16),S(CRE)
         DC    AL1(CLI),C'.',S(CREDIT+6)
         DC    AL2(BE),S(FMTAMT)
         DC    AL1(LA),AL1(3*16),S(DEBIT)
         DC    AL1(LA),AL1(4*16),S(DEB)
FMTAMT   EQU   *
         DC    AL1(MVC),AL1(2-1),S(WKAMT),AL2(3*4096+0)
         DC    AL1(MVC),AL1(3-1),S(WKAMT+2),AL2(3*4096+3)
         DC    AL1(MVC),AL1(2-1),S(WKAMT+5),AL2(3*4096+7)
         DC    AL1(PACK),AL1((4-1)*16+L'WKAMT-1),AL2(4*4096+0),S(WKAMT)
*
         DC    AL1(AP),AL1((L'CTOT-1)*16+L'CRE-1),S(CTOT,CRE)
         DC    AL1(AP),AL1((L'DTOT-1)*16+L'DEB-1),S(DTOT,DEB)
         DC    AL1(ZAP),AL1((L'BTOT-1)*16+L'CTOT-1),S(BTOT,CTOT)
         DC    AL1(SP),AL1((L'BTOT-1)*16+L'DTOT-1),S(BTOT,DTOT)
*
         DC    AL1(L),AL1(6*16),S(FORMAT-4)
         DC    AL2(BR+6)
***********************************************************************
         EJECT
***********************************************************************
*        REPORT                                                       *
***********************************************************************
         DC    F'0'
REPORT   EQU   *
         DC    AL1(ST),AL1(6*16),S(REPORT-4)
*
         DC    AL1(MVC),AL1(L'PRT-1),S(PRT,PRT-1)
         DC    AL1(MVC),AL1(L'DATE-1),S(PRT,DATE)
*
         DC    AL1(LA),AL1(3*16),S(CRE)
         DC    AL1(LA),AL1(4*16),S(PRT+8)
         DC    AL1(CP),AL1((L'CRE-1)*16+L'ZERO-1),S(CRE,ZERO)
         DC    AL2(BNE),S(EDAMT)
         DC    AL1(LA),AL1(3*16),S(DEB)
         DC    AL1(LA),AL1(4*16),S(PRT+18)
EDAMT    EQU   *
         DC    AL1(MVC),AL1(10-1),AL2(4*4096+0),S(ED1)
         DC    AL1(ED),AL1(10-1),AL2(4*4096+0),AL2(3*4096+0)
*
         DC    AL1(MVC),AL1(L'ED1-1),S(PRT+28,ED1)
         DC    AL1(ED),AL1(L'ED1-1),S(PRT+28,BTOT)
         DC    AL1(MVC),AL1(L'DESC-1),S(PRT+40,DESC)
*
         DC    AL1(LA),AL1(1*16),S(FILOT)
         DC    AL1(LA),AL1(0*16),S(PRT)
         DC    AL1(L),AL1(15*16),AL2(#IORTN)
         DC    AL1(BALR),AL1(14*16+15)
*
         DC    AL1(AP),AL1((L'LNCT-1)*16+L'ONE-1),S(LNCT,ONE)
*
         DC    AL1(L),AL1(6*16),S(REPORT-4)
         DC    AL2(BR+6)
***********************************************************************
         EJECT
***********************************************************************
*        HEADING ROUTINE                                              *
***********************************************************************
         DC    F'0'
HEADING  EQU   *
         DC    AL1(ST),AL1(6*16),S(HEADING-4)
*
         DC    AL1(CP),AL1((L'LNCT-1)*16+L'MAX-1),S(LNCT,MAX)
         DC    AL2(BL),S(HEADX)
*
         DC    AL1(BAL),AL1(6*16),S(TOTALS)
*
         DC    AL1(MVC),AL1(L'PRT-1),S(PRT,PRT-1)
         DC    AL1(MVI),X'8B',S(PRT)
*
         DC    AL1(LA),AL1(1*16),S(FILOT)
         DC    AL1(LA),AL1(0*16),S(PRT)
         DC    AL1(L),AL1(15*16),AL2(#IORTN)
         DC    AL1(BALR),AL1(14*16+15)
*
         DC    AL1(AP),AL1((L'PGCT-1)*16+L'ONE-1),S(PGCT,ONE)
         DC    AL1(MVC),AL1(L'H1PAGE-1),S(H1PAGE,ED2)
         DC    AL1(ED),AL1(L'H1PAGE-1),S(H1PAGE,PGCT)
*
         DC    AL1(LA),AL1(1*16),S(FILOT)
         DC    AL1(LA),AL1(0*16),S(H1)
         DC    AL1(L),AL1(15*16),AL2(#IORTN)
         DC    AL1(BALR),AL1(14*16+15)
*
         DC    AL1(LA),AL1(1*16),S(FILOT)
         DC    AL1(LA),AL1(0*16),S(BLANKS)
         DC    AL1(L),AL1(15*16),AL2(#IORTN)
         DC    AL1(BALR),AL1(14*16+15)
*
         DC    AL1(LA),AL1(1*16),S(FILOT)
         DC    AL1(LA),AL1(0*16),S(H2)
         DC    AL1(L),AL1(15*16),AL2(#IORTN)
         DC    AL1(BALR),AL1(14*16+15)
*
         DC    AL1(LA),AL1(1*16),S(FILOT)
         DC    AL1(LA),AL1(0*16),S(DIV)
         DC    AL1(L),AL1(15*16),AL2(#IORTN)
         DC    AL1(BALR),AL1(14*16+15)
*
         DC    AL1(LA),AL1(1*16),S(FILOT)
         DC    AL1(LA),AL1(0*16),S(BLANKS)
         DC    AL1(L),AL1(15*16),AL2(#IORTN)
         DC    AL1(BALR),AL1(14*16+15)
*
         DC    AL1(ZAP),AL1((L'LNCT-1)*16+L'FIVE-1),S(LNCT,FIVE)
HEADX    EQU   *
         DC    AL1(L),AL1(6*16),S(HEADING-4)
         DC    AL2(BR+6)
***********************************************************************
         EJECT
***********************************************************************
*        TOTALS                                                       *
***********************************************************************
         DC    F'0'
TOTALS   EQU   *
         DC    AL1(ST),AL1(6*16),S(TOTALS-4)
*
         DC    AL1(CP),AL1((L'LNCT-1)*16+L'P99-1),S(LNCT,P99)
         DC    AL2(BE),S(TOTALSX)
*
         DC    AL1(LA),AL1(1*16),S(FILOT)
         DC    AL1(LA),AL1(0*16),S(BLANKS)
         DC    AL1(L),AL1(15*16),AL2(#IORTN)
         DC    AL1(BALR),AL1(14*16+15)
*
         DC    AL1(LA),AL1(1*16),S(FILOT)
         DC    AL1(LA),AL1(0*16),S(DIV)
         DC    AL1(L),AL1(15*16),AL2(#IORTN)
         DC    AL1(BALR),AL1(14*16+15)
*
         DC    AL1(LA),AL1(1*16),S(FILOT)
         DC    AL1(LA),AL1(0*16),S(BLANKS)
         DC    AL1(L),AL1(15*16),AL2(#IORTN)
         DC    AL1(BALR),AL1(14*16+15)
*
         DC    AL1(MVC),AL1(L'PRT-1),S(PRT,PRT-1)
         DC    AL1(MVC),AL1(10-1),S(PRT+8,ED1)
         DC    AL1(ED),AL1(10-1),S(PRT+8,CTOT)
         DC    AL1(MVC),AL1(10-1),S(PRT+18,ED1)
         DC    AL1(ED),AL1(10-1),S(PRT+18,DTOT)
         DC    AL1(MVC),AL1(L'ED1-1),S(PRT+28,ED1)
         DC    AL1(ED),AL1(L'ED1-1),S(PRT+28,BTOT)
         DC    AL1(MVC),AL1(L'TOTLIT-1),S(PRT+42,TOTLIT)
*
         DC    AL1(LA),AL1(1*16),S(FILOT)
         DC    AL1(LA),AL1(0*16),S(PRT)
         DC    AL1(L),AL1(15*16),AL2(#IORTN)
         DC    AL1(BALR),AL1(14*16+15)
TOTALSX  EQU   *
         DC    AL1(L),AL1(6*16),S(TOTALS-4)
         DC    AL2(BR+6)
***********************************************************************
         EJECT
***********************************************************************
*        WORKING STORAGE                                              *
***********************************************************************
CRE      DC    PL4'0'                        CREDIT AMOUNT
DEB      DC    PL4'0'                        DEBIT  AMOUNT
BTOT     DC    PL4'0'                        TOTAL  BALANCE
CTOT     DC    PL4'0'                        CREDIT TOTAL
DTOT     DC    PL4'0'                        DEBIT  TOTAL
ED1      DC    XL11'4020206B2020214B202060'  EDIT PATTERN 'BZZ,ZZZ.99'
ED2      DC    XL4'40202120'                 EDIT PATTERN 'BZZ9'
P99      DC    PL2'99'                       INITIAL LINE COUNT VALUE
MAX      DC    PL2'56'                       MAXIMUM LINES PER PAGE
LNCT     DC    PL2'99'                       LINE COUNTER
PGCT     DC    PL2'0'                        PAGE COUNTER
ZERO     DC    PL1'0'                        PACKED ZERO
ONE      DC    PL1'1'                        PACKED ONE
FIVE     DC    PL1'5'                        PACKED FIVE
WKAMT    DC    CL7'ZZZZZ99'                  WORK AMOUNT FIELD
TOTLIT   DC    CL21'***   SUB TOTAL   ***'   TOTAL LITERAL
FINTOT   DC    CL21'***  FINAL TOTAL  ***'   FINAL TOTAL LITERAL
*
EJECT    DC    XL1'8B'
BLANKS   DC    CL80' '
RECORD   DS    0CL80
DATE     DC    CL8'MM/DD/YY'                 DATE OF TRANSACTION
         DC    CL1' '
CREDIT   DC    CL9'ZZ,ZZZ.99'                CREDIT AMOUNT
         DC    CL1' '
DEBIT    DC    CL9'ZZ,ZZZ.99'                DEBIT  AMOUNT
         DC    CL1' '
DESC     DC    CL40' '                       DESCRIPTION OF TRAN
         DC    CL11' '
*
H1       DS    0CL80
         DC    CL30'PGM: TESTASM'
         DC    CL33'BALANCE SHEET'
         DC    CL4'PAGE'
H1PAGE   DC    CL4' ZZ9'
         DC    CL9' '
*
H2       DS    0CL80
         DC    CL40'  DATE     CREDIT     DEBIT   BALANCE   '
         DC    CL40'DESCRIPTION                             '
*
DIV      DS    0CL80
         DC    CL40'******** ********* ********* *********  '
         DC    CL40'****************************************'
*
         DC    CL1' '
PRT      DC    CL80' '
***********************************************************************
         EJECT
***********************************************************************
*        DCB SECTION                                                  *
***********************************************************************
FILEA    DCB   DDNAME=FILEA,DSORG=PS,MACRF=(GM),EODAD=EOF
FILOT    DCB   DDNAME=FILOT,DSORG=PS,MACRF=(PM)
***********************************************************************
*        LITERAL POOL                                                 *
***********************************************************************
         LTORG
***********************************************************************
         EJECT
***********************************************************************
*        OPCODE EQUATES                                               *
***********************************************************************
B        EQU   X'47F0'
BE       EQU   X'4780'
BL       EQU   X'4740'
BNE      EQU   X'4770'
BR       EQU   X'07F0'
AP       EQU   X'FA'
BAL      EQU   X'45'
BALR     EQU   X'05'
CLI      EQU   X'95'
CP       EQU   X'F9'
ED       EQU   X'DE'
L        EQU   X'58'
LA       EQU   X'41'
LR       EQU   X'18'
LM       EQU   X'98'
MVC      EQU   X'D2'
MVI      EQU   X'92'
PACK     EQU   X'F2'
SP       EQU   X'FB'
SR       EQU   X'1B'
ST       EQU   X'50'
STM      EQU   X'90'
SVC      EQU   X'0A'
ZAP      EQU   X'F8'
***********************************************************************
#OPEN    EQU   19
#CLOSE   EQU   20
#INPUT   EQU   128
#OUTPUT  EQU   143
#IORTN   EQU   1*4096+48
***********************************************************************
         END   TESTASM


This ends another look back in programming history...

Credits:
Free 3D Lego Figure, Blocks, Server Cabinets & Circuit Board all found at: Sharecg.com
Free DAZ Studio 3D Software at: www.daz3d.com