.data .asciz "@(#)Faddd.s 1.1 86/02/03 Copyr 1985 Sun Micro" .even .text | Copyright (c) 1985 by Sun Microsystems, Inc. #include "fpcrtdefs.h" /* * double-precision floating math run-time support * * copyright 1981, 1982 Richard E. James III * translated to SUN idiom 10/11 March 1983 rt * parameter passing re-done 22 July 1983 rt */ ARG2PTR = a0 /* * extract exponents from two double-precision numbers. * * input: * d0/d1 one operand * d2/d3 other operand * * output: * d0/d1 mantissa, waiting for hidden bit to be turned on * d2/d3 other mantissa, likewise * d6 exponent from d2/d3 * d7 exponent for d0/d1 * * destroys d4 */ ENTER(d_exte) moveq #11,d4 | size of exponent roll d4,d0 roll d4,d2 roll d4,d1 roll d4,d3 movl #0x7ff,d6 movl d6,d7 andl d2,d6 eorl d6,d2 movl d7,d4 andl d3,d4 eorl d4,d3 lsrl #1,d2 orl d4,d2 | end transformation of larger movl d7,d4 andl d0,d7 eorl d7,d0 andl d1,d4 eorl d4,d1 lsrl #1,d0 orl d4,d0 | end transformation of smaller rts /* * ieee double floating compare * copyright 1981, Richard E. James III * translated to SUN idiom 30 March 1983 rt */ /* * entry conditions: * first argument in d0/d1 * second argument on stack * exit conditions: * result in cc -- carry flag set if either a NAN * problems: * unordered cases (e.e.: projective infinities and NANs) * produce random results. * A NAN, however, does compare not equal to anything. * * register conventions: * d0/d1 first operand * d2/d3 second operand * d4 scratch */ SAVEMASK = 0x3800 | registers d2-d4 RESTMASK = 0x1c NSAVED = 3*4 | 6 registers * sizeof(register) CODE = NSAVED RTENTRY(Fcmpd) subqw #2,sp | save room for result | save registers and load operands into registers moveml #SAVEMASK,sp@- movl ARG2PTR@+,d2 movl ARG2PTR@ ,d3 | we are now set up. movl d2,d4 andl d0,d4 | compare signs bpls nbothmi exg d0,d2 | both minus exg d1,d3 nbothmi:cmpl d2,d0 | main compare bnes gotcmp | got the answer movl d1,d4 subl d3,d4 | compare lowers beqs gotcmp | entirely equal roxrl #1,d4 andb #0xa,cc | clear z, in case differ by 1 ulp gotcmp: andb #0xe,cc | clear carry bgts 1f blts 2f movw #FEQ,sp@(CODE) bras 3f 1: movw #FGT,sp@(CODE) bras 3f 2: movw #FLT,sp@(CODE) 3: lsll #1,d0 lsll #1,d2 cmpl d2,d0 bccs 4$ exg d0,d2 | find larger in magnitude 4$: cmpl #0xffe00000,d0 blss 6$ | no nan movw #FUN,sp@(CODE) | c, nz bras 8$ | one was a nan 6$: orl d1,d0 orl d2,d0 orl d3,d0 bnes 8$ movw #FEQ,sp@(CODE) | -0 == 0 | done, now go 8$: moveml sp@+,#RESTMASK | put back saved registers movw sp@+,cc | install condition code RET /* * ieee double floating add * copyright 1981, Richard E. James III * translated to SUN idiom 10 March 1983 rt */ /* * entry conditions: * first argument in d0/d1 * second argument on stack * exit conditions: * result (8 bytes) in d0/d1 * * register conventions: * d0/d1 smaller operand (d0=most significant) * d2/d3 larger operand * d4 11 or mask of 11 bits * d5 signs: sign of .w = sign of answer * sign of .b = comparison of signs * d6 exponent of larger * d7 exponent of smaller */ SAVEMASK = 0x3f00 | registers d2-d7 RESTMASK = 0xfc NSAVED = 6*4 | 6 registers * sizeof(register) RTENTRY(Fsubd) | save registers and load operands into registers moveml #SAVEMASK,sp@- | registers d2-d7 movl ARG2PTR@+,d2 movl ARG2PTR@ ,d3 bchg #31,d2 jra adding RTENTRY(Faddd) | save registers and load operands into registers moveml #SAVEMASK,sp@- | registers d2-d7 movl ARG2PTR@+,d2 movl ARG2PTR@ ,d3 adding: | extract signs asll #1,d0 | sign ->c scs d4 | c -> d4 asll #1,d2 scs d5 | compare and exchange to put larger in d0/d1 cmpl d2,d0 blss 1$ exg d0,d2 exg d1,d3 exg d4,d5 1$: extw d5 | sign of larger eorb d4,d5 | comparison of signs | extract exponents jbsr d_exte | larger ->d2/d3,d6; smaller ->d0/d1,d7 tstw d7 bnes 2$ | not zero or denormalized | here, smaller is zero or is denormalized movl d0,d4 orl d1,d4 jeq signofzero | if smaller == 0 use larger | (sign of 0-0 unpredictable) lsll #1,d1 roxll #1,d0 tstw d6 | larger exp bnes 3$ | not gradual underflow lsll #1,d3 roxll #1,d2 bras addorsub | both gradual-underflow, no hidden or align needed 2$: bset #31,d0 | add hidden bit 3$: cmpw #0x7ff,d6 jeq a_ovfl | inf/nan bset #31,d2 | align smaller | shift-by-eight loop subw d6,d7 negw d7 | d7 = difference of exponents cmpw #16,d7 jge rsge16 | Branch if shift of 16 or more. rs015: | Right shift 0..15. subqw #8,d7 blts 5$ | exit loop when difference <8 tstb d1 beqs 99$ | Branch if no bits to lose in shift. bset #8,d1 | Turn on the sticky bit if any bits will be lost. 99$: movb d0,d1 | shift eight bits down rorl #8,d1 lsrl #8,d0 bras rs015 5$: addqw #7,d7 bmis addorsub tstb d1 beqs 98$ bset #8,d1 | Turn on sticky bit. 98$: 6$: lsrl #1,d0 roxrl #1,d1 dbra d7,6$ | final part of alignment addorsub: | decide whether to add or subtract tstb d5 | compare signs bmis diff | add them addl d1,d3 | sum addxl d0,d2 bccs endas | no c, ok roxrl #1,d2 roxrl #1,d3 addqw #1,d6 cmpw #0x7ff,d6 blts endas | no overflow jra a_geninf rsge16: | Right shift 16 or more. cmpw #32,d7 blts rs1631 | Branch if shift is 16..31. cmpw #64,d7 blts rs3263 | Branch if shift is 32..63. clrl d0 | Top will be zero. moveq #1,d1 | Bottom will be sticky. bras addorsub rs3263: | Shift 32. tstl d1 beqs 1$ bset #0,d0 | Sticky bit on. 1$: movl d0,d1 clrl d0 subw #32,d7 cmpw #16,d7 blts rs015 | Branch if shift < 16. rs1631: | Shift 16. tstw d1 beq 2$ | Branch if no bits in D. bset #16,d1 | Turn on sticky bit in C. 2$: clrw d1 | d1 gets Cs,0. movw d0,d1 | d1 gets Cs,B. swap d1 | d1 gets B,Cs. clrw d0 | d0 gets A,0. swap d0 | d0 gets 0,A. subw #16,d7 jra rs015 | subtract then diff: subl d1,d3 | subtract lowers subxl d0,d2 | subtract uppers bccs 9$ | cancelled down into 2nd word, but got wrong sign notw d5 | flip result sign negl d3 negxl d2 | negate value 9$: bnes subrenorm | Branch if result nonzero. tstl d3 bnes subrenorm | Branch if result nonzero. clrw d5 | Exact zero result has positive sign. subrenorm: | Renormalize result after cancellation. jbsr d_norm | rejoin, round endas: jbsr d_rcp | round, check, and pack assgn: lslw #1,d5 | get sign roxrl #1,d2 | put in sign | answer is now in d2/d3: put in d0/d1 movl d2,d0 movl d3,d1 asexit: | restore registers and split moveml sp@+,#RESTMASK RET | EXCEPTION CASES signofzero: | Set up proper sign for exact zero. tstb d5 beqs useln | Branch if signs equal: either will do. tstw d6 bnes useln | Branch if not zero or subnormal. tstl d2 bnes useln | Branch if subnormal. tstl d3 bnes useln | Branch if subnormal. clrw d5 | Signs unequal so set positive. useln: tstw d6 beqs usel | Branch if subnormal: don't set i bit. bset #31,d2 | Set i bit of normal number. usel: jbsr d_usel | use the larger bras assgn | larger exponent = 1-23 a_ovfl: movl d2,d4 | larger mantissa orl d3,d4 bnes usel | larger = nan, use it cmpw d6,d7 | exps bnes usel | larger=inf and smaller=number | (need nan...) tstb d5 | comparison of signs bpls usel | inf+inf=inf; inf-inf=nan movl #0x7ff00001,d0 | NAN clrl d1 bras asexit | result overflows a_geninf: movl #0xffe00000,d2 clrl d3 bras assgn /* * subroutine for unpacking one operand, and normalizing a denormalized number * input: * d0/d1 number * output: * d0/d1 mantissa * d7.w exponent * z on iff mantissa is zero_ * * unchanged: * d4 bottom = 0xf77 */ unp: movl d0,d7 | start getting exp andl #0xfffff,d0 | clear out sign and exp swap d7 lsrw #(16-1-11),d7 andw d4,d7 | expondnt bnes 3$ | normal number | denormalized number or zero: tstl d0 | upper bnes 1$ tstl d1 | lower beqs 3$ |zero 1$: addqw #1,d7 2$: subql #1,d7 lsll #1,d1 roxll #1,d0 | normalize btst #20,d0 beqs 2$ | loop until normalized 3$: rts