         ttl       fast floating point log (ffplog)
***************************************
* (c) copyright 1981 by motorola inc. *
***************************************
 
*************************************************
*                  ffplog                       *
*       fast floating point logorithm           *
*                                               *
*  input:   d7 - input argument                 *
*                                               *
*  output:  d7 - logorithmic result to base e   *
*                                               *
*     all other registers totally transparent   *
*                                               *
*  code size: 184 bytes   stack work: 38 bytes  *
*                                               *
*  condition codes:                             *
*        z - set if the result is zero          *
*        n - set if result in is negative       *
*        v - set if invalid negative argument   *
*            or zero argument                   *
*        c - undefined                          *
*        x - undefined                          *
*                                               *
*                                               *
*  notes:                                       *
*    1) spot checks show errors bounded by      *
*       5 x 10**-8.                             *
*    2) negative arguments are illegal and cause*
*       the "v" bit to be set and the absolute  *
*       value used instead.                     *
*    3) a zero argument returns the largest     *
*       negative value possible with the "v" bit*
*       set.                                    *
*                                               *
*  time: (8mhz no wait states assumed)          *
*                                               *
*        times are very data sensitive with     *
*        samples ranging from 170 to 556        *
*        microseconds                           *
*                                               *
*************************************************
         page
ffplog   idnt  1,2 ffp log
 
         opt       pcs
         section   9
 
         xdef      ffplog                        entry point
 
         xref      ffphthet                    hypertangent table
         xref      ffpadd,ffpdiv,ffpsub,ffpmul2 arithmetic primitives
         xref      ffptnorm          transcendental normalize routine
         xref      ffpcpyrt            copyright stub
 
fpone    equ       $80000041           floating value for one
log2     equ       $b1721840           log(2) = .6931471805
 
**************
* log entry  *
**************
 
* insure argument positive
ffplog   tst.b     d7                  ? test sign
         beq.s     fplzro              branch argument zero
         bpl.s     fplok               branch alright
 
* argument is negative - use the absolute value and set the "v" bit
         and.b     #$7f,d7             take absolute value
         bsr.s     fplok               find log(abs(x))
*psetv   or.b      #$02,ccr            set overflow bit
fpsetv   dc.l      $003c0002           ***assembler error***
         rts                           return to caller
 
* argument is zero - return largest negative number with "v" bit
fplzro   move.l    #-1,d7              return largest negative
         bra       fpsetv              return with "v" bit set
 
* save work registers and strip exponent off
fplok    movem.l   d1-d6/a0,-(sp)      save all work registers
         move.b    d7,-(sp)            save original exponent
         move.b    #64+1,d7            force between 1 and 2
         move.l    #fpone,d6           load up a one
         move.l    d7,d2               copy argument
         bsr       ffpadd              create arg+1
         exg.l     d7,d2               swap result with argument
         bsr       ffpsub              create arg-1
         move.l    d2,d6               prepare for divide
         bsr       ffpdiv              result is (arg-1)/(arg+1)
         beq.s     fplnocr             zero so cordic not needed
* convert to bin(31,29) precision
         sub.b     #64+3,d7            adjust exponent
         neg.b     d7                  for shift necessary
         cmp.b     #31,d7              ? insure not too small
         bls.s     fplshf              no, go shift
         move.l    #0,d7               force to zero
fplshf   lsr.l     d7,d7               shift to bin(31,29) precision
 
*****************************************
* cordic calculation registers:         *
* d1 - loop count   a0 - table pointer  *
* d2 - shift count                      *
* d3 - y'   d5 - y                      *
* d4 - x'   d6 - z                      *
* d7 - x                                *
*****************************************
 
         move.l    #0,d6               z=0
         move.l    #1<<29,d5           y=1
         lea       ffphthet,a0         to inverse hyperbolic tangent table
         move.l    #22,d1              loop 23 times
         move.l    #1,d2               prime shift counter
         bra.s     cordic              enter cordic loop
 
* cordic loop
fplpls   asr.l     d2,d4               shift(x')
         sub.l     d4,d5               y = y - x'
         add.l     (a0),d6             z = z + hypertan(i)
cordic   move.l    d7,d4               x' = x
         move.l    d5,d3               y' = y
         asr.l     d2,d3               shift(y')
fplnlp   sub.l     d3,d7               x = x - y'
         bpl.s     fplpls              branch negative
         move.l    d4,d7               restore x
         add.l     #4,a0               to next table entry
         add.b     #1,d2               increment shift count
         lsr.l     #1,d3               shift(y')
         dbra      d1,fplnlp           and loop until done
 
* now convert to float and add exponent*log(2) for final result
         move.l    #0,d7               default zero if too small
         bsr       ffptnorm            float z
         beq.s     fplnocr             branch if too small
         add.b     #1,d6               times two
         move.l    d6,d7               setup in d7 in case exp=0
fplnocr  move.l    d7,d2               save result
         move.l    #0,d6               prepare original exponent load
         move.b    (sp)+,d6            load it back
         sub.b     #64+1,d6            convert exponent to binary
         beq.s     fplzpr              branch zero partial here
         move.b    d6,d1               save sign byte
         bpl.s     fplpos              branch positive value
         neg.b     d6                  force positive
fplpos   ror.l     #8,d6               prepare to convert to integer
         move.l    #$47,d5             setup exponent mask
fplnorm  add.l     d6,d6               shift to left
         dbmi      d5,fplnorm          exp-1 and branch if not normalized
         move.b    d5,d6               fix in exponent
         and.b     #$80,d1             extract sign
         or.b      d1,d6               insert sign in
         move.l    #log2,d7            multiply exponent by log(2)
         bsr       ffpmul2             multiply d6 and d7
         move.l    d2,d6               now add cordic result
         bsr       ffpadd              for final answer
 
fplzpr   movem.l   (sp)+,d1-d6/a0      restore registers
         rts                           return to caller
 
 
         end
