📄 lb1sf68.asm
字号:
bclr IMM (31),d2 | movel d2,d4 | check for zero orl d1,d4 | beq 2f | if zero (either sign) return +zero cmpl IMM (0x7ff00000),d2 | compare to +INFINITY blt 1f | if finite, return bhi Ld$inop | if larger (fraction not zero) is NaN tstl d1 | if d2 == 0x7ff00000 check d1 bne Ld$inop | movel d0,d7 | else get sign and return INFINITY andl IMM (0x80000000),d7 bra Ld$infty 1: lea SYM (_fpCCR),a0 movew IMM (0),a0@#ifndef __mcf5200__ moveml sp@+,d2-d7#else moveml sp@,d2-d7 | XXX if frame pointer is ever removed, stack pointer must | be adjusted here.#endif unlk a6 rts2: bclr IMM (31),d0 bra 1b|=============================================================================| __cmpdf2|=============================================================================GREATER = 1LESS = -1EQUAL = 0| int __cmpdf2(double, double);SYM (__cmpdf2):#ifndef __mcf5200__ link a6,IMM (0) moveml d2-d7,sp@- | save registers#else link a6,IMM (-24) moveml d2-d7,sp@#endif movew IMM (COMPARE),d5 movel a6@(8),d0 | get first operand movel a6@(12),d1 | movel a6@(16),d2 | get second operand movel a6@(20),d3 || First check if a and/or b are (+/-) zero and in that case clear| the sign bit. movel d0,d6 | copy signs into d6 (a) and d7(b) bclr IMM (31),d0 | and clear signs in d0 and d2 movel d2,d7 | bclr IMM (31),d2 | cmpl IMM (0x7fff0000),d0 | check for a == NaN bhi Ld$inop | if d0 > 0x7ff00000, a is NaN beq Lcmpdf$a$nf | if equal can be INFINITY, so check d1 movel d0,d4 | copy into d4 to test for zero orl d1,d4 | beq Lcmpdf$a$0 |Lcmpdf$0: cmpl IMM (0x7fff0000),d2 | check for b == NaN bhi Ld$inop | if d2 > 0x7ff00000, b is NaN beq Lcmpdf$b$nf | if equal can be INFINITY, so check d3 movel d2,d4 | orl d3,d4 | beq Lcmpdf$b$0 |Lcmpdf$1:| Check the signs eorl d6,d7 bpl 1f| If the signs are not equal check if a >= 0 tstl d6 bpl Lcmpdf$a$gt$b | if (a >= 0 && b < 0) => a > b bmi Lcmpdf$b$gt$a | if (a < 0 && b >= 0) => a < b1:| If the signs are equal check for < 0 tstl d6 bpl 1f| If both are negative exchange them#ifndef __mcf5200__ exg d0,d2 exg d1,d3#else movel d0,d7 movel d2,d0 movel d7,d2 movel d1,d7 movel d3,d1 movel d7,d3#endif1:| Now that they are positive we just compare them as longs (does this also| work for denormalized numbers?). cmpl d0,d2 bhi Lcmpdf$b$gt$a | |b| > |a| bne Lcmpdf$a$gt$b | |b| < |a|| If we got here d0 == d2, so we compare d1 and d3. cmpl d1,d3 bhi Lcmpdf$b$gt$a | |b| > |a| bne Lcmpdf$a$gt$b | |b| < |a|| If we got here a == b. movel IMM (EQUAL),d0#ifndef __mcf5200__ moveml sp@+,d2-d7 | put back the registers#else moveml sp@,d2-d7 | XXX if frame pointer is ever removed, stack pointer must | be adjusted here.#endif unlk a6 rtsLcmpdf$a$gt$b: movel IMM (GREATER),d0#ifndef __mcf5200__ moveml sp@+,d2-d7 | put back the registers#else moveml sp@,d2-d7 | XXX if frame pointer is ever removed, stack pointer must | be adjusted here.#endif unlk a6 rtsLcmpdf$b$gt$a: movel IMM (LESS),d0#ifndef __mcf5200__ moveml sp@+,d2-d7 | put back the registers#else moveml sp@,d2-d7 | XXX if frame pointer is ever removed, stack pointer must | be adjusted here.#endif unlk a6 rtsLcmpdf$a$0: bclr IMM (31),d6 bra Lcmpdf$0Lcmpdf$b$0: bclr IMM (31),d7 bra Lcmpdf$1Lcmpdf$a$nf: tstl d1 bne Ld$inop bra Lcmpdf$0Lcmpdf$b$nf: tstl d3 bne Ld$inop bra Lcmpdf$1|=============================================================================| rounding routines|=============================================================================| The rounding routines expect the number to be normalized in registers| d0-d1-d2-d3, with the exponent in register d4. They assume that the | exponent is larger or equal to 1. They return a properly normalized number| if possible, and a denormalized number otherwise. The exponent is returned| in d4.Lround$to$nearest:| We now normalize as suggested by D. Knuth ("Seminumerical Algorithms"):| Here we assume that the exponent is not too small (this should be checked| before entering the rounding routine), but the number could be denormalized.| Check for denormalized numbers:1: btst IMM (DBL_MANT_DIG-32),d0 bne 2f | if set the number is normalized| Normalize shifting left until bit #DBL_MANT_DIG-32 is set or the exponent | is one (remember that a denormalized number corresponds to an | exponent of -D_BIAS+1).#ifndef __mcf5200__ cmpw IMM (1),d4 | remember that the exponent is at least one#else cmpl IMM (1),d4 | remember that the exponent is at least one#endif beq 2f | an exponent of one means denormalized addl d3,d3 | else shift and adjust the exponent addxl d2,d2 | addxl d1,d1 | addxl d0,d0 |#ifndef __mcf5200__ dbra d4,1b |#else subql IMM (1), d4 bpl 1b#endif2:| Now round: we do it as follows: after the shifting we can write the| fraction part as f + delta, where 1 < f < 2^25, and 0 <= delta <= 2.| If delta < 1, do nothing. If delta > 1, add 1 to f. | If delta == 1, we make sure the rounded number will be even (odd?) | (after shifting). btst IMM (0),d1 | is delta < 1? beq 2f | if so, do not do anything orl d2,d3 | is delta == 1? bne 1f | if so round to even movel d1,d3 | andl IMM (2),d3 | bit 1 is the last significant bit movel IMM (0),d2 | addl d3,d1 | addxl d2,d0 | bra 2f | 1: movel IMM (1),d3 | else add 1 movel IMM (0),d2 | addl d3,d1 | addxl d2,d0| Shift right once (because we used bit #DBL_MANT_DIG-32!).2:#ifndef __mcf5200__ lsrl IMM (1),d0 roxrl IMM (1),d1 #else lsrl IMM (1),d1 btst IMM (0),d0 beq 10f bset IMM (31),d110: lsrl IMM (1),d0#endif| Now check again bit #DBL_MANT_DIG-32 (rounding could have produced a| 'fraction overflow' ...). btst IMM (DBL_MANT_DIG-32),d0 beq 1f#ifndef __mcf5200__ lsrl IMM (1),d0 roxrl IMM (1),d1 addw IMM (1),d4#else lsrl IMM (1),d1 btst IMM (0),d0 beq 10f bset IMM (31),d110: lsrl IMM (1),d0 addl IMM (1),d4#endif1:| If bit #DBL_MANT_DIG-32-1 is clear we have a denormalized number, so we | have to put the exponent to zero and return a denormalized number. btst IMM (DBL_MANT_DIG-32-1),d0 beq 1f jmp a0@1: movel IMM (0),d4 jmp a0@Lround$to$zero:Lround$to$plus:Lround$to$minus: jmp a0@#endif /* L_double */#ifdef L_float .globl SYM (_fpCCR) .globl $_exception_handlerQUIET_NaN = 0xffffffffSIGNL_NaN = 0x7f800001INFINITY = 0x7f800000F_MAX_EXP = 0xffF_BIAS = 126FLT_MAX_EXP = F_MAX_EXP - F_BIASFLT_MIN_EXP = 1 - F_BIASFLT_MANT_DIG = 24INEXACT_RESULT = 0x0001UNDERFLOW = 0x0002OVERFLOW = 0x0004DIVIDE_BY_ZERO = 0x0008INVALID_OPERATION = 0x0010SINGLE_FLOAT = 1NOOP = 0ADD = 1MULTIPLY = 2DIVIDE = 3NEGATE = 4COMPARE = 5EXTENDSFDF = 6TRUNCDFSF = 7UNKNOWN = -1ROUND_TO_NEAREST = 0 | round result to nearest representable valueROUND_TO_ZERO = 1 | round result towards zeroROUND_TO_PLUS = 2 | round result towards plus infinityROUND_TO_MINUS = 3 | round result towards minus infinity| Entry points: .globl SYM (__addsf3) .globl SYM (__subsf3) .globl SYM (__mulsf3) .globl SYM (__divsf3) .globl SYM (__negsf2) .globl SYM (__cmpsf2)| These are common routines to return and signal exceptions. .text .evenLf$den:| Return and signal a denormalized number orl d7,d0 movew IMM (INEXACT_RESULT+UNDERFLOW),d7 moveq IMM (SINGLE_FLOAT),d6 jmp $_exception_handlerLf$infty:Lf$overflow:| Return a properly signed INFINITY and set the exception flags movel IMM (INFINITY),d0 orl d7,d0 movew IMM (INEXACT_RESULT+OVERFLOW),d7 moveq IMM (SINGLE_FLOAT),d6 jmp $_exception_handlerLf$underflow:| Return 0 and set the exception flags movel IMM (0),d0 movew IMM (INEXACT_RESULT+UNDERFLOW),d7 moveq IMM (SINGLE_FLOAT),d6 jmp $_exception_handlerLf$inop:| Return a quiet NaN and set the exception flags movel IMM (QUIET_NaN),d0 movew IMM (INEXACT_RESULT+INVALID_OPERATION),d7 moveq IMM (SINGLE_FLOAT),d6 jmp $_exception_handlerLf$div$0:| Return a properly signed INFINITY and set the exception flags movel IMM (INFINITY),d0 orl d7,d0 movew IMM (INEXACT_RESULT+DIVIDE_BY_ZERO),d7 moveq IMM (SINGLE_FLOAT),d6 jmp $_exception_handler|=============================================================================|=============================================================================| single precision routines|=============================================================================|=============================================================================| A single precision floating point number (float) has the format:|| struct _float {| unsigned int sign : 1; /* sign bit */ | unsigned int exponent : 8; /* exponent, shifted by 126 */| unsigned int fraction : 23; /* fraction */| } float;| | Thus sizeof(float) = 4 (32 bits). || All the routines are callable from C programs, and return the result | in the single register d0. They also preserve all registers except | d0-d1 and a0-a1.|=============================================================================| __subsf3|=============================================================================| float __subsf3(float, float);SYM (__subsf3): bchg IMM (31),sp@(8) | change sign of second operand | and fall through|=============================================================================| __addsf3|=============================================================================| float __addsf3(float, float);SYM (__addsf3):#ifndef __mcf5200__ link a6,IMM (0) | everything will be done in registers moveml d2-d7,sp@- | save all data registers but d0-d1#else link a6,IMM (-24) moveml d2-d7,sp@#endif movel a6@(8),d0 | get first operand movel a6@(12),d1 | get second operand movel d0,d6 | get d0's sign bit ' addl d0,d0 | check and clear sign bit of a beq Laddsf$b | if zero return second operand movel d1,d7 | save b's sign bit ' addl d1,d1 | get rid of sign bit beq Laddsf$a | if zero return first operand movel d6,a0 | save signs in address registers movel d7,a1 | so we can use d6 and d7| Get the exponents and check for denormalized and/or infinity. movel IMM (0x00ffffff),d4 | mask to get fraction movel IMM (0x01000000),d5 | mask to put hidden bit back movel d0,d6 | save a to get exponent andl d4,d0 | get fraction in d0 notl d4 | make d4 into a mask for the exponent andl d4,d6 | get exponent in d6 beq Laddsf$a$den | branch if a is denormalized cmpl d4,d6 | check for INFINITY or NaN beq Laddsf$nf swap d6 | put exponent into first word orl d5,d0 | and put hidden bit backLaddsf$1:| Now we have a's exponent in d6 (second byte) and the mantissa in d0. ' movel d1,d7 | get exponent in d7 andl d4,d7 | beq Laddsf$b$den | branch if b is denormalized cmpl d4,d7 | check for INFINITY or NaN beq Laddsf$nf swap d7 | put exponent into first word notl d4 | make d4 into a mask for the fraction 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").#ifndef __mcf5200__ cmpw d6,d7 | compare exponents#else cmpl d6,d7 | compare exponents#endif beq Laddsf$3 | if equal don't shift ' bhi 5f | branch if second exponent largest1: subl d6,d7 | keep the largest exponent negl d7#ifndef __mcf5200__ lsrw IMM (8),d7 | put difference in lower byte#else lsrl IMM (8),d7 | put difference in lower byte#endif| if difference is too large we don't shift (actually, we can just exit) '#ifndef __mcf5200__ cmpw IMM (FLT_MANT_DIG+2),d7 #else cmpl IMM (FLT_MANT_DIG+2),d7 #endif bge Laddsf$b$small#ifndef __mcf5200__ cmpw IMM (16),d7 | if difference >= 16 swap#else cmpl IMM (16),d7 | if difference >= 16 swap#endif bge 4f2:#ifndef __mcf5200__ subw IMM (1),d7#else subql IMM (1), d7#endif3:#ifndef __mcf5200__ lsrl IMM (1),d2 | shift right second operand roxrl IMM (1),d3 dbra d7,3b#else lsrl IMM (1),d3 btst IMM (0),d2 beq 10f bset IMM (31),d310: lsrl IMM (1),d2 subql IMM (1), d7 bpl 3b#endif bra Laddsf$34: movew d2,d3 swap d3 movew d3,d2 swap d2#ifndef __mcf5200__ subw IMM (16),d7#else subl IMM (16),d7#endif bne 2b | if still more bits, go back to normal case bra Laddsf$35:#ifndef __mcf5200__ exg d6,d7 | exchange the exponents#else eorl d6,d7 eorl d7,d6 eorl d6,d7#endif subl d6,d7 | keep the largest exponent negl d7 |#ifndef __mcf5200__ lsrw IMM (8),d7 | put difference in lower byte#else lsrl IMM (8),d7 | put difference in lower byte#endif| if difference is too large we don't shift (and exit!) '#ifndef __mcf5200__ cmpw IMM (FLT_MANT_DIG+2),d7 #else cmpl IMM (FLT_MANT_DIG+2),d7 #endif bge Laddsf$a$small#ifndef __mcf5200__ cmpw IMM (16),d7 | if difference >= 16 swap#else cmpl IMM (16),d7 | if difference >= 16 swap#endif bge 8f6:#ifndef
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -