torsdag den 17. september 2015

How the assembler works (4)

How to let a macro do all the tedious coding for you

This time I will make a macro with you that can be used to make all the tedious work at the start of the program and at the end. I will show the macro in its full at last in the blog. You will then be able to copy and paste it to your own system and tailor it to your needs.(*1)


The Macro is called PROGRAM and it takes four states which are coded right after PROGRAM

PROGRAM EQU

(not mandatory but strongly recommended)
Defines the register EQU
[DSECT name]
PROGRAM STORAGE
[,STORAGEREG=]
First occurrence. Coded before and after your fields
STORAGEREG=[register]
Default is ‘R12’. Base reg for storage DSECT

PROGRAM STORAGE

Second occurrence. Calculates the length of your storage
program name
PROGRAM START
[,SAVEAREA=]
[,SADSECT=]
SAVEAREA=[name of savearea]. Default SAVEAREA’
SADSECT=[Name of the savearea DSECT. Default ‘SA’
return label
PROGRAM END
[,RETURNCODE=]
RETURNCODE=[return code to calling program.]
Default ‘0’


Examples

A minimum program could look like this:
       PROGRAM EQU                                                     00010000
       PROGRAM STORAGE                                                 00020000
HW      DS      0F                                                      00020100
HWLEN   DS      H                                                       00020200
HWTEXT  DS      CL16                                                    00021000
       PROGRAM STORAGE                                                 00030000
PGM3    PROGRAM START                                                   00040000
       MVC     HWTEXT,=CL(L'HWTEXT)'HELLO WORLD'                       00050002
       MVC     HWLEN,=Y(L'HWTEXT)                                      00060000
       LA      R2,HW                                                   00061002
       WTO     TEXT=(R2),ROUTCDE=11                                    00070002
RETURN  PROGRAM END                                                     00080002
       END                                                             00090000


and the output will be this.
19.51.28 JOB05893  +PGM3 - 09/17/15-19.51
19.51.28 JOB05893  +HELLO WORLD
As you can see. Coding gets much easier.




Assembler list

It is much easier to understand with examples. I show you (or some of) the results of each invocation of the macro PROGRAM. One example per state.


EQU
             1         PROGRAM EQU
00000           2+R0       EQU   0                                                        01-PROGR
00001           3+R1       EQU   1                                                        01-PROGR
00002           4+R2       EQU   2                                                        01-PROGR
00003           5+R3       EQU   3                                                        01-PROGR
00004           6+R4       EQU   4                                                        01-PROGR
00005           7+R5       EQU   5                                                        01-PROGR
00006           8+R6       EQU   6                                                        01-PROGR
00007           9+R7       EQU   7                                                        01-PROGR
00008          10+R8       EQU   8                                                        01-PROGR
00009          11+R9       EQU   9                                                        01-PROGR
0000A          12+R10      EQU   10                                                       01-PROGR
0000B          13+R11      EQU   11                                                       01-PROGR
0000B          14+BASEREG  EQU   11                                                       01-PROGR
0000C          15+R12      EQU   12                                                       01-PROGR
0000D          16+R13      EQU   13                                                       01-PROGR
0000E          17+R14      EQU   14                                                       01-PROGR
0000F          18+R15      EQU   15                                                       01-PROGR


STORAGE

              19         PROGRAM STORAGE                                                 00020000
00000 00012       20+STORAGE     DSECT                                                       01-PROGR
              21 HW      DS      0F                                                      00020100
000000         22 HWLEN   DS      H                                                       00020200
000002         23 HWTEXT  DS      CL16                                                    00021000
               24         PROGRAM STORAGE                                                 00030000
               25+STORAGE_LEN       EQU *-STORAGE                                         01-PROGR


START

            26 PGM3    PROGRAM START                                                   00040000
00000 00048    27+SA             DSECT                                                    01-PROGR
000000         28+SAVEAREA       DS    18F    SAVE AREA                                   01-PROGR
00048          29+SA_LEN              EQU *-SA                                            01-PROGR
00000 00188    30+PGM3     CSECT                                                          01-PROGR
               31+PGM3     AMODE 31                                                       01-PROGR
               32+PGM3     RMODE ANY                                                      01-PROGR
               33+         ENTRY PGM3                                                     01-PROGR
              and a lot more ….


The macro will
  • Define the savearea DSECT
  • Save registers in callers savearea
  • Getmain a new savearea for this program
  • set the base register (BASEREG)
  • Getmain the storage for this programs variables/fields
  • and set its base register


END



             131 RETURN  PROGRAM END                                                     00080002
               132+*************************
               133+*
               134+*************************
000120         135+RETURN   DS    0H                                                       01-PROGR
    4120 0012 136+         LA    R2,STORAGE_LEN                                           01-PROGR
000124         140+         CNOP  0,4                                                      02-FREEM
              141+         B     *+12-4*0-2*0                BRANCH AROUND DATA ØO2C      02-FREEM
                                                                and a lot more ….


Freemains areas previous getmained by the macro and returns with cond code (default zero).

Bonus info

The macro above calls the IBM-provided macro FREEMAIN but the assembler does not write the called FREEMAIN macro out in the assembler list. I don’t know why but it writes the calling level and first five characters of the called macro in the very right of the line. That can be useful in a debug situation.


Macro Code

You do not need to read the next if you do not want to know how the macro works. If you will just use it as any other IBM provided macro you just clip the examples below and paste them one after the other into one PROGRAM macro.


Initial code


        MACRO
&LABEL   PROGRAM &STATE,&BASEREG=BASEREG,
              &STORAGEREG=R12,&SAVEAREA=SAVEAREA,&SADSECT=SA,
              &RETURNCODE=0
.***************************************************************
.** DEFINE THIS MACROS GLOBAL VARIABLES
.***************************************************************
        GBLC  &GBLC_SAVEAREA,&GBLC_SADSECT,&GBLC_BASEREG
        GBLC  &GBLC_LABEL,&GBLC_STORAGEREG
        GBLB  &STORAGE_DEFINED,&TRUE,&FALSE
&TRUE    SETB  1
&FALSE   SETB  0
.***************************************************************
.** DETERMINE WHICH SECTION TO EXECUTE
.***************************************************************
        AIF   ('&STATE' EQ 'START').START
        AIF   ('&STATE' EQ 'END').END
        AIF   ('&STATE' EQ 'EQU').EQU
        AIF   ('&STATE' EQ 'STORAGE').STORAGE
        MNOTE 8,'FIRST PARAMETER WRONG.'
        AGO   .MACROEND


We need several Global Literals in this macro so I define them first. That is "best practice" to do it at the top of the macro. I use a boolean test so I set &TRUE and &FALSE. That makes the boolean test and set more readable.
I then test for each state and go to each section accordingly. You will of course get a cond code of eight and an error text if you do not obey the rules of the macro.

EQU
The EQU will create the EQU for the general registers
.EQU        ANOP
R0       EQU   0
R1       EQU   1
R2       EQU   2
R3       EQU   3
R4       EQU   4
R5       EQU   5
R7       EQU   7
R8       EQU   8
R9       EQU   9
R10      EQU   10
R11      EQU   11
BASEREG  EQU   11
R12      EQU   12
R13      EQU   13
R14      EQU   14
R15      EQU   15
         AGO   .MACROEND


Storage

This section is divided into two; one before storage definition and one after.


.STORAGE    ANOP
           AIF   (&STORAGE_DEFINED).STODEF
           AIF    ('&LABEL' EQ '').NO_LABEL
&GBLC_LABEL SETC '&LABEL'
           AGO   .DEFINE
.NO_LABEL   ANOP
&GBLC_LABEL SETC 'STORAGE'
.******************************
.DEFINE     ANOP
&GBLC_STORAGEREG SETC '&STORAGEREG'
&GBLC_LABEL DSECT
&STORAGE_DEFINED SETB (&TRUE)
           AGO   .MACROEND
.******************************
.STODEF     ANOP
&GBLC_LABEL._LEN  EQU *-&GBLC_LABEL
           AGO   .MACROEND


  • First we check which section of STORAGE we will enter by checking the boolean &STORAGE_DEFINED.
  • In the first section we then check to see whether the &LABEL is set. That is used to give name to the DSECT we are about to define. If it is not defined we use the default 'STORAGE'.
  • We can now start defining the DSECT (in bold) and its base register which is in &STORAGEREG. At last we set the boolean (&STORAGE_DEFINED) to &TRUE to indicate that the first definition of storage has been done. (Please note the SETBinary)
  • The second section just calculates the length of the storage. That will be used during getmain of the storage. We never need to know how big our storage is (*2).


START

.START   ANOP
&GBLC_SAVEAREA   SETC '&SAVEAREA'
&GBLC_SADSECT    SETC '&SADSECT'
&GBLC_STORAGEREG SETC '&STORAGEREG'
.**************************
.** DSECT FOR THE REGISTER
.** SAVE AREA
.**************************
&GBLC_SADSECT  DSECT
&GBLC_SAVEAREA DS    18F    SAVE AREA
&GBLC_SADSECT._LEN  EQU *-&GBLC_SADSECT
.**************************
.** START THE CSECT
.**************************
&LABEL   CSECT
&LABEL   AMODE 31
&LABEL   RMODE ANY
        ENTRY &LABEL
        SAVE  (14,12),,'&LABEL - &SYSDATE..&SYSTIME'
        BASR  &BASEREG,0
        USING *,&BASEREG
        LR    2,1         SAVE THE PARM REG FOR LATER USE
        WTO   '&LABEL - &SYSDATE.-&SYSTIME'
RSA      GETMAIN RC,LV=&GBLC_SADSECT._LEN
        ST    1,8(,13)
        ST    13,4(,1)
        LR    13,1
        ST    2,0(,13)
        USING &GBLC_SADSECT,13
        AIF   (NOT &STORAGE_DEFINED).STARTEND
        GETMAIN RC,LV=&GBLC_LABEL._LEN
        LR    &GBLC_STORAGEREG,1
        USING &GBLC_LABEL,&GBLC_STORAGEREG
.STARTEND ANOP
        L     1,0(,13)
        AGO   .MACROEND
  • I start by setting the GBLC’s from the input parameters to the macro
  • and then defines the DSECT for the savearea.
  • The real program starts with a CSECT, AMODE, RMODE, and ENTRY.
  • We save the calling program’s registers
  • Load the base register and set the USING register. Probably 11.
  • Then I save the pointer to the parm (R1) in R2 in order to save it for future use.
  • Then I write the date of assembling out  with WTO. Very nice if the program is not used a million times. You know what I mean.
  • Now it’s time to get some storage for the save area. Try to figure out what the four instruction between GETMAIN and USING are doing. I will probably come back to that in a later blog post.
  • If we also have used the STORAGE state of PROGRAM we will also get some storage for that and set the base register for that storage (Default R12).
  • (Future use): The last instruction sets the register 1 to point to the parm as it does at start in any assembler program.


END

.END     ANOP
        AIF   ('&LABEL' EQ '').NO_LABEL
&LABEL   DS    0H
        AGO   .RETURN
.NOLABEL ANOP
RETURN   DS    0H
.RETURN  ANOP
        AIF   (NOT &STORAGE_DEFINED).NO_STORAGE_DEFINED
        LA    R2,&GBLC_LABEL._LEN
        FREEMAIN RC,LV=&GBLC_LABEL._LEN,A=(&GBLC_STORAGEREG)
.NO_STORAGE_DEFINED ANOP
        L     R13,&GBLC_SAVEAREA+4
        LA    R12,&GBLC_SAVEAREA
        LA    R2,&GBLC_SADSECT._LEN
        FREEMAIN RC,LV=&GBLC_SADSECT._LEN,A=(R12)
        LM    R14,R12,12(R13)
        RETURN RC=&RETURNCODE
        LTORG
        AGO   .MACROEND
  • If the END state has a label we use that label so we can branch to it. You might wish to have more than one END with different RETURNCODEs. Each of these generates all the code here and one could argue that is waste. Yes, - feel free to change the macro to solve it.
  • If we define the storage and getmain’ed it we will of course freemain it again. Every good boy and girl clear up in storage after themselves!!
  • That goes for the save area as well.
  • We return to the caller with a return code.
  • And finally, we define literals.


We conclude the macro with these two lines.


.MACROEND ANOP
         MEND


(*1) - PROGRAM will NOT make you assembler program reentable.
(*2) - I will talk about base register limitations later. Let us assume that 4096 bytes are enough

Ingen kommentarer:

Send en kommentar