Tony DeLia - PeopleSoft Developer | Technical Consultant. Enjoying a productive career in the Information Technology profession, with significant expertise developing pc, client-server, mainframe, relational database & ERP package solutions (PeopleSoft/Oracle). Welcome to my Blog... enjoy the smattering of bits, bytes, & words (that's lo-level machine code lingo)... This blog will serve as a historical monument to some of my past work.
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