******************************************************************************
*       CyberPI_Calc_P
*
*       PowerPC 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    BinToASCIIPPC
                xdef    CalculationPPC
;;/


                cpu     POWERPC
                smalldata
                smallcode

                section "code",code

;// BinToASCIIPPC
******************************************************************************
*       BinToASCIIPPC (_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
******************************************************************************
BinToASCIIPPC
                prolog  1024,r18
                pushgpr r3-r16
                pushgpr _d0/_d1/_a0/_a1
                popgpr  r4-r7
                liw     r11,1000000000
                liw     r16,10000
                lw      r8,ConvertMem   ;-> converter table
                li      r3,"3 "
                sth     r3,0(r7)        ;store digits before decimal point
                addi    r7,r7,2
                tstw    r4              ;when number of decimals is 0
                beq     BTA_exit        ;then only write a "3"
                li      r3,"."
                stb     r3,-1(r7)       ;store decimal point
                addi    r6,r6,4
                clrw    r9
                subi    r5,r5,1
BTA_loop                                ;in this loop the area will be
                slwi    r3,r5,2         ;multiplied with 1000000000
                add     r10,r6,r3       ;r10 -> end of area
                lwz     r3,-4(r10)      ;read first
                tstw    r3
                bne     BTA_cont        ;if not zero then jump
                subi    r10,r10,4       ;else decrease end ptr
                subi    r5,r5,1
BTA_cont
                clrw    r12
BTA_loop2
                lwzu    r14,-4(r10)     ;load one longword
                mulhwu  r15,r11,r14     ;64 bit multiply (r11 = 10 ^ 9)
                mullw   r14,r11,r14
                addc    r14,r14,r12
                addze   r12,r15
                stw     r14,0(r10)
                cmpw    r10,r6
                bgt     BTA_loop2
                divwu   r13,r12,r16     ;now calc offsets to converter table
                mullw   r3,r13,r16
                subf    r3,r3,r12
                divwu   r15,r13,r16
                mullw   r14,r15,r16
                subf    r14,r14,r13
                addi    r15,r15,"0"
                stb     r15,0(r7)
                slwi    r3,r3,2
                slwi    r14,r14,2
                lwzx    r13,r8,r14       ;read a ASCII longword

                stb     r13,4(r7)
                srwi    r13,r13,8
                stb     r13,3(r7)
                srwi    r13,r13,8
                stb     r13,2(r7)
                srwi    r13,r13,8
                stb     r13,1(r7)
;                stw     r13,1(r7)        ;and store
                lwzx    r13,r8,r3        ;once again

                stb     r13,8(r7)
                srwi    r13,r13,8
                stb     r13,7(r7)
                srwi    r13,r13,8
                stb     r13,6(r7)
                srwi    r13,r13,8
                stb     r13,5(r7)

;                stw     r13,5(r7)
                addi    r7,r7,9
BTA_cont2
                addi    r9,r9,9
                cmpw    r9,r4
                blt     BTA_loop
BTA_exit
                popgpr
                epilog
;;/
;// CalculationPPC
******************************************************************************
*       CalculationPPC (_d1)
*
*       Binary Calculation of PI
*       stores the final result in the result area
*
*       _d1 [.L] = length of the areas in Longwords
******************************************************************************
CalculationPPC
                prolog  1024,r18
                pushgpr r3-r17
                push    _d1
                pop     r4
                lw      r0,Count
                tstw    r0
                beq     Calc_End
                lw      r14,Num_ArcTan_57
                lw      r15,Num_ArcTan_239
                lw      r16,Num_ArcTan_682
                lw      r17,Num_ArcTan_12943
                mr      r3,r4
                bl      FirstCalc       ;4*44/57+4*7/239+4*12/682+4*24/12943
                li      r8,1                    ;term counter
                mr      r6,r14                  ;num of terms for arctan(57)
                subic.  r6,r6,1                 ;are we already finished?
                beq     Calc_End                ;then leave
                mtctr   r6
                li      r7,3                    ;2n-1
                li      r9,1                    ;flag (1=subtraction,0=add.)
NextTerm
                la      r13,Area_Q_Actual
                lw      r11,Area_Q_Actual
                mr      r12,r11
                lw      r3,Len_Q_Actual
                li      r4,57*57
                bl      Division16
                lw      r11,Area_Q_Actual
                lw      r12,Area_ArcTan
                lw      r13,Area_Quotient       ;copy Area_Quotient to
                bl      CopyArea                ;Area_ArcTan
                li      r0,0
                stw     r0,-4(r12)              ;optimization trick
                cmplw   r8,r15                  ;do we need more terms of
                bgt     NoSecond                ;arctan(239)? no -> jump
                la      r13,Area_Q2_Actual
                lw      r11,Area_Q2_Actual
                mr      r12,r11
                lw      r3,Len_Q2_Actual
                li      r4,239*239
                bl      Division16
                lw      r11,Area_Q2_Actual
                lw      r12,Area_ArcTan
                lw      r13,Area_Quotient2
                bl      Addition                ;add Area_Quotient2
NoSecond
                cmplw   r8,r16                  ;more terms of arctan(682)?
                bgt     NoThird                 ;no -> jump
                la      r13,Area_Q3_Actual
                lw      r11,Area_Q3_Actual
                mr      r12,r11
                lw      r3,Len_Q3_Actual
                li      r4,682
                bl      Division16
                lw      r11,Area_Q3_Actual
                mr      r12,r11
                lw      r3,Len_Q3_Actual
                bl      Division16
                lw      r11,Area_Q3_Actual
                lw      r12,Area_ArcTan
                lw      r13,Area_Quotient3
                bl      Subtraction             ;sub Area_Quotient3
NoThird
                cmplw   r8,r17                  ;more terms of arctan(12943)?
                bgt     NoFourth                ;no -> jump
                la      r13,Area_Q4_Actual
                lw      r11,Area_Q4_Actual
                mr      r12,r11
                lw      r3,Len_Q4_Actual
                li      r4,12943
                bl      Division16
                lw      r11,Area_Q4_Actual
                mr      r12,r11
                lw      r3,Len_Q4_Actual
                bl      Division16
                lw      r11,Area_Q4_Actual
                lw      r12,Area_ArcTan
                lw      r13,Area_Quotient4
                bl      Addition                ;add Area_Quotient4
NoFourth
                la      r13,Area_AT_Actual
                lw      r11,Area_AT_Actual
                mr      r12,r11
                lw      r3,Len_AT_Actual
                mr      r4,r7
                cmplwi  r7,$ffff
                bgt     .slow
                bl      Division16
                b       .fast
.slow
                bl      Division
.fast
                lw      r11,Area_AT_Actual
                lw      r12,Area_Result
                lw      r13,Area_ArcTan
                tstw    r9
                bne     Subtract
                bl      Addition                ;add new term to result area
                b       NoSubtract
Subtract
                bl      Subtraction             ;sub new term from result area
NoSubtract
                addi    r8,r8,1
                xori    r9,r9,1                 ;change add./sub.
                addi    r7,r7,2                 ;divisor + 2
                bdnz    NextTerm
Calc_End
                popgpr
                epilog
;;/
;// FirstCalc
******************************************************************************
*       FirstCalc (r3)
*
*       calculation of 4*44/57 + 4*7*239 + 4*12*682 + 4*24*12943
*
*       r3 [.L] = length of the areas in Longwords
******************************************************************************
FirstCalc
                pushlr
                lw      r11,Area_Quotient
                li      r4,44*4
                bl      IntToArea               ; first term = 44*4
                lw      r11,Area_Quotient2
                li      r4,7*4
                bl      IntToArea               ; second term = 7*4
                lw      r11,Area_Quotient3
                li      r4,12*4
                bl      IntToArea               ; second term = 12*4
                lw      r11,Area_Quotient4
                li      r4,24*4
                bl      IntToArea               ; second term = 24*4
                la      r13,Area_Q_Actual
                lw      r11,Area_Quotient
                mr      r12,r11
                li      r4,57
                bl      Division16
                la      r13,Area_Q2_Actual
                lw      r11,Area_Quotient2
                mr      r12,r11
                li      r4,239
                bl      Division16
                la      r13,Area_Q3_Actual
                lw      r11,Area_Quotient3
                mr      r12,r11
                li      r4,682
                bl      Division16
                la      r13,Area_Q4_Actual
                lw      r11,Area_Quotient4
                mr      r12,r11
                li      r4,12943
                bl      Division16
                lw      r11,Area_Quotient
                lw      r12,Area_Result
                mr      r13,r11
                bl      CopyArea                ;copy (we only have addition
                lw      r11,Area_Quotient2      ;operation with two operands)
                lw      r12,Area_Result
                mr      r13,r11
                bl      Addition                ;calc 44*4/57 + 7*4/239
                lw      r11,Area_Quotient3      ;operation with two operands)
                lw      r12,Area_Result
                mr      r13,r11
                bl      Subtraction             ;calc previous - 12*4/682
                lw      r11,Area_Quotient4
                lw      r12,Area_Result
                mr      r13,r11
                bl      Addition                ;calc previous + 24*4/12943
                poplr
                blr
;;/
;// IntToArea
******************************************************************************
*       IntToArea (r11,r3,r4)
*
*       Converts the integer (r4) to an area of the length r3
*
*       r11 [.L] -> destination area
*       r3  [.L] = length of the area in Longwords
*       r4  [.W] = integer value to convert
*
******************************************************************************
IntToArea
                pushctr
                pushgpr r3-r5/r11
                extsh   r4,r4
                slwi    r5,r3,2
                add     r11,r11,r5
                mtctr   r3
                li      r5,0
ITA_clear
                stwu    r5,-4(r11)      ;clear the whole area (=0)
                bdnz    ITA_clear
                stw     r4,0(r11)       ;write integer
                popgpr
                popctr
                blr
;;/
;// CopyArea
******************************************************************************
*       CopyArea (r11,r12,r13,r3)
*
*       Copies the source area to dest area
*
*       r11 [.L] -> source area
*       r12 [.L] -> destination area
*       r13 [.L] -> ptr to beginning of the source area
*       r3  [.L] = length of the area in Longwords
*
******************************************************************************
CopyArea
                pushctr
                pushgpr r3/r5/r6/r11/r12
                pushf   f0
                subf    r5,r13,r11
                add     r12,r5,r12
                slwi    r6,r3,2
                add     r11,r11,r6
                add     r12,r12,r6
                andi.   r5,r3,$1f
                srwi.   r3,r3,5
                beq     CA_copy1
                mtctr   r3
CA_copy
                rept    16
                lfdu    f0,-8(r11)
                stfdu   f0,-8(r12)
                endr
                bdnz    CA_copy
                tstw    r5
                beq     CA_nocopy2
CA_copy1
                mtctr   r5
CA_copy2
                lwzu    r0,-4(r11)
                stwu    r0,-4(r12)
                bdnz    CA_copy2
CA_nocopy2
                popf    f0
                popgpr
                popctr
                blr
;;/
;// Addition
******************************************************************************
*       Addition (r11,r12,r13,r3)
*
*       Performs the addition r12-> + r11-> and stores the result in r12->
*
*       r11 [.L] -> source area
*       r12 [.L] -> destination area
*       r13 [.L] -> ptr to beginning of the source area
*       r3  [.L] = length of the area in Longwords
*
******************************************************************************
Addition
                pushctr
                pushgpr r3-r7/r11/r12
                subf    r4,r13,r11
                add     r12,r12,r4
                slwi    r4,r3,2
                add     r11,r11,r4
                add     r12,r12,r4
                addic   r3,r3,0                 ;clear carry!
                srwi.   r4,r3,4
                beq     Add_Next
                mtctr   r4
Add_Loop1
                rept    16
                lwzu    r7,-4(r11)
                lwzu    r5,-4(r12)
                adde    r7,r7,r5
                stw     r7,0(r12)
                endr
                bdnz    Add_Loop1
Add_Next
                andi.   r6,r3,$f
                beq     Add_Last
                mtctr   r6
Add_Loop2
                lwzu    r7,-4(r11)
                lwzu    r5,-4(r12)
                adde    r7,r7,r5
                stw     r7,0(r12)
                bdnz    Add_Loop2
Add_Last
                li      r0,-1
                addze.  r0,r0
                bne     Add_End
                lwzu    r7,-4(r11)
                lwzu    r5,-4(r12)
                adde    r7,r7,r5
                stw     r7,0(r12)
                b       Add_Last
Add_End
                popgpr
                popctr
                blr
;;/
;// Subtraction
******************************************************************************
*       Subtraction (r11,r12,r13,r3)
*
*       Performs the subtraction r12-> - r11-> and stores the result in r12->
*
*       r11 [.L] -> source area
*       r12 [.L] -> destination area
*       r13 [.L] -> ptr to beginning of the source area
*       r3  [.L] = length of the area in Longwords
*
******************************************************************************
Subtraction
                pushctr
                pushgpr r3-r7/r11/r12
                subf    r4,r13,r11
                add     r12,r12,r4
                slwi    r4,r3,2
                add     r11,r11,r4
                add     r12,r12,r4
                subfc   r7,r7,r7                ;set carry to 1!!
                srwi.   r4,r3,4
                beq     Sub_Next
                mtctr   r4
Sub_Loop1
                rept    16
                lwzu    r7,-4(r11)
                lwzu    r5,-4(r12)
                subfe   r7,r7,r5
                stw     r7,0(r12)
                endr
                bdnz    Sub_Loop1
Sub_Next
                andi.   r6,r3,$f
                beq     Sub_Last
                mtctr   r6
Sub_Loop2
                lwzu    r7,-4(r11)
                lwzu    r5,-4(r12)
                subfe   r7,r7,r5
                stw     r7,0(r12)
                bdnz    Sub_Loop2
Sub_Last
                li      r0,-1
                addze.  r0,r0
                beq     Sub_End
                lwzu    r7,-4(r11)
                lwzu    r5,-4(r12)
                subfe   r7,r7,r5
                stw     r7,0(r12)
                b       Sub_Last
Sub_End
                popgpr
                popctr
                blr
;;/
;// Division
******************************************************************************
*       Division (r11,r12,r13,r3,r4)
*
*       Performs the division r11-> / r12 and stores the result in r12->
*
*       r11 [.L] -> source area
*       r12 [.L] -> destination area
*       r13 [.L] -> ptr to Area_x_Actual
*       r3  [.L] = length of the area in Longwords
*       r4  [.L] = divisor
*
******************************************************************************
Division
                pushlr
                pushctr
                pushgpr r3-r9/r11-r13
                lwz     r5,0(r11)
                tstw    r5
                bne     Division_cont
                tstw    r13
                beq     Division_cont
                addi    r11,r11,4
                li      r5,0
                stw     r5,0(r12)
                addi    r12,r12,4
                subic   r3,r3,1
                lwz     r5,0(r13)
                addi    r5,r5,4
                stw     r5,0(r13)
                lwz     r5,4(r13)
                subi    r5,r5,4
                stw     r5,4(r13)
Division_cont
                subi    r11,r11,4       ;prepare for lhzu
                subi    r12,r12,4       ;prepare for sthu
                li      r6,0            ;first high 32 bits = 0
                srwi.   r7,r3,2
                beq     Division_next
                mtctr   r7
Division_loop
                rept    4
                lwzu    r5,4(r11)       ;get first longword
                bl      Div64
                stwu    r5,4(r12)       ;write result
                endr
                bdnz    Division_loop
Division_next
                andi.   r3,r3,$3
                beq     Division_end
                mtctr   r3
Division_loop2
                lwzu    r5,4(r11)
                bl      Div64
                stwu     r5,4(r12)
                bdnz    Division_loop2
Division_end
                popgpr
                popctr
                poplr
                blr
;;/
;// Division16
******************************************************************************
*       Division16 (r11,r12,r13,r3,r4)
*
*       Performs the division r11-> / r12 and stores the result in r12->
*       divisor must be 16 Bit!!
*
*       r11 [.L] -> source area
*       r12 [.L] -> destination area
*       r13 [.L] -> ptr to Area_x_Actual
*       r3  [.L] = length of the area in Longwords
*       r4  [.L] = divisor
*
******************************************************************************
Division16
                pushctr
                pushgpr r3-r7/r11-r13
                andi.   r4,r4,$ffff
                lwz     r5,0(r11)
                tstw    r5
                bne     Division6_cont
                tstw    r13
                beq     Division6_cont
                addi    r11,r11,4
                li      r5,0
                stw     r5,0(r12)
                addi    r12,r12,4
                subic   r3,r3,1
                lwz     r5,0(r13)
                addi    r5,r5,4
                stw     r5,0(r13)
                lwz     r5,4(r13)
                subi    r5,r5,1
                stw     r5,4(r13)
Division6_cont
                subi    r11,r11,2               ;prepare for lhzu
                subi    r12,r12,2               ;prepare for sthu
                li      r6,0
                srwi.   r7,r3,2
                beq     Division6_next
                mtctr   r7
Division6_loop
                rept    8
                lhzu    r5,2(r11)
                mh      r6,r5
                divwu   r5,r6,r4
                sthu    r5,2(r12)
                mullw   r5,r5,r4
                subf    r6,r5,r6
                slwi    r6,r6,16
                endr
                bdnz    Division6_loop
Division6_next
                andi.   r3,r3,$3
                beq     Division6_end
                mtctr   r3
Division6_loop2
                rept    2
                lhzu    r5,2(r11)
                mh      r6,r5
                divwu   r5,r6,r4
                sthu    r5,2(r12)
                mullw   r5,r5,r4
                subf    r6,r5,r6
                slwi    r6,r6,16
                endr
                bdnz    Division6_loop2
Division6_end
                popgpr
                popctr
                blr
;;/
;// Div64
******************************************************************************
*       r5,r6 = Div64 (r4,r5,r6)
*
*       Performs the 64 bit division on PPC systems
*       this emulation is not 100% (no OV, no DIV0, unsigned ...)!
*       r8/r10 are trashed!
*
*       r6 [.L] = high word of dividend
*       r5 [.L] = low word of dividend
*       r4 [.L] = divisor
*
*       r5 [.L] = quotient
*       r6 [.L] = remainder
******************************************************************************
DivCore         macro
                bge     .cont\@
                addc    r5,r5,r5
                adde    r6,r6,r6
                add     r8,r8,r8
                b       .cont1\@
.cont\@
                addc    r5,r5,r5
                adde    r6,r6,r6
                add     r8,r8,r8
                cmplw   r4,r6
                bgt     .cont2\@
.cont1\@
                subf.   r6,r4,r6
                addi    r8,r8,1
.cont2\@
                endm

Div64
                push    r4
                li      r8,0
                tstw    r6
                rept    32
                DivCore
                endr
                mr      r5,r8
                pop     r4
                blr
;;/

