       ttl     fast floating point add/subtract (ffpadd/ffpsub)
***************************************
* (c) copyright 1980 by motorola inc. *
***************************************
 
*************************************************************
*                  ffpadd/ffpsub                            *
*             fast floating point add/subtract              *
*                                                           *
*  ffpadd/ffpsub - fast floating point add and subtract     *
*                                                           *
*  input:                                                   *
*      ffpadd                                               *
*          d6 - floating point addend                       *
*          d7 - floating point adder                        *
*      ffpsub                                               *
*          d6 - floating point subtrahend                   *
*          d7 - floating point minuend                      *
*                                                           *
*  output:                                                  *
*          d7 - floating point add result                   *
*                                                           *
*  condition codes:                                         *
*          n - result is negative                           *
*          z - result is zero                               *
*          v - overflow has occured                         *
*          c - undefined                                    *
*          x - undefined                                    *
*                                                           *
*           registers d3 thru d5 are volatile               *
*                                                           *
*  code size: 228 bytes       stack work area:  0 bytes     *
*                                                           *
*  notes:                                                   *
*    1) addend/subtrahend unaltered (d6).                   *
*    2) underflow returns zero and is unflagged.            *
*    3) overflow returns the highest value with the         *
*       correct sign and the 'v' bit set in the ccr.        *
*                                                           *
*  time: (8 mhz no wait states assumed)                     *
*                                                           *
*           composite average  20.625 microseconds          *
*                                                           *
*  add:         arg1=0              7.75 microseconds       *
*               arg2=0              5.25 microseconds       *
*                                                           *
*          like signs  14.50 - 26.00  microseconds          *
*                    average   18.00  microseconds          *
*         unlike signs 20.13 - 54.38  microceconds          *
*                    average   22.00  microseconds          *
*                                                           *
*  subtract:    arg1=0              4.25 microseconds       *
*               arg2=0              9.88 microseconds       *
*                                                           *
*          like signs  15.75 - 27.25  microseconds          *
*                    average   19.25  microseconds          *
*         unlike signs 21.38 - 55.63  microseconds          *
*                    average   23.25  microseconds          *
*                                                           *
*************************************************************
         page
ffpadd idnt    1,1  ffp add/subtract
 
       xdef    ffpadd,ffpsub   entry points
       xref    ffpcpyrt        copyright notice
 
         section  9
 
************************
* subtract entry point *
************************
ffpsub   move.b  d6,d4    test arg1
         beq.s   fpart2   return arg2 if arg1 zero
         eor.b   #$80,d4  invert copied sign of arg1
         bmi.s   fpami1   branch arg1 minus
* + arg1
         move.b  d7,d5    copy and test arg2
         bmi.s   fpams    branch arg2 minus
         bne.s   fpals    branch positive not zero
         bra.s   fpart1   return arg1 since arg2 is zero
 
*******************
* add entry point *
*******************
ffpadd   move.b  d6,d4    test argument1
         bmi.s   fpami1   branch if arg1 minus
         beq.s   fpart2   return arg2 if zero
 
* + arg1
         move.b  d7,d5    test argument2
         bmi.s   fpams    branch if mixed signs
         beq.s   fpart1   zero so return argument1
 
* +arg1 +arg2
* -arg1 -arg2
fpals    sub.b   d4,d5    test exponent magnitudes
         bmi.s   fpa2lt   branch arg1 greater
         move.b  d7,d4    setup stronger s+exp in d4
 
* arg1exp <= arg2exp
         cmp.b   #24,d5   overbearing size
         bcc.s   fpart2   branch yes, return arg2
         move.l  d6,d3    copy arg1
         clr.b   d3       clean off sign+exponent
         lsr.l   d5,d3    shift to same magnitude
         move.b  #$80,d7  force carry if lsb-1 on
         add.l   d3,d7    add arguments
         bcs.s   fpa2gc   branch if carry produced
fparsr   move.b  d4,d7    restore sign/exponent
         rts              return to caller
 
* add same sign overflow normalization
fpa2gc   roxr.l  #1,d7    shift carry back into result
         add.b   #1,d4    add one to exponent
         bvs.s   fpa2os   branch overflow
         bcc.s   fparsr   branch if no exponent overflow
fpa2os   moveq   #-1,d7   create all ones
         sub.b   #1,d4    back to highest exponent+sign
         move.b  d4,d7    replace in result
*        or.b    #$02,ccr show overflow occurred
         dc.l    $003c0002 ****assembler error****
         rts              return to caller
 
* return argument1
fpart1   move.l  d6,d7    move in as result
         move.b  d4,d7    move in prepared sign+exponent
         rts              return to caller
 
* return argument2
fpart2   tst.b   d7       test for returned value
         rts              return to caller
 
* -arg1exp > -arg2exp
* +arg1exp > +arg2exp
fpa2lt   cmp.b   #-24,d5  ? arguments within range
         ble.s   fpart1   nope, return larger
         neg.b   d5       change difference to positive
         move.l  d6,d3    setup larger value
         clr.b   d7       clean off sign+exponent
         lsr.l   d5,d7    shift to same magnitude
         move.b  #$80,d3  force carry if lsb-1 on
         add.l   d3,d7    add arguments
         bcs.s   fpa2gc   branch if carry produced
         move.b  d4,d7    restore sign/exponent
         rts              return to caller
 
* -arg1
fpami1   move.b  d7,d5    test arg2's sign
         bmi.s   fpals    branch for like signs
         beq.s   fpart1   if zero return argument1
 
* -arg1 +arg2
* +arg1 -arg2
fpams    moveq   #-128,d3  create a carry mask ($80)
         eor.b   d3,d5    strip sign off arg2 s+exp copy
         sub.b   d4,d5    compare magnitudes
         beq.s   fpaeq    branch equal magnitudes
         bmi.s   fpatlt   branch if arg1 larger
* arg1 <= arg2
         cmp.b   #24,d5   compare magnitude difference
         bcc.s   fpart2   branch arg2 much bigger
         move.b  d7,d4    arg2 s+exp dominates
         move.b  d3,d7    setup carry on arg2
         move.l  d6,d3    copy arg1
fpamss   clr.b   d3       clear extraneous bits
         lsr.l   d5,d3    adjust for magnitude
         sub.l   d3,d7    subtract smaller from larger
         bmi.s   fparsr   return final result if no overflow

* mixed signs normalize
fpanor   move.b  d4,d5    save correct sign
fpanrm   clr.b   d7       clear subtract residue
         sub.b   #1,d4    make up for first shift
         cmp.l   #$00007fff,d7   ? small enough for swap
         bhi.s   fpaxqn   branch nope
         swap.w  d7       shift left 16 bits real fast
         sub.b   #16,d4   make up for 16 bit shift
fpaxqn   add.l   d7,d7    shift up one bit
         dbmi    d4,fpaxqn decrement and branch if positive
         eor.b   d4,d5    ? same sign
         bmi.s   fpazro   branch underflow to zero
         move.b  d4,d7    restore sign/exponent
         beq.s   fpazro   return zero if exponent underflowed
         rts              return to caller

* exponent underflowed - return zero
fpazro   moveq.l #0,d7    create a true zero
         rts              return to caller

* arg1 > arg2
fpatlt   cmp.b   #-24,d5  ? arg1 >> arg2
         ble.s   fpart1   return it if so
         neg.b   d5       absolutize difference
         move.l  d7,d3    move arg2 as lower value
         move.l  d6,d7    set up arg1 as high
         move.b  #$80,d7  setup rounding bit
         bra.s   fpamss   perform the addition

* equal magnitudes
fpaeq    move.b   d7,d5    save arg1 sign
         exg.l   d5,d4    swap arg2 with arg1 s+exp
         move.b  d6,d7    insure same low byte
         sub.l   d6,d7    obtain difference
         beq.s   fpazro   return zero if identical
         bpl.s   fpanor   branch if arg2 bigger
         neg.l   d7       correct difference to positive
         move.b  d5,d4    use arg2's sign + exponent
         bra.s   fpanrm   and go normalize

         end


