📄 lb1sf68.asm
字号:
andl d4,d1 | get fraction in d1 orl d5,d1 | and put hidden bit backLaddsf$2:| Now we have b's exponent in d7 (second byte) and the mantissa in d1. '| Note that the hidden bit corresponds to bit #FLT_MANT_DIG-1, and we | shifted right once, so bit #FLT_MANT_DIG is set (so we have one extra| bit). movel d1,d2 | move b to d2, since we want to use | two registers to do the sum movel IMM (0),d1 | and clear the new ones movel d1,d3 || Here we shift the numbers in registers d0 and d1 so the exponents are the| same, and put the largest exponent in d6. Note that we are using two| registers for each number (see the discussion by D. Knuth in "Seminumerical | Algorithms"). cmpw d6,d7 | compare exponents beq Laddsf$3 | if equal don't shift ' bhi 5f | branch if second exponent largest1: subl d6,d7 | keep the largest exponent negl d7 lsrw IMM (8),d7 | put difference in lower byte| if difference is too large we don't shift (actually, we can just exit) ' cmpw IMM (FLT_MANT_DIG+2),d7 bge Laddsf$b$small cmpw IMM (16),d7 | if difference >= 16 swap bge 4f2: subw IMM (1),d73: lsrl IMM (1),d2 | shift right second operand roxrl IMM (1),d3 dbra d7,3b bra Laddsf$34: movew d2,d3 swap d3 movew d3,d2 swap d2 subw IMM (16),d7 bne 2b | if still more bits, go back to normal case bra Laddsf$35: exg d6,d7 | exchange the exponents subl d6,d7 | keep the largest exponent negl d7 | lsrw IMM (8),d7 | put difference in lower byte| if difference is too large we don't shift (and exit!) ' cmpw IMM (FLT_MANT_DIG+2),d7 bge Laddsf$a$small cmpw IMM (16),d7 | if difference >= 16 swap bge 8f6: subw IMM (1),d77: lsrl IMM (1),d0 | shift right first operand roxrl IMM (1),d1 dbra d7,7b bra Laddsf$38: movew d0,d1 swap d1 movew d1,d0 swap d0 subw IMM (16),d7 bne 6b | if still more bits, go back to normal case | otherwise we fall through| Now we have a in d0-d1, b in d2-d3, and the largest exponent in d6 (the| signs are stored in a0 and a1).Laddsf$3:| Here we have to decide whether to add or subtract the numbers exg d6,a0 | get signs back exg d7,a1 | and save the exponents eorl d6,d7 | combine sign bits bmi Lsubsf$0 | if negative a and b have opposite | sign so we actually subtract the | numbers| Here we have both positive or both negative exg d6,a0 | now we have the exponent in d6 movel a0,d7 | and sign in d7 andl IMM (0x80000000),d7| Here we do the addition. addl d3,d1 addxl d2,d0| Note: now we have d2, d3, d4 and d5 to play with! | Put the exponent, in the first byte, in d2, to use the "standard" rounding| routines: movel d6,d2 lsrw IMM (8),d2| Before rounding normalize so bit #FLT_MANT_DIG is set (we will consider| the case of denormalized numbers in the rounding routine itself).| As in the addition (not in the subtraction!) we could have set | one more bit we check this: btst IMM (FLT_MANT_DIG+1),d0 beq 1f lsrl IMM (1),d0 roxrl IMM (1),d1 addl IMM (1),d21: lea Laddsf$4,a0 | to return from rounding routine lea SYM (_fpCCR),a1 | check the rounding mode movew a1@(6),d6 | rounding mode in d6 beq Lround$to$nearest cmpw IMM (ROUND_TO_PLUS),d6 bhi Lround$to$minus blt Lround$to$zero bra Lround$to$plusLaddsf$4:| Put back the exponent, but check for overflow. cmpw IMM (0xff),d2 bhi 1f bclr IMM (FLT_MANT_DIG-1),d0 lslw IMM (7),d2 swap d2 orl d2,d0 bra Laddsf$ret1: movew IMM (ADD),d5 bra Lf$overflowLsubsf$0:| We are here if a > 0 and b < 0 (sign bits cleared).| Here we do the subtraction. movel d6,d7 | put sign in d7 andl IMM (0x80000000),d7 subl d3,d1 | result in d0-d1 subxl d2,d0 | beq Laddsf$ret | if zero just exit bpl 1f | if positive skip the following bchg IMM (31),d7 | change sign bit in d7 negl d1 negxl d01: exg d2,a0 | now we have the exponent in d2 lsrw IMM (8),d2 | put it in the first byte| Now d0-d1 is positive and the sign bit is in d7.| Note that we do not have to normalize, since in the subtraction bit| #FLT_MANT_DIG+1 is never set, and denormalized numbers are handled by| the rounding routines themselves. lea Lsubsf$1,a0 | to return from rounding routine lea SYM (_fpCCR),a1 | check the rounding mode movew a1@(6),d6 | rounding mode in d6 beq Lround$to$nearest cmpw IMM (ROUND_TO_PLUS),d6 bhi Lround$to$minus blt Lround$to$zero bra Lround$to$plusLsubsf$1:| Put back the exponent (we can't have overflow!). ' bclr IMM (FLT_MANT_DIG-1),d0 lslw IMM (7),d2 swap d2 orl d2,d0 bra Laddsf$ret| If one of the numbers was too small (difference of exponents >= | FLT_MANT_DIG+2) we return the other (and now we don't have to '| check for finiteness or zero).Laddsf$a$small: movel a6@(12),d0 lea SYM (_fpCCR),a0 movew IMM (0),a0@ moveml sp@+,d2-d7 | restore data registers unlk a6 | and return rtsLaddsf$b$small: movel a6@(8),d0 lea SYM (_fpCCR),a0 movew IMM (0),a0@ moveml sp@+,d2-d7 | restore data registers unlk a6 | and return rts| If the numbers are denormalized remember to put exponent equal to 1.Laddsf$a$den: movel d5,d6 | d5 contains 0x01000000 swap d6 bra Laddsf$1Laddsf$b$den: movel d5,d7 swap d7 notl d4 | make d4 into a mask for the fraction | (this was not executed after the jump) bra Laddsf$2| The rest is mainly code for the different results which can be | returned (checking always for +/-INFINITY and NaN).Laddsf$b:| Return b (if a is zero). movel a6@(12),d0 bra 1fLaddsf$a:| Return a (if b is zero). movel a6@(8),d01: movew IMM (ADD),d5| We have to check for NaN and +/-infty. movel d0,d7 andl IMM (0x80000000),d7 | put sign in d7 bclr IMM (31),d0 | clear sign cmpl IMM (INFINITY),d0 | check for infty or NaN bge 2f movel d0,d0 | check for zero (we do this because we don't ' bne Laddsf$ret | want to return -0 by mistake bclr IMM (31),d7 | if zero be sure to clear sign bra Laddsf$ret | if everything OK just return2:| The value to be returned is either +/-infty or NaN andl IMM (0x007fffff),d0 | check for NaN bne Lf$inop | if mantissa not zero is NaN bra Lf$inftyLaddsf$ret:| Normal exit (a and b nonzero, result is not NaN nor +/-infty).| We have to clear the exception flags (just the exception type). lea SYM (_fpCCR),a0 movew IMM (0),a0@ orl d7,d0 | put sign bit moveml sp@+,d2-d7 | restore data registers unlk a6 | and return rtsLaddsf$ret$den:| Return a denormalized number (for addition we don't signal underflow) ' lsrl IMM (1),d0 | remember to shift right back once bra Laddsf$ret | and return| Note: when adding two floats of the same sign if either one is | NaN we return NaN without regard to whether the other is finite or | not. When subtracting them (i.e., when adding two numbers of | opposite signs) things are more complicated: if both are INFINITY | we return NaN, if only one is INFINITY and the other is NaN we return| NaN, but if it is finite we return INFINITY with the corresponding sign.Laddsf$nf: movew IMM (ADD),d5| This could be faster but it is not worth the effort, since it is not| executed very often. We sacrifice speed for clarity here. movel a6@(8),d0 | get the numbers back (remember that we movel a6@(12),d1 | did some processing already) movel IMM (INFINITY),d4 | useful constant (INFINITY) movel d0,d2 | save sign bits movel d1,d3 bclr IMM (31),d0 | clear sign bits bclr IMM (31),d1| We know that one of them is either NaN of +/-INFINITY| Check for NaN (if either one is NaN return NaN) cmpl d4,d0 | check first a (d0) bhi Lf$inop cmpl d4,d1 | check now b (d1) bhi Lf$inop | Now comes the check for +/-INFINITY. We know that both are (maybe not| finite) numbers, but we have to check if both are infinite whether we| are adding or subtracting them. eorl d3,d2 | to check sign bits bmi 1f movel d0,d7 andl IMM (0x80000000),d7 | get (common) sign bit bra Lf$infty1:| We know one (or both) are infinite, so we test for equality between the| two numbers (if they are equal they have to be infinite both, so we| return NaN). cmpl d1,d0 | are both infinite? beq Lf$inop | if so return NaN movel d0,d7 andl IMM (0x80000000),d7 | get a's sign bit ' cmpl d4,d0 | test now for infinity beq Lf$infty | if a is INFINITY return with this sign bchg IMM (31),d7 | else we know b is INFINITY and has bra Lf$infty | the opposite sign|=============================================================================| __mulsf3|=============================================================================| float __mulsf3(float, float);SYM (__mulsf3): link a6,IMM (0) moveml d2-d7,sp@- movel a6@(8),d0 | get a into d0 movel a6@(12),d1 | and b into d1 movel d0,d7 | d7 will hold the sign of the product eorl d1,d7 | andl IMM (0x80000000),d7 movel IMM (INFINITY),d6 | useful constant (+INFINITY) movel d6,d5 | another (mask for fraction) notl d5 | movel IMM (0x00800000),d4 | this is to put hidden bit back bclr IMM (31),d0 | get rid of a's sign bit ' movel d0,d2 | beq Lmulsf$a$0 | branch if a is zero bclr IMM (31),d1 | get rid of b's sign bit ' movel d1,d3 | beq Lmulsf$b$0 | branch if b is zero cmpl d6,d0 | is a big? bhi Lmulsf$inop | if a is NaN return NaN beq Lmulsf$inf | if a is INFINITY we have to check b cmpl d6,d1 | now compare b with INFINITY bhi Lmulsf$inop | is b NaN? beq Lmulsf$overflow | is b INFINITY?| Here we have both numbers finite and nonzero (and with no sign bit).| Now we get the exponents into d2 and d3. andl d6,d2 | and isolate exponent in d2 beq Lmulsf$a$den | if exponent is zero we have a denormalized andl d5,d0 | and isolate fraction orl d4,d0 | and put hidden bit back swap d2 | I like exponents in the first byte lsrw IMM (7),d2 | Lmulsf$1: | number andl d6,d3 | beq Lmulsf$b$den | andl d5,d1 | orl d4,d1 | swap d3 | lsrw IMM (7),d3 |Lmulsf$2: | addw d3,d2 | add exponents subw IMM (F_BIAS+1),d2 | and subtract bias (plus one)| We are now ready to do the multiplication. The situation is as follows:| both a and b have bit FLT_MANT_DIG-1 set (even if they were | denormalized to start with!), which means that in the product | bit 2*(FLT_MANT_DIG-1) (that is, bit 2*FLT_MANT_DIG-2-32 of the | high long) is set. | To do the multiplication let us move the number a little bit around ... movel d1,d6 | second operand in d6 movel d0,d5 | first operand in d4-d5 movel IMM (0),d4 movel d4,d1 | the sums will go in d0-d1 movel d4,d0| now bit FLT_MANT_DIG-1 becomes bit 31: lsll IMM (31-FLT_MANT_DIG+1),d6 | Start the loop (we loop #FLT_MANT_DIG times): movew IMM (FLT_MANT_DIG-1),d3 1: addl d1,d1 | shift sum addxl d0,d0 lsll IMM (1),d6 | get bit bn bcc 2f | if not set skip sum addl d5,d1 | add a addxl d4,d02: dbf d3,1b | loop back| Now we have the product in d0-d1, with bit (FLT_MANT_DIG - 1) + FLT_MANT_DIG| (mod 32) of d0 set. The first thing to do now is to normalize it so bit | FLT_MANT_DIG is set (to do the rounding). rorl IMM (6),d1 swap d1 movew d1,d3 andw IMM (0x03ff),d3 andw IMM (0xfd00),d1 lsll IMM (8),d0 addl d0,d0 addl d0,d0 orw d3,d0 movew IMM (MULTIPLY),d5 btst IMM (FLT_MANT_DIG+1),d0 beq Lround$exit lsrl IMM (1),d0 roxrl IMM (1),d1 addw IMM (1),d2 bra Lround$exitLmulsf$inop: movew IMM (MULTIPLY),d5 bra Lf$inopLmulsf$overflow: movew IMM (MULTIPLY),d5 bra Lf$overflowLmulsf$inf: movew IMM (MULTIPLY),d5| If either is NaN return NaN; else both are (maybe infinite) numbers, so| return INFINITY with the correct sign (which is in d7). cmpl d6,d1 | is b NaN? bhi Lf$inop | if so return NaN bra Lf$overflow | else return +/-INFINITY| If either number is zero return zero, unless the other is +/-INFINITY, | or NaN, in which case we return NaN.Lmulsf$b$0:| Here d1 (==b) is zero. movel d1,d0 | put b into d0 (just a zero) movel a6@(8),d1 | get a again to check for non-finiteness bra 1fLmulsf$a$0: movel a6@(12),d1 | get b again to check for non-finiteness1: bclr IMM (31),d1 | clear sign bit cmpl IMM (INFINITY),d1 | and check for a large exponent bge Lf$inop | if b is +/-INFINITY or NaN return NaN lea SYM (_fpCCR),a0 | else return zero movew IMM (0),a0@ | moveml sp@+,d2-d7 | unlk a6 | rts | | If a number is denormalized we put an exponent of 1 but do not put the | hidden bit back into the fraction; instead we shift left until bit 23| (the hidden bit) is set, adjusting the exponent accordingly. We do this| to ensure that the product of the fractions is close to 1.Lmulsf$a$den: movel IMM (1),d2 andl d5,d01: addl d0,d0 | shift a left (until bit 23 is set) subw IMM (1),d2 | and adjust exponent btst IMM (FLT_MANT_DIG-1),d0 bne Lmulsf$1 | bra 1b | else loop backLmulsf$b$den: movel IMM (1),d3 andl d5,d11: addl d1,d1 | shift b left until bit 23 is set subw IMM (1),d3 | and adjust exponent btst IMM (FLT_MANT_DIG-1),d1 bne Lmulsf$2 | bra 1b | else loop back|=============================================================================| __divsf3|=============================================================================| float __divsf3(float, float);SYM (__divsf3): link a6,IMM (0) moveml d2-d7,sp@- movel a6@(8),d0 | get a into d0 movel a6@(12),d1 | and b into d1 movel d0,d7 | d7 will hold the sign of the result eorl d1,d7 | andl IMM (0x80000000),d7 | movel IMM (INFINITY),d6 | useful constant (+INFINITY) movel d6,d5 | another (mask for fraction) notl d5 | movel IMM (0x00800000),d4 | this is to put hidden bit ba
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -