📄 lb1sf68.asm
字号:
.text .even| These are common routines to return and signal exceptions. Ld$den:| Return and signal a denormalized number orl d7,d0 movew IMM (UNDERFLOW),d7 orw IMM (INEXACT_RESULT),d7 movew IMM (DOUBLE_FLOAT),d6 jmp $_exception_handlerLd$infty:Ld$overflow:| Return a properly signed INFINITY and set the exception flags movel IMM (0x7ff00000),d0 movel IMM (0),d1 orl d7,d0 movew IMM (OVERFLOW),d7 orw IMM (INEXACT_RESULT),d7 movew IMM (DOUBLE_FLOAT),d6 jmp $_exception_handlerLd$underflow:| Return 0 and set the exception flags movel IMM (0),d0 movel d0,d1 movew IMM (UNDERFLOW),d7 orw IMM (INEXACT_RESULT),d7 movew IMM (DOUBLE_FLOAT),d6 jmp $_exception_handlerLd$inop:| Return a quiet NaN and set the exception flags movel IMM (QUIET_NaN),d0 movel d0,d1 movew IMM (INVALID_OPERATION),d7 orw IMM (INEXACT_RESULT),d7 movew IMM (DOUBLE_FLOAT),d6 jmp $_exception_handlerLd$div$0:| Return a properly signed INFINITY and set the exception flags movel IMM (0x7ff00000),d0 movel IMM (0),d1 orl d7,d0 movew IMM (DIVIDE_BY_ZERO),d7 orw IMM (INEXACT_RESULT),d7 movew IMM (DOUBLE_FLOAT),d6 jmp $_exception_handler|=============================================================================|=============================================================================| double precision routines|=============================================================================|=============================================================================| A double precision floating point number (double) has the format:|| struct _double {| unsigned int sign : 1; /* sign bit */ | unsigned int exponent : 11; /* exponent, shifted by 126 */| unsigned int fraction : 52; /* fraction */| } double;| | Thus sizeof(double) = 8 (64 bits). || All the routines are callable from C programs, and return the result | in the register pair d0-d1. They also preserve all registers except | d0-d1 and a0-a1.|=============================================================================| __subdf3|=============================================================================| double __subdf3(double, double);SYM (__subdf3): bchg IMM (31),sp@(12) | change sign of second operand | and fall through, so we always add|=============================================================================| __adddf3|=============================================================================| double __adddf3(double, double);SYM (__adddf3): link a6,IMM (0) | everything will be done in registers moveml d2-d7,sp@- | save all data registers and a2 (but d0-d1) movel a6@(8),d0 | get first operand movel a6@(12),d1 | movel a6@(16),d2 | get second operand movel a6@(20),d3 | movel d0,d7 | get d0's sign bit in d7 ' addl d1,d1 | check and clear sign bit of a, and gain one addxl d0,d0 | bit of extra precision beq Ladddf$b | if zero return second operand movel d2,d6 | save sign in d6 addl d3,d3 | get rid of sign bit and gain one bit of addxl d2,d2 | extra precision beq Ladddf$a | if zero return first operand andl IMM (0x80000000),d7 | isolate a's sign bit ' swap d6 | and also b's sign bit ' andw IMM (0x8000),d6 | orw d6,d7 | and combine them into d7, so that a's sign ' | bit is in the high word and b's is in the ' | low word, so d6 is free to be used movel d7,a0 | now save d7 into a0, so d7 is free to | be used also| Get the exponents and check for denormalized and/or infinity. movel IMM (0x001fffff),d6 | mask for the fraction movel IMM (0x00200000),d7 | mask to put hidden bit back movel d0,d4 | andl d6,d0 | get fraction in d0 notl d6 | make d6 into mask for the exponent andl d6,d4 | get exponent in d4 beq Ladddf$a$den | branch if a is denormalized cmpl d6,d4 | check for INFINITY or NaN beq Ladddf$nf | orl d7,d0 | and put hidden bit backLadddf$1: swap d4 | shift right exponent so that it starts lsrw IMM (5),d4 | in bit 0 and not bit 20| Now we have a's exponent in d4 and fraction in d0-d1 ' movel d2,d5 | save b to get exponent andl d6,d5 | get exponent in d5 beq Ladddf$b$den | branch if b is denormalized cmpl d6,d5 | check for INFINITY or NaN beq Ladddf$nf notl d6 | make d6 into mask for the fraction again andl d6,d2 | and get fraction in d2 orl d7,d2 | and put hidden bit backLadddf$2: swap d5 | shift right exponent so that it starts lsrw IMM (5),d5 | in bit 0 and not bit 20| Now we have b's exponent in d5 and fraction in d2-d3. '| The situation now is as follows: the signs are combined in a0, the | numbers are in d0-d1 (a) and d2-d3 (b), and the exponents in d4 (a)| and d5 (b). To do the rounding correctly we need to keep all the| bits until the end, so we need to use d0-d1-d2-d3 for the first number| and d4-d5-d6-d7 for the second. To do this we store (temporarily) the| exponents in a2-a3. moveml a2-a3,sp@- | save the address registers movel d4,a2 | save the exponents movel d5,a3 | movel IMM (0),d7 | and move the numbers around movel d7,d6 | movel d3,d5 | movel d2,d4 | movel d7,d3 | movel d7,d2 || Here we shift the numbers until the exponents are the same, and put | the largest exponent in a2. exg d4,a2 | get exponents back exg d5,a3 | cmpw d4,d5 | compare the exponents beq Ladddf$3 | if equal don't shift ' bhi 9f | branch if second exponent is higher| Here we have a's exponent larger than b's, so we have to shift b. We do | this by using as counter d2:1: movew d4,d2 | move largest exponent to d2 subw d5,d2 | and subtract second exponent exg d4,a2 | get back the longs we saved exg d5,a3 || if difference is too large we don't shift (actually, we can just exit) ' cmpw IMM (DBL_MANT_DIG+2),d2 bge Ladddf$b$small cmpw IMM (32),d2 | if difference >= 32, shift by longs bge 5f2: cmpw IMM (16),d2 | if difference >= 16, shift by words bge 6f bra 3f | enter dbra loop4: lsrl IMM (1),d4 roxrl IMM (1),d5 roxrl IMM (1),d6 roxrl IMM (1),d73: dbra d2,4b movel IMM (0),d2 movel d2,d3 bra Ladddf$45: movel d6,d7 movel d5,d6 movel d4,d5 movel IMM (0),d4 subw IMM (32),d2 bra 2b6: movew d6,d7 swap d7 movew d5,d6 swap d6 movew d4,d5 swap d5 movew IMM (0),d4 swap d4 subw IMM (16),d2 bra 3b 9: exg d4,d5 movew d4,d6 subw d5,d6 | keep d5 (largest exponent) in d4 exg d4,a2 exg d5,a3| if difference is too large we don't shift (actually, we can just exit) ' cmpw IMM (DBL_MANT_DIG+2),d6 bge Ladddf$a$small cmpw IMM (32),d6 | if difference >= 32, shift by longs bge 5f2: cmpw IMM (16),d6 | if difference >= 16, shift by words bge 6f bra 3f | enter dbra loop4: lsrl IMM (1),d0 roxrl IMM (1),d1 roxrl IMM (1),d2 roxrl IMM (1),d33: dbra d6,4b movel IMM (0),d7 movel d7,d6 bra Ladddf$45: movel d2,d3 movel d1,d2 movel d0,d1 movel IMM (0),d0 subw IMM (32),d6 bra 2b6: movew d2,d3 swap d3 movew d1,d2 swap d2 movew d0,d1 swap d1 movew IMM (0),d0 swap d0 subw IMM (16),d6 bra 3bLadddf$3: exg d4,a2 exg d5,a3Ladddf$4: | Now we have the numbers in d0--d3 and d4--d7, the exponent in a2, and| the signs in a4.| Here we have to decide whether to add or subtract the numbers: exg d7,a0 | get the signs exg d6,a3 | a3 is free to be used movel d7,d6 | movew IMM (0),d7 | get a's sign in d7 ' swap d6 | movew IMM (0),d6 | and b's sign in d6 ' eorl d7,d6 | compare the signs bmi Lsubdf$0 | if the signs are different we have | to subtract exg d7,a0 | else we add the numbers exg d6,a3 | addl d7,d3 | addxl d6,d2 | addxl d5,d1 | addxl d4,d0 | movel a2,d4 | return exponent to d4 movel a0,d7 | andl IMM (0x80000000),d7 | d7 now has the sign moveml sp@+,a2-a3 | Before rounding normalize so bit #DBL_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 (DBL_MANT_DIG+1),d0 beq 1f lsrl IMM (1),d0 roxrl IMM (1),d1 roxrl IMM (1),d2 roxrl IMM (1),d3 addw IMM (1),d41: lea Ladddf$5,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$plusLadddf$5:| Put back the exponent and check for overflow cmpw IMM (0x7ff),d4 | is the exponent big? bge 1f bclr IMM (DBL_MANT_DIG-1),d0 lslw IMM (4),d4 | put exponent back into position swap d0 | orw d4,d0 | swap d0 | bra Ladddf$ret1: movew IMM (ADD),d5 bra Ld$overflowLsubdf$0:| Here we do the subtraction. exg d7,a0 | put sign back in a0 exg d6,a3 | subl d7,d3 | subxl d6,d2 | subxl d5,d1 | subxl d4,d0 | beq Ladddf$ret$1 | if zero just exit bpl 1f | if positive skip the following exg d7,a0 | bchg IMM (31),d7 | change sign bit in d7 exg d7,a0 | negl d3 | negxl d2 | negxl d1 | and negate result negxl d0 |1: movel a2,d4 | return exponent to d4 movel a0,d7 andl IMM (0x80000000),d7 | isolate sign bit moveml sp@+,a2-a3 || Before rounding normalize so bit #DBL_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 (DBL_MANT_DIG+1),d0 beq 1f lsrl IMM (1),d0 roxrl IMM (1),d1 roxrl IMM (1),d2 roxrl IMM (1),d3 addw IMM (1),d41: lea Lsubdf$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$plusLsubdf$1:| Put back the exponent and sign (we don't have overflow). ' bclr IMM (DBL_MANT_DIG-1),d0 lslw IMM (4),d4 | put exponent back into position swap d0 | orw d4,d0 | swap d0 | bra Ladddf$ret| If one of the numbers was too small (difference of exponents >= | DBL_MANT_DIG+1) we return the other (and now we don't have to '| check for finiteness or zero).Ladddf$a$small: moveml sp@+,a2-a3 movel a6@(16),d0 movel a6@(20),d1 lea SYM (_fpCCR),a0 movew IMM (0),a0@ moveml sp@+,d2-d7 | restore data registers unlk a6 | and return rtsLadddf$b$small: moveml sp@+,a2-a3 movel a6@(8),d0 movel a6@(12),d1 lea SYM (_fpCCR),a0 movew IMM (0),a0@ moveml sp@+,d2-d7 | restore data registers unlk a6 | and return rtsLadddf$a$den: movel d7,d4 | d7 contains 0x00200000 bra Ladddf$1Ladddf$b$den: movel d7,d5 | d7 contains 0x00200000 notl d6 bra Ladddf$2Ladddf$b:| Return b (if a is zero) movel d2,d0 movel d3,d1 bra 1fLadddf$a: movel a6@(8),d0 movel a6@(12),d11: movew IMM (ADD),d5| Check for NaN and +/-INFINITY. movel d0,d7 | andl IMM (0x80000000),d7 | bclr IMM (31),d0 | cmpl IMM (0x7ff00000),d0 | bge 2f | movel d0,d0 | check for zero, since we don't ' bne Ladddf$ret | want to return -0 by mistake bclr IMM (31),d7 | bra Ladddf$ret |2: andl IMM (0x000fffff),d0 | check for NaN (nonzero fraction) orl d1,d0 | bne Ld$inop | bra Ld$infty | Ladddf$ret$1: moveml sp@+,a2-a3 | restore regs and exitLadddf$ret:| Normal exit. lea SYM (_fpCCR),a0 movew IMM (0),a0@ orl d7,d0 | put sign bit back moveml sp@+,d2-d7 unlk a6 rtsLadddf$ret$den:| Return a denormalized number. lsrl IMM (1),d0 | shift right once more roxrl IMM (1),d1 | bra Ladddf$retLadddf$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 a6@(16),d2 | movel a6@(20),d3 | movel IMM (0x7ff00000),d4 | useful constant (INFINITY) movel d0,d7 | save sign bits movel d2,d6 | bclr IMM (31),d0 | clear sign bits bclr IMM (31),d2 | | We know that one of them is either NaN of +/-INFINITY
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -