         ttl       fast floating point divide (ffpdiv)
*****************************************
*  (c) copyright 1980 by motorola inc.  *
*****************************************
 
********************************************
*           ffpdiv subroutine              *
*                                          *
* input:                                   *
*        d6 - floating point divisor       *
*        d7 - floating point dividend      *
*                                          *
* output:                                  *
*        d7 - floating point quotient      *
*                                          *
* condition codes:                         *
*        n - set if result negative        *
*        z - set if result zero            *
*        v - set if result overflowed      *
*        c - undefined                     *
*        x - undefined                     *
*                                          *
* registers d3 thru d5 volatile            *
*                                          *
* code: 150 bytes     stack work: 0 bytes  *
*                                          *
* notes:                                   *
*   1) divisor is unaltered (d6).          *
*   2) underflows return zero without      *
*      any indicators set.                 *
*   3) overflows return the highest value  *
*      with the proper sign and the 'v'    *
*      bit set in the ccr.                 *
*   4) if a divide by zero is attempted    *
*      the divide by zero exception trap   *
*      is forced by this code with the     *
*      original arguments intact.  if the  *
*      exception returns with the denom-   *
*      inator altered the divide operation *
*      continues, otherwise an overflow    *
*      is forced with the proper sign.     *
*      the floating divide by zero can be  *
*      distinguished from true zero divide *
*      by the fact that it is an immediate *
*      zero dividing into register d7.     *
*                                          *
* time: (8 mhz no wait states assumed)     *
* dividend zero         5.250 microseconds *
* minimum time others  72.750 microseconds *
* maximum time others  85.000 microseconds *
* average others       76.687 microseconds *
*                                          *
********************************************
         page
ffpdiv   idnt      1,1  ffp divide
 
         xdef      ffpdiv     entry point
         xref      ffpcpyrt   copyright notice
 
         section    9
 
* divide by zero exit
fpddzr divu.w #0,d7     **force divide by zero **
 
* if the exception returns with altered denominator - continue divide
         tst.l     d6        ? exception alter the zero
         bne.s     ffpdiv    branch if so to continue
* setup maximum number for divide overflow
fpdovf or.l   #$ffffff7f,d7 maximize with proper sign
       tst.b  d7        set condition code for sign
*      or.w   #$02,ccr  set overflow bit
       dc.l   $003c0002 ******sick assembler******
fpdrtn rts              return to caller
 
* over or underflow detected
fpdov2   swap.w    d6        restore arg1
         swap.w    d7        restore arg2 for sign
fpdovfs eor.b  d6,d7     setup correct sign
       bra.s  fpdovf    and enter overflow handling
fpdouf bmi.s  fpdovfs   branch if overflow
fpdund move.l #0,d7     underflow to zero
       rts              and return to caller
 
***************
* entry point *
***************
 
* first subtract exponents
ffpdiv move.b d6,d5     copy arg1 (divisor)
       beq.s  fpddzr    branch if divide by zero
       move.l d7,d4     copy arg2 (dividend)
       beq.s  fpdrtn    return zero if dividend zero
       moveq  #-128,d3  setup sign mask
       add.w  d5,d5     isolate arg1 sign from exponent
       add.w  d4,d4     isolate arg2 sign from exponent
       eor.b  d3,d5     adjust arg1 exponent to binary
       eor.b  d3,d4     adjust arg2 exponent to binary
       sub.b  d5,d4     subtract exponents
       bvs.s  fpdouf    branch if overflow/underflow
       clr.b  d7        clear arg2 s+exp
       swap.w d7        prepare high 16 bit compare
       swap.w d6        against arg1 and arg2
       cmp.w  d6,d7     ? check if overflow will occur
       bmi.s  fpdnov    branch if not
* adjust for fixed point divide overflow
       add.b  #2,d4     adjust exponent up one
       bvs.s  fpdov2    branch overflow here
       ror.l  #1,d7     shift down by power of two
fpdnov swap.w d7        correct arg2
       move.b d3,d5     move $80 into d5.b
       eor.w  d5,d4     create sign and absolutize exponent
       lsr.w  #1,d4     d4.b now has sign+exponent of result
 
* now divide just using 16 bits into 24
       move.l d7,d3     copy arg1 for initial divide
       divu.w d6,d3     obtain test quotient
       move.w d3,d5     save test quotient
 
* now multiply 16-bit divide result times full 24 bit divisor and compare
* with the dividend.  multiplying back out with the full 24-bits allows
* us to see if the result was too large due to the 8 missing divisor bits
* used in the hardware divide.  the result can only be too large by 1 unit.
       mulu.w d6,d3     high divisor x quotient
       sub.l  d3,d7     d7=partial subtraction
       swap.w d7        to low divisor
       swap.w d6        rebuild arg1 to normal
       move.w d6,d3     setup arg1 for product
       clr.b  d3        zero low byte
       mulu.w d5,d3     find remaining product
       sub.l  d3,d7     now have full subtraction
       bcc.s  fpdqok    branch first 16 bits correct
 
* estimate too high, decrement quotient by one
       move.l d6,d3     rebuild divisor
       clr.b  d3        reverse halves
       add.l  d3,d7     add another divisor
       sub.w  #1,d5     decrement quotient
 
* compute last 8 bits with another divide.  the exact remainder from the
* multiply and compare above is divided again by a 16-bit only divisor.
* however, this time we require only 9 bits of accuracy in the result
* (8 to make 24 bits total and 1 extra bit for rounding purposes) and this
* divide always returns a precision of at least 9 bits.
fpdqok move.l d6,d3     copy arg1 again
       swap.w d3        first 16 bits divisor in d3.w
       clr.w  d7        into first 16 bits of dividend
       divu.w d3,d7     obtain final 16 bit result
       swap.w d5        first 16 quotient to high half
       bmi.s  fpdisn    branch if normalized
* rare occurrance - unnormalized
* happends when mantissa arg1 < arg2 and they differ only in last 8 bits
       move.w d7,d5     insert low word of quotient
       add.l  d5,d5     shift mantissa left one
       sub.b  #1,d4     adjust exponent down (cannot zero)
       move.w d5,d7     cancel next instruction
 
* rebuild our final result and return
fpdisn move.w d7,d5     append next 16 bits
       add.l  #$80,d5   round to 24 bits (cannot overflow)
       move.l d5,d7     return in d7
       move.b d4,d7     finish result with sign+exponent
       beq.s  fpdund    underflow if zero exponent
       rts              return result to caller
 
 
       end
