******************************************************************************
*       CyberPI_Calc
*
*       68K calculation routines
*
*       © 1997 HAAGE&PARTNER Computer GmbH
*
******************************************************************************

;// XREF / XDEF
                xref    Area_Quotient
                xref    Area_Quotient2
                xref    Area_Quotient3
                xref    Area_Quotient4
                xref    Area_ArcTan
                xref    Area_Result
                xref    Area_Q_Actual
                xref    Len_Q_Actual
                xref    Area_Q2_Actual
                xref    Len_Q2_Actual
                xref    Area_Q3_Actual
                xref    Len_Q3_Actual
                xref    Area_Q4_Actual
                xref    Len_Q4_Actual
                xref    Area_AT_Actual
                xref    Len_AT_Actual
                xref    Num_ArcTan_57
                xref    Num_ArcTan_239
                xref    Num_ArcTan_682
                xref    Num_ArcTan_12943
                xref    ConvertMem
                xref    Count
                xref    _060Flag

                xdef    BinToASCII
                xdef    Calculation
;;/

                mc68020

                near    a4,-1
                near    code

                section "code",code

;// BinToASCII
******************************************************************************
*       d2 = BinToASCII (d0,d1,a0,a1)
*
*       Conversion of the result area in a ASCII-String
*
*       a0 [.L] -> source area (result area)
*       a1 [.L] -> destination area for ASCII-String
*       d0 [.L] = number of decimals
*       d1 [.L] = length of the areas in longwords
******************************************************************************
BinToASCII
                movem.l d0/d1,-(sp)
                move.l  ConvertMem(a4),a3
                move    #"3 ",(a1)+
                tst     d0              ; when number of decimals is 0
                beq.w   BTA_exit        ; then only write a "3"
                move.b  #".",-1(a1)
                addq.l  #4,a0
                moveq   #0,d7
                subq.l  #1,d1
BTA_loop                                ; in this loop the area will be
                lea     0(a0,d1.l*4),a2 ; multiplied with 1000000000
                tst.l   -4(a2)
                bne.b   BTA_cont
                lea     -4(a2),a2
                subq.l  #1,d1
BTA_cont
                tst.b   _060Flag(a4)
                bne.b   BTA_060
                move.l  #1000000000,d3
                moveq   #0,d5
                moveq   #0,d6
BTA_loop2
                move.l  -(a2),d2
                mulu.l  d3,d4:d2
                add.l   d5,d2
                addx.l  d6,d4
                move.l  d4,d5
                move.l  d2,(a2)
                cmp.l   a0,a2
                bgt.w   BTA_loop2
                bra.b   BTA_Not060
BTA_060
                move.l  #50000,d3
                moveq   #0,d5
                moveq   #0,d6
                move.l  a2,d4
BTA_loop2a
                move    -(a2),d2
                mulu    d3,d2
                add     d5,d2
                move    d2,(a2)
                swap    d2
                addx    d6,d2
                move    d2,d5
                cmp.l   a0,a2
                bgt.w   BTA_loop2a
                move.l  d4,a2
                move    d5,d4
                move.l  #20000,d3
                moveq   #0,d5
BTA_loop2b
                move    -(a2),d2
                mulu    d3,d2
                add     d5,d2
                move    d2,(a2)
                swap    d2
                addx    d6,d2
                move    d2,d5
                cmp.l   a0,a2
                bgt.w   BTA_loop2b
                mulu    d3,d4
                add.l   d5,d4
                move.l  d4,d5
BTA_Not060
                divul.l #10000,d5:d4    ; turbo conversion
                divu    #10000,d4
                add.b   #"0",d4
                move.b  d4,(a1)+
                swap    d4
                move.l  0(a3,d4.w*4),(a1)+      ; read a ASCII-longword
                move.l  0(a3,d5.w*4),(a1)+      ; and a second
BTA_cont2
                add.l   #9,d7
                cmp.l   d0,d7
                blt     BTA_loop
BTA_exit
                movem.l (sp)+,d0/d1
                rts
;;/
;// Calculation
******************************************************************************
*       Calculation (d1)
*
*       Binary Calculation of PI
*       stores the final result in the result area
*
*       d1 [.L] = length of the areas in Longwords
******************************************************************************
Calculation
                tst.l   Count(a4)               ; don't calc anything when
                bne.w   Calc_start              ; count is 0
                moveq   #-1,d0
                rts
Calc_start
                movem.l d1-d4/a0,-(sp)
                move.l  d1,d0
                bsr     FirstCalc       ; 4*44/57+4*7/239+4*12/682+4*24/12943
                moveq   #1,d5                   ; term counter
                move.l  Num_ArcTan_57(a4),d3    ; num of terms for arctan(57)

                subq.l  #1,d3                   ; are we already finished?
                beq.w   Calc_exit               ; then leave

                moveq   #3,d4                   ; 2n-1
                moveq   #1,d6                   ; flag (1=subtraction,0=add.)
NextTerm
                lea     Area_Q_Actual(a4),a2
                move.l  Area_Q_Actual(a4),a0
                move.l  a0,a1
                move.l  Len_Q_Actual(a4),d0
                move.l  #57*57,d1
                bsr     Division16
                move.l  Area_Q_Actual(a4),a0
                move.l  Area_ArcTan(a4),a1
                move.l  Area_Quotient(a4),a2    ; copy Area_Quotient to
                bsr     CopyArea                ; Area_ArcTan
                clr.l   -4(a1)                  ; optimization trick
                cmp.l   Num_ArcTan_239(a4),d5   ; do we need more terms of
                bhi.b   NoSecond                ; arctan(239)? no -> jump
                move.l  Area_Q2_Actual(a4),a0
                lea     Area_Q2_Actual(a4),a2
                move.l  a0,a1
                move.l  Len_Q2_Actual(a4),d0
                move.l  #239*239,d1
                bsr     Division16
                move.l  Area_Q2_Actual(a4),a0
                move.l  Area_ArcTan(a4),a1
                move.l  Area_Quotient2(a4),a2
                bsr     Addition                ; add Area_Quotient2 to
NoSecond
                cmp.l   Num_ArcTan_682(a4),d5   ; more terms of arctan(682)?
                bhi.b   NoThird                 ; no -> jump
                lea     Area_Q3_Actual(a4),a2
                move.l  Area_Q3_Actual(a4),a0
                move.l  a0,a1
                move.l  Len_Q3_Actual(a4),d0
                tst.b   _060Flag(a4)
                bne.b   .060a
                move.l  #682*682,d1
                bsr     Division                ; calc Area_Quotient / 57^2
                bra.b   .not060a
.060a
                move.l  #682,d1
                bsr     Division16
                move.l  Area_Q3_Actual(a4),a0
                move.l  a0,a1
                move.l  Len_Q3_Actual(a4),d0
                bsr     Division16
.not060a
                move.l  Area_Q3_Actual(a4),a0
                move.l  Area_ArcTan(a4),a1
                move.l  Area_Quotient3(a4),a2
                bsr     Subtraction             ; sub Area_Quotient3 from
NoThird
                cmp.l   Num_ArcTan_12943(a4),d5 ; more terms of arctan(12943)?
                bhi.b   NoFourth                ; no -> jump
                lea     Area_Q4_Actual(a4),a2
                move.l  Area_Q4_Actual(a4),a0
                move.l  a0,a1
                move.l  Len_Q4_Actual(a4),d0
                tst.b   _060Flag(a4)
                bne.b   .060b
                move.l  #12943*12943,d1
                bsr     Division                ; calc Area_Quotient / 12943^2
                bra.b   .not060b
.060b
                move.l  #12943,d1
                bsr     Division16
                move.l  Area_Q4_Actual(a4),a0
                move.l  a0,a1
                move.l  Len_Q4_Actual(a4),d0
                bsr     Division16
.not060b
                move.l  Area_Q4_Actual(a4),a0
                move.l  Area_ArcTan(a4),a1
                move.l  Area_Quotient4(a4),a2
                bsr     Addition                ; add Area_Quotient4 to
NoFourth
                lea     Area_AT_Actual(a4),a2
                move.l  Area_AT_Actual(a4),a0
                move.l  a0,a1
                move.l  d4,d1
                move.l  Len_AT_Actual(a4),d0

                tst.b   _060Flag(a4)
                bne.b   .060c
                bsr     Division                ; Area_ArcTan / d4
                bra.b   .not060c
.060c
                cmp.l   #$ffff,d4
                bhi.b   .slow
                bsr     Division16
                bra.b   .not060c
.slow
                bsr     Division
.not060c
                move.l  Area_AT_Actual(a4),a0
                move.l  Area_Result(a4),a1
                move.l  Area_ArcTan(a4),a2
                tst     d6
                bne.b   Subtract
                bsr     Addition                ; add new term to result area
                bra.b   NoSubtract
Subtract
                bsr     Subtraction             ; sub new term from res. area
NoSubtract
                addq.l  #1,d5
                eor     #1,d6                   ; change add./sub.
                addq.l  #2,d4                   ; divisor + 2
                subq.l  #1,d3                   ; counter
                bne.w   NextTerm
Calc_exit
                moveq   #-1,d0
Calc_End
                movem.l (sp)+,d1-d4/a0
                rts
;;/
;// FirstCalc
******************************************************************************
*       FirstCalc (d0)
*
*       calculation of 4*44/57 + 4*7*239 + 4*12*682 + 4*24*12943
*
*       d0 [.L] = length of the areas in Longwords
******************************************************************************
FirstCalc
                movem.l d1/a0,-(sp)
                move.l  Area_Quotient(a4),a0
                move.l  #44*4,d1
                bsr     IntToArea               ; first term = 44*4
                move.l  Area_Quotient2(a4),a0
                move.l  #7*4,d1
                bsr     IntToArea               ; second term = 7*4
                move.l  Area_Quotient3(a4),a0
                move.l  #12*4,d1
                bsr     IntToArea               ; third term = 12*4
                move.l  Area_Quotient4(a4),a0
                move.l  #24*4,d1
                bsr     IntToArea               ; fourth term = 24*4
                move.l  Area_Quotient(a4),a0
                lea     Area_Q_Actual(a4),a2
                move.l  a0,a1
                move.l  #57,d1
                bsr     Division16
                move.l  Area_Quotient2(a4),a0
                lea     Area_Q2_Actual(a4),a2
                move.l  a0,a1
                move.l  #239,d1
                bsr     Division16
                move.l  Area_Quotient3(a4),a0
                lea     Area_Q3_Actual(a4),a2
                move.l  a0,a1
                move.l  #682,d1
                bsr     Division16
                move.l  Area_Quotient4(a4),a0
                lea     Area_Q4_Actual(a4),a2
                move.l  a0,a1
                move.l  #12943,d1
                bsr     Division16
                move.l  Area_Quotient(a4),a0
                move.l  Area_Result(a4),a1
                move.l  a0,a2
                bsr     CopyArea                ; copy (we only have addition
                move.l  Area_Quotient2(a4),a0   ; operation with two operands)
                move.l  Area_Result(a4),a1
                move.l  a0,a2
                bsr     Addition                ; calc 44*4/57 + 7*4/239
                move.l  Area_Quotient3(a4),a0
                move.l  Area_Result(a4),a1
                move.l  a0,a2
                bsr     Subtraction             ; calc previous - 12*4/682
                move.l  Area_Quotient4(a4),a0
                move.l  Area_Result(a4),a1
                move.l  a0,a2
                bsr     Addition                ; calc previous + 24*4/12943
                movem.l (sp)+,d1/a0
                rts
;;/
;// IntToArea
******************************************************************************
*       IntToArea (a0,d0,d1)
*
*       Converts the integer (d1) to an area of the length d0
*
*       a0 [.L] -> destination area
*       d0 [.L] = length of the area in Longwords
*       d1 [.W] = integer value to convert
*
******************************************************************************
IntToArea
                movem.l d0-d2/a0,-(sp)
                ext.l   d1
                move.l  a0,d2
ITA_clear
                clr.l   (a0)+           ; clear the whole area (=0)
                subq.l  #1,d0
                bne.b   ITA_clear
                move.l  d2,a0
                move.l  d1,(a0)         ; write integer
                movem.l (sp)+,d0-d2/a0
                rts
;;/
;// CopyArea
******************************************************************************
*       CopyArea (a0,a1,a2,d0)
*
*       Copies the source area to dest area
*
*       a0 [.L] -> source area
*       a1 [.L] -> destination area
*       a2 [.L] -> ptr to beginning of the source area
*       d0 [.L] = length of the area in Longwords
*
******************************************************************************
CopyArea
                movem.l d0-d2/a0-a2,-(sp)

                move.l  a0,d2
                sub.l   a2,d2
                add.l   d2,a1

                move.l  d0,d2
                and.l   #$f,d2
                lsr.l   #4,d0
                beq.b   CA_copy2
CA_copy
                rept    16
                move.l  (a0)+,(a1)+
                endr
                subq.l  #1,d0
                bne.b   CA_copy
                tst.l   d2
                beq.b   CA_nocopy2
CA_copy2
                move.l  (a0)+,(a1)+
                subq    #1,d2
                bne.b   CA_copy2
CA_nocopy2
                movem.l (sp)+,d0-d2/a0-a2
                rts
;;/
;// Addition
******************************************************************************
*       Addition (a0,a1,a2,d0)
*
*       Performs the addition a1-> + a0-> and stores the result in a1->
*
*       a0 [.L] -> source area
*       a1 [.L] -> destination area
*       a2 [.L] -> ptr to beginning of the source area
*       d0 [.L] = length of the area in Longwords
*
******************************************************************************
Addition
                movem.l d0-d4/a0/a1,-(sp)

                move.l  a0,d2
                sub.l   a2,d2
                add.l   d2,a1

                move.l  d0,d1
                lsl.l   #2,d0
                add.l   d0,a0
                add.l   d0,a1

                move.l  d1,d0
                swap    d0

                move    d1,d3
                lsr     #4,d1
                and     #$f,d3

                subq    #1,d3
                move    d3,d4

                subq    #1,d1
                and.b   #$ef,ccr
                move    d1,d2
Add_Loop
                bmi.b   Add_Next
Add_Loop1
                rept    16
                addx.l  -(a0),-(a1)
                endr
                dbra    d1,Add_Loop1
Add_Next
                tst     d3
                bmi.b   Add_Next2
Add_Next1
                addx.l  -(a0),-(a1)
                dbra    d3,Add_Next1
Add_Next2
                move    d4,d3
                move    d2,d1
                dbra    d0,Add_Loop

                move    ccr,d0          ; do we have an carry out?
                btst    #4,d0
                beq.b   Add_End         ; no -> jump
Add_last
                addx.l  -(a0),-(a1)     ; then another addition
                bcs.b   Add_last
Add_End

                movem.l (sp)+,d0-d4/a0/a1
                rts
;;/
;// Subtraction
******************************************************************************
*       Subtraction (a0,a1,a2,d0)
*
*       Performs the subtraction a1-> - a0-> and stores the result in a1->
*
*       a0 [.L] -> source area
*       a1 [.L] -> destination area
*       a2 [.L] -> ptr to beginning of the source area
*       d0 [.L] = length of the area in Longwords
*
******************************************************************************
Subtraction
                movem.l d0-d4/a0-a2,-(sp)

                move.l  a0,d2
                sub.l   a2,d2
                add.l   d2,a1

                move.l  d0,d1
                lsl.l   #2,d0
                add.l   d0,a0
                add.l   d0,a1

                move.l  d1,d0
                swap    d0

                move    d1,d3
                lsr     #4,d1
                and     #$f,d3

                subq    #1,d3
                move    d3,d4

                subq    #1,d1
                and.b   #$ef,ccr
                move    d1,d2
Sub_Loop
                bmi.b   Sub_Next
Sub_Loop1
                rept    16
                subx.l  -(a0),-(a1)
                endr
                dbra    d1,Sub_Loop1
Sub_Next
                tst     d3
                bmi.b   Sub_Next2
Sub_Next1
                subx.l  -(a0),-(a1)
                dbra    d3,Sub_Next1
Sub_Next2
                move    d4,d3
                move    d2,d1
                dbra    d0,Sub_Loop

                move    CCR,d0
                btst    #4,d0           ;carry-out ?
                beq.b   Sub_End
Sub_last
                subx.l  -(a0),-(a1)     ;another subtraction
                bcs.b   Sub_last
Sub_End

                movem.l (sp)+,d0-d4/a0-a2
                rts
;;/
;// Division
******************************************************************************
*       Division (a0,a1,a2,d0,d1)
*
*       Performs the division a0-> / d1 and stores the result in a1->
*       optimized for 68020-040
*
*       a0 [.L] -> source area
*       a1 [.L] -> destination area
*       a2 [.L] -> ptr to Area_x_Actual
*       d0 [.L] = length of the area in Longwords
*       d1 [.L] = divisor
*
******************************************************************************
Division
                tst.b   _060Flag(a4)
                bne.w   Division060
                movem.l d0-d6/a0-a2,-(sp)
                tst.l   (a0)
                bne.b   Division_cont
                tst.l   a2
                beq.b   Division_cont
                lea     4(a0),a0
                clr.l   (a1)+
                subq.l  #1,d0
                addq.l  #4,(a2)
                subq.l  #1,4(a2)
Division_cont
                moveq   #0,d3           ; first high 32 bits = 0
                move.l  d0,d4
                and.l   #$3,d4
                lsr.l   #2,d0
                beq.b   Division_next
Division_loop
                rept    4
                move.l  (a0)+,d2        ; get first longword
                divu.l  d1,d3:d2        ; divide
                move.l  d2,(a1)+        ; write result (d3 is automatically
                                        ; the new remainder)
                endr
                subq.l  #1,d0
                bne.b   Division_loop   ; repeat
Division_next
                subq    #1,d4
                bmi.b   Division_end
Division_loop2
                move.l  (a0)+,d2
                divu.l  d1,d3:d2        ; divide
                move.l  d2,(a1)+
                dbra    d4,Division_loop2
Division_end
                movem.l (sp)+,d0-d6/a0-a2
                rts
;;/
;// Division060
******************************************************************************
*       Division060 (a0,a1,a2,d0,d1)
*
*       Performs the division a0-> / d1 and stores the result in a1->
*       optimized for 68060
*
*       a0 [.L] -> source area
*       a1 [.L] -> destination area
*       a2 [.L] -> ptr to Area_x_Actual
*       d0 [.L] = length of the area in Longwords
*       d1 [.L] = divisor
*
******************************************************************************
Division060
                movem.l d0-d6/a0-a2,-(sp)
                tst.l   (a0)
                bne.b   Division0_cont
                tst.l   a2
                beq.b   Division0_cont
                lea     4(a0),a0
                clr.l   (a1)+
                subq.l  #1,d0
                addq.l  #4,(a2)
                subq.l  #1,4(a2)
Division0_cont
                moveq   #0,d3           ; first high 32 bits = 0
                move.l  d0,d4
                and.l   #$3,d4
                lsr.l   #2,d0
                beq.b   Division0_next
Division0_loop
                rept    4
                move.l  (a0)+,d2        ; get first longword
                bsr     Div64
                move.l  d2,(a1)+        ; write result
                endr
                subq.l  #1,d0
                bne.b   Division0_loop   ; repeat
Division0_next
                subq    #1,d4
                bmi.b   Division0_end
Division0_loop2
                move.l  (a0)+,d2
                bsr     Div64
                move.l  d2,(a1)+
                dbra    d4,Division0_loop2
Division0_end
                movem.l (sp)+,d0-d6/a0-a2
                rts
;;/
;// Division16
******************************************************************************
*       Division16 (a0,a1,a2,d0,d1)
*
*       Performs the division a0-> / d1 and stores the result in a1->
*       optimized for 68060
*       divisor must be 16 Bit!!
*
*       a0 [.L] -> source area
*       a1 [.L] -> destination area
*       a2 [.L] -> ptr to Area_x_Actual
*       d0 [.L] = length of the area in Longwords
*       d1 [.L] = divisor
*
******************************************************************************
Division16
                tst.b   _060Flag(a4)
                beq.w   Division
                movem.l d0-d4/a0-a2,-(sp)
                tst.l   (a0)
                bne.b   Division6_cont
                tst.l   a2
                beq.b   Division6_cont
                lea     4(a0),a0
                clr.l   (a1)+
                subq.l  #1,d0
                addq.l  #4,(a2)
                subq.l  #1,4(a2)
Division6_cont
                moveq   #0,d3           ; first high 16 bits = 0
                move.l  d0,d4
                and.l   #$3,d4
                lsr.l   #2,d0
                beq.b   Division6_next
Division6_loop
                rept    8
                move    (a0)+,d3
                divu    d1,d3
                move    d3,(a1)+
                endr
                subq.l  #1,d0
                bne.b   Division6_loop  ; repeat
Division6_next
                subq    #1,d4
                bmi.b   Division6_end
Division6_loop2
                rept    2
                move    (a0)+,d3
                divu    d1,d3
                move    d3,(a1)+
                endr
                dbra    d4,Division6_loop2
Division6_end
                movem.l (sp)+,d0-d4/a0-a2
                rts
;;/
;// Div64
******************************************************************************
*       d2,d3 = Div64 (d1,d2,d3)
*
*       Performs the 64 bit division on 68060 systems
*       this emulation is not 100% (no OV, no DIV0, unsigned ...)!
*       d5-d7 are trashed!
*
*       d3 [.L] = high word of dividend
*       d2 [.L] = low word of dividend
*       d1 [.L] = divisor
*
*       d2 [.L] = quotient
*       d3 [.L] = remainder
******************************************************************************
DivCore         macro
                add.l   d2,d2
                addx.l  d3,d3
                bcs.b   .do\@
                cmp.l   d3,d1
                bhi.b   .cont\@
.do\@
                sub.l   d1,d3
                neg.l   d6
.cont\@
                addx.l  d5,d5
                endm

Div64
                move.l  d1,-(sp)
                moveq   #0,d5
                moveq   #1,d6
                rept    32
                DivCore
                endr
                move.l  d5,d2
                move.l  (sp)+,d1
                rts
;;/

