16 October 2012

Little bitty z/Architecture assembler tips and tricks not worthy of their own blog entry

This blog entry will be updated continually and reposted when I come up with little tips and techniques not worthy of their own blog entry.


High half register check

Can't use those bitchin' new high-half register instructions because you have customers not on the latest z196/z114? Need to check the upper half of a register for non-zero so your AMODE 64 doesn't run amok? Use the following:
CLG   R0,=X'00000000FFFFFFFF'
JH    THERE_IS_SOMETHING_IN_THE_HIGH_HALF_OF_THE_REGISTER
And you also have an example of a label longer than 8 characters.


Make sure your base register is clean in AR mode

LAE is a nice instruction for setting a base register if you aren't sure your code will be called in primary or AR mode. If the B2 field is 0, when you are in AR mode, 00000000 is placed into the corresponding R1 access register, so you can code 

LAE   R12,0(R15)

and get your entry point without the possibility of getting messed up by a stray ALET in AR12.


WAIT LONG=YES and baseless programming (z/OS, 1.12 and earlier)

If you've tried this combination before, you've gotten bit because the macro generates a BCR GPR8,0 instruction followed by an ICM of the second byte via an "*-1" operand. If you're baseless, this fails because you are baseless. However, there is no need to fret. The following code works and gets around this issue.

         IILH  GPR0,X'8000'
         IILL  GPR0,1
         WAIT  (0),ECB=MYECB

The macro generates an unnecessary LR GPR0,GPR0 followed by the appropriate code. If you are using an ECBLIST, just put the number of this-many-POSTed ECBs in GPR0; in this case, it might be easier to load GPR0 first, then use an OILH GPR0,X'8000' instruction.

As noted in the comments below, starting with 1.13, if you are SYSSTATE ARCHLVL=2, WAIT will generate appropriate code for baseless situations.

More to come as I think of them...


05 September 2012

An interesting way to implement a multi-entry-point API for an LE assembler module

Today I came up with an idea for implementing an API assembler module when LE is involved. Let me first say that although  LE is very functional and usually makes life easier for high-level languages, when assembler gets involved it complicates things until you get used to LE thinking.


The original code had an entry point which did the STM for the save area and then loaded a function code into a register. Unfortunately, this does not work well with LE because the CEEENTRY macro has the STM in it. So I came up with this interesting implementation to get the function code and have only one CEEENTRY macro. Here is a very simple example, without the required CEEPPA, CEEDSA, CEECAA, and CEETERM macros:



API      CSECT
         ENTRY INIT,READ,WRITE,TERM
INIT     DC    0H
         J     LEENTRY
READ     DC    0H
         J     LEENTRY
WRITE    DC    0H
         J     LEENTRY
TERM     DC    0H
         J     LEENTRY
LEENTRY  DC    0H 
API      CEEENTRY MAIN=NO,BASE=R11 (default base)
         L     R15,4(,R13)        Backchain save area
         L     R15,16(,R15)       Get R15 at call
* R15 now is the address of the entry point
         LA    R14,0(,R11)        Clear out HOB just in case (SEE BELOW)
         LA    R15,4(,R15)        Clear out HOB and make 1-based 
         SR    R14,R15            Calculate offset from beginning of CSECT 
         SRA   R14,2              Divide by 4, preserving sign (allows use of JM BAD)
* R14 now has a function code ranging from 1 to 4
* Obviously we add some additional checking of R14 to make sure
* it is valid for our purposes.

So now GPR14 has a value ranging from 1 to 4, with 1 being INIT, 2 being READ, etc.. Good programmers will test GPR14 for falling within the required boundaries. You could also forgo the SRA and use the value of 4, 8, 12, or 16. In current releases of z/OS, CEEENTRY uses LARL to load the base register with the address of API, so the LA of GPR14 from GPR11 could just be an LR. This also works with non-LE assembler code; if you have a base register use LA, and if "baseless" use an LARL of the CSECT name. Just make sure that if you have a standard entry macro (most shops do) that generates a CSECT, the CSECT name used at the beginning of the module has to match that generated by your macro.

31 August 2012

Some uncommonly used features of WTO in z/OS (and maybe z/VSE)

The past few days I have worked on a couple enhancements that exploited some lesser-known WTO features. None of these require APF authorization.


Multiple-line WTOs

So, you ask, why multiple-line WTOs? Why don't I just send lots of WTOs? Well, that sucks up system resources, and if there are any console exits, you're driving them every time. A multple-line WTO can give the console subsystem and your hardcopy log a little breather. There is one drawback – you can only have 71 characters per line…but we're all professionals, that's not a big deal. (A normal single-line WTO can have up to 126 characters.)

Everybody who is a z/OS mainframe programmer has already been exposed to one example - the IEA995A message. This is the one issued when an abend occurs and it has eventually percolated to RTM. You can identify multiple-line WTOs in the JES message log (first SYSOUT data set), JES system messages (third SYSOUT data set), the hardcopy log, or your TSO session as there is no repetition of the date, time, nor the JES job identifier. They are replaced by the three-digit number which appears to the right of the first line of the message. Here's a contrived example (if you don't know, S806-4 means that the load module could not be found in the STEPLIB/JOBLIB/link pack/LPA chain), and I apologize for the small print but since I'm using a basic blogger.com template, this is the only way I could get it to show up without line wrapping:


13.14.51 JOB74042  IEA995I SYMPTOM DUMP OUTPUT  864                                    
   864             SYSTEM COMPLETION CODE=806  REASON CODE=00000004                    
   864              TIME=13.14.51  SEQ=28924  CPU=0000  ASID=0062                      
   864              PSW AT TIME OF ERROR  070C1000   8141F276  ILC 2  INTC 0D          
   864                NO ACTIVE MODULE FOUND                                          
   864                NAME=UNKNOWN                                                    
   864                DATA AT PSW  0141F270 - 8400181E  0A0D18FB  180C181D            
   864                AR/GR 0: 936AF47A/00000000_00001F00   1: 00000000/00000000_84806000
   864                      2: FFFFFFFF/FFFFFFFF_00000000   3: FFFFFFFF/FFFFFFFF_00000000
   864                      4: FFFFFFFF/FFFFFFFF_00000000   5: FFFFFFFF/FFFFFFFF_007E69F8
   864                      6: FFFFFFFF/FFFFFFFF_000000FF   7: FFFFFFFF/FFFFFFFF_00000000
   864                      8: FFFFFFFF/FFFFFFFF_007B5150   9: FFFFFFFF/FFFFFFFF_0141F778
   864                      A: FFFFFFFF/FFFFFFFF_00000000   B: FFFFFFFF/FFFFFFFF_00000000
   864                      C: FFFFFFFF/FFFFFFFF_00000000   D: FFFFFFFF/FFFFFFFF_007B5150
   864                      E: 00000000/00000000_84806000   F: 00000000/00000000_00000004
   864              END OF SYMPTOM DUMP                                                  
There are two variations of how to code the WTO macro to do this. Both utilize the second subparameter of either the first positional parameter (traditional WTO) or the TEXT= operand, and in both cases it is for each multiple subparameter. The first of these is "D", which indicates that the text is part of a multiple-line WTO. The other is your choice - "DE" or "E". "E" indicates that the WTO is fniished; "DE" means that the text supplied on this invocation is the last line. I have found that the easiest way to implement this is to use TEXT= and MF=L/E, something similar to this (only the required stuff shown so not to clutter with DESC= and ROUTCDE=):

         MVC   @WTOD,#WTOD
         MVC   WTOTEXT,MSG1
* put in variable parts of MSG1
         WTO   TEXT=WTOTEXT,MF=(E,@WTOD)
         ST    R1,WTOCONN
         MVC   WTOTEXT,MSG2
* put in variable parts of MSG2
         WTO   TEXT=WTOTEXT,CONNECT=WTOCONN,MF=(E,@WTOD)
         MVC   @WTOE,#WTOE
         WTO   CONNECT=WTOCONN,MF=(E,@WTOE)

#WTOD    WTO   TEXT=(,D),MF=L
#WTOD_L  EQU   *-#WTOD
#WTOE    WTO   TEXT=(,E),MF=L
#WTOE_L  EQU   *-#WTOE

@WTOD    DS    CL(#WTOD_L)
         ORG   @WTOD
@WTOE    DS    CL(#WTOE_L)
         ORG   ,

(Now, yes, I could have mapped the WTO parm list and manipulated things directly for the E invocation, but I believe this explains the concept better.)

The "D" and "E" invocations are tied together via the CONNECT parameter. The CONNECT token is returned in GPR1 if a multiple-line WTO is started. It is then referenced in subsequent WTO invocations. (In the old days, before CONNECT, you put it in GPR0 before the call, and you can still do this if you don't use TEXT=.) The WTO is not issued until you make the "E" invocation.

You can use the field where you save the CONNECT token as a switch in a loop. If it is zero, it's the first time, so you invoke the WTO without CONNECT and store the token, and with subsequent iterations you invoke the WTO with CONNECT.

But remember – you need that "E" call, otherwise your partially built WTO will be discarded after a few seconds, which is eons to a 5.5Ghz model 2827 (zEC12) CPU.

Non-authorized callers are limited to 10 lines maximum, but authorized callers can have up to 255 lines, and that's a whole lotta lines.


Command response WTO

Have you entered an operator command via "/" in SDSF and wonder how it was able to (usually) display the response from the command? It is not an "ancient Chinese secret," if you are old enough to remember that USA commercial from the 1970s. One crucial piece of information is required: the command-and-response token (CART).


When your task that processes operator MODIFY or STOP commands (or if you're really fancy, from the START command, or through operator command or subsystem interface exits) retrieves the command, the CART is located in both the CIBX (addressable by adding CIBXOFF to the CIB address), the CSCB, or the aforementioned exits. (Modern processing uses the CIB.) Once you have this piece of information, you can specify it via the CART= operand on the WTO. This identifies this WTO as a command response, and certain processes that use the console subsystem can retrieve just these WTOs and tie them to the originating command. This is how SDSF does it, and it becomes useful for the next section…


Limiting a command response WTO to the console where the command was issued

When using the console subsystem for issuing operator commands and retrieving WTOs, such as IBM's NetView or Software AG's Entire System Server, it is nice to only send the WTO command response to the originating console, rather than to every console (hardware and subsystem) in the LPAR. You limit this by specifying the console ID on the WTO through either CONSID=. The console ID is available in the CIBX, the CSCB, and the aforementioned exits. It is also possible to put a console ID that was obtained elsewhere, if you have an environment that has well-defined consoles. If you know the console name, you can use CONSNAME=. (CONSNAME and CONSID are mutually exclusive, however.)


The IEZWPL DSECT

If you are feeling adventurous, you can build your own parameter list to SVC 35 using the IEZWPL DSECT (found in SYS1.MODGEN). However, you really need to be careful in building this list, because a mistake can lead to an SD23 abend, incomplete WTO, or pure garbage and messages incorrectly flagged as critical.

If you want to try this, I recommend that you do some sample assemblies with various expansions of the WTO macro to see how it builds the parameter list. I also recommend you talk to your systems programmer, and if you are nice maybe s/he will allow you to try this on a sandbox system.

WTOs and commands in z/VSE

In the late 1990s, the OS/390 console support was ported to VSE/ESA., retaining many of the same design concepts. Therefore, many of the concepts above apply as well, however I have to admit that I have not done a multiple-line or a specific command-response WTO in a z/VSE task as a response to the MSG console command. If there is interest, I'll get our z/VSE expert Martin to elaborate.