Assembler course
I thought I might explain the basics of IBM mainframe assembler,
but it's much harder than I thought. Anyway, here's what I wrote.
If your masochistic nature is insufficiently satisified, then maybe:
Introduction to IBM assembler. You have lots of memory these days.
And you have registers (that hold #s or addresses).
Maybe first, learn to count. You count 1,2,3,4,5,6,7,8,9,10,11
In hex, we count 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,10
Always start with 0, and A-F = 10-15 in decimal. X'10' is dec-16.
(At 81 years old, I'm x'51'. Doesn't that sound better.~)
Your code is never loaded at loc=0, so what you want to do is have
a register that points to your code no matter where it gets loaded
in memory. Instructions reference memory locations in what is called
base-displacement format. IE whatever is in a register, plus an 'offset'
from the address in the register. Here's an instruction.
MVC A,B Move what ever is at B to A. (yes, they do it backwards.)
The generated executable code, using reg-12 as the base register is
D21EC0A1C0D3 move 31 bytes to reg-12+161, from reg-12+207
D2 = move character inst.
1E = 30 in hex. Intructions like this move the length+1 (D200 moves 1 byte)
C0A1 = C=reg-12 + 0A1 so reg-12 + 0A1 in hex converts to 161 in decimal.
C0C3 = C=reg-12 + 0C3 so reg-12 + 0C3 in hex converts to 207 in decimal.
Another thing to learn is that some program calls your program, (starts
your program) and your program might call another program (have that
program do something for your program. First we'll look at simple copy.
OPEN (INFILE,INPUT,OUTFILE,OUTPUT) open 2 files
GET GET INFILE read a record, put it's address in reg-1
LR R0,R1 put the record address into reg-0
PUT OUTFILE,(R0) write that record
B GET branch to label GET.
END CLOSE (INFILE,,OUTFILE) at end-of-file, close the 2 files
That would be a real program that would work, but remember, I said
that some program calls (starts) your program, and in some cases,
your program might call another. What we need are standard
LINKAGE CONVENTIONS. We need to save the registers of whoever
called us, in a SAVEAREA that he provides, and we need to
establish a savearea that someone we call can use to save
our registers (0-15). We also need to save the address of out caller's
savearea, and set it up so whoever we call can do the same.
BTW, GET and PUT are called routines, and will use our savearea.
Savearea format (in WORDS. A word is 4 BYTES (characters) of storage)
Word 1 - not used (generally)
Word 2 - your caller's savearea address
Word 3 - address of the saveare of whoever you call
Words 4-19 will contain the contents of reg-14 thru reg-12 (wrap around)
YOURPGM START 0 Start your program
STM 14,12,12(13) Store callers regs
BALR 12,0 load the addr of the next inst in reg-12
USING *,12 tell the assembler were reg-12 points
LA 2,SAVEA load addr of your savearea
ST 2,8(13) store a(your savea) in caller's savea
ST 13,4(2) store a(caller's savea) in yours
LR 13,2 put the savea address in reg-13 (always)
OPEN ..... etc.
And then when you're all done, clean up and return to caller
END CLOSE (INFILE,,OUTFILE) Close the files
L 13,4(13) load addr of caller's savea
LM 14,12,12(13) load callers regs
SR 15,15 reg-15 =0 is a successful return code
BR 14 go back to caller.
We now have nearly all the parts to make a successful program.
But we haven't defined the input and output files.
We do that with a DCB or Data Control Block.
INFILE DCB DDNAME=INPUT,DSORG=PS,DEVD=DA,MACRF=GL,EODAD=END
OUTFILE DCB DDNAME=OUTPUT,DSORG=PS,DEVD=DA,MACRF=PM
To put the whole thing together:
YOURPGM START 0 Start your program
YREGS , so you can use r1 for reg-1, etc.
* (asterisk in col-1 = comment)
STM 14,12,12(13) Store multiple (save) user's regs
BALR 12,0 load the addr of the next inst into reg-12
USING *,12 tell the assembler were reg-12 points
LA 2,SAVEA load addr of your savearea
ST 2,8(13) store a(your savea) in caller's savea
ST 13,4(2) store a(caller's savea) in yours
LR 13,2 put the savea address in reg-13 (always)
OPEN (INFILE,INPUT,OUTFILE,OUTPUT) open 2 files
*
GET GET INFILE read a record, put address in reg-1
LR R0,R1 put the record address into reg-0
PUT OUTFILE,(R0) write that record
B GET branch to label GET.
*
END CLOSE (INFILE,,OUTFILE) Close the files
L 13,4(13) load addr of caller's savea
LM 14,12,12(13) load multiple, callers regs
SR 15,15 reg-15=0 is a successful return code
BR 14 go back to caller.
*
SAVEA DC 18F'0' SAVEAREA
OUTFILE DCB DDNAME=OUTPUT,DSORG=PS,DEVD=DA,MACRF=PM
INFILE DCB DDNAME=INPUT,DSORG=PS,DEVD=DA,MACRF=GL,EODAD=END
END YOURPGM
Every file has characterists. In mainframe land, they are:
LRECL=#### logical record length
BLKSIZE=#### number of bytes in a block of records
RECFM=?? Record Format.
Let's suppose we have a file of 80 byte (card image) records
LRECL=80,BLKSIZE=2400,RECFM=FB 80 byte recs, 30/block, all recs the same.
You'd attach that line to the OUTFILE DCB unless you're copying to an
already existing file. In that case, the system already knows that info.
You have a working program. Let's add 1 more thing - a routine to copy
the LRECL, BLKSIZE, RECFM from INPUT to OUTPUT, only if needed.
EXITLIST DC X'87',AL3(EXITLIST+4)
USING *,15
USING IHADCB,1
CLI DCBRECFM,0 do we need to copy?
BNER 14 no, just return.
MVC DCBRECFM,DCBRECFM-IHADCB+INFILE yes, do the copy
MVC DCBLRECL,DCBLRECL-IHADCB+INFILE
* MVC DCBBLKSI,DCBBLKSI-IHADCB+INFILE (system will pick blksi
BR 14
OUTFILE DCB DDNAME=OUTPUT,DSORG=PS,DEVD=DA,MACRF=PM,EXLST=EXITLIST
You need to put this code right before the 2 DCB statements.
And, right before the end of your program, code:
DCBD DEVD=DA
Now you have a pretty simple KISS program.
What's KISS? Keep It Simple Stupid. The good programmer's mantra.
I've been doing this 50 years. Email me to tell me what I forgot.
or what is not understandable.
--------------------------------------------------------------
AGO .START (tell the assembler to skip these comments)
IF YOU WANT TO TRY THIS ASSEMBLER PROGRAM, THEN YOU COULD:
GO TO Z390.ORG AND CLICK Z390 V1.8.1 IS NOW AVAILABLE FOR DOWNLOAD
AND DO IT. I PUT ALL MY STUFF IN
C:\USERS\LIN\DOCUMENTS\Z390CODE\ (USE YOUR NAME)
CREATE A FILE C:\USERS\LIN\DOCUMENTS\Z390CODE\YOURPGM.BAT AND CONTAINS
SET G=C:\USERS\LIN\DOCUMENTS\Z390CODE\yourpgm
SET INPUT=%G%.PRN.TXT
SET OUTPUT=%G%.OUT.TXT
BAT\ASMLG %G%.MLC TIME(1)
WHEN YOU'VE DONE THAT, START Z390 AND ENTER:
C:\USERS\LIN\DOCUMENTS\Z390CODE\YOURPGM
WHAT THAT SHOULD DO IS COPY YOUR LISTING TO THE .OUT.TXT FILE
.START ANOP
*
YOURPGM START 0 Start your program
YREGS , so you can use r1 for reg-1, etc.
* (asterisk in col-1 = comment)
STM 14,12,12(13) Store multiple (save) user's regs
BALR 12,0 load the addr of the next inst into reg-12
USING *,12 tell the assembler were reg-12 points
LA 2,SAVEA load addr of your savearea
ST 2,8(13) store a(your savea) in caller's savea
ST 13,4(2) store a(caller's savea) in yours
LR 13,2 put the savea address in reg-13 (always)
OPEN (INFILE,INPUT,OUTFILE,OUTPUT) open 2 files
*
GET GET INFILE read a record, put address in reg-1
LR R0,R1 put the record address into reg-0
PUT OUTFILE,(R0) write that record
B GET branch to label GET.
*
END CLOSE (INFILE,,OUTFILE) Close the files
L 13,4(13) load addr of caller's savea
LM 14,12,12(13) load multiple, callers regs
SR 15,15 reg-15=0 is a successful return code
BR 14 go back to caller.
*
SAVEA DC 18F'0' SAVEAREA
OUTFILE DCB DDNAME=OUTPUT,DSORG=PS,DEVD=DA,MACRF=PM
INFILE DCB DDNAME=INPUT,DSORG=PS,DEVD=DA,MACRF=GL,EODAD=END
END YOURPGM