// MACRO        Test repeat blocks and macros
        .data                     // Declare storage
        .align  8                 // Desired alignment
sq1:    .skip   8                 // Storage for square 1
sq2:    .skip   8                 // Storage for square 2
sq3:    .skip   8                 // Storage for square 3
                                  // etc.
        .text                     // Section for code
        .align  32                // Desirable alignment
        .global main              // These three lines
        .proc   main              //  mark the mandatory
main:   .body                     //   'main' program entry
                                  // Now we really begin...

// E.2.1 Simple Repeat Blocks
        N       = 9
        .data
s1:     .skip   8*N               // Space for N squares
        .text
rept:   mov     r21 = -1          // Gr21 = first difference
        mov     r22 = 2           // Gr22 = 2nd difference
        mov     r20 = 0           // Gr20 = current square
        addl    r14 = @gprel(s1),gp  // Point to storage
        .auto
        .rept   N
        add     r21 = r22,r21     // Adjust first difference
        add     r20 = r21,r20     // Gr20 = nth square
        st8     [r14] = r20,8     //         to be stored
        .endr
        .default
done1:  mov     ret0 = 0          // Signal all is normal

// E.2.2 Indefinite Repeat Blocks Using the .irp Directive
irp:    mov     r21 = -1          // Gr21 = first difference
        mov     r22 = 2           // Gr22 = 2nd difference
        mov     r20 = 0           // Gr20 = current square
        .auto
        .irp    N, 1,2,3,4,5,6,7,8,9
        .data
s2\N:   .skip   8                 // Space for square \N
        .text
        add     r21 = r22,r21     // Adjust first difference
        add     r20 = r21,r20     // Gr20 = square \N
        addl    r14 = @gprel(s2\N),gp  // Point to storage
        st8     [r14] = r20       //       for square \N
        .endr
        .default
done2:  mov     ret0 = 0          // Signal all is normal

// E.2.3 Indefinite Repeat Blocks Using the .irpc Directive
irpc:   mov     r21 = -1          // Gr21 = first difference
        mov     r22 = 2           // Gr22 = 2nd difference
        mov     r20 = 0           // Gr20 = current square
        .auto
        .irpc   N, 123456789
        .data
s3\N:   .skip   8                 // Space for square \N
        .text
        add     r21 = r22,r21     // Adjust first difference
        add     r20 = r21,r20     // Gr20 = square \N
        addl    r14 = @gprel(s3\N),gp  // Point to storage
        st8     [r14] = r20       //       for square \N
        .endr
        .default
done3:  mov     ret0 = 0          // Signal all is normal

// E.4.2 Invoking a Macro
        .text
        .macro  clr     REG
        add     \REG = r0,r0      // \REG <-- 0
        .endm
m4:     clr     r14

        .macro  clr     REGLIST
        .irp    REG, \REGLIST
        add     \REG = r0,r0      // \REG <-- 0
        .endr
        .endm
m5:     clr     "r15,r16,r17"

// E.4.3 Processing of Positional Parameters
        .macro  count   ONE, TWO, THREE
        data8   \ONE
        data8   \TWO
        data8   \THREE
        .endm
        .data
d6:     count   25,,30
        .text
        
// E.4.4 Processing of Default Values and Keyword Parameters
        .macro  clr     REG=r18
        add     \REG = r0,r0      // \REG <-- 0
        .endm
m7:     clr
        clr     r19
        .data
d8:     count   THREE=30, ONE=25

// E.4.5 Processing of String Parameters
        .macro  asc     STR
        stringz "\STR"
        .endm
        .data
d9:     asc     Abc
        asc     "d,e f"

// E.5 Using Labels with Macros
        .macro  equal   PAR
        addl    r14=@gprel(\PAR),gp  // r14 -> \PAR
        ld8     r15 = [r14]          // r15 = mem(\PAR)
        cmp.ne  p6,p0 = r15,r0       // if \PAR ne 0
        (p6) br.cond.sptk    10f     //  then skip ahead
        nop.f 0
10:     nop.i 0
        .endm
        .text
        .auto
m10:    equal   s21
        equal   s31
        .default

//E.6 Recursive Macros
        .macro  factorial       INT
         .if \INT
           factorial    (\INT-1)
           F = F * \INT
         .else
           F = 1
         .endc
        .endm
m11:    factorial 4         // Verify value of F using nm command

.macro  choice WHEN
 .if (\WHEN > 1984)
        mov r14 = \WHEN
   // case for FUTURE
   .exitm
 .endc
 .if (\WHEN == 1984)
        mov r15 = \WHEN
   // case for THAT YEAR
   .exitm
 .endc
 .if (\WHEN == 1983)
        mov r16 = \WHEN
   // case for YEAR BEFORE
   .exitm
 .endc
 .if (\WHEN < 1983)
        mov r17 = \WHEN
   // case for earlier
   .exitm
 .endc
 .err // Should never assemble this line
.endm
        .text
        .auto
m12:    choice 2001
        choice 1983
        choice 1901
        choice 1984
        .default

// E.8 MONEY: A Macro Illustrating Sections

        .data
        .align 8
        .section VALUES, "a", "progbits"
valu:
        .section WHERE, "a", "progbits"
sloc:
        .section WORDS, "a", "progbits"
byte:
        .macro money AMT, PHRASE
        .section WORDS
        T\@ = .
        stringz "\PHRASE"
        .section VALUES
        data8  \AMT
        .section WHERE
        data8  T\@
        .endm
        .auto
m13:    money 1000, "one thousand "
        money 900, "nine hundred "
        money 100, "one hundred "
        money 90, "ninety "
        money 20, "twenty "
        money 1, "one"
        .default
        .text

        br.ret.sptk.many b0;;     // Back to command line
        .endp   main              // Mark end of procedure