;
;   Terminal output test module
;
;
;


        .entry  fmt_int, ^m<r2,r3,r4,r5,r6,r7,r8>

;
;   We're going to allocate some stack space.  So move the SP down to
;   prepare room for it.

        subl2   #4,sp


        movl    b^4(ap), r2                     ; Get the value to format
        tstl    r2                              ; Is it zero?

        beql    _zero                           ; If so, special case

;
;   Allocate some "automatic storage" on the stack by marking where we
;   are (since we want the end of the buffer anyway) and move the SP
;   down in case we need it for something else.
;

        movl    sp,r6                           ; Point to end of space
        subl2   #20,sp                          ; and move end of stack down

        clrl    r7                              ; init the counter

_loop:  divl3   #^d10, r2, r3                   ; Shift off digit
        mull3   r3, #^d10, r4                   ; And back again
        subl3   r4, r2, r5                      ; Difference is digit
        addl2   #30, r5                         ; Make ASCII

        movb    r5, -(r6)                       ; copy to buffer, decrement
        incl    r7                              ; and increment counter

        tstl   r4                               ; Is there more?
        beql   _exit                            ; No, done

        movl   r3, r2                           ; Yes, set it up
        brb    _loop                            ; And loop again

_zero:  movl   sp, r6                           ; Get address of stack buffer
        movb   #30, (r6)                        ; Write "0" to buffer
        movl   #1, r7                           ; return length of 1

_exit:  movl   b^8(ap), r8                      ; Get address of buffer
        movc3  r7, (r6), (r8)                   ; Copy to user's buffer
        movl   r7, r0                           ; and return the length
        ret                                     ; Go home.

;
;       n = sum( n1 [, n2...]);
;
;

        .entry  calcsum, ^m<r2,r3>

        clrl    r0								; Initialize sum to zero
        movl    (ap), r2						; Get the count of arguments
        tstl    r2								; See if it's zero (no arguments)
        beql    _exit							; ...if so, we are done

        moval   b^4(ap), r3						; Get address of argument list

_sum:   addl2   (r3)+, r0						; Add next argument to sum
        sobgtr  r2, _sum						; Decrement arg count and loop

_exit:  ret										; Return sum in R0


;
;       Print the sum of all arguments passed.
;

        .entry  printsum, ^m<r2>

        callg   ap, @#calcsum
        movl    r0, r2

        pushl   #0d                       ; last parts of message are the
        pushl   #0a                       ; carriage control

        pushal  @#msgb                    ; Format the number into buffer
        pushl   r2
        calls   #2,@#fmt_int

        movw    r0, @#msg2                ; Make it a descriptor and push
        pushal  @#msg2

        pushal  @#msg1                   ; Message prefix

        calls   #4, @#lib$put_output

        ret

msg1:   .ascid "The sum of the arguments is "

msg2:   .word  0, 0
        .long  msgb

msgb:   .blkb  ^d20


;
;       Main test program.  Calculate and print the sum of the arguments.
;

        .entry  sumtest, ^m<r2>

        moval   @#table, r2
        callg   r2, @#printsum
        ret

table:  .long   3
        .long   ^d100
        .long   ^d20
        .long   ^d3

        .entry  psltst

        clrl    r0
        tstl    r0
        calls   #0, @#main

;
;       Main test program.  Find the largest prime less than 1000 and
;       print it out.
;

        .entry  main, ^m<r2>

        tstl    (ap)                      ; see if we have an argument?
        bneq    _10                       ; yes we have one
        movl    #^d1000,r2                ; no, invent one
        brb     _20

_10:    movl    b^4(ap),r2

_20:    pushl   #0d                       ; last parts of message are the
        pushl   #0a                       ; carriage control

        pushal  @#_msgb                    ; Format the number into buffer

        pushl   r2                         ; Calculate largest prime <1000
        calls   #1, @#sieve

        pushl   r0
        calls   #2,@#fmt_int

        movw    r0, @#_msg2                ; Make it a descriptor and push
        pushal  @#_msg2

        pushal  @#_msg1                   ; Message prefix

        calls   #4, @#lib$put_output

        ret

_msg1:  .ascid "The largest prime number is "

_msg2:  .word  0, 0
        .long  _msgb

_msgb:   .blkb  ^d20


;
;   SIEVE of ERISTOTHANIES
;
;   maxprime = sieve( maxnum );
;
;   Returns the largest prime number less than maxnum.
;


        .entry  sieve, ^m<r2,r3,r4,r5,r6,iv>

;
;       Let's get the size of the array.  Create an automatic storage
;       area on the stack to hold it.
;


        movl    b^4(ap),r5
        subl2   r5, sp
        movl    sp, r6

;
;       Establish a condition handler
;

        movab   @#errors, (fp)

;
;   Initialize the array
;

        movl    r5, r0

_init:  movab   (r6)[r0], r4    ;   Get address of cell (debug)
        clrb    (r4)            ;   and zap it.
        sobgtr  r0, _init

;
;   Choose the first prime number
;

        movl    #2, r1

;
;   Mark out the nth elements of the array
;

        movl    r1, r2       ;   prime is index

_mark:  movb    #1, (r6)[r2]    ;   write the marker byte
        addl2   r1, r2       ;   stride by prime
        cmpl    r2, r5       ;   are we done?

        bleq    _mark        ;   nope, go some more

;
;   Find the next free element
;

        movl    r1, r3       ;   make copy of last prime

_find:  incl    r1           ;   step to next cell
        cmpl    r1, r5       ;   are we at end of array?
        bgtr    _done        ;   yes, all done

        tstb    (r6)[r1]     ;   see if cell empty
        bneq    _find        ;   no, look some more

        movl    r1, r2       ;   yes, cell empty, so mark
        brb _mark            ;   this as new prime

_done:   movl    r3, r0      ;   we return last prime
                             ;   as function result
        ret

;
;   Condition handler (currently does nothing)
;
        .entry errors, ^m<>
        movl #1, r0         ;   just signal success
        ret


        .end    main

