6.2 HEXNUM2: Using Logical Masks

We will now apply logical masking and a shift instruction to the HEXNUM program (Figure 4-3). In this new version, shown in Figure 6-1, we will encode the input digits as ASCII characters and store them in memory, using a null byte to terminate the string.

This program illustrates the instruction types just introduced while presenting programming techniques that will continue in future examples.

Character strings are typically stored in memory with a NUL character (Table 2-3) marking their end. This allows the processing of strings of arbitrary length by first testing each byte against zero (NUL). Thus the loop in HEXNUM2 is of the form while <nonzero> do…, requiring a predicated exit branch at the top and an unconditional return branch at the bottom.

The central portion of this program has four tasks: to load each character code as a zero-extended 64-bit value in register r20; to ensure that the character is within one of the ranges of ASCII codes for hexadecimal digits; to obtain the character's value; and finally to apply positional weighting to that digit, as done previously (Figure 4-3).

Allowing for mixed case, hexadecimal digits have three ranges: 0 9, A F, and a f. Since parallel compare instructions are typically tests against zero, we cannot use a sequence of them to determine if a value is in a given range. Therefore we build the range checks from pairs of regular comparisons, using predicate register p8 to flag cases where a character is not within one of the three tested ranges. The two alphabetic ranges are conveniently collapsed into one by use of a complemented mask (~0x20) that forces lowercase a z to uppercase A Z (see hex codes in Table 2-3).

Once we have determined that a character is a valid hexadecimal digit, its numeric equivalent must be determined from its ASCII representation. For the numerals 0 9, the xor instruction with a mask of 0x30 toggles off bits <5:4>, leaving the binary numeric value. For the letters A-F, an add instruction with a suitable negative immediate value ( 0x37 = 0d55) as a mask is used to convert the ASCII code for A to the value 10, B to 11, and so forth. This method with a different mask could have also been used for the numerals, though it is not as "elegant."

Figure 6-1 HEXNUM2: Illustrating masking with logical instructions
 // HEXNUM2      Number Conversion // This program will convert the positive number expressed // by hexadecimal digits stored as a string beginning // at H2 into a value in register r20 for inspection.          .data                    // Declare storage          .align  8                // Desired alignment H2:      stringz "3a2"            // Number to convert          .text                    // Section for code          .align  32               // Desired alignment          .global main             // These three lines          .proc   main             //  mark the mandatory main:                             //   'main' program entry          .body                    // Now we really begin... first:   mov     r20 = 0          // Gr20 = value computed          addl    r14 = @gprel(H2),gp;;  // Point to storage more:    ld1     r21 = [r14],1;;  // Get a character; bump          cmp.eq  p6,p0 = r21,r0   // Null code marks end    (p6)  br.cond.spnt.few done;;  //  of our work          cmp.ge  p6,p7 = 0x39,r21;;  // See if <=9    (p6)  cmp.le  p6,p8 = 0x30,r21;;  // See if >=0     (p6)  xor     r21 = 0x30,r21   // Value of numeral    (p7)  and     r21 = ~0x20,r21;; // Force a-z to A-Z    (p7)  cmp.le  p7,p8 = 0x41,r21;;  // See if >=A    (p7)  cmp.ge  p7,p8 = 0x46,r21    // See if <=F    (p8)  br.cond.spnt.few bad;;   //  None of the above    (p7)  add     r21 = -(0x41-0xa),r21;;  // Get digit value          shladd  r20 = r20,4,r21  // Value = 16*prev + next          br.cond.sptk.few more    // Go back for more bad:                              // Could handle errors...                                   // Inspect r20 here... done:    mov     r8 = 0           // Signal all is normal          br.ret.sptk.many b0;;    // Back to command line          .endp   main             // Mark end of procedure 

When you study this example at the computer, you should monitor the contents of registers r21 and r20. Watch the values in those registers change as you step through the loop until it exits to the line at done. You will see the masking, shifting, and accumulation. The final numeric value in register r20 should be 930.



ItaniumR Architecture for Programmers. Understanding 64-Bit Processors and EPIC Principles
ItaniumR Architecture for Programmers. Understanding 64-Bit Processors and EPIC Principles
ISBN: N/A
EAN: N/A
Year: 2003
Pages: 223

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net