home *** CD-ROM | disk | FTP | other *** search
- ! C68 8 byte floating point add/subtract routines
- !-----------------------------------------------------------------------------
- ! ported to 68000 by Kai-Uwe Bloem, 12/89
- ! #1 original author: Peter S. Housel 9/21/88,01/17/89,03/19/89,5/24/89
- ! #2 replaced shifts by swap if possible for speed increase -kub-, 01/90
- ! #3 Redid register usage, and then added wrapper routine
- ! to provide C68 IEEE compatibility Dave & Keith Walker 02/92
- ! #4 Changed exit code to put pointer to result in D0 Dave Walker 12/92
- ! #5 Changed entry point names for use with C68 v4.3
- ! Changed exit code to C68 v4.3 compatibility
- ! Removed ACK entry points. -djw- 09/93
- !-----------------------------------------------------------------------------
-
- .define .Xdfadd
- .define .Xdfsub
- .define .Xasdfadd
- .define .Xasdfsub
-
- SAVEREG = 6*4 ! Size of saved registers on stack
-
- .sect .text
- !----------------------------------------
- ! sp Return address
- ! sp+4 address of result
- ! sp+8 address of v
- ! sp+12 address of u
- !----------------------------------------
-
- .Xdfadd:
- moveq.l #0,d0 ! set for add
- bra 1f
- .Xdfsub:
- move.l #0x80000000,d0 ! set for subtract
-
- 1: movem.l d2-d7,-(sp) ! save registers
- move.l SAVEREG+12(sp),a1 ! address of v
- movem.l (a1),d4-d5 ! ... load v
- move.l SAVEREG+8(sp),a1 ! address of u
- movem.l (a1),d6-d7 ! ... load u
- move.l SAVEREG+4(sp),a1 ! result address
- bsr dfaddsub ! go to do operation
- movem.l (sp)+,d2-d7 ! restore saved registers
-
- move.l (sp)+,a1 ! get return address
- lea 12(sp),sp ! remove 3 parameters from stack
- jmp (a1) ! ... and return
-
-
- !----------------------------------------
- ! sp Return address
- ! sp+4 address of result/v
- ! sp+8 address of u
- !----------------------------------------
-
- .Xasdfadd:
- moveq.l #0,d0 ! set for add
- bra 1f
-
- .Xasdfsub:
- move.l #0x80000000,d0 ! set for subtract
-
- 1: movem.l d2-d7,-(sp) ! save registers
- move.l SAVEREG+8(sp),a1 ! address of u
- movem.l (a1),d4-d5 ! ... load u
- move.l SAVEREG+4(sp),a1 ! address of v / result address
- movem.l (a1),d6-d7 ! ... load v
- bsr dfaddsub ! go to do operation
- movem.l (sp)+,d2-d7 ! restore saved registers
-
- move.l (sp)+,a1 ! get return address
- move.l (sp),d0 ! address of v returned as result
- addq.l #8,sp ! remove 2 parameters from stack
- jmp (a1) ! ... and return
-
-
- !-------------------------------------------------------------------------
- ! This is the routine that actually carries out the operation.
- !
- ! Register usage:
- !
- ! Entry Exit
- !
- ! d0 add/subtract mask undefined
- ! d1 ? undefined
- ! d2 ? undefined
- ! d3 ? undefined
- ! d4-d5 v undefined
- ! d6-d7 u undefined
- !
- ! A1 Address for result preserved
- !
- !-----------------------------------------------------------------------------
-
- dfaddsub:
- eor.l d0,d4 ! reverse sign of v if needed (frees d0 for use)
- move.l d6,d0 ! d0 = u.exp
- swap d0
- move.l d6,d2 ! d2.h = u.sign
- move.w d0,d2
- lsr.w #4,d0
- and.w #0x07ff,d0 ! kill sign bit
-
- move.l d4,d1 ! d1 = v.exp
- swap d1
- eor.w d1,d2 ! d2.l = u.sign ^ v.sign
- lsr.w #4,d1
- and.w #0x07ff,d1 ! kill sign bit
-
- and.l #0x0fffff,d6 ! remove exponent from u.mantissa
- tst.w d0 ! check for zero exponent - no leading "1"
- beq 0f
- or.l #0x100000,d6 ! restore implied leading "1"
- bra 1f
- 0: add.w #1,d0 ! "normalize" exponent
- 1:
- and.l #0x0fffff,d4 ! remove exponent from v.mantissa
- tst.w d1 ! check for zero exponent - no leading "1"
- beq 0f
- or.l #0x100000,d4 ! restore implied leading "1"
- bra 1f
- 0: add.w #1,d1 ! "normalize" exponent
- 1:
- clr.w d3 ! (put initial zero rounding bits in d3)
- neg.w d1 ! d1 = u.exp - v.exp
- add.w d0,d1
- beq 5f ! exponents are equal - no shifting neccessary
- bgt 1f ! not equal but no exchange neccessary
- exg d4,d6 ! exchange u and v
- exg d5,d7
- sub.w d1,d0 ! d0 = u.exp - (u.exp - v.exp) = v.exp
- neg.w d1
- tst.w d2 ! d2.h = u.sign ^ (u.sign ^ v.sign) = v.sign
- bpl 1f
- bchg #31,d2
- 1:
- cmp.w #53,d1 ! is u so much bigger that v is not
- bge 7f ! significant ?
-
- move.w #10-1,d3 ! shift u left up to 10 bits to minimize loss
- 2:
- add.l d7,d7
- addx.l d6,d6
- sub.w #1,d0 ! decrement exponent
- sub.w #1,d1 ! done shifting altogether ?
- dbeq d3,2b ! loop if still can shift u.mant more
- clr.w d3
- 3:
- cmp.w #16,d1 ! see if fast rotate possible
- blt 4f
- or.b d5,d3 ! set rounding bits
- or.b d2,d3
- sne d2 ! "sticky byte"
- move.w d5,d3
- lsr.w #8,d3
- move.w d4,d5 ! rotate by swapping register halfs
- swap d5
- clr.w d4
- swap d4
- sub.w #16,d1
- bra 3b
- 0:
- lsr.l #1,d4 ! shift v.mant right the rest of the way
- roxr.l #1,d5 ! to line it up with u.mant
- or.b d3,d2 ! set "sticky byte" if necessary
- roxr.w #1,d3 ! shift into rounding bits
- 4: dbra d1,0b ! loop
- and.b #1,d2 ! see if "sticky bit" should be set
- or.b d2,d3
- 5:
- tst.w d2 ! are the signs equal ?
- bpl 6f ! yes, no negate necessary
-
- neg.b d3 ! negate rounding bits and v.mant
- neg.l d5
- negx.l d4
- 6:
- add.l d5,d7 ! u.mant = u.mant + v.mant
- addx.l d4,d6
- bcs 7f ! need not negate
- tst.w d2 ! opposite signs ?
- bpl 7f ! do not need to negate result
-
- neg.b d3 ! negate rounding bits and u.mant
- neg.l d7
- negx.l d6
- not.l d2 ! switch sign
- 7:
- movem.l d6-d7,(a1) ! move result on stack
- move.b d3,d1 ! put rounding bits in d1 for .norm8
- swap d2 ! put sign into d2
- jmp .Xnorm8 ! exit via normalising routine
-