URL
https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk
Subversion Repositories openrisc_me
[/] [openrisc/] [trunk/] [gnu-src/] [gcc-4.5.1/] [gcc/] [config/] [m68k/] [lb1sf68.asm] - Rev 282
Compare with Previous | Blame | View Log
/* libgcc routines for 68000 w/o floating-point hardware.Copyright (C) 1994, 1996, 1997, 1998, 2008, 2009 Free Software Foundation, Inc.This file is part of GCC.GCC is free software; you can redistribute it and/or modify itunder the terms of the GNU General Public License as published by theFree Software Foundation; either version 3, or (at your option) anylater version.This file is distributed in the hope that it will be useful, butWITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNUGeneral Public License for more details.Under Section 7 of GPL version 3, you are granted additionalpermissions described in the GCC Runtime Library Exception, version3.1, as published by the Free Software Foundation.You should have received a copy of the GNU General Public License anda copy of the GCC Runtime Library Exception along with this program;see the files COPYING3 and COPYING.RUNTIME respectively. If not, see<http://www.gnu.org/licenses/>. *//* Use this one for any 680x0; assumes no floating point hardware.The trailing " '" appearing on some lines is for ANSI preprocessors. Yuk.Some of this code comes from MINIX, via the folks at ericsson.D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992*//* These are predefined by new versions of GNU cpp. */#ifndef __USER_LABEL_PREFIX__#define __USER_LABEL_PREFIX__ _#endif#ifndef __REGISTER_PREFIX__#define __REGISTER_PREFIX__#endif#ifndef __IMMEDIATE_PREFIX__#define __IMMEDIATE_PREFIX__ ##endif/* ANSI concatenation macros. */#define CONCAT1(a, b) CONCAT2(a, b)#define CONCAT2(a, b) a ## b/* Use the right prefix for global labels. */#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)/* Note that X is a function. */#ifdef __ELF__#define FUNC(x) .type SYM(x),function#else/* The .proc pseudo-op is accepted, but ignored, by GAS. We could justdefine this to the empty string for non-ELF systems, but defining itto .proc means that the information is available to the assembler ifthe need arises. */#define FUNC(x) .proc#endif/* Use the right prefix for registers. */#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x)/* Use the right prefix for immediate values. */#define IMM(x) CONCAT1 (__IMMEDIATE_PREFIX__, x)#define d0 REG (d0)#define d1 REG (d1)#define d2 REG (d2)#define d3 REG (d3)#define d4 REG (d4)#define d5 REG (d5)#define d6 REG (d6)#define d7 REG (d7)#define a0 REG (a0)#define a1 REG (a1)#define a2 REG (a2)#define a3 REG (a3)#define a4 REG (a4)#define a5 REG (a5)#define a6 REG (a6)#define fp REG (fp)#define sp REG (sp)#define pc REG (pc)/* Provide a few macros to allow for PIC code support.* With PIC, data is stored A5 relative so we've got to take a bit of special* care to ensure that all loads of global data is via A5. PIC also requires* jumps and subroutine calls to be PC relative rather than absolute. We cheat* a little on this and in the PIC case, we use short offset branches and* hope that the final object code is within range (which it should be).*/#ifndef __PIC__/* Non PIC (absolute/relocatable) versions */.macro PICCALL addrjbsr \addr.endm.macro PICJUMP addrjmp \addr.endm.macro PICLEA sym, reglea \sym, \reg.endm.macro PICPEA sym, aregpea \sym.endm#else /* __PIC__ */# if defined (__uClinux__)/* Versions for uClinux */# if defined(__ID_SHARED_LIBRARY__)/* -mid-shared-library versions */.macro PICLEA sym, regmovel a5@(_current_shared_library_a5_offset_), \regmovel \sym@GOT(\reg), \reg.endm.macro PICPEA sym, aregmovel a5@(_current_shared_library_a5_offset_), \aregmovel \sym@GOT(\areg), sp@-.endm.macro PICCALL addrPICLEA \addr,a0jsr a0@.endm.macro PICJUMP addrPICLEA \addr,a0jmp a0@.endm# else /* !__ID_SHARED_LIBRARY__ *//* Versions for -msep-data */.macro PICLEA sym, regmovel \sym@GOT(a5), \reg.endm.macro PICPEA sym, aregmovel \sym@GOT(a5), sp@-.endm.macro PICCALL addr#if defined (__mcoldfire__) && !defined (__mcfisab__) && !defined (__mcfisac__)lea \addr-.-8,a0jsr pc@(a0)#elsejbsr \addr#endif.endm.macro PICJUMP addr/* ISA C has no bra.l instruction, and since this assembly filegets assembled into multiple object files, we avoid thebra instruction entirely. */#if defined (__mcoldfire__) && !defined (__mcfisab__)lea \addr-.-8,a0jmp pc@(a0)#elsebra \addr#endif.endm# endif# else /* !__uClinux__ *//* Versions for Linux */.macro PICLEA sym, regmovel #_GLOBAL_OFFSET_TABLE_@GOTPC, \reglea (-6, pc, \reg), \regmovel \sym@GOT(\reg), \reg.endm.macro PICPEA sym, aregmovel #_GLOBAL_OFFSET_TABLE_@GOTPC, \areglea (-6, pc, \areg), \aregmovel \sym@GOT(\areg), sp@-.endm.macro PICCALL addr#if defined (__mcoldfire__) && !defined (__mcfisab__) && !defined (__mcfisac__)lea \addr-.-8,a0jsr pc@(a0)#elsejbsr \addr#endif.endm.macro PICJUMP addr/* ISA C has no bra.l instruction, and since this assembly filegets assembled into multiple object files, we avoid thebra instruction entirely. */#if defined (__mcoldfire__) && !defined (__mcfisab__)lea \addr-.-8,a0jmp pc@(a0)#elsebra \addr#endif.endm# endif#endif /* __PIC__ */#ifdef L_floatex| This is an attempt at a decent floating point (single, double and| extended double) code for the GNU C compiler. It should be easy to| adapt to other compilers (but beware of the local labels!).| Starting date: 21 October, 1990| It is convenient to introduce the notation (s,e,f) for a floating point| number, where s=sign, e=exponent, f=fraction. We will call a floating| point number fpn to abbreviate, independently of the precision.| Let MAX_EXP be in each case the maximum exponent (255 for floats, 1023| for doubles and 16383 for long doubles). We then have the following| different cases:| 1. Normalized fpns have 0 < e < MAX_EXP. They correspond to| (-1)^s x 1.f x 2^(e-bias-1).| 2. Denormalized fpns have e=0. They correspond to numbers of the form| (-1)^s x 0.f x 2^(-bias).| 3. +/-INFINITY have e=MAX_EXP, f=0.| 4. Quiet NaN (Not a Number) have all bits set.| 5. Signaling NaN (Not a Number) have s=0, e=MAX_EXP, f=1.|=============================================================================| exceptions|=============================================================================| This is the floating point condition code register (_fpCCR):|| struct {| short _exception_bits;| short _trap_enable_bits;| short _sticky_bits;| short _rounding_mode;| short _format;| short _last_operation;| union {| float sf;| double df;| } _operand1;| union {| float sf;| double df;| } _operand2;| } _fpCCR;.data.even.globl SYM (_fpCCR)SYM (_fpCCR):__exception_bits:.word 0__trap_enable_bits:.word 0__sticky_bits:.word 0__rounding_mode:.word ROUND_TO_NEAREST__format:.word NIL__last_operation:.word NOOP__operand1:.long 0.long 0__operand2:.long 0.long 0| Offsets:EBITS = __exception_bits - SYM (_fpCCR)TRAPE = __trap_enable_bits - SYM (_fpCCR)STICK = __sticky_bits - SYM (_fpCCR)ROUND = __rounding_mode - SYM (_fpCCR)FORMT = __format - SYM (_fpCCR)LASTO = __last_operation - SYM (_fpCCR)OPER1 = __operand1 - SYM (_fpCCR)OPER2 = __operand2 - SYM (_fpCCR)| The following exception types are supported:INEXACT_RESULT = 0x0001UNDERFLOW = 0x0002OVERFLOW = 0x0004DIVIDE_BY_ZERO = 0x0008INVALID_OPERATION = 0x0010| The allowed rounding modes are:UNKNOWN = -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| The allowed values of format are:NIL = 0SINGLE_FLOAT = 1DOUBLE_FLOAT = 2LONG_FLOAT = 3| The allowed values for the last operation are:NOOP = 0ADD = 1MULTIPLY = 2DIVIDE = 3NEGATE = 4COMPARE = 5EXTENDSFDF = 6TRUNCDFSF = 7|=============================================================================| __clear_sticky_bits|=============================================================================| The sticky bits are normally not cleared (thus the name), whereas the| exception type and exception value reflect the last computation.| This routine is provided to clear them (you can also write to _fpCCR,| since it is globally visible)..globl SYM (__clear_sticky_bit).text.even| void __clear_sticky_bits(void);SYM (__clear_sticky_bit):PICLEA SYM (_fpCCR),a0#ifndef __mcoldfire__movew IMM (0),a0@(STICK)#elseclr.w a0@(STICK)#endifrts|=============================================================================| $_exception_handler|=============================================================================.globl $_exception_handler.text.even| This is the common exit point if an exception occurs.| NOTE: it is NOT callable from C!| It expects the exception type in d7, the format (SINGLE_FLOAT,| DOUBLE_FLOAT or LONG_FLOAT) in d6, and the last operation code in d5.| It sets the corresponding exception and sticky bits, and the format.| Depending on the format if fills the corresponding slots for the| operands which produced the exception (all this information is provided| so if you write your own exception handlers you have enough information| to deal with the problem).| Then checks to see if the corresponding exception is trap-enabled,| in which case it pushes the address of _fpCCR and traps through| trap FPTRAP (15 for the moment).FPTRAP = 15$_exception_handler:PICLEA SYM (_fpCCR),a0movew d7,a0@(EBITS) | set __exception_bits#ifndef __mcoldfire__orw d7,a0@(STICK) | and __sticky_bits#elsemovew a0@(STICK),d4orl d7,d4movew d4,a0@(STICK)#endifmovew d6,a0@(FORMT) | and __formatmovew d5,a0@(LASTO) | and __last_operation| Now put the operands in place:#ifndef __mcoldfire__cmpw IMM (SINGLE_FLOAT),d6#elsecmpl IMM (SINGLE_FLOAT),d6#endifbeq 1fmovel a6@(8),a0@(OPER1)movel a6@(12),a0@(OPER1+4)movel a6@(16),a0@(OPER2)movel a6@(20),a0@(OPER2+4)bra 2f1: movel a6@(8),a0@(OPER1)movel a6@(12),a0@(OPER2)2:| And check whether the exception is trap-enabled:#ifndef __mcoldfire__andw a0@(TRAPE),d7 | is exception trap-enabled?#elseclrl d6movew a0@(TRAPE),d6andl d6,d7#endifbeq 1f | no, exitPICPEA SYM (_fpCCR),a1 | yes, push address of _fpCCRtrap IMM (FPTRAP) | and trap#ifndef __mcoldfire__1: moveml sp@+,d2-d7 | restore data registers#else1: moveml sp@,d2-d7| XXX if frame pointer is ever removed, stack pointer must| be adjusted here.#endifunlk a6 | and returnrts#endif /* L_floatex */#ifdef L_mulsi3.textFUNC(__mulsi3).globl SYM (__mulsi3)SYM (__mulsi3):movew sp@(4), d0 /* x0 -> d0 */muluw sp@(10), d0 /* x0*y1 */movew sp@(6), d1 /* x1 -> d1 */muluw sp@(8), d1 /* x1*y0 */#ifndef __mcoldfire__addw d1, d0#elseaddl d1, d0#endifswap d0clrw d0movew sp@(6), d1 /* x1 -> d1 */muluw sp@(10), d1 /* x1*y1 */addl d1, d0rts#endif /* L_mulsi3 */#ifdef L_udivsi3.textFUNC(__udivsi3).globl SYM (__udivsi3)SYM (__udivsi3):#ifndef __mcoldfire__movel d2, sp@-movel sp@(12), d1 /* d1 = divisor */movel sp@(8), d0 /* d0 = dividend */cmpl IMM (0x10000), d1 /* divisor >= 2 ^ 16 ? */jcc L3 /* then try next algorithm */movel d0, d2clrw d2swap d2divu d1, d2 /* high quotient in lower word */movew d2, d0 /* save high quotient */swap d0movew sp@(10), d2 /* get low dividend + high rest */divu d1, d2 /* low quotient */movew d2, d0jra L6L3: movel d1, d2 /* use d2 as divisor backup */L4: lsrl IMM (1), d1 /* shift divisor */lsrl IMM (1), d0 /* shift dividend */cmpl IMM (0x10000), d1 /* still divisor >= 2 ^ 16 ? */jcc L4divu d1, d0 /* now we have 16-bit divisor */andl IMM (0xffff), d0 /* mask out divisor, ignore remainder *//* Multiply the 16-bit tentative quotient with the 32-bit divisor. Because ofthe operand ranges, this might give a 33-bit product. If this product isgreater than the dividend, the tentative quotient was too large. */movel d2, d1mulu d0, d1 /* low part, 32 bits */swap d2mulu d0, d2 /* high part, at most 17 bits */swap d2 /* align high part with low part */tstw d2 /* high part 17 bits? */jne L5 /* if 17 bits, quotient was too large */addl d2, d1 /* add parts */jcs L5 /* if sum is 33 bits, quotient was too large */cmpl sp@(8), d1 /* compare the sum with the dividend */jls L6 /* if sum > dividend, quotient was too large */L5: subql IMM (1), d0 /* adjust quotient */L6: movel sp@+, d2rts#else /* __mcoldfire__ *//* ColdFire implementation of non-restoring division algorithm fromHennessy & Patterson, Appendix A. */link a6,IMM (-12)moveml d2-d4,sp@movel a6@(8),d0movel a6@(12),d1clrl d2 | clear pmoveq IMM (31),d4L1: addl d0,d0 | shift reg pair (p,a) one bit leftaddxl d2,d2movl d2,d3 | subtract b from p, store in tmp.subl d1,d3jcs L2 | if no carry,bset IMM (0),d0 | set the low order bit of a to 1,movl d3,d2 | and store tmp in p.L2: subql IMM (1),d4jcc L1moveml sp@,d2-d4 | restore data registersunlk a6 | and returnrts#endif /* __mcoldfire__ */#endif /* L_udivsi3 */#ifdef L_divsi3.textFUNC(__divsi3).globl SYM (__divsi3)SYM (__divsi3):movel d2, sp@-moveq IMM (1), d2 /* sign of result stored in d2 (=1 or =-1) */movel sp@(12), d1 /* d1 = divisor */jpl L1negl d1#ifndef __mcoldfire__negb d2 /* change sign because divisor <0 */#elsenegl d2 /* change sign because divisor <0 */#endifL1: movel sp@(8), d0 /* d0 = dividend */jpl L2negl d0#ifndef __mcoldfire__negb d2#elsenegl d2#endifL2: movel d1, sp@-movel d0, sp@-PICCALL SYM (__udivsi3) /* divide abs(dividend) by abs(divisor) */addql IMM (8), sptstb d2jpl L3negl d0L3: movel sp@+, d2rts#endif /* L_divsi3 */#ifdef L_umodsi3.textFUNC(__umodsi3).globl SYM (__umodsi3)SYM (__umodsi3):movel sp@(8), d1 /* d1 = divisor */movel sp@(4), d0 /* d0 = dividend */movel d1, sp@-movel d0, sp@-PICCALL SYM (__udivsi3)addql IMM (8), spmovel sp@(8), d1 /* d1 = divisor */#ifndef __mcoldfire__movel d1, sp@-movel d0, sp@-PICCALL SYM (__mulsi3) /* d0 = (a/b)*b */addql IMM (8), sp#elsemulsl d1,d0#endifmovel sp@(4), d1 /* d1 = dividend */subl d0, d1 /* d1 = a - (a/b)*b */movel d1, d0rts#endif /* L_umodsi3 */#ifdef L_modsi3.textFUNC(__modsi3).globl SYM (__modsi3)SYM (__modsi3):movel sp@(8), d1 /* d1 = divisor */movel sp@(4), d0 /* d0 = dividend */movel d1, sp@-movel d0, sp@-PICCALL SYM (__divsi3)addql IMM (8), spmovel sp@(8), d1 /* d1 = divisor */#ifndef __mcoldfire__movel d1, sp@-movel d0, sp@-PICCALL SYM (__mulsi3) /* d0 = (a/b)*b */addql IMM (8), sp#elsemulsl d1,d0#endifmovel sp@(4), d1 /* d1 = dividend */subl d0, d1 /* d1 = a - (a/b)*b */movel d1, d0rts#endif /* L_modsi3 */#ifdef L_double.globl SYM (_fpCCR).globl $_exception_handlerQUIET_NaN = 0xffffffffD_MAX_EXP = 0x07ffD_BIAS = 1022DBL_MAX_EXP = D_MAX_EXP - D_BIASDBL_MIN_EXP = 1 - D_BIASDBL_MANT_DIG = 53INEXACT_RESULT = 0x0001UNDERFLOW = 0x0002OVERFLOW = 0x0004DIVIDE_BY_ZERO = 0x0008INVALID_OPERATION = 0x0010DOUBLE_FLOAT = 2NOOP = 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 (__adddf3).globl SYM (__subdf3).globl SYM (__muldf3).globl SYM (__divdf3).globl SYM (__negdf2).globl SYM (__cmpdf2).globl SYM (__cmpdf2_internal).hidden SYM (__cmpdf2_internal).text.even| These are common routines to return and signal exceptions.Ld$den:| Return and signal a denormalized numberorl d7,d0movew IMM (INEXACT_RESULT+UNDERFLOW),d7moveq IMM (DOUBLE_FLOAT),d6PICJUMP $_exception_handlerLd$infty:Ld$overflow:| Return a properly signed INFINITY and set the exception flagsmovel IMM (0x7ff00000),d0movel IMM (0),d1orl d7,d0movew IMM (INEXACT_RESULT+OVERFLOW),d7moveq IMM (DOUBLE_FLOAT),d6PICJUMP $_exception_handlerLd$underflow:| Return 0 and set the exception flagsmovel IMM (0),d0movel d0,d1movew IMM (INEXACT_RESULT+UNDERFLOW),d7moveq IMM (DOUBLE_FLOAT),d6PICJUMP $_exception_handlerLd$inop:| Return a quiet NaN and set the exception flagsmovel IMM (QUIET_NaN),d0movel d0,d1movew IMM (INEXACT_RESULT+INVALID_OPERATION),d7moveq IMM (DOUBLE_FLOAT),d6PICJUMP $_exception_handlerLd$div$0:| Return a properly signed INFINITY and set the exception flagsmovel IMM (0x7ff00000),d0movel IMM (0),d1orl d7,d0movew IMM (INEXACT_RESULT+DIVIDE_BY_ZERO),d7moveq IMM (DOUBLE_FLOAT),d6PICJUMP $_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);FUNC(__subdf3)SYM (__subdf3):bchg IMM (31),sp@(12) | change sign of second operand| and fall through, so we always add|=============================================================================| __adddf3|=============================================================================| double __adddf3(double, double);FUNC(__adddf3)SYM (__adddf3):#ifndef __mcoldfire__link a6,IMM (0) | everything will be done in registersmoveml d2-d7,sp@- | save all data registers and a2 (but d0-d1)#elselink a6,IMM (-24)moveml d2-d7,sp@#endifmovel a6@(8),d0 | get first operandmovel a6@(12),d1 |movel a6@(16),d2 | get second operandmovel 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 oneaddxl d0,d0 | bit of extra precisionbeq Ladddf$b | if zero return second operandmovel d2,d6 | save sign in d6addl d3,d3 | get rid of sign bit and gain one bit ofaddxl d2,d2 | extra precisionbeq Ladddf$a | if zero return first operandandl IMM (0x80000000),d7 | isolate a's sign bit 'swap d6 | and also b's sign bit '#ifndef __mcoldfire__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#elseandl IMM (0x8000),d6orl d6,d7#endifmovel 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 fractionmovel IMM (0x00200000),d7 | mask to put hidden bit backmovel d0,d4 |andl d6,d0 | get fraction in d0notl d6 | make d6 into mask for the exponentandl d6,d4 | get exponent in d4beq Ladddf$a$den | branch if a is denormalizedcmpl d6,d4 | check for INFINITY or NaNbeq Ladddf$nf |orl d7,d0 | and put hidden bit backLadddf$1:swap d4 | shift right exponent so that it starts#ifndef __mcoldfire__lsrw IMM (5),d4 | in bit 0 and not bit 20#elselsrl IMM (5),d4 | in bit 0 and not bit 20#endif| Now we have a's exponent in d4 and fraction in d0-d1 'movel d2,d5 | save b to get exponentandl d6,d5 | get exponent in d5beq Ladddf$b$den | branch if b is denormalizedcmpl d6,d5 | check for INFINITY or NaNbeq Ladddf$nfnotl d6 | make d6 into mask for the fraction againandl d6,d2 | and get fraction in d2orl d7,d2 | and put hidden bit backLadddf$2:swap d5 | shift right exponent so that it starts#ifndef __mcoldfire__lsrw IMM (5),d5 | in bit 0 and not bit 20#elselsrl IMM (5),d5 | in bit 0 and not bit 20#endif| 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.#ifndef __mcoldfire__moveml a2-a3,sp@- | save the address registers#elsemovel a2,sp@-movel a3,sp@-movel a4,sp@-#endifmovel d4,a2 | save the exponentsmovel d5,a3 |movel IMM (0),d7 | and move the numbers aroundmovel 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.#ifndef __mcoldfire__exg d4,a2 | get exponents backexg d5,a3 |cmpw d4,d5 | compare the exponents#elsemovel d4,a4 | get exponents backmovel a2,d4movel a4,a2movel d5,a4movel a3,d5movel a4,a3cmpl d4,d5 | compare the exponents#endifbeq 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#ifndef __mcoldfire__subw d5,d2 | and subtract second exponentexg d4,a2 | get back the longs we savedexg d5,a3 |#elsesubl d5,d2 | and subtract second exponentmovel d4,a4 | get back the longs we savedmovel a2,d4movel a4,a2movel d5,a4movel a3,d5movel a4,a3#endif| if difference is too large we don't shift (actually, we can just exit) '#ifndef __mcoldfire__cmpw IMM (DBL_MANT_DIG+2),d2#elsecmpl IMM (DBL_MANT_DIG+2),d2#endifbge Ladddf$b$small#ifndef __mcoldfire__cmpw IMM (32),d2 | if difference >= 32, shift by longs#elsecmpl IMM (32),d2 | if difference >= 32, shift by longs#endifbge 5f2:#ifndef __mcoldfire__cmpw IMM (16),d2 | if difference >= 16, shift by words#elsecmpl IMM (16),d2 | if difference >= 16, shift by words#endifbge 6fbra 3f | enter dbra loop4:#ifndef __mcoldfire__lsrl IMM (1),d4roxrl IMM (1),d5roxrl IMM (1),d6roxrl IMM (1),d7#elselsrl IMM (1),d7btst IMM (0),d6beq 10fbset IMM (31),d710: lsrl IMM (1),d6btst IMM (0),d5beq 11fbset IMM (31),d611: lsrl IMM (1),d5btst IMM (0),d4beq 12fbset IMM (31),d512: lsrl IMM (1),d4#endif3:#ifndef __mcoldfire__dbra d2,4b#elsesubql IMM (1),d2bpl 4b#endifmovel IMM (0),d2movel d2,d3bra Ladddf$45:movel d6,d7movel d5,d6movel d4,d5movel IMM (0),d4#ifndef __mcoldfire__subw IMM (32),d2#elsesubl IMM (32),d2#endifbra 2b6:movew d6,d7swap d7movew d5,d6swap d6movew d4,d5swap d5movew IMM (0),d4swap d4#ifndef __mcoldfire__subw IMM (16),d2#elsesubl IMM (16),d2#endifbra 3b9:#ifndef __mcoldfire__exg d4,d5movew d4,d6subw d5,d6 | keep d5 (largest exponent) in d4exg d4,a2exg d5,a3#elsemovel d5,d6movel d4,d5movel d6,d4subl d5,d6movel d4,a4movel a2,d4movel a4,a2movel d5,a4movel a3,d5movel a4,a3#endif| if difference is too large we don't shift (actually, we can just exit) '#ifndef __mcoldfire__cmpw IMM (DBL_MANT_DIG+2),d6#elsecmpl IMM (DBL_MANT_DIG+2),d6#endifbge Ladddf$a$small#ifndef __mcoldfire__cmpw IMM (32),d6 | if difference >= 32, shift by longs#elsecmpl IMM (32),d6 | if difference >= 32, shift by longs#endifbge 5f2:#ifndef __mcoldfire__cmpw IMM (16),d6 | if difference >= 16, shift by words#elsecmpl IMM (16),d6 | if difference >= 16, shift by words#endifbge 6fbra 3f | enter dbra loop4:#ifndef __mcoldfire__lsrl IMM (1),d0roxrl IMM (1),d1roxrl IMM (1),d2roxrl IMM (1),d3#elselsrl IMM (1),d3btst IMM (0),d2beq 10fbset IMM (31),d310: lsrl IMM (1),d2btst IMM (0),d1beq 11fbset IMM (31),d211: lsrl IMM (1),d1btst IMM (0),d0beq 12fbset IMM (31),d112: lsrl IMM (1),d0#endif3:#ifndef __mcoldfire__dbra d6,4b#elsesubql IMM (1),d6bpl 4b#endifmovel IMM (0),d7movel d7,d6bra Ladddf$45:movel d2,d3movel d1,d2movel d0,d1movel IMM (0),d0#ifndef __mcoldfire__subw IMM (32),d6#elsesubl IMM (32),d6#endifbra 2b6:movew d2,d3swap d3movew d1,d2swap d2movew d0,d1swap d1movew IMM (0),d0swap d0#ifndef __mcoldfire__subw IMM (16),d6#elsesubl IMM (16),d6#endifbra 3bLadddf$3:#ifndef __mcoldfire__exg d4,a2exg d5,a3#elsemovel d4,a4movel a2,d4movel a4,a2movel d5,a4movel a3,d5movel a4,a3#endifLadddf$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:#ifndef __mcoldfire__exg d7,a0 | get the signsexg d6,a3 | a3 is free to be used#elsemovel d7,a4movel a0,d7movel a4,a0movel d6,a4movel a3,d6movel a4,a3#endifmovel 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 signsbmi Lsubdf$0 | if the signs are different we have| to subtract#ifndef __mcoldfire__exg d7,a0 | else we add the numbersexg d6,a3 |#elsemovel d7,a4movel a0,d7movel a4,a0movel d6,a4movel a3,d6movel a4,a3#endifaddl d7,d3 |addxl d6,d2 |addxl d5,d1 |addxl d4,d0 |movel a2,d4 | return exponent to d4movel a0,d7 |andl IMM (0x80000000),d7 | d7 now has the sign#ifndef __mcoldfire__moveml sp@+,a2-a3#elsemovel sp@+,a4movel sp@+,a3movel sp@+,a2#endif| 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),d0beq 1f#ifndef __mcoldfire__lsrl IMM (1),d0roxrl IMM (1),d1roxrl IMM (1),d2roxrl IMM (1),d3addw IMM (1),d4#elselsrl IMM (1),d3btst IMM (0),d2beq 10fbset IMM (31),d310: lsrl IMM (1),d2btst IMM (0),d1beq 11fbset IMM (31),d211: lsrl IMM (1),d1btst IMM (0),d0beq 12fbset IMM (31),d112: lsrl IMM (1),d0addl IMM (1),d4#endif1:lea pc@(Ladddf$5),a0 | to return from rounding routinePICLEA SYM (_fpCCR),a1 | check the rounding mode#ifdef __mcoldfire__clrl d6#endifmovew a1@(6),d6 | rounding mode in d6beq Lround$to$nearest#ifndef __mcoldfire__cmpw IMM (ROUND_TO_PLUS),d6#elsecmpl IMM (ROUND_TO_PLUS),d6#endifbhi Lround$to$minusblt Lround$to$zerobra Lround$to$plusLadddf$5:| Put back the exponent and check for overflow#ifndef __mcoldfire__cmpw IMM (0x7ff),d4 | is the exponent big?#elsecmpl IMM (0x7ff),d4 | is the exponent big?#endifbge 1fbclr IMM (DBL_MANT_DIG-1),d0#ifndef __mcoldfire__lslw IMM (4),d4 | put exponent back into position#elselsll IMM (4),d4 | put exponent back into position#endifswap d0 |#ifndef __mcoldfire__orw d4,d0 |#elseorl d4,d0 |#endifswap d0 |bra Ladddf$ret1:moveq IMM (ADD),d5bra Ld$overflowLsubdf$0:| Here we do the subtraction.#ifndef __mcoldfire__exg d7,a0 | put sign back in a0exg d6,a3 |#elsemovel d7,a4movel a0,d7movel a4,a0movel d6,a4movel a3,d6movel a4,a3#endifsubl d7,d3 |subxl d6,d2 |subxl d5,d1 |subxl d4,d0 |beq Ladddf$ret$1 | if zero just exitbpl 1f | if positive skip the followingmovel a0,d7 |bchg IMM (31),d7 | change sign bit in d7movel d7,a0 |negl d3 |negxl d2 |negxl d1 | and negate resultnegxl d0 |1:movel a2,d4 | return exponent to d4movel a0,d7andl IMM (0x80000000),d7 | isolate sign bit#ifndef __mcoldfire__moveml sp@+,a2-a3 |#elsemovel sp@+,a4movel sp@+,a3movel sp@+,a2#endif| 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),d0beq 1f#ifndef __mcoldfire__lsrl IMM (1),d0roxrl IMM (1),d1roxrl IMM (1),d2roxrl IMM (1),d3addw IMM (1),d4#elselsrl IMM (1),d3btst IMM (0),d2beq 10fbset IMM (31),d310: lsrl IMM (1),d2btst IMM (0),d1beq 11fbset IMM (31),d211: lsrl IMM (1),d1btst IMM (0),d0beq 12fbset IMM (31),d112: lsrl IMM (1),d0addl IMM (1),d4#endif1:lea pc@(Lsubdf$1),a0 | to return from rounding routinePICLEA SYM (_fpCCR),a1 | check the rounding mode#ifdef __mcoldfire__clrl d6#endifmovew a1@(6),d6 | rounding mode in d6beq Lround$to$nearest#ifndef __mcoldfire__cmpw IMM (ROUND_TO_PLUS),d6#elsecmpl IMM (ROUND_TO_PLUS),d6#endifbhi Lround$to$minusblt Lround$to$zerobra Lround$to$plusLsubdf$1:| Put back the exponent and sign (we don't have overflow). 'bclr IMM (DBL_MANT_DIG-1),d0#ifndef __mcoldfire__lslw IMM (4),d4 | put exponent back into position#elselsll IMM (4),d4 | put exponent back into position#endifswap d0 |#ifndef __mcoldfire__orw d4,d0 |#elseorl d4,d0 |#endifswap 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:#ifndef __mcoldfire__moveml sp@+,a2-a3#elsemovel sp@+,a4movel sp@+,a3movel sp@+,a2#endifmovel a6@(16),d0movel a6@(20),d1PICLEA SYM (_fpCCR),a0movew IMM (0),a0@#ifndef __mcoldfire__moveml sp@+,d2-d7 | restore data registers#elsemoveml sp@,d2-d7| XXX if frame pointer is ever removed, stack pointer must| be adjusted here.#endifunlk a6 | and returnrtsLadddf$b$small:#ifndef __mcoldfire__moveml sp@+,a2-a3#elsemovel sp@+,a4movel sp@+,a3movel sp@+,a2#endifmovel a6@(8),d0movel a6@(12),d1PICLEA SYM (_fpCCR),a0movew IMM (0),a0@#ifndef __mcoldfire__moveml sp@+,d2-d7 | restore data registers#elsemoveml sp@,d2-d7| XXX if frame pointer is ever removed, stack pointer must| be adjusted here.#endifunlk a6 | and returnrtsLadddf$a$den:movel d7,d4 | d7 contains 0x00200000bra Ladddf$1Ladddf$b$den:movel d7,d5 | d7 contains 0x00200000notl d6bra Ladddf$2Ladddf$b:| Return b (if a is zero)movel d2,d0movel d3,d1bne 1f | Check if b is -0cmpl IMM (0x80000000),d0bne 1fandl IMM (0x80000000),d7 | Use the sign of aclrl d0bra Ladddf$retLadddf$a:movel a6@(8),d0movel a6@(12),d11:moveq 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 mistakebclr 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:#ifndef __mcoldfire__moveml sp@+,a2-a3 | restore regs and exit#elsemovel sp@+,a4movel sp@+,a3movel sp@+,a2#endifLadddf$ret:| Normal exit.PICLEA SYM (_fpCCR),a0movew IMM (0),a0@orl d7,d0 | put sign bit back#ifndef __mcoldfire__moveml sp@+,d2-d7#elsemoveml sp@,d2-d7| XXX if frame pointer is ever removed, stack pointer must| be adjusted here.#endifunlk a6rtsLadddf$ret$den:| Return a denormalized number.#ifndef __mcoldfire__lsrl IMM (1),d0 | shift right once moreroxrl IMM (1),d1 |#elselsrl IMM (1),d1btst IMM (0),d0beq 10fbset IMM (31),d110: lsrl IMM (1),d0#endifbra Ladddf$retLadddf$nf:moveq 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 wemovel 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 bitsmovel d2,d6 |bclr IMM (31),d0 | clear sign bitsbclr IMM (31),d2 || 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 Ld$inop | if d0 > 0x7ff00000 or equal andbne 2ftstl d1 | d1 > 0, a is NaNbne Ld$inop |2: cmpl d4,d2 | check now b (d1)bhi Ld$inop |bne 3ftstl d3 |bne Ld$inop |3:| 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 d7,d6 | to check sign bitsbmi 1fandl IMM (0x80000000),d7 | get (common) sign bitbra Ld$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 d2,d0 | are both infinite?bne 1f | if d0 <> d2 they are not equalcmpl d3,d1 | if d0 == d2 test d3 and d1beq Ld$inop | if equal return NaN1:andl IMM (0x80000000),d7 | get a's sign bit 'cmpl d4,d0 | test now for infinitybeq Ld$infty | if a is INFINITY return with this signbchg IMM (31),d7 | else we know b is INFINITY and hasbra Ld$infty | the opposite sign|=============================================================================| __muldf3|=============================================================================| double __muldf3(double, double);FUNC(__muldf3)SYM (__muldf3):#ifndef __mcoldfire__link a6,IMM (0)moveml d2-d7,sp@-#elselink a6,IMM (-24)moveml d2-d7,sp@#endifmovel a6@(8),d0 | get a into d0-d1movel a6@(12),d1 |movel a6@(16),d2 | and b into d2-d3movel a6@(20),d3 |movel d0,d7 | d7 will hold the sign of the producteorl d2,d7 |andl IMM (0x80000000),d7 |movel d7,a0 | save sign bit into a0movel IMM (0x7ff00000),d7 | useful constant (+INFINITY)movel d7,d6 | another (mask for fraction)notl d6 |bclr IMM (31),d0 | get rid of a's sign bit 'movel d0,d4 |orl d1,d4 |beq Lmuldf$a$0 | branch if a is zeromovel d0,d4 |bclr IMM (31),d2 | get rid of b's sign bit 'movel d2,d5 |orl d3,d5 |beq Lmuldf$b$0 | branch if b is zeromovel d2,d5 |cmpl d7,d0 | is a big?bhi Lmuldf$inop | if a is NaN return NaNbeq Lmuldf$a$nf | we still have to check d1 and b ...cmpl d7,d2 | now compare b with INFINITYbhi Lmuldf$inop | is b NaN?beq Lmuldf$b$nf | we still have to check d3 ...| Here we have both numbers finite and nonzero (and with no sign bit).| Now we get the exponents into d4 and d5.andl d7,d4 | isolate exponent in d4beq Lmuldf$a$den | if exponent zero, have denormalizedandl d6,d0 | isolate fractionorl IMM (0x00100000),d0 | and put hidden bit backswap d4 | I like exponents in the first byte#ifndef __mcoldfire__lsrw IMM (4),d4 |#elselsrl IMM (4),d4 |#endifLmuldf$1:andl d7,d5 |beq Lmuldf$b$den |andl d6,d2 |orl IMM (0x00100000),d2 | and put hidden bit backswap d5 |#ifndef __mcoldfire__lsrw IMM (4),d5 |#elselsrl IMM (4),d5 |#endifLmuldf$2: |#ifndef __mcoldfire__addw d5,d4 | add exponentssubw IMM (D_BIAS+1),d4 | and subtract bias (plus one)#elseaddl d5,d4 | add exponentssubl IMM (D_BIAS+1),d4 | and subtract bias (plus one)#endif| We are now ready to do the multiplication. The situation is as follows:| both a and b have bit 52 ( bit 20 of d0 and d2) set (even if they were| denormalized to start with!), which means that in the product bit 104| (which will correspond to bit 8 of the fourth long) is set.| Here we have to do the product.| To do it we have to juggle the registers back and forth, as there are not| enough to keep everything in them. So we use the address registers to keep| some intermediate data.#ifndef __mcoldfire__moveml a2-a3,sp@- | save a2 and a3 for temporary use#elsemovel a2,sp@-movel a3,sp@-movel a4,sp@-#endifmovel IMM (0),a2 | a2 is a null registermovel d4,a3 | and a3 will preserve the exponent| First, shift d2-d3 so bit 20 becomes bit 31:#ifndef __mcoldfire__rorl IMM (5),d2 | rotate d2 5 places rightswap d2 | and swap itrorl IMM (5),d3 | do the same thing with d3swap d3 |movew d3,d6 | get the rightmost 11 bits of d3andw IMM (0x07ff),d6 |orw d6,d2 | and put them into d2andw IMM (0xf800),d3 | clear those bits in d3#elsemoveq IMM (11),d7 | left shift d2 11 bitslsll d7,d2movel d3,d6 | get a copy of d3lsll d7,d3 | left shift d3 11 bitsandl IMM (0xffe00000),d6 | get the top 11 bits of d3moveq IMM (21),d7 | right shift them 21 bitslsrl d7,d6orl d6,d2 | stick them at the end of d2#endifmovel d2,d6 | move b into d6-d7movel d3,d7 | move a into d4-d5movel d0,d4 | and clear d0-d1-d2-d3 (to put result)movel d1,d5 |movel IMM (0),d3 |movel d3,d2 |movel d3,d1 |movel d3,d0 || We use a1 as counter:movel IMM (DBL_MANT_DIG-1),a1#ifndef __mcoldfire__exg d7,a1#elsemovel d7,a4movel a1,d7movel a4,a1#endif1:#ifndef __mcoldfire__exg d7,a1 | put counter back in a1#elsemovel d7,a4movel a1,d7movel a4,a1#endifaddl d3,d3 | shift sum once leftaddxl d2,d2 |addxl d1,d1 |addxl d0,d0 |addl d7,d7 |addxl d6,d6 |bcc 2f | if bit clear skip the following#ifndef __mcoldfire__exg d7,a2 |#elsemovel d7,a4movel a2,d7movel a4,a2#endifaddl d5,d3 | else add a to the sumaddxl d4,d2 |addxl d7,d1 |addxl d7,d0 |#ifndef __mcoldfire__exg d7,a2 |#elsemovel d7,a4movel a2,d7movel a4,a2#endif2:#ifndef __mcoldfire__exg d7,a1 | put counter in d7dbf d7,1b | decrement and branch#elsemovel d7,a4movel a1,d7movel a4,a1subql IMM (1),d7bpl 1b#endifmovel a3,d4 | restore exponent#ifndef __mcoldfire__moveml sp@+,a2-a3#elsemovel sp@+,a4movel sp@+,a3movel sp@+,a2#endif| Now we have the product in d0-d1-d2-d3, with bit 8 of d0 set. The| first thing to do now is to normalize it so bit 8 becomes bit| DBL_MANT_DIG-32 (to do the rounding); later we will shift right.swap d0swap d1movew d1,d0swap d2movew d2,d1swap d3movew d3,d2movew IMM (0),d3#ifndef __mcoldfire__lsrl IMM (1),d0roxrl IMM (1),d1roxrl IMM (1),d2roxrl IMM (1),d3lsrl IMM (1),d0roxrl IMM (1),d1roxrl IMM (1),d2roxrl IMM (1),d3lsrl IMM (1),d0roxrl IMM (1),d1roxrl IMM (1),d2roxrl IMM (1),d3#elsemoveq IMM (29),d6lsrl IMM (3),d3movel d2,d7lsll d6,d7orl d7,d3lsrl IMM (3),d2movel d1,d7lsll d6,d7orl d7,d2lsrl IMM (3),d1movel d0,d7lsll d6,d7orl d7,d1lsrl IMM (3),d0#endif| Now round, check for over- and underflow, and exit.movel a0,d7 | get sign bit back into d7moveq IMM (MULTIPLY),d5btst IMM (DBL_MANT_DIG+1-32),d0beq Lround$exit#ifndef __mcoldfire__lsrl IMM (1),d0roxrl IMM (1),d1addw IMM (1),d4#elselsrl IMM (1),d1btst IMM (0),d0beq 10fbset IMM (31),d110: lsrl IMM (1),d0addl IMM (1),d4#endifbra Lround$exitLmuldf$inop:moveq IMM (MULTIPLY),d5bra Ld$inopLmuldf$b$nf:moveq IMM (MULTIPLY),d5movel a0,d7 | get sign bit back into d7tstl d3 | we know d2 == 0x7ff00000, so check d3bne Ld$inop | if d3 <> 0 b is NaNbra Ld$overflow | else we have overflow (since a is finite)Lmuldf$a$nf:moveq IMM (MULTIPLY),d5movel a0,d7 | get sign bit back into d7tstl d1 | we know d0 == 0x7ff00000, so check d1bne Ld$inop | if d1 <> 0 a is NaNbra Ld$overflow | else signal overflow| If either number is zero return zero, unless the other is +/-INFINITY or| NaN, in which case we return NaN.Lmuldf$b$0:moveq IMM (MULTIPLY),d5#ifndef __mcoldfire__exg d2,d0 | put b (==0) into d0-d1exg d3,d1 | and a (with sign bit cleared) into d2-d3movel a0,d0 | set result sign#elsemovel d0,d2 | put a into d2-d3movel d1,d3movel a0,d0 | put result zero into d0-d1movq IMM(0),d1#endifbra 1fLmuldf$a$0:movel a0,d0 | set result signmovel a6@(16),d2 | put b into d2-d3 againmovel a6@(20),d3 |bclr IMM (31),d2 | clear sign bit1: cmpl IMM (0x7ff00000),d2 | check for non-finitenessbge Ld$inop | in case NaN or +/-INFINITY return NaNPICLEA SYM (_fpCCR),a0movew IMM (0),a0@#ifndef __mcoldfire__moveml sp@+,d2-d7#elsemoveml sp@,d2-d7| XXX if frame pointer is ever removed, stack pointer must| be adjusted here.#endifunlk a6rts| 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 21| (the hidden bit) is set, adjusting the exponent accordingly. We do this| to ensure that the product of the fractions is close to 1.Lmuldf$a$den:movel IMM (1),d4andl d6,d01: addl d1,d1 | shift a left until bit 20 is setaddxl d0,d0 |#ifndef __mcoldfire__subw IMM (1),d4 | and adjust exponent#elsesubl IMM (1),d4 | and adjust exponent#endifbtst IMM (20),d0 |bne Lmuldf$1 |bra 1bLmuldf$b$den:movel IMM (1),d5andl d6,d21: addl d3,d3 | shift b left until bit 20 is setaddxl d2,d2 |#ifndef __mcoldfire__subw IMM (1),d5 | and adjust exponent#elsesubql IMM (1),d5 | and adjust exponent#endifbtst IMM (20),d2 |bne Lmuldf$2 |bra 1b|=============================================================================| __divdf3|=============================================================================| double __divdf3(double, double);FUNC(__divdf3)SYM (__divdf3):#ifndef __mcoldfire__link a6,IMM (0)moveml d2-d7,sp@-#elselink a6,IMM (-24)moveml d2-d7,sp@#endifmovel a6@(8),d0 | get a into d0-d1movel a6@(12),d1 |movel a6@(16),d2 | and b into d2-d3movel a6@(20),d3 |movel d0,d7 | d7 will hold the sign of the resulteorl d2,d7 |andl IMM (0x80000000),d7movel d7,a0 | save sign into a0movel IMM (0x7ff00000),d7 | useful constant (+INFINITY)movel d7,d6 | another (mask for fraction)notl d6 |bclr IMM (31),d0 | get rid of a's sign bit 'movel d0,d4 |orl d1,d4 |beq Ldivdf$a$0 | branch if a is zeromovel d0,d4 |bclr IMM (31),d2 | get rid of b's sign bit 'movel d2,d5 |orl d3,d5 |beq Ldivdf$b$0 | branch if b is zeromovel d2,d5cmpl d7,d0 | is a big?bhi Ldivdf$inop | if a is NaN return NaNbeq Ldivdf$a$nf | if d0 == 0x7ff00000 we check d1cmpl d7,d2 | now compare b with INFINITYbhi Ldivdf$inop | if b is NaN return NaNbeq Ldivdf$b$nf | if d2 == 0x7ff00000 we check d3| Here we have both numbers finite and nonzero (and with no sign bit).| Now we get the exponents into d4 and d5 and normalize the numbers to| ensure that the ratio of the fractions is around 1. We do this by| making sure that both numbers have bit #DBL_MANT_DIG-32-1 (hidden bit)| set, even if they were denormalized to start with.| Thus, the result will satisfy: 2 > result > 1/2.andl d7,d4 | and isolate exponent in d4beq Ldivdf$a$den | if exponent is zero we have a denormalizedandl d6,d0 | and isolate fractionorl IMM (0x00100000),d0 | and put hidden bit backswap d4 | I like exponents in the first byte#ifndef __mcoldfire__lsrw IMM (4),d4 |#elselsrl IMM (4),d4 |#endifLdivdf$1: |andl d7,d5 |beq Ldivdf$b$den |andl d6,d2 |orl IMM (0x00100000),d2swap d5 |#ifndef __mcoldfire__lsrw IMM (4),d5 |#elselsrl IMM (4),d5 |#endifLdivdf$2: |#ifndef __mcoldfire__subw d5,d4 | subtract exponentsaddw IMM (D_BIAS),d4 | and add bias#elsesubl d5,d4 | subtract exponentsaddl IMM (D_BIAS),d4 | and add bias#endif| We are now ready to do the division. We have prepared things in such a way| that the ratio of the fractions will be less than 2 but greater than 1/2.| At this point the registers in use are:| d0-d1 hold a (first operand, bit DBL_MANT_DIG-32=0, bit| DBL_MANT_DIG-1-32=1)| d2-d3 hold b (second operand, bit DBL_MANT_DIG-32=1)| d4 holds the difference of the exponents, corrected by the bias| a0 holds the sign of the ratio| To do the rounding correctly we need to keep information about the| nonsignificant bits. One way to do this would be to do the division| using four registers; another is to use two registers (as originally| I did), but use a sticky bit to preserve information about the| fractional part. Note that we can keep that info in a1, which is not| used.movel IMM (0),d6 | d6-d7 will hold the resultmovel d6,d7 |movel IMM (0),a1 | and a1 will hold the sticky bitmovel IMM (DBL_MANT_DIG-32+1),d51: cmpl d0,d2 | is a < b?bhi 3f | if b > a skip the followingbeq 4f | if d0==d2 check d1 and d32: subl d3,d1 |subxl d2,d0 | a <-- a - bbset d5,d6 | set the corresponding bit in d63: addl d1,d1 | shift a by 1addxl d0,d0 |#ifndef __mcoldfire__dbra d5,1b | and branch back#elsesubql IMM (1), d5bpl 1b#endifbra 5f4: cmpl d1,d3 | here d0==d2, so check d1 and d3bhi 3b | if d1 > d2 skip the subtractionbra 2b | else go do it5:| Here we have to start setting the bits in the second long.movel IMM (31),d5 | again d5 is counter1: cmpl d0,d2 | is a < b?bhi 3f | if b > a skip the followingbeq 4f | if d0==d2 check d1 and d32: subl d3,d1 |subxl d2,d0 | a <-- a - bbset d5,d7 | set the corresponding bit in d73: addl d1,d1 | shift a by 1addxl d0,d0 |#ifndef __mcoldfire__dbra d5,1b | and branch back#elsesubql IMM (1), d5bpl 1b#endifbra 5f4: cmpl d1,d3 | here d0==d2, so check d1 and d3bhi 3b | if d1 > d2 skip the subtractionbra 2b | else go do it5:| Now go ahead checking until we hit a one, which we store in d2.movel IMM (DBL_MANT_DIG),d51: cmpl d2,d0 | is a < b?bhi 4f | if b < a, exitbeq 3f | if d0==d2 check d1 and d32: addl d1,d1 | shift a by 1addxl d0,d0 |#ifndef __mcoldfire__dbra d5,1b | and branch back#elsesubql IMM (1), d5bpl 1b#endifmovel IMM (0),d2 | here no sticky bit was foundmovel d2,d3bra 5f3: cmpl d1,d3 | here d0==d2, so check d1 and d3bhi 2b | if d1 > d2 go back4:| Here put the sticky bit in d2-d3 (in the position which actually corresponds| to it; if you don't do this the algorithm loses in some cases). 'movel IMM (0),d2movel d2,d3#ifndef __mcoldfire__subw IMM (DBL_MANT_DIG),d5addw IMM (63),d5cmpw IMM (31),d5#elsesubl IMM (DBL_MANT_DIG),d5addl IMM (63),d5cmpl IMM (31),d5#endifbhi 2f1: bset d5,d3bra 5f#ifndef __mcoldfire__subw IMM (32),d5#elsesubl IMM (32),d5#endif2: bset d5,d25:| Finally we are finished! Move the longs in the address registers to| their final destination:movel d6,d0movel d7,d1movel IMM (0),d3| Here we have finished the division, with the result in d0-d1-d2-d3, with| 2^21 <= d6 < 2^23. Thus bit 23 is not set, but bit 22 could be set.| If it is not, then definitely bit 21 is set. Normalize so bit 22 is| not set:btst IMM (DBL_MANT_DIG-32+1),d0beq 1f#ifndef __mcoldfire__lsrl IMM (1),d0roxrl IMM (1),d1roxrl IMM (1),d2roxrl IMM (1),d3addw IMM (1),d4#elselsrl IMM (1),d3btst IMM (0),d2beq 10fbset IMM (31),d310: lsrl IMM (1),d2btst IMM (0),d1beq 11fbset IMM (31),d211: lsrl IMM (1),d1btst IMM (0),d0beq 12fbset IMM (31),d112: lsrl IMM (1),d0addl IMM (1),d4#endif1:| Now round, check for over- and underflow, and exit.movel a0,d7 | restore sign bit to d7moveq IMM (DIVIDE),d5bra Lround$exitLdivdf$inop:moveq IMM (DIVIDE),d5bra Ld$inopLdivdf$a$0:| If a is zero check to see whether b is zero also. In that case return| NaN; then check if b is NaN, and return NaN also in that case. Else| return a properly signed zero.moveq IMM (DIVIDE),d5bclr IMM (31),d2 |movel d2,d4 |orl d3,d4 |beq Ld$inop | if b is also zero return NaNcmpl IMM (0x7ff00000),d2 | check for NaNbhi Ld$inop |blt 1f |tstl d3 |bne Ld$inop |1: movel a0,d0 | else return signed zeromoveq IMM(0),d1 |PICLEA SYM (_fpCCR),a0 | clear exception flagsmovew IMM (0),a0@ |#ifndef __mcoldfire__moveml sp@+,d2-d7 |#elsemoveml sp@,d2-d7 || XXX if frame pointer is ever removed, stack pointer must| be adjusted here.#endifunlk a6 |rts |Ldivdf$b$0:moveq IMM (DIVIDE),d5| If we got here a is not zero. Check if a is NaN; in that case return NaN,| else return +/-INFINITY. Remember that a is in d0 with the sign bit| cleared already.movel a0,d7 | put a's sign bit back in d7 'cmpl IMM (0x7ff00000),d0 | compare d0 with INFINITYbhi Ld$inop | if larger it is NaNtstl d1 |bne Ld$inop |bra Ld$div$0 | else signal DIVIDE_BY_ZEROLdivdf$b$nf:moveq IMM (DIVIDE),d5| If d2 == 0x7ff00000 we have to check d3.tstl d3 |bne Ld$inop | if d3 <> 0, b is NaNbra Ld$underflow | else b is +/-INFINITY, so signal underflowLdivdf$a$nf:moveq IMM (DIVIDE),d5| If d0 == 0x7ff00000 we have to check d1.tstl d1 |bne Ld$inop | if d1 <> 0, a is NaN| If a is INFINITY we have to check bcmpl d7,d2 | compare b with INFINITYbge Ld$inop | if b is NaN or INFINITY return NaNtstl d3 |bne Ld$inop |bra Ld$overflow | else return overflow| If a number is denormalized we put an exponent of 1 but do not put the| bit back into the fraction.Ldivdf$a$den:movel IMM (1),d4andl d6,d01: addl d1,d1 | shift a left until bit 20 is setaddxl d0,d0#ifndef __mcoldfire__subw IMM (1),d4 | and adjust exponent#elsesubl IMM (1),d4 | and adjust exponent#endifbtst IMM (DBL_MANT_DIG-32-1),d0bne Ldivdf$1bra 1bLdivdf$b$den:movel IMM (1),d5andl d6,d21: addl d3,d3 | shift b left until bit 20 is setaddxl d2,d2#ifndef __mcoldfire__subw IMM (1),d5 | and adjust exponent#elsesubql IMM (1),d5 | and adjust exponent#endifbtst IMM (DBL_MANT_DIG-32-1),d2bne Ldivdf$2bra 1bLround$exit:| This is a common exit point for __muldf3 and __divdf3. When they enter| this point the sign of the result is in d7, the result in d0-d1, normalized| so that 2^21 <= d0 < 2^22, and the exponent is in the lower byte of d4.| First check for underlow in the exponent:#ifndef __mcoldfire__cmpw IMM (-DBL_MANT_DIG-1),d4#elsecmpl IMM (-DBL_MANT_DIG-1),d4#endifblt Ld$underflow| It could happen that the exponent is less than 1, in which case the| number is denormalized. In this case we shift right and adjust the| exponent until it becomes 1 or the fraction is zero (in the latter case| we signal underflow and return zero).movel d7,a0 |movel IMM (0),d6 | use d6-d7 to collect bits flushed rightmovel d6,d7 | use d6-d7 to collect bits flushed right#ifndef __mcoldfire__cmpw IMM (1),d4 | if the exponent is less than 1 we#elsecmpl IMM (1),d4 | if the exponent is less than 1 we#endifbge 2f | have to shift right (denormalize)1:#ifndef __mcoldfire__addw IMM (1),d4 | adjust the exponentlsrl IMM (1),d0 | shift right onceroxrl IMM (1),d1 |roxrl IMM (1),d2 |roxrl IMM (1),d3 |roxrl IMM (1),d6 |roxrl IMM (1),d7 |cmpw IMM (1),d4 | is the exponent 1 already?#elseaddl IMM (1),d4 | adjust the exponentlsrl IMM (1),d7btst IMM (0),d6beq 13fbset IMM (31),d713: lsrl IMM (1),d6btst IMM (0),d3beq 14fbset IMM (31),d614: lsrl IMM (1),d3btst IMM (0),d2beq 10fbset IMM (31),d310: lsrl IMM (1),d2btst IMM (0),d1beq 11fbset IMM (31),d211: lsrl IMM (1),d1btst IMM (0),d0beq 12fbset IMM (31),d112: lsrl IMM (1),d0cmpl IMM (1),d4 | is the exponent 1 already?#endifbeq 2f | if not loop backbra 1b |bra Ld$underflow | safety check, shouldn't execute '2: orl d6,d2 | this is a trick so we don't lose 'orl d7,d3 | the bits which were flushed rightmovel a0,d7 | get back sign bit into d7| Now call the rounding routine (which takes care of denormalized numbers):lea pc@(Lround$0),a0 | to return from rounding routinePICLEA SYM (_fpCCR),a1 | check the rounding mode#ifdef __mcoldfire__clrl d6#endifmovew a1@(6),d6 | rounding mode in d6beq Lround$to$nearest#ifndef __mcoldfire__cmpw IMM (ROUND_TO_PLUS),d6#elsecmpl IMM (ROUND_TO_PLUS),d6#endifbhi Lround$to$minusblt Lround$to$zerobra Lround$to$plusLround$0:| Here we have a correctly rounded result (either normalized or denormalized).| Here we should have either a normalized number or a denormalized one, and| the exponent is necessarily larger or equal to 1 (so we don't have to '| check again for underflow!). We have to check for overflow or for a| denormalized number (which also signals underflow).| Check for overflow (i.e., exponent >= 0x7ff).#ifndef __mcoldfire__cmpw IMM (0x07ff),d4#elsecmpl IMM (0x07ff),d4#endifbge Ld$overflow| Now check for a denormalized number (exponent==0):movew d4,d4beq Ld$den1:| Put back the exponents and sign and return.#ifndef __mcoldfire__lslw IMM (4),d4 | exponent back to fourth byte#elselsll IMM (4),d4 | exponent back to fourth byte#endifbclr IMM (DBL_MANT_DIG-32-1),d0swap d0 | and put back exponent#ifndef __mcoldfire__orw d4,d0 |#elseorl d4,d0 |#endifswap d0 |orl d7,d0 | and sign alsoPICLEA SYM (_fpCCR),a0movew IMM (0),a0@#ifndef __mcoldfire__moveml sp@+,d2-d7#elsemoveml sp@,d2-d7| XXX if frame pointer is ever removed, stack pointer must| be adjusted here.#endifunlk a6rts|=============================================================================| __negdf2|=============================================================================| double __negdf2(double, double);FUNC(__negdf2)SYM (__negdf2):#ifndef __mcoldfire__link a6,IMM (0)moveml d2-d7,sp@-#elselink a6,IMM (-24)moveml d2-d7,sp@#endifmoveq IMM (NEGATE),d5movel a6@(8),d0 | get number to negate in d0-d1movel a6@(12),d1 |bchg IMM (31),d0 | negatemovel d0,d2 | make a positive copy (for the tests)bclr IMM (31),d2 |movel d2,d4 | check for zeroorl d1,d4 |beq 2f | if zero (either sign) return +zerocmpl IMM (0x7ff00000),d2 | compare to +INFINITYblt 1f | if finite, returnbhi Ld$inop | if larger (fraction not zero) is NaNtstl d1 | if d2 == 0x7ff00000 check d1bne Ld$inop |movel d0,d7 | else get sign and return INFINITYandl IMM (0x80000000),d7bra Ld$infty1: PICLEA SYM (_fpCCR),a0movew IMM (0),a0@#ifndef __mcoldfire__moveml sp@+,d2-d7#elsemoveml sp@,d2-d7| XXX if frame pointer is ever removed, stack pointer must| be adjusted here.#endifunlk a6rts2: bclr IMM (31),d0bra 1b|=============================================================================| __cmpdf2|=============================================================================GREATER = 1LESS = -1EQUAL = 0| int __cmpdf2_internal(double, double, int);SYM (__cmpdf2_internal):#ifndef __mcoldfire__link a6,IMM (0)moveml d2-d7,sp@- | save registers#elselink a6,IMM (-24)moveml d2-d7,sp@#endifmoveq IMM (COMPARE),d5movel a6@(8),d0 | get first operandmovel a6@(12),d1 |movel a6@(16),d2 | get second operandmovel 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 d2movel d2,d7 |bclr IMM (31),d2 |cmpl IMM (0x7ff00000),d0 | check for a == NaNbhi Lcmpd$inop | if d0 > 0x7ff00000, a is NaNbeq Lcmpdf$a$nf | if equal can be INFINITY, so check d1movel d0,d4 | copy into d4 to test for zeroorl d1,d4 |beq Lcmpdf$a$0 |Lcmpdf$0:cmpl IMM (0x7ff00000),d2 | check for b == NaNbhi Lcmpd$inop | if d2 > 0x7ff00000, b is NaNbeq Lcmpdf$b$nf | if equal can be INFINITY, so check d3movel d2,d4 |orl d3,d4 |beq Lcmpdf$b$0 |Lcmpdf$1:| Check the signseorl d6,d7bpl 1f| If the signs are not equal check if a >= 0tstl d6bpl Lcmpdf$a$gt$b | if (a >= 0 && b < 0) => a > bbmi Lcmpdf$b$gt$a | if (a < 0 && b >= 0) => a < b1:| If the signs are equal check for < 0tstl d6bpl 1f| If both are negative exchange them#ifndef __mcoldfire__exg d0,d2exg d1,d3#elsemovel d0,d7movel d2,d0movel d7,d2movel d1,d7movel d3,d1movel d7,d3#endif1:| Now that they are positive we just compare them as longs (does this also| work for denormalized numbers?).cmpl d0,d2bhi 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,d3bhi Lcmpdf$b$gt$a | |b| > |a|bne Lcmpdf$a$gt$b | |b| < |a|| If we got here a == b.movel IMM (EQUAL),d0#ifndef __mcoldfire__moveml sp@+,d2-d7 | put back the registers#elsemoveml sp@,d2-d7| XXX if frame pointer is ever removed, stack pointer must| be adjusted here.#endifunlk a6rtsLcmpdf$a$gt$b:movel IMM (GREATER),d0#ifndef __mcoldfire__moveml sp@+,d2-d7 | put back the registers#elsemoveml sp@,d2-d7| XXX if frame pointer is ever removed, stack pointer must| be adjusted here.#endifunlk a6rtsLcmpdf$b$gt$a:movel IMM (LESS),d0#ifndef __mcoldfire__moveml sp@+,d2-d7 | put back the registers#elsemoveml sp@,d2-d7| XXX if frame pointer is ever removed, stack pointer must| be adjusted here.#endifunlk a6rtsLcmpdf$a$0:bclr IMM (31),d6bra Lcmpdf$0Lcmpdf$b$0:bclr IMM (31),d7bra Lcmpdf$1Lcmpdf$a$nf:tstl d1bne Ld$inopbra Lcmpdf$0Lcmpdf$b$nf:tstl d3bne Ld$inopbra Lcmpdf$1Lcmpd$inop:movl a6@(24),d0moveq IMM (INEXACT_RESULT+INVALID_OPERATION),d7moveq IMM (DOUBLE_FLOAT),d6PICJUMP $_exception_handler| int __cmpdf2(double, double);FUNC(__cmpdf2)SYM (__cmpdf2):link a6,IMM (0)pea 1movl a6@(20),sp@-movl a6@(16),sp@-movl a6@(12),sp@-movl a6@(8),sp@-PICCALL SYM (__cmpdf2_internal)unlk a6rts|=============================================================================| 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),d0bne 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 __mcoldfire__cmpw IMM (1),d4 | remember that the exponent is at least one#elsecmpl IMM (1),d4 | remember that the exponent is at least one#endifbeq 2f | an exponent of one means denormalizedaddl d3,d3 | else shift and adjust the exponentaddxl d2,d2 |addxl d1,d1 |addxl d0,d0 |#ifndef __mcoldfire__dbra d4,1b |#elsesubql IMM (1), d4bpl 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 anythingorl d2,d3 | is delta == 1?bne 1f | if so round to evenmovel d1,d3 |andl IMM (2),d3 | bit 1 is the last significant bitmovel IMM (0),d2 |addl d3,d1 |addxl d2,d0 |bra 2f |1: movel IMM (1),d3 | else add 1movel IMM (0),d2 |addl d3,d1 |addxl d2,d0| Shift right once (because we used bit #DBL_MANT_DIG-32!).2:#ifndef __mcoldfire__lsrl IMM (1),d0roxrl IMM (1),d1#elselsrl IMM (1),d1btst IMM (0),d0beq 10fbset 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),d0beq 1f#ifndef __mcoldfire__lsrl IMM (1),d0roxrl IMM (1),d1addw IMM (1),d4#elselsrl IMM (1),d1btst IMM (0),d0beq 10fbset IMM (31),d110: lsrl IMM (1),d0addl 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),d0beq 1fjmp a0@1: movel IMM (0),d4jmp 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).globl SYM (__cmpsf2_internal).hidden SYM (__cmpsf2_internal)| These are common routines to return and signal exceptions..text.evenLf$den:| Return and signal a denormalized numberorl d7,d0moveq IMM (INEXACT_RESULT+UNDERFLOW),d7moveq IMM (SINGLE_FLOAT),d6PICJUMP $_exception_handlerLf$infty:Lf$overflow:| Return a properly signed INFINITY and set the exception flagsmovel IMM (INFINITY),d0orl d7,d0moveq IMM (INEXACT_RESULT+OVERFLOW),d7moveq IMM (SINGLE_FLOAT),d6PICJUMP $_exception_handlerLf$underflow:| Return 0 and set the exception flagsmoveq IMM (0),d0moveq IMM (INEXACT_RESULT+UNDERFLOW),d7moveq IMM (SINGLE_FLOAT),d6PICJUMP $_exception_handlerLf$inop:| Return a quiet NaN and set the exception flagsmovel IMM (QUIET_NaN),d0moveq IMM (INEXACT_RESULT+INVALID_OPERATION),d7moveq IMM (SINGLE_FLOAT),d6PICJUMP $_exception_handlerLf$div$0:| Return a properly signed INFINITY and set the exception flagsmovel IMM (INFINITY),d0orl d7,d0moveq IMM (INEXACT_RESULT+DIVIDE_BY_ZERO),d7moveq IMM (SINGLE_FLOAT),d6PICJUMP $_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);FUNC(__subsf3)SYM (__subsf3):bchg IMM (31),sp@(8) | change sign of second operand| and fall through|=============================================================================| __addsf3|=============================================================================| float __addsf3(float, float);FUNC(__addsf3)SYM (__addsf3):#ifndef __mcoldfire__link a6,IMM (0) | everything will be done in registersmoveml d2-d7,sp@- | save all data registers but d0-d1#elselink a6,IMM (-24)moveml d2-d7,sp@#endifmovel a6@(8),d0 | get first operandmovel a6@(12),d1 | get second operandmovel d0,a0 | get d0's sign bit 'addl d0,d0 | check and clear sign bit of abeq Laddsf$b | if zero return second operandmovel d1,a1 | save b's sign bit 'addl d1,d1 | get rid of sign bitbeq Laddsf$a | if zero return first operand| Get the exponents and check for denormalized and/or infinity.movel IMM (0x00ffffff),d4 | mask to get fractionmovel IMM (0x01000000),d5 | mask to put hidden bit backmovel d0,d6 | save a to get exponentandl d4,d0 | get fraction in d0notl d4 | make d4 into a mask for the exponentandl d4,d6 | get exponent in d6beq Laddsf$a$den | branch if a is denormalizedcmpl d4,d6 | check for INFINITY or NaNbeq Laddsf$nfswap d6 | put exponent into first wordorl 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 d7andl d4,d7 |beq Laddsf$b$den | branch if b is denormalizedcmpl d4,d7 | check for INFINITY or NaNbeq Laddsf$nfswap d7 | put exponent into first wordnotl d4 | make d4 into a mask for the fractionandl d4,d1 | get fraction in d1orl 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 summovel IMM (0),d1 | and clear the new onesmovel 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 __mcoldfire__cmpw d6,d7 | compare exponents#elsecmpl d6,d7 | compare exponents#endifbeq Laddsf$3 | if equal don't shift 'bhi 5f | branch if second exponent largest1:subl d6,d7 | keep the largest exponentnegl d7#ifndef __mcoldfire__lsrw IMM (8),d7 | put difference in lower byte#elselsrl IMM (8),d7 | put difference in lower byte#endif| if difference is too large we don't shift (actually, we can just exit) '#ifndef __mcoldfire__cmpw IMM (FLT_MANT_DIG+2),d7#elsecmpl IMM (FLT_MANT_DIG+2),d7#endifbge Laddsf$b$small#ifndef __mcoldfire__cmpw IMM (16),d7 | if difference >= 16 swap#elsecmpl IMM (16),d7 | if difference >= 16 swap#endifbge 4f2:#ifndef __mcoldfire__subw IMM (1),d7#elsesubql IMM (1), d7#endif3:#ifndef __mcoldfire__lsrl IMM (1),d2 | shift right second operandroxrl IMM (1),d3dbra d7,3b#elselsrl IMM (1),d3btst IMM (0),d2beq 10fbset IMM (31),d310: lsrl IMM (1),d2subql IMM (1), d7bpl 3b#endifbra Laddsf$34:movew d2,d3swap d3movew d3,d2swap d2#ifndef __mcoldfire__subw IMM (16),d7#elsesubl IMM (16),d7#endifbne 2b | if still more bits, go back to normal casebra Laddsf$35:#ifndef __mcoldfire__exg d6,d7 | exchange the exponents#elseeorl d6,d7eorl d7,d6eorl d6,d7#endifsubl d6,d7 | keep the largest exponentnegl d7 |#ifndef __mcoldfire__lsrw IMM (8),d7 | put difference in lower byte#elselsrl IMM (8),d7 | put difference in lower byte#endif| if difference is too large we don't shift (and exit!) '#ifndef __mcoldfire__cmpw IMM (FLT_MANT_DIG+2),d7#elsecmpl IMM (FLT_MANT_DIG+2),d7#endifbge Laddsf$a$small#ifndef __mcoldfire__cmpw IMM (16),d7 | if difference >= 16 swap#elsecmpl IMM (16),d7 | if difference >= 16 swap#endifbge 8f6:#ifndef __mcoldfire__subw IMM (1),d7#elsesubl IMM (1),d7#endif7:#ifndef __mcoldfire__lsrl IMM (1),d0 | shift right first operandroxrl IMM (1),d1dbra d7,7b#elselsrl IMM (1),d1btst IMM (0),d0beq 10fbset IMM (31),d110: lsrl IMM (1),d0subql IMM (1),d7bpl 7b#endifbra Laddsf$38:movew d0,d1swap d1movew d1,d0swap d0#ifndef __mcoldfire__subw IMM (16),d7#elsesubl IMM (16),d7#endifbne 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#ifndef __mcoldfire__exg d6,a0 | get signs backexg d7,a1 | and save the exponents#elsemovel d6,d4movel a0,d6movel d4,a0movel d7,d4movel a1,d7movel d4,a1#endifeorl d6,d7 | combine sign bitsbmi Lsubsf$0 | if negative a and b have opposite| sign so we actually subtract the| numbers| Here we have both positive or both negative#ifndef __mcoldfire__exg d6,a0 | now we have the exponent in d6#elsemovel d6,d4movel a0,d6movel d4,a0#endifmovel a0,d7 | and sign in d7andl IMM (0x80000000),d7| Here we do the addition.addl d3,d1addxl 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#ifndef __mcoldfire__lsrw IMM (8),d2#elselsrl IMM (8),d2#endif| 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),d0beq 1f#ifndef __mcoldfire__lsrl IMM (1),d0roxrl IMM (1),d1#elselsrl IMM (1),d1btst IMM (0),d0beq 10fbset IMM (31),d110: lsrl IMM (1),d0#endifaddl IMM (1),d21:lea pc@(Laddsf$4),a0 | to return from rounding routinePICLEA SYM (_fpCCR),a1 | check the rounding mode#ifdef __mcoldfire__clrl d6#endifmovew a1@(6),d6 | rounding mode in d6beq Lround$to$nearest#ifndef __mcoldfire__cmpw IMM (ROUND_TO_PLUS),d6#elsecmpl IMM (ROUND_TO_PLUS),d6#endifbhi Lround$to$minusblt Lround$to$zerobra Lround$to$plusLaddsf$4:| Put back the exponent, but check for overflow.#ifndef __mcoldfire__cmpw IMM (0xff),d2#elsecmpl IMM (0xff),d2#endifbhi 1fbclr IMM (FLT_MANT_DIG-1),d0#ifndef __mcoldfire__lslw IMM (7),d2#elselsll IMM (7),d2#endifswap d2orl d2,d0bra Laddsf$ret1:moveq IMM (ADD),d5bra 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 d7andl IMM (0x80000000),d7subl d3,d1 | result in d0-d1subxl d2,d0 |beq Laddsf$ret | if zero just exitbpl 1f | if positive skip the followingbchg IMM (31),d7 | change sign bit in d7negl d1negxl d01:#ifndef __mcoldfire__exg d2,a0 | now we have the exponent in d2lsrw IMM (8),d2 | put it in the first byte#elsemovel d2,d4movel a0,d2movel d4,a0lsrl IMM (8),d2 | put it in the first byte#endif| 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 pc@(Lsubsf$1),a0 | to return from rounding routinePICLEA SYM (_fpCCR),a1 | check the rounding mode#ifdef __mcoldfire__clrl d6#endifmovew a1@(6),d6 | rounding mode in d6beq Lround$to$nearest#ifndef __mcoldfire__cmpw IMM (ROUND_TO_PLUS),d6#elsecmpl IMM (ROUND_TO_PLUS),d6#endifbhi Lround$to$minusblt Lround$to$zerobra Lround$to$plusLsubsf$1:| Put back the exponent (we can't have overflow!). 'bclr IMM (FLT_MANT_DIG-1),d0#ifndef __mcoldfire__lslw IMM (7),d2#elselsll IMM (7),d2#endifswap d2orl d2,d0bra 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),d0PICLEA SYM (_fpCCR),a0movew IMM (0),a0@#ifndef __mcoldfire__moveml sp@+,d2-d7 | restore data registers#elsemoveml sp@,d2-d7| XXX if frame pointer is ever removed, stack pointer must| be adjusted here.#endifunlk a6 | and returnrtsLaddsf$b$small:movel a6@(8),d0PICLEA SYM (_fpCCR),a0movew IMM (0),a0@#ifndef __mcoldfire__moveml sp@+,d2-d7 | restore data registers#elsemoveml sp@,d2-d7| XXX if frame pointer is ever removed, stack pointer must| be adjusted here.#endifunlk a6 | and returnrts| If the numbers are denormalized remember to put exponent equal to 1.Laddsf$a$den:movel d5,d6 | d5 contains 0x01000000swap d6bra Laddsf$1Laddsf$b$den:movel d5,d7swap d7notl 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),d0cmpl IMM (0x80000000),d0 | Check if b is -0bne 1fmovel a0,d7andl IMM (0x80000000),d7 | Use the sign of aclrl d0bra Laddsf$retLaddsf$a:| Return a (if b is zero).movel a6@(8),d01:moveq IMM (ADD),d5| We have to check for NaN and +/-infty.movel d0,d7andl IMM (0x80000000),d7 | put sign in d7bclr IMM (31),d0 | clear signcmpl IMM (INFINITY),d0 | check for infty or NaNbge 2fmovel d0,d0 | check for zero (we do this because we don't 'bne Laddsf$ret | want to return -0 by mistakebclr IMM (31),d7 | if zero be sure to clear signbra Laddsf$ret | if everything OK just return2:| The value to be returned is either +/-infty or NaNandl IMM (0x007fffff),d0 | check for NaNbne Lf$inop | if mantissa not zero is NaNbra 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).PICLEA SYM (_fpCCR),a0movew IMM (0),a0@orl d7,d0 | put sign bit#ifndef __mcoldfire__moveml sp@+,d2-d7 | restore data registers#elsemoveml sp@,d2-d7| XXX if frame pointer is ever removed, stack pointer must| be adjusted here.#endifunlk a6 | and returnrtsLaddsf$ret$den:| Return a denormalized number (for addition we don't signal underflow) 'lsrl IMM (1),d0 | remember to shift right back oncebra 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:moveq 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 wemovel a6@(12),d1 | did some processing already)movel IMM (INFINITY),d4 | useful constant (INFINITY)movel d0,d2 | save sign bitsmovel d1,d3bclr IMM (31),d0 | clear sign bitsbclr 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$inopcmpl 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 bitsbmi 1fmovel d0,d7andl IMM (0x80000000),d7 | get (common) sign bitbra 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 NaNmovel d0,d7andl IMM (0x80000000),d7 | get a's sign bit 'cmpl d4,d0 | test now for infinitybeq Lf$infty | if a is INFINITY return with this signbchg IMM (31),d7 | else we know b is INFINITY and hasbra Lf$infty | the opposite sign|=============================================================================| __mulsf3|=============================================================================| float __mulsf3(float, float);FUNC(__mulsf3)SYM (__mulsf3):#ifndef __mcoldfire__link a6,IMM (0)moveml d2-d7,sp@-#elselink a6,IMM (-24)moveml d2-d7,sp@#endifmovel a6@(8),d0 | get a into d0movel a6@(12),d1 | and b into d1movel d0,d7 | d7 will hold the sign of the producteorl d1,d7 |andl IMM (0x80000000),d7movel 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 backbclr IMM (31),d0 | get rid of a's sign bit 'movel d0,d2 |beq Lmulsf$a$0 | branch if a is zerobclr IMM (31),d1 | get rid of b's sign bit 'movel d1,d3 |beq Lmulsf$b$0 | branch if b is zerocmpl d6,d0 | is a big?bhi Lmulsf$inop | if a is NaN return NaNbeq Lmulsf$inf | if a is INFINITY we have to check bcmpl d6,d1 | now compare b with INFINITYbhi 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 d2beq Lmulsf$a$den | if exponent is zero we have a denormalizedandl d5,d0 | and isolate fractionorl d4,d0 | and put hidden bit backswap d2 | I like exponents in the first byte#ifndef __mcoldfire__lsrw IMM (7),d2 |#elselsrl IMM (7),d2 |#endifLmulsf$1: | numberandl d6,d3 |beq Lmulsf$b$den |andl d5,d1 |orl d4,d1 |swap d3 |#ifndef __mcoldfire__lsrw IMM (7),d3 |#elselsrl IMM (7),d3 |#endifLmulsf$2: |#ifndef __mcoldfire__addw d3,d2 | add exponentssubw IMM (F_BIAS+1),d2 | and subtract bias (plus one)#elseaddl d3,d2 | add exponentssubl IMM (F_BIAS+1),d2 | and subtract bias (plus one)#endif| 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 d6movel d0,d5 | first operand in d4-d5movel IMM (0),d4movel d4,d1 | the sums will go in d0-d1movel 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):moveq IMM (FLT_MANT_DIG-1),d31: addl d1,d1 | shift sumaddxl d0,d0lsll IMM (1),d6 | get bit bnbcc 2f | if not set skip sumaddl d5,d1 | add aaddxl d4,d02:#ifndef __mcoldfire__dbf d3,1b | loop back#elsesubql IMM (1),d3bpl 1b#endif| 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).#ifndef __mcoldfire__rorl IMM (6),d1swap d1movew d1,d3andw IMM (0x03ff),d3andw IMM (0xfd00),d1#elsemovel d1,d3lsll IMM (8),d1addl d1,d1addl d1,d1moveq IMM (22),d5lsrl d5,d3orl d3,d1andl IMM (0xfffffd00),d1#endiflsll IMM (8),d0addl d0,d0addl d0,d0#ifndef __mcoldfire__orw d3,d0#elseorl d3,d0#endifmoveq IMM (MULTIPLY),d5btst IMM (FLT_MANT_DIG+1),d0beq Lround$exit#ifndef __mcoldfire__lsrl IMM (1),d0roxrl IMM (1),d1addw IMM (1),d2#elselsrl IMM (1),d1btst IMM (0),d0beq 10fbset IMM (31),d110: lsrl IMM (1),d0addql IMM (1),d2#endifbra Lround$exitLmulsf$inop:moveq IMM (MULTIPLY),d5bra Lf$inopLmulsf$overflow:moveq IMM (MULTIPLY),d5bra Lf$overflowLmulsf$inf:moveq 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 NaNbra 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 a6@(8),d1 | get a again to check for non-finitenessbra 1fLmulsf$a$0:movel a6@(12),d1 | get b again to check for non-finiteness1: bclr IMM (31),d1 | clear sign bitcmpl IMM (INFINITY),d1 | and check for a large exponentbge Lf$inop | if b is +/-INFINITY or NaN return NaNmovel d7,d0 | else return signed zeroPICLEA SYM (_fpCCR),a0 |movew IMM (0),a0@ |#ifndef __mcoldfire__moveml sp@+,d2-d7 |#elsemoveml sp@,d2-d7| XXX if frame pointer is ever removed, stack pointer must| be adjusted here.#endifunlk 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),d2andl d5,d01: addl d0,d0 | shift a left (until bit 23 is set)#ifndef __mcoldfire__subw IMM (1),d2 | and adjust exponent#elsesubql IMM (1),d2 | and adjust exponent#endifbtst IMM (FLT_MANT_DIG-1),d0bne Lmulsf$1 |bra 1b | else loop backLmulsf$b$den:movel IMM (1),d3andl d5,d11: addl d1,d1 | shift b left until bit 23 is set#ifndef __mcoldfire__subw IMM (1),d3 | and adjust exponent#elsesubql IMM (1),d3 | and adjust exponent#endifbtst IMM (FLT_MANT_DIG-1),d1bne Lmulsf$2 |bra 1b | else loop back|=============================================================================| __divsf3|=============================================================================| float __divsf3(float, float);FUNC(__divsf3)SYM (__divsf3):#ifndef __mcoldfire__link a6,IMM (0)moveml d2-d7,sp@-#elselink a6,IMM (-24)moveml d2-d7,sp@#endifmovel a6@(8),d0 | get a into d0movel a6@(12),d1 | and b into d1movel d0,d7 | d7 will hold the sign of the resulteorl 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 backbclr IMM (31),d0 | get rid of a's sign bit 'movel d0,d2 |beq Ldivsf$a$0 | branch if a is zerobclr IMM (31),d1 | get rid of b's sign bit 'movel d1,d3 |beq Ldivsf$b$0 | branch if b is zerocmpl d6,d0 | is a big?bhi Ldivsf$inop | if a is NaN return NaNbeq Ldivsf$inf | if a is INFINITY we have to check bcmpl d6,d1 | now compare b with INFINITYbhi Ldivsf$inop | if b is NaN return NaNbeq Ldivsf$underflow| Here we have both numbers finite and nonzero (and with no sign bit).| Now we get the exponents into d2 and d3 and normalize the numbers to| ensure that the ratio of the fractions is close to 1. We do this by| making sure that bit #FLT_MANT_DIG-1 (hidden bit) is set.andl d6,d2 | and isolate exponent in d2beq Ldivsf$a$den | if exponent is zero we have a denormalizedandl d5,d0 | and isolate fractionorl d4,d0 | and put hidden bit backswap d2 | I like exponents in the first byte#ifndef __mcoldfire__lsrw IMM (7),d2 |#elselsrl IMM (7),d2 |#endifLdivsf$1: |andl d6,d3 |beq Ldivsf$b$den |andl d5,d1 |orl d4,d1 |swap d3 |#ifndef __mcoldfire__lsrw IMM (7),d3 |#elselsrl IMM (7),d3 |#endifLdivsf$2: |#ifndef __mcoldfire__subw d3,d2 | subtract exponentsaddw IMM (F_BIAS),d2 | and add bias#elsesubl d3,d2 | subtract exponentsaddl IMM (F_BIAS),d2 | and add bias#endif| We are now ready to do the division. We have prepared things in such a way| that the ratio of the fractions will be less than 2 but greater than 1/2.| At this point the registers in use are:| d0 holds a (first operand, bit FLT_MANT_DIG=0, bit FLT_MANT_DIG-1=1)| d1 holds b (second operand, bit FLT_MANT_DIG=1)| d2 holds the difference of the exponents, corrected by the bias| d7 holds the sign of the ratio| d4, d5, d6 hold some constantsmovel d7,a0 | d6-d7 will hold the ratio of the fractionsmovel IMM (0),d6 |movel d6,d7moveq IMM (FLT_MANT_DIG+1),d31: cmpl d0,d1 | is a < b?bhi 2f |bset d3,d6 | set a bit in d6subl d1,d0 | if a >= b a <-- a-bbeq 3f | if a is zero, exit2: addl d0,d0 | multiply a by 2#ifndef __mcoldfire__dbra d3,1b#elsesubql IMM (1),d3bpl 1b#endif| Now we keep going to set the sticky bit ...moveq IMM (FLT_MANT_DIG),d31: cmpl d0,d1ble 2faddl d0,d0#ifndef __mcoldfire__dbra d3,1b#elsesubql IMM(1),d3bpl 1b#endifmovel IMM (0),d1bra 3f2: movel IMM (0),d1#ifndef __mcoldfire__subw IMM (FLT_MANT_DIG),d3addw IMM (31),d3#elsesubl IMM (FLT_MANT_DIG),d3addl IMM (31),d3#endifbset d3,d13:movel d6,d0 | put the ratio in d0-d1movel a0,d7 | get sign back| Because of the normalization we did before we are guaranteed that| d0 is smaller than 2^26 but larger than 2^24. Thus bit 26 is not set,| bit 25 could be set, and if it is not set then bit 24 is necessarily set.btst IMM (FLT_MANT_DIG+1),d0beq 1f | if it is not set, then bit 24 is setlsrl IMM (1),d0 |#ifndef __mcoldfire__addw IMM (1),d2 |#elseaddl IMM (1),d2 |#endif1:| Now round, check for over- and underflow, and exit.moveq IMM (DIVIDE),d5bra Lround$exitLdivsf$inop:moveq IMM (DIVIDE),d5bra Lf$inopLdivsf$overflow:moveq IMM (DIVIDE),d5bra Lf$overflowLdivsf$underflow:moveq IMM (DIVIDE),d5bra Lf$underflowLdivsf$a$0:moveq IMM (DIVIDE),d5| If a is zero check to see whether b is zero also. In that case return| NaN; then check if b is NaN, and return NaN also in that case. Else| return a properly signed zero.andl IMM (0x7fffffff),d1 | clear sign bit and test bbeq Lf$inop | if b is also zero return NaNcmpl IMM (INFINITY),d1 | check for NaNbhi Lf$inop |movel d7,d0 | else return signed zeroPICLEA SYM (_fpCCR),a0 |movew IMM (0),a0@ |#ifndef __mcoldfire__moveml sp@+,d2-d7 |#elsemoveml sp@,d2-d7 || XXX if frame pointer is ever removed, stack pointer must| be adjusted here.#endifunlk a6 |rts |Ldivsf$b$0:moveq IMM (DIVIDE),d5| If we got here a is not zero. Check if a is NaN; in that case return NaN,| else return +/-INFINITY. Remember that a is in d0 with the sign bit| cleared already.cmpl IMM (INFINITY),d0 | compare d0 with INFINITYbhi Lf$inop | if larger it is NaNbra Lf$div$0 | else signal DIVIDE_BY_ZEROLdivsf$inf:moveq IMM (DIVIDE),d5| If a is INFINITY we have to check bcmpl IMM (INFINITY),d1 | compare b with INFINITYbge Lf$inop | if b is NaN or INFINITY return NaNbra Lf$overflow | else return overflow| If a number is denormalized we put an exponent of 1 but do not put the| bit back into the fraction.Ldivsf$a$den:movel IMM (1),d2andl d5,d01: addl d0,d0 | shift a left until bit FLT_MANT_DIG-1 is set#ifndef __mcoldfire__subw IMM (1),d2 | and adjust exponent#elsesubl IMM (1),d2 | and adjust exponent#endifbtst IMM (FLT_MANT_DIG-1),d0bne Ldivsf$1bra 1bLdivsf$b$den:movel IMM (1),d3andl d5,d11: addl d1,d1 | shift b left until bit FLT_MANT_DIG is set#ifndef __mcoldfire__subw IMM (1),d3 | and adjust exponent#elsesubl IMM (1),d3 | and adjust exponent#endifbtst IMM (FLT_MANT_DIG-1),d1bne Ldivsf$2bra 1bLround$exit:| This is a common exit point for __mulsf3 and __divsf3.| First check for underlow in the exponent:#ifndef __mcoldfire__cmpw IMM (-FLT_MANT_DIG-1),d2#elsecmpl IMM (-FLT_MANT_DIG-1),d2#endifblt Lf$underflow| It could happen that the exponent is less than 1, in which case the| number is denormalized. In this case we shift right and adjust the| exponent until it becomes 1 or the fraction is zero (in the latter case| we signal underflow and return zero).movel IMM (0),d6 | d6 is used temporarily#ifndef __mcoldfire__cmpw IMM (1),d2 | if the exponent is less than 1 we#elsecmpl IMM (1),d2 | if the exponent is less than 1 we#endifbge 2f | have to shift right (denormalize)1:#ifndef __mcoldfire__addw IMM (1),d2 | adjust the exponentlsrl IMM (1),d0 | shift right onceroxrl IMM (1),d1 |roxrl IMM (1),d6 | d6 collect bits we would lose otherwisecmpw IMM (1),d2 | is the exponent 1 already?#elseaddql IMM (1),d2 | adjust the exponentlsrl IMM (1),d6btst IMM (0),d1beq 11fbset IMM (31),d611: lsrl IMM (1),d1btst IMM (0),d0beq 10fbset IMM (31),d110: lsrl IMM (1),d0cmpl IMM (1),d2 | is the exponent 1 already?#endifbeq 2f | if not loop backbra 1b |bra Lf$underflow | safety check, shouldn't execute '2: orl d6,d1 | this is a trick so we don't lose '| the extra bits which were flushed right| Now call the rounding routine (which takes care of denormalized numbers):lea pc@(Lround$0),a0 | to return from rounding routinePICLEA SYM (_fpCCR),a1 | check the rounding mode#ifdef __mcoldfire__clrl d6#endifmovew a1@(6),d6 | rounding mode in d6beq Lround$to$nearest#ifndef __mcoldfire__cmpw IMM (ROUND_TO_PLUS),d6#elsecmpl IMM (ROUND_TO_PLUS),d6#endifbhi Lround$to$minusblt Lround$to$zerobra Lround$to$plusLround$0:| Here we have a correctly rounded result (either normalized or denormalized).| Here we should have either a normalized number or a denormalized one, and| the exponent is necessarily larger or equal to 1 (so we don't have to '| check again for underflow!). We have to check for overflow or for a| denormalized number (which also signals underflow).| Check for overflow (i.e., exponent >= 255).#ifndef __mcoldfire__cmpw IMM (0x00ff),d2#elsecmpl IMM (0x00ff),d2#endifbge Lf$overflow| Now check for a denormalized number (exponent==0).movew d2,d2beq Lf$den1:| Put back the exponents and sign and return.#ifndef __mcoldfire__lslw IMM (7),d2 | exponent back to fourth byte#elselsll IMM (7),d2 | exponent back to fourth byte#endifbclr IMM (FLT_MANT_DIG-1),d0swap d0 | and put back exponent#ifndef __mcoldfire__orw d2,d0 |#elseorl d2,d0#endifswap d0 |orl d7,d0 | and sign alsoPICLEA SYM (_fpCCR),a0movew IMM (0),a0@#ifndef __mcoldfire__moveml sp@+,d2-d7#elsemoveml sp@,d2-d7| XXX if frame pointer is ever removed, stack pointer must| be adjusted here.#endifunlk a6rts|=============================================================================| __negsf2|=============================================================================| This is trivial and could be shorter if we didn't bother checking for NaN '| and +/-INFINITY.| float __negsf2(float);FUNC(__negsf2)SYM (__negsf2):#ifndef __mcoldfire__link a6,IMM (0)moveml d2-d7,sp@-#elselink a6,IMM (-24)moveml d2-d7,sp@#endifmoveq IMM (NEGATE),d5movel a6@(8),d0 | get number to negate in d0bchg IMM (31),d0 | negatemovel d0,d1 | make a positive copybclr IMM (31),d1 |tstl d1 | check for zerobeq 2f | if zero (either sign) return +zerocmpl IMM (INFINITY),d1 | compare to +INFINITYblt 1f |bhi Lf$inop | if larger (fraction not zero) is NaNmovel d0,d7 | else get sign and return INFINITYandl IMM (0x80000000),d7bra Lf$infty1: PICLEA SYM (_fpCCR),a0movew IMM (0),a0@#ifndef __mcoldfire__moveml sp@+,d2-d7#elsemoveml sp@,d2-d7| XXX if frame pointer is ever removed, stack pointer must| be adjusted here.#endifunlk a6rts2: bclr IMM (31),d0bra 1b|=============================================================================| __cmpsf2|=============================================================================GREATER = 1LESS = -1EQUAL = 0| int __cmpsf2_internal(float, float, int);SYM (__cmpsf2_internal):#ifndef __mcoldfire__link a6,IMM (0)moveml d2-d7,sp@- | save registers#elselink a6,IMM (-24)moveml d2-d7,sp@#endifmoveq IMM (COMPARE),d5movel a6@(8),d0 | get first operandmovel a6@(12),d1 | get second operand| Check if either is NaN, and in that case return garbage and signal| INVALID_OPERATION. Check also if either is zero, and clear the signs| if necessary.movel d0,d6andl IMM (0x7fffffff),d0beq Lcmpsf$a$0cmpl IMM (0x7f800000),d0bhi Lcmpf$inopLcmpsf$1:movel d1,d7andl IMM (0x7fffffff),d1beq Lcmpsf$b$0cmpl IMM (0x7f800000),d1bhi Lcmpf$inopLcmpsf$2:| Check the signseorl d6,d7bpl 1f| If the signs are not equal check if a >= 0tstl d6bpl Lcmpsf$a$gt$b | if (a >= 0 && b < 0) => a > bbmi Lcmpsf$b$gt$a | if (a < 0 && b >= 0) => a < b1:| If the signs are equal check for < 0tstl d6bpl 1f| If both are negative exchange them#ifndef __mcoldfire__exg d0,d1#elsemovel d0,d7movel d1,d0movel d7,d1#endif1:| Now that they are positive we just compare them as longs (does this also| work for denormalized numbers?).cmpl d0,d1bhi Lcmpsf$b$gt$a | |b| > |a|bne Lcmpsf$a$gt$b | |b| < |a|| If we got here a == b.movel IMM (EQUAL),d0#ifndef __mcoldfire__moveml sp@+,d2-d7 | put back the registers#elsemoveml sp@,d2-d7#endifunlk a6rtsLcmpsf$a$gt$b:movel IMM (GREATER),d0#ifndef __mcoldfire__moveml sp@+,d2-d7 | put back the registers#elsemoveml sp@,d2-d7| XXX if frame pointer is ever removed, stack pointer must| be adjusted here.#endifunlk a6rtsLcmpsf$b$gt$a:movel IMM (LESS),d0#ifndef __mcoldfire__moveml sp@+,d2-d7 | put back the registers#elsemoveml sp@,d2-d7| XXX if frame pointer is ever removed, stack pointer must| be adjusted here.#endifunlk a6rtsLcmpsf$a$0:bclr IMM (31),d6bra Lcmpsf$1Lcmpsf$b$0:bclr IMM (31),d7bra Lcmpsf$2Lcmpf$inop:movl a6@(16),d0moveq IMM (INEXACT_RESULT+INVALID_OPERATION),d7moveq IMM (SINGLE_FLOAT),d6PICJUMP $_exception_handler| int __cmpsf2(float, float);FUNC(__cmpsf2)SYM (__cmpsf2):link a6,IMM (0)pea 1movl a6@(12),sp@-movl a6@(8),sp@-PICCALL SYM (__cmpsf2_internal)unlk a6rts|=============================================================================| rounding routines|=============================================================================| The rounding routines expect the number to be normalized in registers| d0-d1, with the exponent in register d2. 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 d2.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 (FLT_MANT_DIG),d0bne 2f | if set the number is normalized| Normalize shifting left until bit #FLT_MANT_DIG is set or the exponent| is one (remember that a denormalized number corresponds to an| exponent of -F_BIAS+1).#ifndef __mcoldfire__cmpw IMM (1),d2 | remember that the exponent is at least one#elsecmpl IMM (1),d2 | remember that the exponent is at least one#endifbeq 2f | an exponent of one means denormalizedaddl d1,d1 | else shift and adjust the exponentaddxl d0,d0 |#ifndef __mcoldfire__dbra d2,1b |#elsesubql IMM (1),d2bpl 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),d0 | is delta < 1?beq 2f | if so, do not do anythingtstl d1 | is delta == 1?bne 1f | if so round to evenmovel d0,d1 |andl IMM (2),d1 | bit 1 is the last significant bitaddl d1,d0 |bra 2f |1: movel IMM (1),d1 | else add 1addl d1,d0 || Shift right once (because we used bit #FLT_MANT_DIG!).2: lsrl IMM (1),d0| Now check again bit #FLT_MANT_DIG (rounding could have produced a| 'fraction overflow' ...).btst IMM (FLT_MANT_DIG),d0beq 1flsrl IMM (1),d0#ifndef __mcoldfire__addw IMM (1),d2#elseaddql IMM (1),d2#endif1:| If bit #FLT_MANT_DIG-1 is clear we have a denormalized number, so we| have to put the exponent to zero and return a denormalized number.btst IMM (FLT_MANT_DIG-1),d0beq 1fjmp a0@1: movel IMM (0),d2jmp a0@Lround$to$zero:Lround$to$plus:Lround$to$minus:jmp a0@#endif /* L_float */| gcc expects the routines __eqdf2, __nedf2, __gtdf2, __gedf2,| __ledf2, __ltdf2 to all return the same value as a direct call to| __cmpdf2 would. In this implementation, each of these routines| simply calls __cmpdf2. It would be more efficient to give the| __cmpdf2 routine several names, but separating them out will make it| easier to write efficient versions of these routines someday.| If the operands recompare unordered unordered __gtdf2 and __gedf2 return -1.| The other routines return 1.#ifdef L_eqdf2.textFUNC(__eqdf2).globl SYM (__eqdf2)SYM (__eqdf2):link a6,IMM (0)pea 1movl a6@(20),sp@-movl a6@(16),sp@-movl a6@(12),sp@-movl a6@(8),sp@-PICCALL SYM (__cmpdf2_internal)unlk a6rts#endif /* L_eqdf2 */#ifdef L_nedf2.textFUNC(__nedf2).globl SYM (__nedf2)SYM (__nedf2):link a6,IMM (0)pea 1movl a6@(20),sp@-movl a6@(16),sp@-movl a6@(12),sp@-movl a6@(8),sp@-PICCALL SYM (__cmpdf2_internal)unlk a6rts#endif /* L_nedf2 */#ifdef L_gtdf2.textFUNC(__gtdf2).globl SYM (__gtdf2)SYM (__gtdf2):link a6,IMM (0)pea -1movl a6@(20),sp@-movl a6@(16),sp@-movl a6@(12),sp@-movl a6@(8),sp@-PICCALL SYM (__cmpdf2_internal)unlk a6rts#endif /* L_gtdf2 */#ifdef L_gedf2.textFUNC(__gedf2).globl SYM (__gedf2)SYM (__gedf2):link a6,IMM (0)pea -1movl a6@(20),sp@-movl a6@(16),sp@-movl a6@(12),sp@-movl a6@(8),sp@-PICCALL SYM (__cmpdf2_internal)unlk a6rts#endif /* L_gedf2 */#ifdef L_ltdf2.textFUNC(__ltdf2).globl SYM (__ltdf2)SYM (__ltdf2):link a6,IMM (0)pea 1movl a6@(20),sp@-movl a6@(16),sp@-movl a6@(12),sp@-movl a6@(8),sp@-PICCALL SYM (__cmpdf2_internal)unlk a6rts#endif /* L_ltdf2 */#ifdef L_ledf2.textFUNC(__ledf2).globl SYM (__ledf2)SYM (__ledf2):link a6,IMM (0)pea 1movl a6@(20),sp@-movl a6@(16),sp@-movl a6@(12),sp@-movl a6@(8),sp@-PICCALL SYM (__cmpdf2_internal)unlk a6rts#endif /* L_ledf2 */| The comments above about __eqdf2, et. al., also apply to __eqsf2,| et. al., except that the latter call __cmpsf2 rather than __cmpdf2.#ifdef L_eqsf2.textFUNC(__eqsf2).globl SYM (__eqsf2)SYM (__eqsf2):link a6,IMM (0)pea 1movl a6@(12),sp@-movl a6@(8),sp@-PICCALL SYM (__cmpsf2_internal)unlk a6rts#endif /* L_eqsf2 */#ifdef L_nesf2.textFUNC(__nesf2).globl SYM (__nesf2)SYM (__nesf2):link a6,IMM (0)pea 1movl a6@(12),sp@-movl a6@(8),sp@-PICCALL SYM (__cmpsf2_internal)unlk a6rts#endif /* L_nesf2 */#ifdef L_gtsf2.textFUNC(__gtsf2).globl SYM (__gtsf2)SYM (__gtsf2):link a6,IMM (0)pea -1movl a6@(12),sp@-movl a6@(8),sp@-PICCALL SYM (__cmpsf2_internal)unlk a6rts#endif /* L_gtsf2 */#ifdef L_gesf2.textFUNC(__gesf2).globl SYM (__gesf2)SYM (__gesf2):link a6,IMM (0)pea -1movl a6@(12),sp@-movl a6@(8),sp@-PICCALL SYM (__cmpsf2_internal)unlk a6rts#endif /* L_gesf2 */#ifdef L_ltsf2.textFUNC(__ltsf2).globl SYM (__ltsf2)SYM (__ltsf2):link a6,IMM (0)pea 1movl a6@(12),sp@-movl a6@(8),sp@-PICCALL SYM (__cmpsf2_internal)unlk a6rts#endif /* L_ltsf2 */#ifdef L_lesf2.textFUNC(__lesf2).globl SYM (__lesf2)SYM (__lesf2):link a6,IMM (0)pea 1movl a6@(12),sp@-movl a6@(8),sp@-PICCALL SYM (__cmpsf2_internal)unlk a6rts#endif /* L_lesf2 */#if defined (__ELF__) && defined (__linux__)/* Make stack non-executable for ELF linux targets. */.section .note.GNU-stack,"",@progbits#endif
