[comp.lang.asm370] help for new assembly'er

laird@chinet.chi.il.us (Laird J. Heal) (02/27/91)

In article <9102261052.AA16278@ucbvax.Berkeley.EDU> IBM 370 Assembly Programming Discussion List <ASM370@OHSTVMA.BITNET> writes:
>
>My girl friend starts to working with system 370 assembler.
>But she don't care syntax and rules of 370 assembly !  

There are really very few bad practices in 370 assembler, or perhaps
there are really very few good practices in 370 assembler.  Now that
I sound confused too, let me lay down a few rules, of thumb that is.

Since registers zero, one and two can be modified by everything from
SVCs to TRTs, use them for scratch areas.  R15 is your entry address
but you should save it off - R12 is typically used for this and thus
as the code base register.  R14 is the return address but can be used
within your code as can R15, as the OS never really relies on them.
R13, on the other hand, should always point to your Register Save
Area, unless you are working with DOS/VSE/POWER, in which case I
commend your soul to the appropriate power.

Always observe register saving and save area chaining scrupulously.
That is, use the SAVE and RETURN macros or write code yourself to
put R14-R12 at 12(R13), then save the address of your area in the
caller's area and save hers in yours.  Note:  a calling process is
generally called the `mother' process.

All other registers can be used for base or scratch as you like.
Writing reentrant code (use RU-type GETMAIN for all data areas)
is good practice but not much good otherwise.

Always use DS 0H for all branch labels.  There was a much better
reason once (in the days of punch-cards) but now it just helps to
clarify the scene.  Never write self-modifying code - there is
always a better way to accomplish the same thing, generally with
a table of things to pick up and EXECUTE with, if your program is
so constituted.

Have fun.

-- 
Laird J. Heal                           The Usenet is dead!
Here:  laird@chinet.chi.il.us		Long live the Usenet!

laird@GARGOYLE.UCHICAGO.EDU ("Laird J. Heal") (02/27/91)

In article <9102261052.AA16278@ucbvax.Berkeley.EDU> IBM 370 Assembly
        Programming Discussion List <ASM370@OHSTVMA.BITNET> writes:
>
>My girl friend starts to working with system 370 assembler.
>But she don't care syntax and rules of 370 assembly !

There are really very few bad practices in 370 assembler, or perhaps
there are really very few good practices in 370 assembler.  Now that
I sound confused too, let me lay down a few rules, of thumb that is.

Since registers zero, one and two can be modified by everything from
SVCs to TRTs, use them for scratch areas.  R15 is your entry address
but you should save it off - R12 is typically used for this and thus
as the code base register.  R14 is the return address but can be used
within your code as can R15, as the OS never really relies on them.
R13, on the other hand, should always point to your Register Save
Area, unless you are working with DOS/VSE/POWER, in which case I
commend your soul to the appropriate power.

Always observe register saving and save area chaining scrupulously.
That is, use the SAVE and RETURN macros or write code yourself to
put R14-R12 at 12(R13), then save the address of your area in the
caller's area and save hers in yours.  Note:  a calling process is
generally called the `mother' process.

All other registers can be used for base or scratch as you like.
Writing reentrant code (use RU-type GETMAIN for all data areas)
is good practice but not much good otherwise.

Always use DS 0H for all branch labels.  There was a much better
reason once (in the days of punch-cards) but now it just helps to
clarify the scene.  Never write self-modifying code - there is
always a better way to accomplish the same thing, generally with
a table of things to pick up and EXECUTE with, if your program is
so constituted.

Have fun.

--
Laird J. Heal                           The Usenet is dead!
Here:  laird@chinet.chi.il.us           Long live the Usenet!

VALDIS@VTVM1.CC.VT.EDU (Valdis Kletnieks) (02/28/91)

On Wed, 27 Feb 91 04:32:34 GMT Laird J. Heal said:
>Since registers zero, one and two can be modified by everything from
>SVCs to TRTs, use them for scratch areas.  R15 is your entry address
>but you should save it off - R12 is typically used for this and thus
>as the code base register.  R14 is the return address but can be used
>within your code as can R15, as the OS never really relies on them.
>R13, on the other hand, should always point to your Register Save
>Area, unless you are working with DOS/VSE/POWER, in which case I
>commend your soul to the appropriate power.

Please note that at least in OS/MVT and VS/1 and (presumably) the
various MVS variants, and the OS Simulation routines under VM/CMS,
that the various QSAM I/O macros (such as GET and PUT), involve
a  BALR  14,15  - so these registers should *not* be used except as
scratch unless you *know* that any system macros you use don't modify
these registers.  Incidentally, macros like this are the *REASON* you
usually use R12 as the base rather than R15....


                                  Valdis Kletnieks
                                  Computer Systems Engineer
                                  Virginia Polytechnic Institute

ralerche@lindy.stanford.edu (Robert A. Lerche) (02/28/91)

laird@chinet.chi.il.us (Laird J. Heal) writes:

   ... 

>Always observe register saving and save area chaining scrupulously.
>That is, use the SAVE and RETURN macros or write code yourself to
>put R14-R12 at 12(R13), then save the address of your area in the
>caller's area and save hers in yours.  Note:  a calling process is
>generally called the `mother' process.

In OS the common entry sequence is...

MODULE   CSECT
         SAVE  (14,12),,*
         LR    R12,R15                   (OS PROVIDES MY ENTRY POINT IN R15)
         USING MODULE,R12
         LR    R2,R1                     PRESERVE PARM POINTER ACROSS GETMAIN
         GETMAIN R,LV=SVLENGTH           MINIMUM LENGTH IS 72 FOR A SAVE AREA
         ST    R13,4(,R1)                BACK-CHAIN NEW TO OLD SAVE AREA
         ST    R1,8(,R13)                FWD-CHAIN OLD TO NEW SAVE AREA
         XC    8(4,R1),8(R1)             CLEAR FWD CHAIN OF NEW SAVE AREA
         LR    R13,R1                    OK -- SAVE AREA ALL SET UP

>All other registers [besides 0, 1, 2, 13, 14 and 15]
>can be used for base or scratch as you like.
>Writing reentrant code (use RU-type GETMAIN for all data areas)
>is good practice but not much good otherwise.

Actually R2 is not used by any usual operating system functions, so
it's safe too (though the TRT instruction does use it as an implicit
operand).

Reentrant code is not that hard to do, and besides being good practice it
is critical if you ever use multiple tasks.  An easy way to arrange the
data areas is to make your save area (gotten above via GETMAIN) include
them after the register save area.  E. g.,

         USING R13,SAVEAREA

   ...

SAVEAREA DSECT
         DS    18F                      STANDARD OS SAVE AREA
<writable data areas go here>
SVLENGTH EQU   *-SAVEAREA               TOTAL LENGTH OF GETMAIN'ED AREA

You also need to learn about the MF=E forms of the MACROs -- what it
amounts to is that the standard forms of some MACROs don't generate
reentrant code because they have to create some kind of parameter list,
so they put it directly in the code and branch around it.  Those MACROs
all provide an MF=L form to generate the parameter list (as a constant)
and an MF=E form to fill it in and execute the operation.  You copy
the MF=L list into your work storage (again, in the GETMAIN'ed area)
and use MF=(E,<area>) to point to it.

>...  Never write self-modifying code - there is
>always a better way to accomplish the same thing, generally with
>a table of things to pick up and EXECUTE with, if your program is
>so constituted.

Amen!

-----

(other points)

Note the use of symbolic names R<n> for the registers.  This helps because
it causes register references to appear in the cross-reference listing
generated by the assembler.  In a complex piece of code it can be
difficult to follow the register usage; having a listing can help this.

A related point:  pick a convention for your use of the registers,
document it in comments in the beginning of the routine, and STICK TO IT!
There is nothing more difficult than keeping track in one's mind of
the meaning of all the registers.  LOTS of bugs come from failing
to notice some subtlety in this area.

Finally, remember that no matter how well you write assembler code 
it is almost always easier to write (and debug!) in a high-level language.
If what you are doing requires the use of assembler (e.g., because you need
to access some system interface that is only available from assembler),
a good approach is to write a small, well-defined subroutine in assembler
that can be called from a high-level language.

ralerche@LINDY.STANFORD.EDU ("Robert A. Lerche") (02/28/91)

laird@chinet.chi.il.us (Laird J. Heal) writes:

   ...

>Always observe register saving and save area chaining scrupulously.
>That is, use the SAVE and RETURN macros or write code yourself to
>put R14-R12 at 12(R13), then save the address of your area in the
>caller's area and save hers in yours.  Note:  a calling process is
>generally called the `mother' process.

In OS the common entry sequence is...

MODULE   CSECT
         SAVE  (14,12),,*
         LR    R12,R15                   (OS PROVIDES MY ENTRY POINT IN R15)
         USING MODULE,R12
         LR    R2,R1                     PRESERVE PARM POINTER ACROSS GETMAIN
         GETMAIN R,LV=SVLENGTH           MINIMUM LENGTH IS 72 FOR A SAVE AREA
         ST    R13,4(,R1)                BACK-CHAIN NEW TO OLD SAVE AREA
         ST    R1,8(,R13)                FWD-CHAIN OLD TO NEW SAVE AREA
         XC    8(4,R1),8(R1)             CLEAR FWD CHAIN OF NEW SAVE AREA
         LR    R13,R1                    OK -- SAVE AREA ALL SET UP

>All other registers [besides 0, 1, 2, 13, 14 and 15]
>can be used for base or scratch as you like.
>Writing reentrant code (use RU-type GETMAIN for all data areas)
>is good practice but not much good otherwise.

Actually R2 is not used by any usual operating system functions, so
it's safe too (though the TRT instruction does use it as an implicit
operand).

Reentrant code is not that hard to do, and besides being good practice it
is critical if you ever use multiple tasks.  An easy way to arrange the
data areas is to make your save area (gotten above via GETMAIN) include
them after the register save area.  E. g.,

         USING R13,SAVEAREA

   ...

SAVEAREA DSECT
         DS    18F                      STANDARD OS SAVE AREA
<writable data areas go here>
SVLENGTH EQU   *-SAVEAREA               TOTAL LENGTH OF GETMAIN'ED AREA

You also need to learn about the MF=E forms of the MACROs -- what it
amounts to is that the standard forms of some MACROs don't generate
reentrant code because they have to create some kind of parameter list,
so they put it directly in the code and branch around it.  Those MACROs
all provide an MF=L form to generate the parameter list (as a constant)
and an MF=E form to fill it in and execute the operation.  You copy
the MF=L list into your work storage (again, in the GETMAIN'ed area)
and use MF=(E,<area>) to point to it.

>...  Never write self-modifying code - there is
>always a better way to accomplish the same thing, generally with
>a table of things to pick up and EXECUTE with, if your program is
>so constituted.

Amen!

-----

(other points)

Note the use of symbolic names R<n> for the registers.  This helps because
it causes register references to appear in the cross-reference listing
generated by the assembler.  In a complex piece of code it can be
difficult to follow the register usage; having a listing can help this.

A related point:  pick a convention for your use of the registers,
document it in comments in the beginning of the routine, and STICK TO IT!
There is nothing more difficult than keeping track in one's mind of
the meaning of all the registers.  LOTS of bugs come from failing
to notice some subtlety in this area.

Finally, remember that no matter how well you write assembler code
it is almost always easier to write (and debug!) in a high-level language.
If what you are doing requires the use of assembler (e.g., because you need
to access some system interface that is only available from assembler),
a good approach is to write a small, well-defined subroutine in assembler
that can be called from a high-level language.

laird@chinet.chi.il.us (Laird J. Heal) (03/03/91)

In article <9102272012.AA08264@ucbvax.Berkeley.EDU> IBM 370 Assembly Programming Discussion List <ASM370@OHSTVMA.BITNET> writes:
>On Wed, 27 Feb 91 04:32:34 GMT Laird J. Heal said:
>
>>All other registers [besides 0, 1, 2, 13, 14 and 15]
>>can be used for base or scratch as you like.
>>Writing reentrant code (use RU-type GETMAIN for all data areas)
>>is good practice but not much good otherwise.
>
>Actually R2 is not used by any usual operating system functions, so
>it's safe too (though the TRT instruction does use it as an implicit

I find its special status a good excuse to use it as a single scratch
register whose contents will not be normally modified by the operating
system.  There is no special error in using it, for example, as a base
register, but I can remember well solving a nightmare for a co-worker
by noting that the last byte of R2 was providing him with a little
unexpected auto-indexing.

>>Since registers zero, one and two can be modified by everything from
>>SVCs to TRTs, use them for scratch areas.  R15 is your entry address
>>but you should save it off - R12 is typically used for this and thus
>>as the code base register.  R14 is the return address but can be used
>>within your code as can R15, as the OS never really relies on them.
>>R13, on the other hand, should always point to your Register Save
>>Area, unless you are working with DOS/VSE/POWER, in which case I
>>commend your soul to the appropriate power.

>Please note that at least in OS/MVT and VS/1 and (presumably) the
>various MVS variants, and the OS Simulation routines under VM/CMS,
>that the various QSAM I/O macros (such as GET and PUT), involve
>a  BALR  14,15  - so these registers should *not* be used except as
>scratch unless you *know* that any system macros you use don't modify
>these registers.  Incidentally, macros like this are the *REASON* you
>usually use R12 as the base rather than R15....

Excuses for the extensive attributions.  You note that I was commenting
on scratch registers.  Simply put, I was cautioning against using R13
for anything except save area chaining.  The other registers (from R14
to R2) are not so sacrosanct.  Some folks use R2 for a base register or
such - I feel this is a mistake of style, but since TRT is not normally
used, it often is harmless.

During my first class in BAL, the assistant (who was grading all of the
exercises) said "always use PRINT GEN" to which the instructor said
"you mean, never use PRINT GEN".  I tend to the "always" mode.
-- 
Laird J. Heal                           The Usenet is dead!
Here:  laird@chinet.chi.il.us		Long live the Usenet!

laird@GARGOYLE.UCHICAGO.EDU ("Laird J. Heal") (03/03/91)

In article <9102272012.AA08264@ucbvax.Berkeley.EDU> IBM 370 Assembly
        Programming Discussion List <ASM370@OHSTVMA.BITNET> writes:
>On Wed, 27 Feb 91 04:32:34 GMT Laird J. Heal said:
>
>>All other registers [besides 0, 1, 2, 13, 14 and 15]
>>can be used for base or scratch as you like.
>>Writing reentrant code (use RU-type GETMAIN for all data areas)
>>is good practice but not much good otherwise.
>
>Actually R2 is not used by any usual operating system functions, so
>it's safe too (though the TRT instruction does use it as an implicit

I find its special status a good excuse to use it as a single scratch
register whose contents will not be normally modified by the operating
system.  There is no special error in using it, for example, as a base
register, but I can remember well solving a nightmare for a co-worker
by noting that the last byte of R2 was providing him with a little
unexpected auto-indexing.

>>Since registers zero, one and two can be modified by everything from
>>SVCs to TRTs, use them for scratch areas.  R15 is your entry address
>>but you should save it off - R12 is typically used for this and thus
>>as the code base register.  R14 is the return address but can be used
>>within your code as can R15, as the OS never really relies on them.
>>R13, on the other hand, should always point to your Register Save
>>Area, unless you are working with DOS/VSE/POWER, in which case I
>>commend your soul to the appropriate power.

>Please note that at least in OS/MVT and VS/1 and (presumably) the
>various MVS variants, and the OS Simulation routines under VM/CMS,
>that the various QSAM I/O macros (such as GET and PUT), involve
>a  BALR  14,15  - so these registers should *not* be used except as
>scratch unless you *know* that any system macros you use don't modify
>these registers.  Incidentally, macros like this are the *REASON* you
>usually use R12 as the base rather than R15....

Excuses for the extensive attributions.  You note that I was commenting
on scratch registers.  Simply put, I was cautioning against using R13
for anything except save area chaining.  The other registers (from R14
to R2) are not so sacrosanct.  Some folks use R2 for a base register or
such - I feel this is a mistake of style, but since TRT is not normally
used, it often is harmless.

During my first class in BAL, the assistant (who was grading all of the
exercises) said "always use PRINT GEN" to which the instructor said
"you mean, never use PRINT GEN".  I tend to the "always" mode.
--
Laird J. Heal                           The Usenet is dead!
Here:  laird@chinet.chi.il.us           Long live the Usenet!

SOMITCW@VCCSCENT.BITNET (03/04/91)

 On Sun, 3 Mar 91, chinet!laird@GARGOYLE.UCHICAGO.EDU said:
>During my first class in BAL, the assistant (who was grading all of the
>exercises) said "always use PRINT GEN" to which the instructor said
>"you mean, never use PRINT GEN".  I tend to the "always" mode.

    If the class was really BAL, then why were you using PRINT GEN?

    Note: The last S/360 BAL that IBM had was for the S/360-20.
 Later, when IBM came out with the MACRO Assemblers, they called
 them Full Assemblers.

    Classes that teach assembler without teaching macros are still
 called BAL, even though there has never been a S/370 BAL product.

LDW@USCMVSA.BITNET (Leonard D Woren) (03/09/91)

> During my first class in BAL, the assistant (who was grading all of the
> exercises) said "always use PRINT GEN" to which the instructor said
> "you mean, never use PRINT GEN".  I tend to the "always" mode.

PRINT NOGEN can hide programming errors.  Long ago, as a consultant
for student programmers, I was presented with an abend S0C4 in low
core (yep, it was long ago).  It was abending on a PUT to a file.
Given the logic flow of the simple program, it was clear that there
was no way the open could not have been executed, yet the file wasn't
open!  Here is the relevant part of what I saw:

       LA    R4,SYSPRINT
       OPEN  (R4)
       ...
       LA    R4,SYSPRINT
       PUT   (R4),...

With PRINT NOGEN, this error is extremely difficult to spot.  I told
the student to never use PRINT NOGEN around executable code.


Leonard D. Woren      Senior MVS Systems Programmer
<LDW@USCMVSA.BITNET>  <LDW@MVSA.USC.EDU>      Disclaimer???
University of Southern California             What would be the point?