MVS TOOLS AND TRICKS OF THE TRADE AUGUST 2001 Sam Golob MVS Systems Programmer P.O. Box 906 Tallman, New York 10982 Sam Golob is a Senior Systems Programmer. He also participates in library tours and book signings with his wife, author Courtney Taylor. Sam can be contacted at sbgolob@cbttape.org. Information about the CBT MVS Tapes can be found on the web, at http://www.cbttape.org. ASSEMBLER PROGRAMMING REVISITED If we think about it, we can see that progress in Systems Programming (and in related areas) is fed by technology improvements and newly developed software tools. And after the technology improvements and the better software tools feed further improvements in Systems Programming techniques, it becomes easier as a result, to develop even more technology improvements, and even better software tools. So the process becomes a very productive cycle. We must observe something about the nature of this cycle. The truth is, that such progress occurs in fits and starts. It takes time, after any new tool is developed, for people to learn to use the tool. So after any new tool is released to the public, it will be a while before we can expect to see changes in people's techniques, which this new tool has made possible. But even though there are time delays in the mechanism, this process inexorably goes on, and progress will occur. Therefore it pays to re-survey your own techniques every few years, to see if any new facilities and services which have come out, can help improve them. For example, I remember when the Edit Macro Facility was introduced into ISPF. After the capability was introduced, people began developing their own sets of edit macros, which in turn, made it easier for them to write programs and to set up their MVS systems. Now that the edit macros made it easier for people to program, they in turn developed more new tools, with new capabilities, which weren't there before. And those new tools, in turn helped some of them to develop still more facilities and tools for the public to use. So the cycle of progress goes on. One new tool spawns dozens of new techniques, which in turn, encourage the development of more new tools. The same thing has happened in Assembler Programming since the new IBM High Level Assembler (HLASM) was introduced. New features and facilities introduced into that version of the Assembler, have made it easier to write and debug programs. And in turn, using these new facilities, people can write other new tools, which will again change everybody's techniques for the better. A technology improvement in the High Level Assembler which has helped me, has been the introduction of the General Register Cross Reference, introduced with HLASM Release 3. The General Register Cross Reference looks at the source code being assembled, and figures out any instructions which use registers, telling you ALL occurrences and uses of ALL general registers in the entire program, even if there were no register equates defined, such as R0 EQU 0, and R1 EQU 1. Therefore, if you are modifying somebody's Assembler program, you don't have to worry if the programmer used Register Equate symbols, so they will occur in the regular symbol cross reference. Even if the program used no register equates at all, you get to find out ALL of the registers that were used, and in what lines of the listing, by looking at the new General Register Cross Reference in the Assembly Listing. So now, you can better modify Assembler programs, because you can find out which registers have NOT been used. If you need a new work register, or a BAL register, or a BCT register, or a new base register, you just have to look at the General Register Cross Reference, and you can find out which registers haven't been used, or which registers have been used the least. I recently used this facility to modify a big program that we needed at work, where NO register equates had been used. The programmer would code an instruction such as LA 3,1(,3) , instead of being clearer, and saying LA R3,1(,R3). With the General Register Cross Reference, modifying this program proved to be no problem for me. A few years earlier, without this Register Cross Reference facility, that job would have been a true nightmare. RE-EVALUATING SOME ASSEMBLER TECHNIQUES It has been a long time since many of us went to Assembler Programming School, and the newer folks who are now learning Assembler, might be learning it from people who had to work on the machines of thirty years ago. I think that some techniques ought to be re-evaluated. Of course, it depends on the kind of code you're writing. Lately, I've been writing a lot of data manipulation utilities on the system level, but which use QSAM I/O to read records, massage the data, and put out output files and SYSPRINT. They are much like application programs. The "efficiency stuff" I learned years ago, doesn't apply to these programs, in my opinion. Today's machines are bigger and faster, and they have much more "working storage". For example, when I was younger, I was told "rules" such as: "Real Assembler Programmers don't use more than one base register". In my opinion, that is malarkey (most of the time). Nowadays, even if I'm writing a "small program", I'll set up three base registers, right from the beginning. In my years of experience, I've seen too many "small programs" that eventually became big programs, after more capabilities and features had been added to them. I like to have "breathing room" in my programs. I've had too much trouble, once a program was written and had to be modified, finding a free register for a new base. Sorry. I'm going to put a bunch of base registers out there, right from the beginning! (And I like eating quiche.) My attitude is just the opposite concerning work registers. These are registers which have to be used temporarily to point to some storage, or to hold some data quantity for a while. I am very stingy with assigning work registers. That's because if I have to modify the program later, and I'll really need another work register, one will be available. But all such "rules" have to be reasonable. You don't want one process, that needs one work register, to interfere with a completely different process, that also needs a work register. THEN, I use two different registers so the two processes won't "step on each other", and it doesn't bother by conscience at all. The desire is to have clean, bug-free programs, and that comes first! How do I save on assigning work registers? I use fullwords of storage. I only keep the info in a register while I need to. I'm very generous with saving and restoring register contents to fullwords. Why? Main storage is cheap nowadays! Registers are just as expensive as they always were! Instructions are executed very quickly on modern machines! A sequence of STore or STM (store multiple) instructions followed by a corresponding Load or LM (load multiple) instruction, don't add much overhead to a program, on today's computers. You can reuse a lot of registers by saving their contents to (one or more) fullword(s), using them for processing, and restoring the old contents back, right afterwards. What's the obvious advantage of doing this? If I expand the program later, and I really do need a new work register for something, one will be available. The new General Register Cross Reference in the HLASM Assembly Listing will show me the complete picture. SOME OTHER "NEW" TECHNIQUES Have you ever seen reports with hex zeros (X'00') in them instead of blanks (X'40')? This can come from another old Assembler technique, which needs revisiting. When you're defining storage, the old tendency was to use DS (Define Storage) instructions instead of DC (Define Constant) instructions, in the work areas. DC instructions initialize the work area the way you want it, and you have control over their initial contents. It's like initializing a COBOL or PL/I work area with a PIC expression. On the other hand, DS instructions don't initialize the bytes of the area they define. IBM, in a "good move", will force the latest linkage editors to initialize DS-defined areas, but to hex zeros (their best guess as to what is right). But the old 360-vintage linkage editors did not initialize DS-defined areas at all, and whatever junk was in storage there, at the time of linkage edit, would be propagated right into the load modules. So you see that it pays to keep control, with DC instructions, that initialize program areas with constants. If you are GETMAINing some storage and using it for work areas, these constants will have to be copied there, because you have no initial control over what data was previously in the storage you're GETMAINing. But in the constants that are defined in your program itself, you should retain full control, and use DC instructions to initialize the work areas with blanks, or with whatever you want to put there. I usually define a routine, which I BAL to, that initializes work areas the way I want them. This way, I can run the same routine more than once, during the execution of my program. I have another related tip for safeguarding my report lines. Main storage is cheap nowadays. Programs will run in bigger regions. Therefore, I "pad" many storage areas with blanks, or whatever is reasonable, before and after, particularly the print areas. For example, suppose I want to define a report line area to have a length attribute of 133 bytes, and I want to break it up into fields afterwards. I'll define the initial area as DS 0CL133, to be able to deal with one 133-byte field. But the trick is that I have to be careful to put 133 "real bytes" afterwards, with DC (or DS) instructions defining the individual print line fields. Suppose I haven't added up the bytes correctly, and there are only 127 bytes defined after the 0CL133 instruction. Well, the program will just grab the next 6 bytes after the 127 I defined, and include them them in the report line. If I initialize the 133-byte report line as a whole, say to blanks, the 6 data bytes that follow, will be overlaid too, and we'll have a bug. We can avoid this problem, if we put, say, a DC 30XL'40' or DC 30CL' ', after any print area, just to make sure that the total bytes of "real data", add up to at least as many bytes, as are supposed to be in the print line. These "padding bytes" protect the data lying afterward. And as another tip: Before each print area, define a few blanks too, with DC's. That will guarantee, if you are "initializing" the print area with a MVC AREA,AREA-1 instruction, that AREA-1 will contain a blank, and not something else. You don't want junk in your print lines, and with modern computer storage capacities and improved instruction speeds, you don't have to worry about inefficiency. In conclusion, I'm recommending the re-evaluation of your Assembler programming techniques, taking into account: today's better Assembler, faster instruction speeds, and improved main storage capacities. Concentration should be on expandability, clean code, and safeguarding from unnecessary bugs. Re-using the same bytes for program instructions, a hundred times, is a concept that usually can be thrown out the window nowadays. Best of luck and happy coding! I hope to see you again next month.