* Calculates the square root of a number in machine code

   movem.l a0/d0-d4,-(sp)             /SAVE
   clr.l d0-d4                    {no such opcode, can't clear multiple regs}
   move.l 28(sp),a0
END OF FILE??

{Something must have happened to the rest of that file, so I disassembled
 the binary code in the BASIC program using the demo version of the
 "resource" disassembler, which produced the following (transcribed by hand
 as the demo version has the save feature disabled). The comments are my
 own, and may therefore be incorrect, any experts on assembler are free to
 comment. -ed.}

*arguments pushed onto top of stack, in this case just 1 long word (4 bytes)
        MoveM.l D0-D4/A0,-(SP)    ;Save A0,D4,D3,D2,D1,D0 on stack (24 bytes)
        Clr.l   D0                ;? waste of time?
        Move.l  28(SP),A0         ;Get arg. addr., which is on the stack just
                                  ;before the 24 bytes we just pushed on plus
                                  ;4 bytes back to the start of the long word
        Move.l  (A0),D0           ;Get value of arg. to find sqrt of
        Move.l  D0,D1             ;arg. to D1 to be turned into 1st approx
        MoveQ.l #10,D3            ;iterate process 10 times

        Lsr.w   #1,D1             ;first approx. to sqrt is just a guestamit!
                                  ;(arg/2)
        Move.w  D1,D2             ;store approximaton in D2
Loop:   Move.l  D0,D4             ;copy original argument to D4

*should check D1 is not zero, if it is, set it to 1
        DivU    D1,D4             ;try our approximation (arg/approx)

        Move.w  D4,D1             ;extract result (result in low word of D4)
        Add.w   D1,D2             ;add result to last approximation
        Lsr.w   #1,D2             ;new approximation is half of sum
        Move.w  D2,D1             ;copy new approximation to D1
        DBra    D3,Loop           ;repeat 10 times

        And.w   #$ffff,D2         ;maskoff answer = low word of d2 ??
* I think that's an error (perhaps it's just the disassembler)
* I think it should have been AndI.l #$ffff,D2

        Move.l  D2,(A0)           ;stuff result into arg. storage location
        MoveM.l (SP)+,D0-D4/A0    ;restore d0,d1,d2,d3,d4,a0
        RTS                       ;return to BASIC
        END

examples of algorithm execution:

sqrt(9)
arg    iteration   approx.    result      sum     new approx (sum/2)
 9         1         4           2         6           3
 9         2         3           3         6           3
next 8 iteration are the same (redundant), result is 3

sqrt(24)
24         1        12           2        14           7
24         2         7           3        10           5
24         3         5           4         9           4
24         4         4           5         9           4
next 6 iterations are the same (redundant), result is 4

sqrt(1)
 1         1         0         oops! 1/0!!
will "guru" with divide by zero error!

sqrt(65535)
65535      1     32767           2     32769       16384
65535      2     16384           3     16387        8193
65535      3      8193           7      8200        4100
65535      4      4100          15      4115        2057
65535      5      2057          31      2088        1044
65535      6      1044          62      1106         553
65535      7       553         118       671         335
65535      8       335         195       530         265
65535      9       265         247       512         256
65535     10       256         255       511         255
65535     11       255         257       512         256
just made it!, result 256 (if we keep going the result wavers between
255 and 256).  NB the DBRA tests to see if the count has reached zero then
does the decrement, and branches back.  So the counter started at 10 causes
11 iterations.


{Anyway, whatever the merits of the code, as far as interfacing to assembler
routines is concerned, the main thing to note is the passing of arguments to
the assembly language program via addresses on the stack, the saving and
restoration of all registers used, and the passing of results back to the
main program by directly modifing the variables via their addresses.  You
must be very careful to ensure you know exactly what size (byte, word, long
word) all parameters (arguments and results) are. -ed.}

    ======================================================================

If you really want an assembly language long integer square root routine try
this one from Dr. Dobbs Journal, November 1985.  Doesn't contain any of those
slow MUL or DIV opcodes (the DIV instruction in the above routine would
account for up to 700 clock cycles alone).  Too use from BASIC you would
have to add saving of registers and passing of parameters to and from the
routine - that is left as an excercise for the reader!!!!! -ed} :

*  By Jim Cathey (DDJ May 1985) with mods by Mike Morton (DDJ Nov 1985)
*  Integer Square Root (32 to 16 bit)
*
*  (Exact method, not approximate)
*
*  Call with :
*    D0.L = Unsigned number
*
*  Returns :
*    D0.L = SQRT
*    D1.L <> 0 if not exact root
*
*  Uses :
*    D1-D4 as temporaries ---
*    D1 = Error term
*    D2 = Running estimate
*    D3 = High bracket
*    D4 = Loop counter
*
*  Notes :
*    Result first in D0.W, but is valid in longword.
*    Takes from 1480 to 1832 cycles (including RTS).
*    (Word version is from 548 to 660 cycles).
lsqrt    moveq.w  #15,d4        ;Loop count (bits-1 of result)
         moveq    #0,d1         ;Result in D1
         moveq    #0,d2
sqrt1    asl.l    #1,d0         ;Get 2 leading bits at a time and
         roxl.l   #1,d1         ; into Error term for extrapolation.
*       {asl.l    #1,d0}        ;Mike Morton sugested replacing asl with add
                                ; as it's faster
         add.l    d0,d0         ;(Classical method, easy in binary)
         roxl.l   #1,d1
*       {asl.l    #1,d2}
         add.l    d2,d2         ;Running estimate * 2
         move.l   d2,d3
*       {asl.l    #1,d3}
         add.l    d3,d3
         cmp.l    d3,d1
         bls      sqrt2         ;New error term > 2* running ext.?
         addq.l   #1,d2         ;Yes, we want 1 bit then.
         addq.l   #1,d3         ;Fix up new error term.
         sub.l    d3,d1
sqrt2    dbra     d4,sqrt1      ;Do all 16 bit-pairs.
         move.l   d2,d0         ;Returns answer in D0.W
         rts


{Mike suggests that you may be able to change roxl.l #1,d1 to addx.l d1,d1
 to speed things up a tiny bit.  Also can unroll loop for faster speed}

