Anne

The contents of the register, given the symbolic name R0 in this example,
are stored in the double-word, eight bytes that used to need to be
double-word aligned but probably don't any more, a storage area identified
by RWORK in this case. The contents are stored in packed decimal format.
This means that the result is the number expressed as decimal digits, one
digit occupying half a byte. The digits are stored from the second half-byte
from the right end of the field half a byte at a time moving leftwards. The
rightmost half-byte contains either X'C' in the number is positive or X'D'
if the number is negative.[1]

The edit mask X'402120202020', specified using a "literal", is moved to a
field identified as a location one byte less than the field identified by
the name M1CC. What we can't see is how the length L'M1CC, the number the
Assembler notes as the length depending on how the field M1CC was defined,
plus one matches up to the length 6 which is the length of the literal.

It seems reasonable that the field M1CC is defined as having length 5. If
not, the programming is a mess. If so, the "L'M1CC+1" specification is
stupid. It's stupid because the expression already indicates the length by
virtue of having included the literal which - dare I say literally - no,
I'll just say - obviously has length 6.

I'll proceed on the assumption that M1CC is a field of length 5.

The contents of the area defined by the location RWORK+5, 5 bytes into the
double-word area are now taken a half-byte at a time and managed according
to the "edit mask". If the edit mask specifies X'20" or X'21', a half-byte
containing what should be a decimal number, i.e. a number from 0 to 9 (and
*not* X'A' to X'F'), replaces the X'20' or X'21' character simply by taking
the half-byte and prepending a X'F' before storing over the X'20' or X'21'
byte. If the character is other than X'20' or X'21', there is, in principle,
no change[2]. The first character is important in that it can be used also
as a substitute for "0", X'F0', if there have been no previous non-zero
half-bytes selected. Clearly a "blank", X'40', means that "leading zeros"
are suppressed with blank characters, Another popular alternative is an
"asterisk", "*", X'5C', which can be used when printing cheques ("chiefly
Amer." check).

Why X'20' and X'21'? X'21' has an additional function which switches off the
suppressing "leading zeros" mechanism.

[2] The "in principle" is because the character can be replaced by the first
byte if "leading zeros" are still being suppressed. Think of how "commas"
separating groups of 3 decimal digits would need to show up.

Note that the "edit mask" specifies 5 bytes containing X'20" or X'21'. This
means that 5 half-byte decimal values will be selected from storage area
RWORK+5 and this happens to be all the packed decimal half-bytes up to the
last half-byte, the "sign half-byte". All very neat.

Note also that this pattern of coding works well for an odd number of
eventual decimal digits since the result can usually be "unwrapped" into the
target location needing only a single initial typically blank character. For
an even number of characters, the "unwrapping can be performed into the
target location if two leading blanks are available - or the field to the
left can be moved in after the decimal digits are "unwrapped" rather than
before - or the "unwrapping" can be performed in a work area and the data
without the necessary prefix moved to the target location.

Incidentally, using this coding, the programmer had better be sure that
he/she doesn't care about the byte immediately in front of the M1CC field
since it gets trashed by the first byte of the literal. It's not really good
coding practice, this "minus" addressing.

What this means in your case is that the 5 lower digits of the binary number
stored in the register will show as a string of digits with no "leading
zeros" suppressed.

Once all this has been done it's far too late to consider presenting the
binary number in the register as a hexadecimal string; you need to start
again - or, in a more American version of the language - to start over. <g>
As the reputed Irishman said, "If oi wanted to go there, oi wouldn't start
from here!" <g>

What you have done with your instructions achieves nothing since, after
execution, the contents of field M1CC is unchanged. In effect your first
instruction removers the first half-byte of all but the first byte of the
assumed 5-byte M1CC field and then the second instruction simply puts the
X'F' half-bytes back.

Never code anything without understanding it.

One reason it isn't translating decimal to hexadecimal is because you don't
understand it. It's possible you didn't understand the context of the code
you took as your sample.

I know you have had at least one example of how the code you posted here
works even if you didn't get the general description as above.

Unfortunately, having given you sample code to achieve what you want, nobody
has explained in detail what happens so you may be in the half-way house of
having code which works while still not understanding it. In fact the "print
hexadecimal" case is even trickier that the "print decimal" case since, in
the letter case, all the instructions were doing precisely what the
Principles of Operation says they do - even if the "edit" instruction is a
bit complicated. There's a touch of "smoke and mirrors" about the various
sample codings you have been offered for the former.

Let's have a look at Shmuel's eventual offering, the following - with a
missing bit of the "unpack" instruction inserted. This has the virtue of
being as symbolic as possible.

         ST    R0,BINWORK
         UNPK  HEXWORK(L'HEXWORK+1),BINWORK(L'BINWORK+1)
         TR    HEXWORK,TRTAB

TRTAB    EQU   *-C'0'
         DC    C'0123456789ABCDEF'

BINWORK  DS    F

HEXWORK  DS    CL8
         DS    C

I don't think I need explain the "store register" instruction. Suffice to
say that BINWORK now contains a full-word, 4 bytes, 8 half-bytes, binary
number.

The "unpack" instruction makes what is, in fact, an incorrect assumption.
It, poor thing, *thinks* it is working on a packed decimal number - having
the format I explained above.

In fact the "unpack" instruction is being used in a clandestine way to
"unwrap" the 8 half-bytes of the BINWORK field into the 8 bytes of the
HEXWORK field, each in turn being taken a half-byte at a time, prepended
with X'F' and stored a byte at a time.

The reason for the extra "1" added to the length of both HEXWORK and BINWORK
is that the "unpack" instruction, true to its defined role as an instruction
for use with decimal fields, knows that it has to treat the last byte in the
"from" field differently than the preceding bytes. That last byte simply has
the two constituent half-bytes reversed before they are stored in the last
byte of the "to" field.

Because an additional byte was indicated in the "unpack" instruction the
"last" byte is from outside the BINWORK field and, after the reversal, it is
stored outside the HEXWORK field, The lengths in the "unpack" instruction
are, in fact, 5 and 9 respectively rather than 4 and 8.

Converting that "last" byte was actually a total waste of time and resources
but it was forced on us because we lack the precise instruction for the task
in hand and the "unpack" instruction, in essence, had to be fooled into
doing the job for us.

Whatever byte follows BINWORK is of no consequence since it is "read". Quite
the contrary, whatever byte follows HEXWORK had better not matter since it
is going to get "written" on. Just be sure this is taken care of either as a
work area known to be used later or a wasted byte.

What's tricky about the "translate" instruction is that you are obliged to
pretend that it has a whole 256 bytes to work with so that each byte
selected can be used to index into the table. What the "unpack" instruction
did was to guarantee that the first half-byte of each character to be
translated definitely contained X'F' and thus that the range of values to
work on is from 240, X'F0', to 255, X'FF', rather than 0 to 255. Thus there
is no harm in having the characters at positions 0 to 239 in the translate
table consist of random code within the program leading up to the string of
16 characters we really need.

Another sample from Alan Field is the following:

        ST      R0,IN
        UNPK    OUT(9),IN(5)
        MVZ     OUT(8),OUT-1
        TR      OUT(8),=C'0123456789ABCDEF'

This is the same as Shmuel's except that there is an additional instruction
before the "translate" instruction and the "translate" is allowed to be a
bit more honest.

However, there is an assumption here which is that the byte at location
OUT-1 needs to have the first half-byte, the "zone" half-byte, set to X'0'.
Assuming this is the case, the "move zones" instruction will overwrite the
"zone" half-byte in each of the 8 bytes in field OUT with X'0' replacing the
X'F'. Now the "translate" instruction, still thinking it has a table of 256
bytes to work with, in fact only ever uses the first 16 bytes in the table
for characters ranging from 0, X'00', to 15, X'0F'.

Your original sample used the "and character" (NC) instruction in order to
perform the same function as the "move zones" instruction in the example
above. The "move zones" instruction is marginally more storage efficient -
and I was brought up using Assembler programming in the days when storage
efficiency was considered a virtue[1]: the "move zones" instruction needs
just one additional byte whereas the "and character" instruction needs as
many bytes as the field to be modified.

So now I hope you not only have a piece of working code but even know *how*
it works. <g>

Incidentally Peter Hunkeler was right. Bill Fairchild, usually so reliable,
must have has a minor rush of blood. <g>

Chris Mason

[1] In fact the "packed decimal standard", as it were, allows some
flexibility in the hexadecimal digit which forms the, so-called, "sign
half-byte". I forget every last detail but it may be as simple as only the
lowest bit being significant and the rest ignored so that a positive number
is one which has B'0' as this lowest bit and a negative number is one which
has B'1' as this lowest bit - except that X'F' has to indicate a positive
number - so maybe it's not quite so simple. Suffice to say that it was once
proposed that the "Add Register" instruction code, X'1A', could be used as a
positive packed decimal "1" when a package for some basic "spooling" in
under 4K for DOS (now VSE) was being discussed (in the days before POWER
obviously) and the author/presenter was canvassing for space-saving ideas.

----- Original Message ----- 
From: "Anne Crabtree" <[EMAIL PROTECTED]>
Newsgroups: bit.listserv.ibm-main
To: <IBM-MAIN@BAMA.UA.EDU>
Sent: Tuesday, 24 October, 2006 9:11 PM
Subject: Assembler question


> Working on the IEFACTRT routine and it has the following assembler
statements for getting return code ready to print on hasp:
>
> CVD   R0,RWORK            GET ADDRESS OF COND FIELD
> MVC   M1CC-1(L'M1CC+1),=X'402120202020' MOVE IN EDIT MASK
> ED    M1CC-1(L'M1CC+1),RWORK+5 CONVERT RET CODE TO CHAR
>
> However, I want the return code to print as hexidecimal instead of
decimal.  I tried the following after these prior 3 statements:
>
> NC    M1CC+1(4),=4X'0F'
> TR    M1CC+1(4),=C'0123456789ABCDEF'
>
> (I don't understand exactly how this works but it is how it is coded in
our old exit which used the SMF type 4 records).
>
> Why is it not translating the decimal to hexadecimal???

----------------------------------------------------------------------
For IBM-MAIN subscribe / signoff / archive access instructions,
send email to [EMAIL PROTECTED] with the message: GET IBM-MAIN INFO
Search the archives at http://bama.ua.edu/archives/ibm-main.html

Reply via email to