|
|
1.1 root 1: /* libgcc1 routines for 68000 w/o floating-point hardware. */
2: /* Copyright (C) 1994 Free Software Foundation, Inc.
3:
4: This file is free software; you can redistribute it and/or modify it
5: under the terms of the GNU General Public License as published by the
6: Free Software Foundation; either version 2, or (at your option) any
7: later version.
8:
9: In addition to the permissions in the GNU General Public License, the
10: Free Software Foundation gives you unlimited permission to link the
11: compiled version of this file with other programs, and to distribute
12: those programs without any restriction coming from the use of this
13: file. (The General Public License restrictions do apply in other
14: respects; for example, they cover modification of the file, and
15: distribution when not linked into another program.)
16:
17: This file is distributed in the hope that it will be useful, but
18: WITHOUT ANY WARRANTY; without even the implied warranty of
19: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20: General Public License for more details.
21:
22: You should have received a copy of the GNU General Public License
23: along with this program; see the file COPYING. If not, write to
24: the Free Software Foundation, 59 Temple Place - Suite 330,
25: Boston, MA 02111-1307, USA. */
26:
27: /* As a special exception, if you link this library with files
28: compiled with GCC to produce an executable, this does not cause
29: the resulting executable to be covered by the GNU General Public License.
30: This exception does not however invalidate any other reasons why
31: the executable file might be covered by the GNU General Public License. */
32:
33: /* Use this one for any 680x0; assumes no floating point hardware.
34: The trailing " '" appearing on some lines is for ANSI preprocessors. Yuk.
35: Some of this code comes from MINIX, via the folks at ericsson.
36: D. V. Henkel-Wallace ([email protected]) Fete Bastille, 1992
37: */
38:
39: /* These are predefined by new versions of GNU cpp. */
40:
41: #ifndef __USER_LABEL_PREFIX__
42: #define __USER_LABEL_PREFIX__ _
43: #endif
44:
45: #ifndef __REGISTER_PREFIX__
46: #define __REGISTER_PREFIX__
47: #endif
48:
49: #ifndef __IMMEDIATE_PREFIX__
50: #define __IMMEDIATE_PREFIX__ #
51: #endif
52:
53: /* ANSI concatenation macros. */
54:
55: #define CONCAT1(a, b) CONCAT2(a, b)
56: #define CONCAT2(a, b) a ## b
57:
58: /* Use the right prefix for global labels. */
59:
60: #define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
61:
62: /* Use the right prefix for registers. */
63:
64: #define REG(x) CONCAT1 (__REGISTER_PREFIX__, x)
65:
66: /* Use the right prefix for immediate values. */
67:
68: #define IMM(x) CONCAT1 (__IMMEDIATE_PREFIX__, x)
69:
70: #define d0 REG (d0)
71: #define d1 REG (d1)
72: #define d2 REG (d2)
73: #define d3 REG (d3)
74: #define d4 REG (d4)
75: #define d5 REG (d5)
76: #define d6 REG (d6)
77: #define d7 REG (d7)
78: #define a0 REG (a0)
79: #define a1 REG (a1)
80: #define a2 REG (a2)
81: #define a3 REG (a3)
82: #define a4 REG (a4)
83: #define a5 REG (a5)
84: #define a6 REG (a6)
85: #define fp REG (fp)
86: #define sp REG (sp)
87:
88: #ifdef L_floatex
89:
90: | This is an attempt at a decent floating point (single, double and
91: | extended double) code for the GNU C compiler. It should be easy to
92: | adapt to other compilers (but beware of the local labels!).
93:
94: | Starting date: 21 October, 1990
95:
96: | It is convenient to introduce the notation (s,e,f) for a floating point
97: | number, where s=sign, e=exponent, f=fraction. We will call a floating
98: | point number fpn to abbreviate, independently of the precision.
99: | Let MAX_EXP be in each case the maximum exponent (255 for floats, 1023
100: | for doubles and 16383 for long doubles). We then have the following
101: | different cases:
102: | 1. Normalized fpns have 0 < e < MAX_EXP. They correspond to
103: | (-1)^s x 1.f x 2^(e-bias-1).
104: | 2. Denormalized fpns have e=0. They correspond to numbers of the form
105: | (-1)^s x 0.f x 2^(-bias).
106: | 3. +/-INFINITY have e=MAX_EXP, f=0.
107: | 4. Quiet NaN (Not a Number) have all bits set.
108: | 5. Signaling NaN (Not a Number) have s=0, e=MAX_EXP, f=1.
109:
110: |=============================================================================
111: | exceptions
112: |=============================================================================
113:
114: | This is the floating point condition code register (_fpCCR):
115: |
116: | struct {
117: | short _exception_bits;
118: | short _trap_enable_bits;
119: | short _sticky_bits;
120: | short _rounding_mode;
121: | short _format;
122: | short _last_operation;
123: | union {
124: | float sf;
125: | double df;
126: | } _operand1;
127: | union {
128: | float sf;
129: | double df;
130: | } _operand2;
131: | } _fpCCR;
132:
133: .data
134: .even
135:
136: .globl SYM (_fpCCR)
137:
138: SYM (_fpCCR):
139: __exception_bits:
140: .word 0
141: __trap_enable_bits:
142: .word 0
143: __sticky_bits:
144: .word 0
145: __rounding_mode:
146: .word ROUND_TO_NEAREST
147: __format:
148: .word NIL
149: __last_operation:
150: .word NOOP
151: __operand1:
152: .long 0
153: .long 0
154: __operand2:
155: .long 0
156: .long 0
157:
158: | Offsets:
159: EBITS = __exception_bits - SYM (_fpCCR)
160: TRAPE = __trap_enable_bits - SYM (_fpCCR)
161: STICK = __sticky_bits - SYM (_fpCCR)
162: ROUND = __rounding_mode - SYM (_fpCCR)
163: FORMT = __format - SYM (_fpCCR)
164: LASTO = __last_operation - SYM (_fpCCR)
165: OPER1 = __operand1 - SYM (_fpCCR)
166: OPER2 = __operand2 - SYM (_fpCCR)
167:
168: | The following exception types are supported:
169: INEXACT_RESULT = 0x0001
170: UNDERFLOW = 0x0002
171: OVERFLOW = 0x0004
172: DIVIDE_BY_ZERO = 0x0008
173: INVALID_OPERATION = 0x0010
174:
175: | The allowed rounding modes are:
176: UNKNOWN = -1
177: ROUND_TO_NEAREST = 0 | round result to nearest representable value
178: ROUND_TO_ZERO = 1 | round result towards zero
179: ROUND_TO_PLUS = 2 | round result towards plus infinity
180: ROUND_TO_MINUS = 3 | round result towards minus infinity
181:
182: | The allowed values of format are:
183: NIL = 0
184: SINGLE_FLOAT = 1
185: DOUBLE_FLOAT = 2
186: LONG_FLOAT = 3
187:
188: | The allowed values for the last operation are:
189: NOOP = 0
190: ADD = 1
191: MULTIPLY = 2
192: DIVIDE = 3
193: NEGATE = 4
194: COMPARE = 5
195: EXTENDSFDF = 6
196: TRUNCDFSF = 7
197:
198: |=============================================================================
199: | __clear_sticky_bits
200: |=============================================================================
201:
202: | The sticky bits are normally not cleared (thus the name), whereas the
203: | exception type and exception value reflect the last computation.
204: | This routine is provided to clear them (you can also write to _fpCCR,
205: | since it is globally visible).
206:
207: .globl SYM (__clear_sticky_bit)
208:
209: .text
210: .even
211:
212: | void __clear_sticky_bits(void);
213: SYM (__clear_sticky_bit):
214: lea SYM (_fpCCR),a0
215: movew IMM (0),a0@(STICK)
216: rts
217:
218: |=============================================================================
219: | $_exception_handler
220: |=============================================================================
221:
222: .globl $_exception_handler
223:
224: .text
225: .even
226:
227: | This is the common exit point if an exception occurs.
228: | NOTE: it is NOT callable from C!
229: | It expects the exception type in d7, the format (SINGLE_FLOAT,
230: | DOUBLE_FLOAT or LONG_FLOAT) in d6, and the last operation code in d5.
231: | It sets the corresponding exception and sticky bits, and the format.
232: | Depending on the format if fills the corresponding slots for the
233: | operands which produced the exception (all this information is provided
234: | so if you write your own exception handlers you have enough information
235: | to deal with the problem).
236: | Then checks to see if the corresponding exception is trap-enabled,
237: | in which case it pushes the address of _fpCCR and traps through
238: | trap FPTRAP (15 for the moment).
239:
240: FPTRAP = 15
241:
242: $_exception_handler:
243: lea SYM (_fpCCR),a0
244: movew d7,a0@(EBITS) | set __exception_bits
245: orw d7,a0@(STICK) | and __sticky_bits
246: movew d6,a0@(FORMT) | and __format
247: movew d5,a0@(LASTO) | and __last_operation
248:
249: | Now put the operands in place:
250: cmpw IMM (SINGLE_FLOAT),d6
251: beq 1f
252: movel a6@(8),a0@(OPER1)
253: movel a6@(12),a0@(OPER1+4)
254: movel a6@(16),a0@(OPER2)
255: movel a6@(20),a0@(OPER2+4)
256: bra 2f
257: 1: movel a6@(8),a0@(OPER1)
258: movel a6@(12),a0@(OPER2)
259: 2:
260: | And check whether the exception is trap-enabled:
261: andw a0@(TRAPE),d7 | is exception trap-enabled?
262: beq 1f | no, exit
263: pea SYM (_fpCCR) | yes, push address of _fpCCR
264: trap IMM (FPTRAP) | and trap
265: 1: moveml sp@+,d2-d7 | restore data registers
266: unlk a6 | and return
267: rts
268: #endif /* L_floatex */
269:
270: #ifdef L_mulsi3
271: .text
272: .proc
273: .globl SYM (__mulsi3)
274: SYM (__mulsi3):
275: movew sp@(4), d0 /* x0 -> d0 */
276: muluw sp@(10), d0 /* x0*y1 */
277: movew sp@(6), d1 /* x1 -> d1 */
278: muluw sp@(8), d1 /* x1*y0 */
279: addw d1, d0
280: swap d0
281: clrw d0
282: movew sp@(6), d1 /* x1 -> d1 */
283: muluw sp@(10), d1 /* x1*y1 */
284: addl d1, d0
285:
286: rts
287: #endif /* L_mulsi3 */
288:
289: #ifdef L_udivsi3
290: .text
291: .proc
292: .globl SYM (__udivsi3)
293: SYM (__udivsi3):
294: movel d2, sp@-
295: movel sp@(12), d1 /* d1 = divisor */
296: movel sp@(8), d0 /* d0 = dividend */
297:
298: cmpl IMM (0x10000), d1 /* divisor >= 2 ^ 16 ? */
299: jcc L3 /* then try next algorithm */
300: movel d0, d2
301: clrw d2
302: swap d2
303: divu d1, d2 /* high quotient in lower word */
304: movew d2, d0 /* save high quotient */
305: swap d0
306: movew sp@(10), d2 /* get low dividend + high rest */
307: divu d1, d2 /* low quotient */
308: movew d2, d0
309: jra L6
310:
311: L3: movel d1, d2 /* use d2 as divisor backup */
312: L4: lsrl IMM (1), d1 /* shift divisor */
313: lsrl IMM (1), d0 /* shift dividend */
314: cmpl IMM (0x10000), d1 /* still divisor >= 2 ^ 16 ? */
315: jcc L4
316: divu d1, d0 /* now we have 16 bit divisor */
317: andl IMM (0xffff), d0 /* mask out divisor, ignore remainder */
318:
319: /* Multiply the 16 bit tentative quotient with the 32 bit divisor. Because of
320: the operand ranges, this might give a 33 bit product. If this product is
321: greater than the dividend, the tentative quotient was too large. */
322: movel d2, d1
323: mulu d0, d1 /* low part, 32 bits */
324: swap d2
325: mulu d0, d2 /* high part, at most 17 bits */
326: swap d2 /* align high part with low part */
327: btst IMM (0), d2 /* high part 17 bits? */
328: jne L5 /* if 17 bits, quotient was too large */
329: addl d2, d1 /* add parts */
330: jcs L5 /* if sum is 33 bits, quotient was too large */
331: cmpl sp@(8), d1 /* compare the sum with the dividend */
332: jls L6 /* if sum > dividend, quotient was too large */
333: L5: subql IMM (1), d0 /* adjust quotient */
334:
335: L6: movel sp@+, d2
336: rts
337: #endif /* L_udivsi3 */
338:
339: #ifdef L_divsi3
340: .text
341: .proc
342: .globl SYM (__divsi3)
343: SYM (__divsi3):
344: movel d2, sp@-
345:
346: moveb IMM (1), d2 /* sign of result stored in d2 (=1 or =-1) */
347: movel sp@(12), d1 /* d1 = divisor */
348: jpl L1
349: negl d1
350: negb d2 /* change sign because divisor <0 */
351: L1: movel sp@(8), d0 /* d0 = dividend */
352: jpl L2
353: negl d0
354: negb d2
355:
356: L2: movel d1, sp@-
357: movel d0, sp@-
358: jbsr SYM (__udivsi3) /* divide abs(dividend) by abs(divisor) */
359: addql IMM (8), sp
360:
361: tstb d2
362: jpl L3
363: negl d0
364:
365: L3: movel sp@+, d2
366: rts
367: #endif /* L_divsi3 */
368:
369: #ifdef L_umodsi3
370: .text
371: .proc
372: .globl SYM (__umodsi3)
373: SYM (__umodsi3):
374: movel sp@(8), d1 /* d1 = divisor */
375: movel sp@(4), d0 /* d0 = dividend */
376: movel d1, sp@-
377: movel d0, sp@-
378: jbsr SYM (__udivsi3)
379: addql IMM (8), sp
380: movel sp@(8), d1 /* d1 = divisor */
381: movel d1, sp@-
382: movel d0, sp@-
383: jbsr SYM (__mulsi3) /* d0 = (a/b)*b */
384: addql IMM (8), sp
385: movel sp@(4), d1 /* d1 = dividend */
386: subl d0, d1 /* d1 = a - (a/b)*b */
387: movel d1, d0
388: rts
389: #endif /* L_umodsi3 */
390:
391: #ifdef L_modsi3
392: .text
393: .proc
394: .globl SYM (__modsi3)
395: SYM (__modsi3):
396: movel sp@(8), d1 /* d1 = divisor */
397: movel sp@(4), d0 /* d0 = dividend */
398: movel d1, sp@-
399: movel d0, sp@-
400: jbsr SYM (__divsi3)
401: addql IMM (8), sp
402: movel sp@(8), d1 /* d1 = divisor */
403: movel d1, sp@-
404: movel d0, sp@-
405: jbsr SYM (__mulsi3) /* d0 = (a/b)*b */
406: addql IMM (8), sp
407: movel sp@(4), d1 /* d1 = dividend */
408: subl d0, d1 /* d1 = a - (a/b)*b */
409: movel d1, d0
410: rts
411: #endif /* L_modsi3 */
412:
413:
414: #ifdef L_double
415:
416: .globl SYM (_fpCCR)
417: .globl $_exception_handler
418:
419: QUIET_NaN = 0xffffffff
420:
421: D_MAX_EXP = 0x07ff
422: D_BIAS = 1022
423: DBL_MAX_EXP = D_MAX_EXP - D_BIAS
424: DBL_MIN_EXP = 1 - D_BIAS
425: DBL_MANT_DIG = 53
426:
427: INEXACT_RESULT = 0x0001
428: UNDERFLOW = 0x0002
429: OVERFLOW = 0x0004
430: DIVIDE_BY_ZERO = 0x0008
431: INVALID_OPERATION = 0x0010
432:
433: DOUBLE_FLOAT = 2
434:
435: NOOP = 0
436: ADD = 1
437: MULTIPLY = 2
438: DIVIDE = 3
439: NEGATE = 4
440: COMPARE = 5
441: EXTENDSFDF = 6
442: TRUNCDFSF = 7
443:
444: UNKNOWN = -1
445: ROUND_TO_NEAREST = 0 | round result to nearest representable value
446: ROUND_TO_ZERO = 1 | round result towards zero
447: ROUND_TO_PLUS = 2 | round result towards plus infinity
448: ROUND_TO_MINUS = 3 | round result towards minus infinity
449:
450: | Entry points:
451:
452: .globl SYM (__adddf3)
453: .globl SYM (__subdf3)
454: .globl SYM (__muldf3)
455: .globl SYM (__divdf3)
456: .globl SYM (__negdf2)
457: .globl SYM (__cmpdf2)
458:
459: .text
460: .even
461:
462: | These are common routines to return and signal exceptions.
463:
464: Ld$den:
465: | Return and signal a denormalized number
466: orl d7,d0
467: movew IMM (UNDERFLOW),d7
468: orw IMM (INEXACT_RESULT),d7
469: movew IMM (DOUBLE_FLOAT),d6
470: jmp $_exception_handler
471:
472: Ld$infty:
473: Ld$overflow:
474: | Return a properly signed INFINITY and set the exception flags
475: movel IMM (0x7ff00000),d0
476: movel IMM (0),d1
477: orl d7,d0
478: movew IMM (OVERFLOW),d7
479: orw IMM (INEXACT_RESULT),d7
480: movew IMM (DOUBLE_FLOAT),d6
481: jmp $_exception_handler
482:
483: Ld$underflow:
484: | Return 0 and set the exception flags
485: movel IMM (0),d0
486: movel d0,d1
487: movew IMM (UNDERFLOW),d7
488: orw IMM (INEXACT_RESULT),d7
489: movew IMM (DOUBLE_FLOAT),d6
490: jmp $_exception_handler
491:
492: Ld$inop:
493: | Return a quiet NaN and set the exception flags
494: movel IMM (QUIET_NaN),d0
495: movel d0,d1
496: movew IMM (INVALID_OPERATION),d7
497: orw IMM (INEXACT_RESULT),d7
498: movew IMM (DOUBLE_FLOAT),d6
499: jmp $_exception_handler
500:
501: Ld$div$0:
502: | Return a properly signed INFINITY and set the exception flags
503: movel IMM (0x7ff00000),d0
504: movel IMM (0),d1
505: orl d7,d0
506: movew IMM (DIVIDE_BY_ZERO),d7
507: orw IMM (INEXACT_RESULT),d7
508: movew IMM (DOUBLE_FLOAT),d6
509: jmp $_exception_handler
510:
511: |=============================================================================
512: |=============================================================================
513: | double precision routines
514: |=============================================================================
515: |=============================================================================
516:
517: | A double precision floating point number (double) has the format:
518: |
519: | struct _double {
520: | unsigned int sign : 1; /* sign bit */
521: | unsigned int exponent : 11; /* exponent, shifted by 126 */
522: | unsigned int fraction : 52; /* fraction */
523: | } double;
524: |
525: | Thus sizeof(double) = 8 (64 bits).
526: |
527: | All the routines are callable from C programs, and return the result
528: | in the register pair d0-d1. They also preserve all registers except
529: | d0-d1 and a0-a1.
530:
531: |=============================================================================
532: | __subdf3
533: |=============================================================================
534:
535: | double __subdf3(double, double);
536: SYM (__subdf3):
537: bchg IMM (31),sp@(12) | change sign of second operand
538: | and fall through, so we always add
539: |=============================================================================
540: | __adddf3
541: |=============================================================================
542:
543: | double __adddf3(double, double);
544: SYM (__adddf3):
545: link a6,IMM (0) | everything will be done in registers
546: moveml d2-d7,sp@- | save all data registers and a2 (but d0-d1)
547: movel a6@(8),d0 | get first operand
548: movel a6@(12),d1 |
549: movel a6@(16),d2 | get second operand
550: movel a6@(20),d3 |
551:
552: movel d0,d7 | get d0's sign bit in d7 '
553: addl d1,d1 | check and clear sign bit of a, and gain one
554: addxl d0,d0 | bit of extra precision
555: beq Ladddf$b | if zero return second operand
556:
557: movel d2,d6 | save sign in d6
558: addl d3,d3 | get rid of sign bit and gain one bit of
559: addxl d2,d2 | extra precision
560: beq Ladddf$a | if zero return first operand
561:
562: andl IMM (0x80000000),d7 | isolate a's sign bit '
563: swap d6 | and also b's sign bit '
564: andw IMM (0x8000),d6 |
565: orw d6,d7 | and combine them into d7, so that a's sign '
566: | bit is in the high word and b's is in the '
567: | low word, so d6 is free to be used
568: movel d7,a0 | now save d7 into a0, so d7 is free to
569: | be used also
570:
571: | Get the exponents and check for denormalized and/or infinity.
572:
573: movel IMM (0x001fffff),d6 | mask for the fraction
574: movel IMM (0x00200000),d7 | mask to put hidden bit back
575:
576: movel d0,d4 |
577: andl d6,d0 | get fraction in d0
578: notl d6 | make d6 into mask for the exponent
579: andl d6,d4 | get exponent in d4
580: beq Ladddf$a$den | branch if a is denormalized
581: cmpl d6,d4 | check for INFINITY or NaN
582: beq Ladddf$nf |
583: orl d7,d0 | and put hidden bit back
584: Ladddf$1:
585: swap d4 | shift right exponent so that it starts
586: lsrw IMM (5),d4 | in bit 0 and not bit 20
587: | Now we have a's exponent in d4 and fraction in d0-d1 '
588: movel d2,d5 | save b to get exponent
589: andl d6,d5 | get exponent in d5
590: beq Ladddf$b$den | branch if b is denormalized
591: cmpl d6,d5 | check for INFINITY or NaN
592: beq Ladddf$nf
593: notl d6 | make d6 into mask for the fraction again
594: andl d6,d2 | and get fraction in d2
595: orl d7,d2 | and put hidden bit back
596: Ladddf$2:
597: swap d5 | shift right exponent so that it starts
598: lsrw IMM (5),d5 | in bit 0 and not bit 20
599:
600: | Now we have b's exponent in d5 and fraction in d2-d3. '
601:
602: | The situation now is as follows: the signs are combined in a0, the
603: | numbers are in d0-d1 (a) and d2-d3 (b), and the exponents in d4 (a)
604: | and d5 (b). To do the rounding correctly we need to keep all the
605: | bits until the end, so we need to use d0-d1-d2-d3 for the first number
606: | and d4-d5-d6-d7 for the second. To do this we store (temporarily) the
607: | exponents in a2-a3.
608:
609: moveml a2-a3,sp@- | save the address registers
610:
611: movel d4,a2 | save the exponents
612: movel d5,a3 |
613:
614: movel IMM (0),d7 | and move the numbers around
615: movel d7,d6 |
616: movel d3,d5 |
617: movel d2,d4 |
618: movel d7,d3 |
619: movel d7,d2 |
620:
621: | Here we shift the numbers until the exponents are the same, and put
622: | the largest exponent in a2.
623: exg d4,a2 | get exponents back
624: exg d5,a3 |
625: cmpw d4,d5 | compare the exponents
626: beq Ladddf$3 | if equal don't shift '
627: bhi 9f | branch if second exponent is higher
628:
629: | Here we have a's exponent larger than b's, so we have to shift b. We do
630: | this by using as counter d2:
631: 1: movew d4,d2 | move largest exponent to d2
632: subw d5,d2 | and subtract second exponent
633: exg d4,a2 | get back the longs we saved
634: exg d5,a3 |
635: | if difference is too large we don't shift (actually, we can just exit) '
636: cmpw IMM (DBL_MANT_DIG+2),d2
637: bge Ladddf$b$small
638: cmpw IMM (32),d2 | if difference >= 32, shift by longs
639: bge 5f
640: 2: cmpw IMM (16),d2 | if difference >= 16, shift by words
641: bge 6f
642: bra 3f | enter dbra loop
643:
644: 4: lsrl IMM (1),d4
645: roxrl IMM (1),d5
646: roxrl IMM (1),d6
647: roxrl IMM (1),d7
648: 3: dbra d2,4b
649: movel IMM (0),d2
650: movel d2,d3
651: bra Ladddf$4
652: 5:
653: movel d6,d7
654: movel d5,d6
655: movel d4,d5
656: movel IMM (0),d4
657: subw IMM (32),d2
658: bra 2b
659: 6:
660: movew d6,d7
661: swap d7
662: movew d5,d6
663: swap d6
664: movew d4,d5
665: swap d5
666: movew IMM (0),d4
667: swap d4
668: subw IMM (16),d2
669: bra 3b
670:
671: 9: exg d4,d5
672: movew d4,d6
673: subw d5,d6 | keep d5 (largest exponent) in d4
674: exg d4,a2
675: exg d5,a3
676: | if difference is too large we don't shift (actually, we can just exit) '
677: cmpw IMM (DBL_MANT_DIG+2),d6
678: bge Ladddf$a$small
679: cmpw IMM (32),d6 | if difference >= 32, shift by longs
680: bge 5f
681: 2: cmpw IMM (16),d6 | if difference >= 16, shift by words
682: bge 6f
683: bra 3f | enter dbra loop
684:
685: 4: lsrl IMM (1),d0
686: roxrl IMM (1),d1
687: roxrl IMM (1),d2
688: roxrl IMM (1),d3
689: 3: dbra d6,4b
690: movel IMM (0),d7
691: movel d7,d6
692: bra Ladddf$4
693: 5:
694: movel d2,d3
695: movel d1,d2
696: movel d0,d1
697: movel IMM (0),d0
698: subw IMM (32),d6
699: bra 2b
700: 6:
701: movew d2,d3
702: swap d3
703: movew d1,d2
704: swap d2
705: movew d0,d1
706: swap d1
707: movew IMM (0),d0
708: swap d0
709: subw IMM (16),d6
710: bra 3b
711: Ladddf$3:
712: exg d4,a2
713: exg d5,a3
714: Ladddf$4:
715: | Now we have the numbers in d0--d3 and d4--d7, the exponent in a2, and
716: | the signs in a4.
717:
718: | Here we have to decide whether to add or subtract the numbers:
719: exg d7,a0 | get the signs
720: exg d6,a3 | a3 is free to be used
721: movel d7,d6 |
722: movew IMM (0),d7 | get a's sign in d7 '
723: swap d6 |
724: movew IMM (0),d6 | and b's sign in d6 '
725: eorl d7,d6 | compare the signs
726: bmi Lsubdf$0 | if the signs are different we have
727: | to subtract
728: exg d7,a0 | else we add the numbers
729: exg d6,a3 |
730: addl d7,d3 |
731: addxl d6,d2 |
732: addxl d5,d1 |
733: addxl d4,d0 |
734:
735: movel a2,d4 | return exponent to d4
736: movel a0,d7 |
737: andl IMM (0x80000000),d7 | d7 now has the sign
738:
739: moveml sp@+,a2-a3
740:
741: | Before rounding normalize so bit #DBL_MANT_DIG is set (we will consider
742: | the case of denormalized numbers in the rounding routine itself).
743: | As in the addition (not in the subtraction!) we could have set
744: | one more bit we check this:
745: btst IMM (DBL_MANT_DIG+1),d0
746: beq 1f
747: lsrl IMM (1),d0
748: roxrl IMM (1),d1
749: roxrl IMM (1),d2
750: roxrl IMM (1),d3
751: addw IMM (1),d4
752: 1:
753: lea Ladddf$5,a0 | to return from rounding routine
754: lea SYM (_fpCCR),a1 | check the rounding mode
755: movew a1@(6),d6 | rounding mode in d6
756: beq Lround$to$nearest
757: cmpw IMM (ROUND_TO_PLUS),d6
758: bhi Lround$to$minus
759: blt Lround$to$zero
760: bra Lround$to$plus
761: Ladddf$5:
762: | Put back the exponent and check for overflow
763: cmpw IMM (0x7ff),d4 | is the exponent big?
764: bge 1f
765: bclr IMM (DBL_MANT_DIG-1),d0
766: lslw IMM (4),d4 | put exponent back into position
767: swap d0 |
768: orw d4,d0 |
769: swap d0 |
770: bra Ladddf$ret
771: 1:
772: movew IMM (ADD),d5
773: bra Ld$overflow
774:
775: Lsubdf$0:
776: | Here we do the subtraction.
777: exg d7,a0 | put sign back in a0
778: exg d6,a3 |
779: subl d7,d3 |
780: subxl d6,d2 |
781: subxl d5,d1 |
782: subxl d4,d0 |
783: beq Ladddf$ret$1 | if zero just exit
784: bpl 1f | if positive skip the following
785: exg d7,a0 |
786: bchg IMM (31),d7 | change sign bit in d7
787: exg d7,a0 |
788: negl d3 |
789: negxl d2 |
790: negxl d1 | and negate result
791: negxl d0 |
792: 1:
793: movel a2,d4 | return exponent to d4
794: movel a0,d7
795: andl IMM (0x80000000),d7 | isolate sign bit
796: moveml sp@+,a2-a3 |
797:
798: | Before rounding normalize so bit #DBL_MANT_DIG is set (we will consider
799: | the case of denormalized numbers in the rounding routine itself).
800: | As in the addition (not in the subtraction!) we could have set
801: | one more bit we check this:
802: btst IMM (DBL_MANT_DIG+1),d0
803: beq 1f
804: lsrl IMM (1),d0
805: roxrl IMM (1),d1
806: roxrl IMM (1),d2
807: roxrl IMM (1),d3
808: addw IMM (1),d4
809: 1:
810: lea Lsubdf$1,a0 | to return from rounding routine
811: lea SYM (_fpCCR),a1 | check the rounding mode
812: movew a1@(6),d6 | rounding mode in d6
813: beq Lround$to$nearest
814: cmpw IMM (ROUND_TO_PLUS),d6
815: bhi Lround$to$minus
816: blt Lround$to$zero
817: bra Lround$to$plus
818: Lsubdf$1:
819: | Put back the exponent and sign (we don't have overflow). '
820: bclr IMM (DBL_MANT_DIG-1),d0
821: lslw IMM (4),d4 | put exponent back into position
822: swap d0 |
823: orw d4,d0 |
824: swap d0 |
825: bra Ladddf$ret
826:
827: | If one of the numbers was too small (difference of exponents >=
828: | DBL_MANT_DIG+1) we return the other (and now we don't have to '
829: | check for finiteness or zero).
830: Ladddf$a$small:
831: moveml sp@+,a2-a3
832: movel a6@(16),d0
833: movel a6@(20),d1
834: lea SYM (_fpCCR),a0
835: movew IMM (0),a0@
836: moveml sp@+,d2-d7 | restore data registers
837: unlk a6 | and return
838: rts
839:
840: Ladddf$b$small:
841: moveml sp@+,a2-a3
842: movel a6@(8),d0
843: movel a6@(12),d1
844: lea SYM (_fpCCR),a0
845: movew IMM (0),a0@
846: moveml sp@+,d2-d7 | restore data registers
847: unlk a6 | and return
848: rts
849:
850: Ladddf$a$den:
851: movel d7,d4 | d7 contains 0x00200000
852: bra Ladddf$1
853:
854: Ladddf$b$den:
855: movel d7,d5 | d7 contains 0x00200000
856: notl d6
857: bra Ladddf$2
858:
859: Ladddf$b:
860: | Return b (if a is zero)
861: movel d2,d0
862: movel d3,d1
863: bra 1f
864: Ladddf$a:
865: movel a6@(8),d0
866: movel a6@(12),d1
867: 1:
868: movew IMM (ADD),d5
869: | Check for NaN and +/-INFINITY.
870: movel d0,d7 |
871: andl IMM (0x80000000),d7 |
872: bclr IMM (31),d0 |
873: cmpl IMM (0x7ff00000),d0 |
874: bge 2f |
875: movel d0,d0 | check for zero, since we don't '
876: bne Ladddf$ret | want to return -0 by mistake
877: bclr IMM (31),d7 |
878: bra Ladddf$ret |
879: 2:
880: andl IMM (0x000fffff),d0 | check for NaN (nonzero fraction)
881: orl d1,d0 |
882: bne Ld$inop |
883: bra Ld$infty |
884:
885: Ladddf$ret$1:
886: moveml sp@+,a2-a3 | restore regs and exit
887:
888: Ladddf$ret:
889: | Normal exit.
890: lea SYM (_fpCCR),a0
891: movew IMM (0),a0@
892: orl d7,d0 | put sign bit back
893: moveml sp@+,d2-d7
894: unlk a6
895: rts
896:
897: Ladddf$ret$den:
898: | Return a denormalized number.
899: lsrl IMM (1),d0 | shift right once more
900: roxrl IMM (1),d1 |
901: bra Ladddf$ret
902:
903: Ladddf$nf:
904: movew IMM (ADD),d5
905: | This could be faster but it is not worth the effort, since it is not
906: | executed very often. We sacrifice speed for clarity here.
907: movel a6@(8),d0 | get the numbers back (remember that we
908: movel a6@(12),d1 | did some processing already)
909: movel a6@(16),d2 |
910: movel a6@(20),d3 |
911: movel IMM (0x7ff00000),d4 | useful constant (INFINITY)
912: movel d0,d7 | save sign bits
913: movel d2,d6 |
914: bclr IMM (31),d0 | clear sign bits
915: bclr IMM (31),d2 |
916: | We know that one of them is either NaN of +/-INFINITY
917: | Check for NaN (if either one is NaN return NaN)
918: cmpl d4,d0 | check first a (d0)
919: bhi Ld$inop | if d0 > 0x7ff00000 or equal and
920: bne 2f
921: tstl d1 | d1 > 0, a is NaN
922: bne Ld$inop |
923: 2: cmpl d4,d2 | check now b (d1)
924: bhi Ld$inop |
925: bne 3f
926: tstl d3 |
927: bne Ld$inop |
928: 3:
929: | Now comes the check for +/-INFINITY. We know that both are (maybe not
930: | finite) numbers, but we have to check if both are infinite whether we
931: | are adding or subtracting them.
932: eorl d7,d6 | to check sign bits
933: bmi 1f
934: andl IMM (0x80000000),d7 | get (common) sign bit
935: bra Ld$infty
936: 1:
937: | We know one (or both) are infinite, so we test for equality between the
938: | two numbers (if they are equal they have to be infinite both, so we
939: | return NaN).
940: cmpl d2,d0 | are both infinite?
941: bne 1f | if d0 <> d2 they are not equal
942: cmpl d3,d1 | if d0 == d2 test d3 and d1
943: beq Ld$inop | if equal return NaN
944: 1:
945: andl IMM (0x80000000),d7 | get a's sign bit '
946: cmpl d4,d0 | test now for infinity
947: beq Ld$infty | if a is INFINITY return with this sign
948: bchg IMM (31),d7 | else we know b is INFINITY and has
949: bra Ld$infty | the opposite sign
950:
951: |=============================================================================
952: | __muldf3
953: |=============================================================================
954:
955: | double __muldf3(double, double);
956: SYM (__muldf3):
957: link a6,IMM (0)
958: moveml d2-d7,sp@-
959: movel a6@(8),d0 | get a into d0-d1
960: movel a6@(12),d1 |
961: movel a6@(16),d2 | and b into d2-d3
962: movel a6@(20),d3 |
963: movel d0,d7 | d7 will hold the sign of the product
964: eorl d2,d7 |
965: andl IMM (0x80000000),d7 |
966: movel d7,a0 | save sign bit into a0
967: movel IMM (0x7ff00000),d7 | useful constant (+INFINITY)
968: movel d7,d6 | another (mask for fraction)
969: notl d6 |
970: bclr IMM (31),d0 | get rid of a's sign bit '
971: movel d0,d4 |
972: orl d1,d4 |
973: beq Lmuldf$a$0 | branch if a is zero
974: movel d0,d4 |
975: bclr IMM (31),d2 | get rid of b's sign bit '
976: movel d2,d5 |
977: orl d3,d5 |
978: beq Lmuldf$b$0 | branch if b is zero
979: movel d2,d5 |
980: cmpl d7,d0 | is a big?
981: bhi Lmuldf$inop | if a is NaN return NaN
982: beq Lmuldf$a$nf | we still have to check d1 and b ...
983: cmpl d7,d2 | now compare b with INFINITY
984: bhi Lmuldf$inop | is b NaN?
985: beq Lmuldf$b$nf | we still have to check d3 ...
986: | Here we have both numbers finite and nonzero (and with no sign bit).
987: | Now we get the exponents into d4 and d5.
988: andl d7,d4 | isolate exponent in d4
989: beq Lmuldf$a$den | if exponent zero, have denormalized
990: andl d6,d0 | isolate fraction
991: orl IMM (0x00100000),d0 | and put hidden bit back
992: swap d4 | I like exponents in the first byte
993: lsrw IMM (4),d4 |
994: Lmuldf$1:
995: andl d7,d5 |
996: beq Lmuldf$b$den |
997: andl d6,d2 |
998: orl IMM (0x00100000),d2 | and put hidden bit back
999: swap d5 |
1000: lsrw IMM (4),d5 |
1001: Lmuldf$2: |
1002: addw d5,d4 | add exponents
1003: subw IMM (D_BIAS+1),d4 | and subtract bias (plus one)
1004:
1005: | We are now ready to do the multiplication. The situation is as follows:
1006: | both a and b have bit 52 ( bit 20 of d0 and d2) set (even if they were
1007: | denormalized to start with!), which means that in the product bit 104
1008: | (which will correspond to bit 8 of the fourth long) is set.
1009:
1010: | Here we have to do the product.
1011: | To do it we have to juggle the registers back and forth, as there are not
1012: | enough to keep everything in them. So we use the address registers to keep
1013: | some intermediate data.
1014:
1015: moveml a2-a3,sp@- | save a2 and a3 for temporary use
1016: movel IMM (0),a2 | a2 is a null register
1017: movel d4,a3 | and a3 will preserve the exponent
1018:
1019: | First, shift d2-d3 so bit 20 becomes bit 31:
1020: rorl IMM (5),d2 | rotate d2 5 places right
1021: swap d2 | and swap it
1022: rorl IMM (5),d3 | do the same thing with d3
1023: swap d3 |
1024: movew d3,d6 | get the rightmost 11 bits of d3
1025: andw IMM (0x07ff),d6 |
1026: orw d6,d2 | and put them into d2
1027: andw IMM (0xf800),d3 | clear those bits in d3
1028:
1029: movel d2,d6 | move b into d6-d7
1030: movel d3,d7 | move a into d4-d5
1031: movel d0,d4 | and clear d0-d1-d2-d3 (to put result)
1032: movel d1,d5 |
1033: movel IMM (0),d3 |
1034: movel d3,d2 |
1035: movel d3,d1 |
1036: movel d3,d0 |
1037:
1038: | We use a1 as counter:
1039: movel IMM (DBL_MANT_DIG-1),a1
1040: exg d7,a1
1041:
1042: 1: exg d7,a1 | put counter back in a1
1043: addl d3,d3 | shift sum once left
1044: addxl d2,d2 |
1045: addxl d1,d1 |
1046: addxl d0,d0 |
1047: addl d7,d7 |
1048: addxl d6,d6 |
1049: bcc 2f | if bit clear skip the following
1050: exg d7,a2 |
1051: addl d5,d3 | else add a to the sum
1052: addxl d4,d2 |
1053: addxl d7,d1 |
1054: addxl d7,d0 |
1055: exg d7,a2 |
1056: 2: exg d7,a1 | put counter in d7
1057: dbf d7,1b | decrement and branch
1058:
1059: movel a3,d4 | restore exponent
1060: moveml sp@+,a2-a3
1061:
1062: | Now we have the product in d0-d1-d2-d3, with bit 8 of d0 set. The
1063: | first thing to do now is to normalize it so bit 8 becomes bit
1064: | DBL_MANT_DIG-32 (to do the rounding); later we will shift right.
1065: swap d0
1066: swap d1
1067: movew d1,d0
1068: swap d2
1069: movew d2,d1
1070: swap d3
1071: movew d3,d2
1072: movew IMM (0),d3
1073: lsrl IMM (1),d0
1074: roxrl IMM (1),d1
1075: roxrl IMM (1),d2
1076: roxrl IMM (1),d3
1077: lsrl IMM (1),d0
1078: roxrl IMM (1),d1
1079: roxrl IMM (1),d2
1080: roxrl IMM (1),d3
1081: lsrl IMM (1),d0
1082: roxrl IMM (1),d1
1083: roxrl IMM (1),d2
1084: roxrl IMM (1),d3
1085:
1086: | Now round, check for over- and underflow, and exit.
1087: movel a0,d7 | get sign bit back into d7
1088: movew IMM (MULTIPLY),d5
1089:
1090: btst IMM (DBL_MANT_DIG+1-32),d0
1091: beq Lround$exit
1092: lsrl IMM (1),d0
1093: roxrl IMM (1),d1
1094: addw IMM (1),d4
1095: bra Lround$exit
1096:
1097: Lmuldf$inop:
1098: movew IMM (MULTIPLY),d5
1099: bra Ld$inop
1100:
1101: Lmuldf$b$nf:
1102: movew IMM (MULTIPLY),d5
1103: movel a0,d7 | get sign bit back into d7
1104: tstl d3 | we know d2 == 0x7ff00000, so check d3
1105: bne Ld$inop | if d3 <> 0 b is NaN
1106: bra Ld$overflow | else we have overflow (since a is finite)
1107:
1108: Lmuldf$a$nf:
1109: movew IMM (MULTIPLY),d5
1110: movel a0,d7 | get sign bit back into d7
1111: tstl d1 | we know d0 == 0x7ff00000, so check d1
1112: bne Ld$inop | if d1 <> 0 a is NaN
1113: bra Ld$overflow | else signal overflow
1114:
1115: | If either number is zero return zero, unless the other is +/-INFINITY or
1116: | NaN, in which case we return NaN.
1117: Lmuldf$b$0:
1118: movew IMM (MULTIPLY),d5
1119: exg d2,d0 | put b (==0) into d0-d1
1120: exg d3,d1 | and a (with sign bit cleared) into d2-d3
1121: bra 1f
1122: Lmuldf$a$0:
1123: movel a6@(16),d2 | put b into d2-d3 again
1124: movel a6@(20),d3 |
1125: bclr IMM (31),d2 | clear sign bit
1126: 1: cmpl IMM (0x7ff00000),d2 | check for non-finiteness
1127: bge Ld$inop | in case NaN or +/-INFINITY return NaN
1128: lea SYM (_fpCCR),a0
1129: movew IMM (0),a0@
1130: moveml sp@+,d2-d7
1131: unlk a6
1132: rts
1133:
1134: | If a number is denormalized we put an exponent of 1 but do not put the
1135: | hidden bit back into the fraction; instead we shift left until bit 21
1136: | (the hidden bit) is set, adjusting the exponent accordingly. We do this
1137: | to ensure that the product of the fractions is close to 1.
1138: Lmuldf$a$den:
1139: movel IMM (1),d4
1140: andl d6,d0
1141: 1: addl d1,d1 | shift a left until bit 20 is set
1142: addxl d0,d0 |
1143: subw IMM (1),d4 | and adjust exponent
1144: btst IMM (20),d0 |
1145: bne Lmuldf$1 |
1146: bra 1b
1147:
1148: Lmuldf$b$den:
1149: movel IMM (1),d5
1150: andl d6,d2
1151: 1: addl d3,d3 | shift b left until bit 20 is set
1152: addxl d2,d2 |
1153: subw IMM (1),d5 | and adjust exponent
1154: btst IMM (20),d2 |
1155: bne Lmuldf$2 |
1156: bra 1b
1157:
1158:
1159: |=============================================================================
1160: | __divdf3
1161: |=============================================================================
1162:
1163: | double __divdf3(double, double);
1164: SYM (__divdf3):
1165: link a6,IMM (0)
1166: moveml d2-d7,sp@-
1167: movel a6@(8),d0 | get a into d0-d1
1168: movel a6@(12),d1 |
1169: movel a6@(16),d2 | and b into d2-d3
1170: movel a6@(20),d3 |
1171: movel d0,d7 | d7 will hold the sign of the result
1172: eorl d2,d7 |
1173: andl IMM (0x80000000),d7
1174: movel d7,a0 | save sign into a0
1175: movel IMM (0x7ff00000),d7 | useful constant (+INFINITY)
1176: movel d7,d6 | another (mask for fraction)
1177: notl d6 |
1178: bclr IMM (31),d0 | get rid of a's sign bit '
1179: movel d0,d4 |
1180: orl d1,d4 |
1181: beq Ldivdf$a$0 | branch if a is zero
1182: movel d0,d4 |
1183: bclr IMM (31),d2 | get rid of b's sign bit '
1184: movel d2,d5 |
1185: orl d3,d5 |
1186: beq Ldivdf$b$0 | branch if b is zero
1187: movel d2,d5
1188: cmpl d7,d0 | is a big?
1189: bhi Ldivdf$inop | if a is NaN return NaN
1190: beq Ldivdf$a$nf | if d0 == 0x7ff00000 we check d1
1191: cmpl d7,d2 | now compare b with INFINITY
1192: bhi Ldivdf$inop | if b is NaN return NaN
1193: beq Ldivdf$b$nf | if d2 == 0x7ff00000 we check d3
1194: | Here we have both numbers finite and nonzero (and with no sign bit).
1195: | Now we get the exponents into d4 and d5 and normalize the numbers to
1196: | ensure that the ratio of the fractions is around 1. We do this by
1197: | making sure that both numbers have bit #DBL_MANT_DIG-32-1 (hidden bit)
1198: | set, even if they were denormalized to start with.
1199: | Thus, the result will satisfy: 2 > result > 1/2.
1200: andl d7,d4 | and isolate exponent in d4
1201: beq Ldivdf$a$den | if exponent is zero we have a denormalized
1202: andl d6,d0 | and isolate fraction
1203: orl IMM (0x00100000),d0 | and put hidden bit back
1204: swap d4 | I like exponents in the first byte
1205: lsrw IMM (4),d4 |
1206: Ldivdf$1: |
1207: andl d7,d5 |
1208: beq Ldivdf$b$den |
1209: andl d6,d2 |
1210: orl IMM (0x00100000),d2
1211: swap d5 |
1212: lsrw IMM (4),d5 |
1213: Ldivdf$2: |
1214: subw d5,d4 | subtract exponents
1215: addw IMM (D_BIAS),d4 | and add bias
1216:
1217: | We are now ready to do the division. We have prepared things in such a way
1218: | that the ratio of the fractions will be less than 2 but greater than 1/2.
1219: | At this point the registers in use are:
1220: | d0-d1 hold a (first operand, bit DBL_MANT_DIG-32=0, bit
1221: | DBL_MANT_DIG-1-32=1)
1222: | d2-d3 hold b (second operand, bit DBL_MANT_DIG-32=1)
1223: | d4 holds the difference of the exponents, corrected by the bias
1224: | a0 holds the sign of the ratio
1225:
1226: | To do the rounding correctly we need to keep information about the
1227: | nonsignificant bits. One way to do this would be to do the division
1228: | using four registers; another is to use two registers (as originally
1229: | I did), but use a sticky bit to preserve information about the
1230: | fractional part. Note that we can keep that info in a1, which is not
1231: | used.
1232: movel IMM (0),d6 | d6-d7 will hold the result
1233: movel d6,d7 |
1234: movel IMM (0),a1 | and a1 will hold the sticky bit
1235:
1236: movel IMM (DBL_MANT_DIG-32+1),d5
1237:
1238: 1: cmpl d0,d2 | is a < b?
1239: bhi 3f | if b > a skip the following
1240: beq 4f | if d0==d2 check d1 and d3
1241: 2: subl d3,d1 |
1242: subxl d2,d0 | a <-- a - b
1243: bset d5,d6 | set the corresponding bit in d6
1244: 3: addl d1,d1 | shift a by 1
1245: addxl d0,d0 |
1246: dbra d5,1b | and branch back
1247: bra 5f
1248: 4: cmpl d1,d3 | here d0==d2, so check d1 and d3
1249: bhi 3b | if d1 > d2 skip the subtraction
1250: bra 2b | else go do it
1251: 5:
1252: | Here we have to start setting the bits in the second long.
1253: movel IMM (31),d5 | again d5 is counter
1254:
1255: 1: cmpl d0,d2 | is a < b?
1256: bhi 3f | if b > a skip the following
1257: beq 4f | if d0==d2 check d1 and d3
1258: 2: subl d3,d1 |
1259: subxl d2,d0 | a <-- a - b
1260: bset d5,d7 | set the corresponding bit in d7
1261: 3: addl d1,d1 | shift a by 1
1262: addxl d0,d0 |
1263: dbra d5,1b | and branch back
1264: bra 5f
1265: 4: cmpl d1,d3 | here d0==d2, so check d1 and d3
1266: bhi 3b | if d1 > d2 skip the subtraction
1267: bra 2b | else go do it
1268: 5:
1269: | Now go ahead checking until we hit a one, which we store in d2.
1270: movel IMM (DBL_MANT_DIG),d5
1271: 1: cmpl d2,d0 | is a < b?
1272: bhi 4f | if b < a, exit
1273: beq 3f | if d0==d2 check d1 and d3
1274: 2: addl d1,d1 | shift a by 1
1275: addxl d0,d0 |
1276: dbra d5,1b | and branch back
1277: movel IMM (0),d2 | here no sticky bit was found
1278: movel d2,d3
1279: bra 5f
1280: 3: cmpl d1,d3 | here d0==d2, so check d1 and d3
1281: bhi 2b | if d1 > d2 go back
1282: 4:
1283: | Here put the sticky bit in d2-d3 (in the position which actually corresponds
1284: | to it; if you don't do this the algorithm loses in some cases). '
1285: movel IMM (0),d2
1286: movel d2,d3
1287: subw IMM (DBL_MANT_DIG),d5
1288: addw IMM (63),d5
1289: cmpw IMM (31),d5
1290: bhi 2f
1291: 1: bset d5,d3
1292: bra 5f
1293: subw IMM (32),d5
1294: 2: bset d5,d2
1295: 5:
1296: | Finally we are finished! Move the longs in the address registers to
1297: | their final destination:
1298: movel d6,d0
1299: movel d7,d1
1300: movel IMM (0),d3
1301:
1302: | Here we have finished the division, with the result in d0-d1-d2-d3, with
1303: | 2^21 <= d6 < 2^23. Thus bit 23 is not set, but bit 22 could be set.
1304: | If it is not, then definitely bit 21 is set. Normalize so bit 22 is
1305: | not set:
1306: btst IMM (DBL_MANT_DIG-32+1),d0
1307: beq 1f
1308: lsrl IMM (1),d0
1309: roxrl IMM (1),d1
1310: roxrl IMM (1),d2
1311: roxrl IMM (1),d3
1312: addw IMM (1),d4
1313: 1:
1314: | Now round, check for over- and underflow, and exit.
1315: movel a0,d7 | restore sign bit to d7
1316: movew IMM (DIVIDE),d5
1317: bra Lround$exit
1318:
1319: Ldivdf$inop:
1320: movew IMM (DIVIDE),d5
1321: bra Ld$inop
1322:
1323: Ldivdf$a$0:
1324: | If a is zero check to see whether b is zero also. In that case return
1325: | NaN; then check if b is NaN, and return NaN also in that case. Else
1326: | return zero.
1327: movew IMM (DIVIDE),d5
1328: bclr IMM (31),d2 |
1329: movel d2,d4 |
1330: orl d3,d4 |
1331: beq Ld$inop | if b is also zero return NaN
1332: cmpl IMM (0x7ff00000),d2 | check for NaN
1333: bhi Ld$inop |
1334: blt 1f |
1335: tstl d3 |
1336: bne Ld$inop |
1337: 1: movel IMM (0),d0 | else return zero
1338: movel d0,d1 |
1339: lea SYM (_fpCCR),a0 | clear exception flags
1340: movew IMM (0),a0@ |
1341: moveml sp@+,d2-d7 |
1342: unlk a6 |
1343: rts |
1344:
1345: Ldivdf$b$0:
1346: movew IMM (DIVIDE),d5
1347: | If we got here a is not zero. Check if a is NaN; in that case return NaN,
1348: | else return +/-INFINITY. Remember that a is in d0 with the sign bit
1349: | cleared already.
1350: movel a0,d7 | put a's sign bit back in d7 '
1351: cmpl IMM (0x7ff00000),d0 | compare d0 with INFINITY
1352: bhi Ld$inop | if larger it is NaN
1353: tstl d1 |
1354: bne Ld$inop |
1355: bra Ld$div$0 | else signal DIVIDE_BY_ZERO
1356:
1357: Ldivdf$b$nf:
1358: movew IMM (DIVIDE),d5
1359: | If d2 == 0x7ff00000 we have to check d3.
1360: tstl d3 |
1361: bne Ld$inop | if d3 <> 0, b is NaN
1362: bra Ld$underflow | else b is +/-INFINITY, so signal underflow
1363:
1364: Ldivdf$a$nf:
1365: movew IMM (DIVIDE),d5
1366: | If d0 == 0x7ff00000 we have to check d1.
1367: tstl d1 |
1368: bne Ld$inop | if d1 <> 0, a is NaN
1369: | If a is INFINITY we have to check b
1370: cmpl d7,d2 | compare b with INFINITY
1371: bge Ld$inop | if b is NaN or INFINITY return NaN
1372: tstl d3 |
1373: bne Ld$inop |
1374: bra Ld$overflow | else return overflow
1375:
1376: | If a number is denormalized we put an exponent of 1 but do not put the
1377: | bit back into the fraction.
1378: Ldivdf$a$den:
1379: movel IMM (1),d4
1380: andl d6,d0
1381: 1: addl d1,d1 | shift a left until bit 20 is set
1382: addxl d0,d0
1383: subw IMM (1),d4 | and adjust exponent
1384: btst IMM (DBL_MANT_DIG-32-1),d0
1385: bne Ldivdf$1
1386: bra 1b
1387:
1388: Ldivdf$b$den:
1389: movel IMM (1),d5
1390: andl d6,d2
1391: 1: addl d3,d3 | shift b left until bit 20 is set
1392: addxl d2,d2
1393: subw IMM (1),d5 | and adjust exponent
1394: btst IMM (DBL_MANT_DIG-32-1),d2
1395: bne Ldivdf$2
1396: bra 1b
1397:
1398: Lround$exit:
1399: | This is a common exit point for __muldf3 and __divdf3. When they enter
1400: | this point the sign of the result is in d7, the result in d0-d1, normalized
1401: | so that 2^21 <= d0 < 2^22, and the exponent is in the lower byte of d4.
1402:
1403: | First check for underlow in the exponent:
1404: cmpw IMM (-DBL_MANT_DIG-1),d4
1405: blt Ld$underflow
1406: | It could happen that the exponent is less than 1, in which case the
1407: | number is denormalized. In this case we shift right and adjust the
1408: | exponent until it becomes 1 or the fraction is zero (in the latter case
1409: | we signal underflow and return zero).
1410: movel d7,a0 |
1411: movel IMM (0),d6 | use d6-d7 to collect bits flushed right
1412: movel d6,d7 | use d6-d7 to collect bits flushed right
1413: cmpw IMM (1),d4 | if the exponent is less than 1 we
1414: bge 2f | have to shift right (denormalize)
1415: 1: addw IMM (1),d4 | adjust the exponent
1416: lsrl IMM (1),d0 | shift right once
1417: roxrl IMM (1),d1 |
1418: roxrl IMM (1),d2 |
1419: roxrl IMM (1),d3 |
1420: roxrl IMM (1),d6 |
1421: roxrl IMM (1),d7 |
1422: cmpw IMM (1),d4 | is the exponent 1 already?
1423: beq 2f | if not loop back
1424: bra 1b |
1425: bra Ld$underflow | safety check, shouldn't execute '
1426: 2: orl d6,d2 | this is a trick so we don't lose '
1427: orl d7,d3 | the bits which were flushed right
1428: movel a0,d7 | get back sign bit into d7
1429: | Now call the rounding routine (which takes care of denormalized numbers):
1430: lea Lround$0,a0 | to return from rounding routine
1431: lea SYM (_fpCCR),a1 | check the rounding mode
1432: movew a1@(6),d6 | rounding mode in d6
1433: beq Lround$to$nearest
1434: cmpw IMM (ROUND_TO_PLUS),d6
1435: bhi Lround$to$minus
1436: blt Lround$to$zero
1437: bra Lround$to$plus
1438: Lround$0:
1439: | Here we have a correctly rounded result (either normalized or denormalized).
1440:
1441: | Here we should have either a normalized number or a denormalized one, and
1442: | the exponent is necessarily larger or equal to 1 (so we don't have to '
1443: | check again for underflow!). We have to check for overflow or for a
1444: | denormalized number (which also signals underflow).
1445: | Check for overflow (i.e., exponent >= 0x7ff).
1446: cmpw IMM (0x07ff),d4
1447: bge Ld$overflow
1448: | Now check for a denormalized number (exponent==0):
1449: movew d4,d4
1450: beq Ld$den
1451: 1:
1452: | Put back the exponents and sign and return.
1453: lslw IMM (4),d4 | exponent back to fourth byte
1454: bclr IMM (DBL_MANT_DIG-32-1),d0
1455: swap d0 | and put back exponent
1456: orw d4,d0 |
1457: swap d0 |
1458: orl d7,d0 | and sign also
1459:
1460: lea SYM (_fpCCR),a0
1461: movew IMM (0),a0@
1462: moveml sp@+,d2-d7
1463: unlk a6
1464: rts
1465:
1466: |=============================================================================
1467: | __negdf2
1468: |=============================================================================
1469:
1470: | double __negdf2(double, double);
1471: SYM (__negdf2):
1472: link a6,IMM (0)
1473: moveml d2-d7,sp@-
1474: movew IMM (NEGATE),d5
1475: movel a6@(8),d0 | get number to negate in d0-d1
1476: movel a6@(12),d1 |
1477: bchg IMM (31),d0 | negate
1478: movel d0,d2 | make a positive copy (for the tests)
1479: bclr IMM (31),d2 |
1480: movel d2,d4 | check for zero
1481: orl d1,d4 |
1482: beq 2f | if zero (either sign) return +zero
1483: cmpl IMM (0x7ff00000),d2 | compare to +INFINITY
1484: blt 1f | if finite, return
1485: bhi Ld$inop | if larger (fraction not zero) is NaN
1486: tstl d1 | if d2 == 0x7ff00000 check d1
1487: bne Ld$inop |
1488: movel d0,d7 | else get sign and return INFINITY
1489: andl IMM (0x80000000),d7
1490: bra Ld$infty
1491: 1: lea SYM (_fpCCR),a0
1492: movew IMM (0),a0@
1493: moveml sp@+,d2-d7
1494: unlk a6
1495: rts
1496: 2: bclr IMM (31),d0
1497: bra 1b
1498:
1499: |=============================================================================
1500: | __cmpdf2
1501: |=============================================================================
1502:
1503: GREATER = 1
1504: LESS = -1
1505: EQUAL = 0
1506:
1507: | int __cmpdf2(double, double);
1508: SYM (__cmpdf2):
1509: link a6,IMM (0)
1510: moveml d2-d7,sp@- | save registers
1511: movew IMM (COMPARE),d5
1512: movel a6@(8),d0 | get first operand
1513: movel a6@(12),d1 |
1514: movel a6@(16),d2 | get second operand
1515: movel a6@(20),d3 |
1516: | First check if a and/or b are (+/-) zero and in that case clear
1517: | the sign bit.
1518: movel d0,d6 | copy signs into d6 (a) and d7(b)
1519: bclr IMM (31),d0 | and clear signs in d0 and d2
1520: movel d2,d7 |
1521: bclr IMM (31),d2 |
1522: cmpl IMM (0x7fff0000),d0 | check for a == NaN
1523: bhi Ld$inop | if d0 > 0x7ff00000, a is NaN
1524: beq Lcmpdf$a$nf | if equal can be INFINITY, so check d1
1525: movel d0,d4 | copy into d4 to test for zero
1526: orl d1,d4 |
1527: beq Lcmpdf$a$0 |
1528: Lcmpdf$0:
1529: cmpl IMM (0x7fff0000),d2 | check for b == NaN
1530: bhi Ld$inop | if d2 > 0x7ff00000, b is NaN
1531: beq Lcmpdf$b$nf | if equal can be INFINITY, so check d3
1532: movel d2,d4 |
1533: orl d3,d4 |
1534: beq Lcmpdf$b$0 |
1535: Lcmpdf$1:
1536: | Check the signs
1537: eorl d6,d7
1538: bpl 1f
1539: | If the signs are not equal check if a >= 0
1540: tstl d6
1541: bpl Lcmpdf$a$gt$b | if (a >= 0 && b < 0) => a > b
1542: bmi Lcmpdf$b$gt$a | if (a < 0 && b >= 0) => a < b
1543: 1:
1544: | If the signs are equal check for < 0
1545: tstl d6
1546: bpl 1f
1547: | If both are negative exchange them
1548: exg d0,d2
1549: exg d1,d3
1550: 1:
1551: | Now that they are positive we just compare them as longs (does this also
1552: | work for denormalized numbers?).
1553: cmpl d0,d2
1554: bhi Lcmpdf$b$gt$a | |b| > |a|
1555: bne Lcmpdf$a$gt$b | |b| < |a|
1556: | If we got here d0 == d2, so we compare d1 and d3.
1557: cmpl d1,d3
1558: bhi Lcmpdf$b$gt$a | |b| > |a|
1559: bne Lcmpdf$a$gt$b | |b| < |a|
1560: | If we got here a == b.
1561: movel IMM (EQUAL),d0
1562: moveml sp@+,d2-d7 | put back the registers
1563: unlk a6
1564: rts
1565: Lcmpdf$a$gt$b:
1566: movel IMM (GREATER),d0
1567: moveml sp@+,d2-d7 | put back the registers
1568: unlk a6
1569: rts
1570: Lcmpdf$b$gt$a:
1571: movel IMM (LESS),d0
1572: moveml sp@+,d2-d7 | put back the registers
1573: unlk a6
1574: rts
1575:
1576: Lcmpdf$a$0:
1577: bclr IMM (31),d6
1578: bra Lcmpdf$0
1579: Lcmpdf$b$0:
1580: bclr IMM (31),d7
1581: bra Lcmpdf$1
1582:
1583: Lcmpdf$a$nf:
1584: tstl d1
1585: bne Ld$inop
1586: bra Lcmpdf$0
1587:
1588: Lcmpdf$b$nf:
1589: tstl d3
1590: bne Ld$inop
1591: bra Lcmpdf$1
1592:
1593: |=============================================================================
1594: | rounding routines
1595: |=============================================================================
1596:
1597: | The rounding routines expect the number to be normalized in registers
1598: | d0-d1-d2-d3, with the exponent in register d4. They assume that the
1599: | exponent is larger or equal to 1. They return a properly normalized number
1600: | if possible, and a denormalized number otherwise. The exponent is returned
1601: | in d4.
1602:
1603: Lround$to$nearest:
1604: | We now normalize as suggested by D. Knuth ("Seminumerical Algorithms"):
1605: | Here we assume that the exponent is not too small (this should be checked
1606: | before entering the rounding routine), but the number could be denormalized.
1607:
1608: | Check for denormalized numbers:
1609: 1: btst IMM (DBL_MANT_DIG-32),d0
1610: bne 2f | if set the number is normalized
1611: | Normalize shifting left until bit #DBL_MANT_DIG-32 is set or the exponent
1612: | is one (remember that a denormalized number corresponds to an
1613: | exponent of -D_BIAS+1).
1614: cmpw IMM (1),d4 | remember that the exponent is at least one
1615: beq 2f | an exponent of one means denormalized
1616: addl d3,d3 | else shift and adjust the exponent
1617: addxl d2,d2 |
1618: addxl d1,d1 |
1619: addxl d0,d0 |
1620: dbra d4,1b |
1621: 2:
1622: | Now round: we do it as follows: after the shifting we can write the
1623: | fraction part as f + delta, where 1 < f < 2^25, and 0 <= delta <= 2.
1624: | If delta < 1, do nothing. If delta > 1, add 1 to f.
1625: | If delta == 1, we make sure the rounded number will be even (odd?)
1626: | (after shifting).
1627: btst IMM (0),d1 | is delta < 1?
1628: beq 2f | if so, do not do anything
1629: orl d2,d3 | is delta == 1?
1630: bne 1f | if so round to even
1631: movel d1,d3 |
1632: andl IMM (2),d3 | bit 1 is the last significant bit
1633: movel IMM (0),d2 |
1634: addl d3,d1 |
1635: addxl d2,d0 |
1636: bra 2f |
1637: 1: movel IMM (1),d3 | else add 1
1638: movel IMM (0),d2 |
1639: addl d3,d1 |
1640: addxl d2,d0
1641: | Shift right once (because we used bit #DBL_MANT_DIG-32!).
1642: 2: lsrl IMM (1),d0
1643: roxrl IMM (1),d1
1644:
1645: | Now check again bit #DBL_MANT_DIG-32 (rounding could have produced a
1646: | 'fraction overflow' ...).
1647: btst IMM (DBL_MANT_DIG-32),d0
1648: beq 1f
1649: lsrl IMM (1),d0
1650: roxrl IMM (1),d1
1651: addw IMM (1),d4
1652: 1:
1653: | If bit #DBL_MANT_DIG-32-1 is clear we have a denormalized number, so we
1654: | have to put the exponent to zero and return a denormalized number.
1655: btst IMM (DBL_MANT_DIG-32-1),d0
1656: beq 1f
1657: jmp a0@
1658: 1: movel IMM (0),d4
1659: jmp a0@
1660:
1661: Lround$to$zero:
1662: Lround$to$plus:
1663: Lround$to$minus:
1664: jmp a0@
1665: #endif /* L_double */
1666:
1667: #ifdef L_float
1668:
1669: .globl SYM (_fpCCR)
1670: .globl $_exception_handler
1671:
1672: QUIET_NaN = 0xffffffff
1673: SIGNL_NaN = 0x7f800001
1674: INFINITY = 0x7f800000
1675:
1676: F_MAX_EXP = 0xff
1677: F_BIAS = 126
1678: FLT_MAX_EXP = F_MAX_EXP - F_BIAS
1679: FLT_MIN_EXP = 1 - F_BIAS
1680: FLT_MANT_DIG = 24
1681:
1682: INEXACT_RESULT = 0x0001
1683: UNDERFLOW = 0x0002
1684: OVERFLOW = 0x0004
1685: DIVIDE_BY_ZERO = 0x0008
1686: INVALID_OPERATION = 0x0010
1687:
1688: SINGLE_FLOAT = 1
1689:
1690: NOOP = 0
1691: ADD = 1
1692: MULTIPLY = 2
1693: DIVIDE = 3
1694: NEGATE = 4
1695: COMPARE = 5
1696: EXTENDSFDF = 6
1697: TRUNCDFSF = 7
1698:
1699: UNKNOWN = -1
1700: ROUND_TO_NEAREST = 0 | round result to nearest representable value
1701: ROUND_TO_ZERO = 1 | round result towards zero
1702: ROUND_TO_PLUS = 2 | round result towards plus infinity
1703: ROUND_TO_MINUS = 3 | round result towards minus infinity
1704:
1705: | Entry points:
1706:
1707: .globl SYM (__addsf3)
1708: .globl SYM (__subsf3)
1709: .globl SYM (__mulsf3)
1710: .globl SYM (__divsf3)
1711: .globl SYM (__negsf2)
1712: .globl SYM (__cmpsf2)
1713:
1714: | These are common routines to return and signal exceptions.
1715:
1716: .text
1717: .even
1718:
1719: Lf$den:
1720: | Return and signal a denormalized number
1721: orl d7,d0
1722: movew IMM (UNDERFLOW),d7
1723: orw IMM (INEXACT_RESULT),d7
1724: movew IMM (SINGLE_FLOAT),d6
1725: jmp $_exception_handler
1726:
1727: Lf$infty:
1728: Lf$overflow:
1729: | Return a properly signed INFINITY and set the exception flags
1730: movel IMM (INFINITY),d0
1731: orl d7,d0
1732: movew IMM (OVERFLOW),d7
1733: orw IMM (INEXACT_RESULT),d7
1734: movew IMM (SINGLE_FLOAT),d6
1735: jmp $_exception_handler
1736:
1737: Lf$underflow:
1738: | Return 0 and set the exception flags
1739: movel IMM (0),d0
1740: movew IMM (UNDERFLOW),d7
1741: orw IMM (INEXACT_RESULT),d7
1742: movew IMM (SINGLE_FLOAT),d6
1743: jmp $_exception_handler
1744:
1745: Lf$inop:
1746: | Return a quiet NaN and set the exception flags
1747: movel IMM (QUIET_NaN),d0
1748: movew IMM (INVALID_OPERATION),d7
1749: orw IMM (INEXACT_RESULT),d7
1750: movew IMM (SINGLE_FLOAT),d6
1751: jmp $_exception_handler
1752:
1753: Lf$div$0:
1754: | Return a properly signed INFINITY and set the exception flags
1755: movel IMM (INFINITY),d0
1756: orl d7,d0
1757: movew IMM (DIVIDE_BY_ZERO),d7
1758: orw IMM (INEXACT_RESULT),d7
1759: movew IMM (SINGLE_FLOAT),d6
1760: jmp $_exception_handler
1761:
1762: |=============================================================================
1763: |=============================================================================
1764: | single precision routines
1765: |=============================================================================
1766: |=============================================================================
1767:
1768: | A single precision floating point number (float) has the format:
1769: |
1770: | struct _float {
1771: | unsigned int sign : 1; /* sign bit */
1772: | unsigned int exponent : 8; /* exponent, shifted by 126 */
1773: | unsigned int fraction : 23; /* fraction */
1774: | } float;
1775: |
1776: | Thus sizeof(float) = 4 (32 bits).
1777: |
1778: | All the routines are callable from C programs, and return the result
1779: | in the single register d0. They also preserve all registers except
1780: | d0-d1 and a0-a1.
1781:
1782: |=============================================================================
1783: | __subsf3
1784: |=============================================================================
1785:
1786: | float __subsf3(float, float);
1787: SYM (__subsf3):
1788: bchg IMM (31),sp@(8) | change sign of second operand
1789: | and fall through
1790: |=============================================================================
1791: | __addsf3
1792: |=============================================================================
1793:
1794: | float __addsf3(float, float);
1795: SYM (__addsf3):
1796: link a6,IMM (0) | everything will be done in registers
1797: moveml d2-d7,sp@- | save all data registers but d0-d1
1798: movel a6@(8),d0 | get first operand
1799: movel a6@(12),d1 | get second operand
1800: movel d0,d6 | get d0's sign bit '
1801: addl d0,d0 | check and clear sign bit of a
1802: beq Laddsf$b | if zero return second operand
1803: movel d1,d7 | save b's sign bit '
1804: addl d1,d1 | get rid of sign bit
1805: beq Laddsf$a | if zero return first operand
1806:
1807: movel d6,a0 | save signs in address registers
1808: movel d7,a1 | so we can use d6 and d7
1809:
1810: | Get the exponents and check for denormalized and/or infinity.
1811:
1812: movel IMM (0x00ffffff),d4 | mask to get fraction
1813: movel IMM (0x01000000),d5 | mask to put hidden bit back
1814:
1815: movel d0,d6 | save a to get exponent
1816: andl d4,d0 | get fraction in d0
1817: notl d4 | make d4 into a mask for the exponent
1818: andl d4,d6 | get exponent in d6
1819: beq Laddsf$a$den | branch if a is denormalized
1820: cmpl d4,d6 | check for INFINITY or NaN
1821: beq Laddsf$nf
1822: swap d6 | put exponent into first word
1823: orl d5,d0 | and put hidden bit back
1824: Laddsf$1:
1825: | Now we have a's exponent in d6 (second byte) and the mantissa in d0. '
1826: movel d1,d7 | get exponent in d7
1827: andl d4,d7 |
1828: beq Laddsf$b$den | branch if b is denormalized
1829: cmpl d4,d7 | check for INFINITY or NaN
1830: beq Laddsf$nf
1831: swap d7 | put exponent into first word
1832: notl d4 | make d4 into a mask for the fraction
1833: andl d4,d1 | get fraction in d1
1834: orl d5,d1 | and put hidden bit back
1835: Laddsf$2:
1836: | Now we have b's exponent in d7 (second byte) and the mantissa in d1. '
1837:
1838: | Note that the hidden bit corresponds to bit #FLT_MANT_DIG-1, and we
1839: | shifted right once, so bit #FLT_MANT_DIG is set (so we have one extra
1840: | bit).
1841:
1842: movel d1,d2 | move b to d2, since we want to use
1843: | two registers to do the sum
1844: movel IMM (0),d1 | and clear the new ones
1845: movel d1,d3 |
1846:
1847: | Here we shift the numbers in registers d0 and d1 so the exponents are the
1848: | same, and put the largest exponent in d6. Note that we are using two
1849: | registers for each number (see the discussion by D. Knuth in "Seminumerical
1850: | Algorithms").
1851: cmpw d6,d7 | compare exponents
1852: beq Laddsf$3 | if equal don't shift '
1853: bhi 5f | branch if second exponent largest
1854: 1:
1855: subl d6,d7 | keep the largest exponent
1856: negl d7
1857: lsrw IMM (8),d7 | put difference in lower byte
1858: | if difference is too large we don't shift (actually, we can just exit) '
1859: cmpw IMM (FLT_MANT_DIG+2),d7
1860: bge Laddsf$b$small
1861: cmpw IMM (16),d7 | if difference >= 16 swap
1862: bge 4f
1863: 2:
1864: subw IMM (1),d7
1865: 3: lsrl IMM (1),d2 | shift right second operand
1866: roxrl IMM (1),d3
1867: dbra d7,3b
1868: bra Laddsf$3
1869: 4:
1870: movew d2,d3
1871: swap d3
1872: movew d3,d2
1873: swap d2
1874: subw IMM (16),d7
1875: bne 2b | if still more bits, go back to normal case
1876: bra Laddsf$3
1877: 5:
1878: exg d6,d7 | exchange the exponents
1879: subl d6,d7 | keep the largest exponent
1880: negl d7 |
1881: lsrw IMM (8),d7 | put difference in lower byte
1882: | if difference is too large we don't shift (and exit!) '
1883: cmpw IMM (FLT_MANT_DIG+2),d7
1884: bge Laddsf$a$small
1885: cmpw IMM (16),d7 | if difference >= 16 swap
1886: bge 8f
1887: 6:
1888: subw IMM (1),d7
1889: 7: lsrl IMM (1),d0 | shift right first operand
1890: roxrl IMM (1),d1
1891: dbra d7,7b
1892: bra Laddsf$3
1893: 8:
1894: movew d0,d1
1895: swap d1
1896: movew d1,d0
1897: swap d0
1898: subw IMM (16),d7
1899: bne 6b | if still more bits, go back to normal case
1900: | otherwise we fall through
1901:
1902: | Now we have a in d0-d1, b in d2-d3, and the largest exponent in d6 (the
1903: | signs are stored in a0 and a1).
1904:
1905: Laddsf$3:
1906: | Here we have to decide whether to add or subtract the numbers
1907: exg d6,a0 | get signs back
1908: exg d7,a1 | and save the exponents
1909: eorl d6,d7 | combine sign bits
1910: bmi Lsubsf$0 | if negative a and b have opposite
1911: | sign so we actually subtract the
1912: | numbers
1913:
1914: | Here we have both positive or both negative
1915: exg d6,a0 | now we have the exponent in d6
1916: movel a0,d7 | and sign in d7
1917: andl IMM (0x80000000),d7
1918: | Here we do the addition.
1919: addl d3,d1
1920: addxl d2,d0
1921: | Note: now we have d2, d3, d4 and d5 to play with!
1922:
1923: | Put the exponent, in the first byte, in d2, to use the "standard" rounding
1924: | routines:
1925: movel d6,d2
1926: lsrw IMM (8),d2
1927:
1928: | Before rounding normalize so bit #FLT_MANT_DIG is set (we will consider
1929: | the case of denormalized numbers in the rounding routine itself).
1930: | As in the addition (not in the subtraction!) we could have set
1931: | one more bit we check this:
1932: btst IMM (FLT_MANT_DIG+1),d0
1933: beq 1f
1934: lsrl IMM (1),d0
1935: roxrl IMM (1),d1
1936: addl IMM (1),d2
1937: 1:
1938: lea Laddsf$4,a0 | to return from rounding routine
1939: lea SYM (_fpCCR),a1 | check the rounding mode
1940: movew a1@(6),d6 | rounding mode in d6
1941: beq Lround$to$nearest
1942: cmpw IMM (ROUND_TO_PLUS),d6
1943: bhi Lround$to$minus
1944: blt Lround$to$zero
1945: bra Lround$to$plus
1946: Laddsf$4:
1947: | Put back the exponent, but check for overflow.
1948: cmpw IMM (0xff),d2
1949: bhi 1f
1950: bclr IMM (FLT_MANT_DIG-1),d0
1951: lslw IMM (7),d2
1952: swap d2
1953: orl d2,d0
1954: bra Laddsf$ret
1955: 1:
1956: movew IMM (ADD),d5
1957: bra Lf$overflow
1958:
1959: Lsubsf$0:
1960: | We are here if a > 0 and b < 0 (sign bits cleared).
1961: | Here we do the subtraction.
1962: movel d6,d7 | put sign in d7
1963: andl IMM (0x80000000),d7
1964:
1965: subl d3,d1 | result in d0-d1
1966: subxl d2,d0 |
1967: beq Laddsf$ret | if zero just exit
1968: bpl 1f | if positive skip the following
1969: bchg IMM (31),d7 | change sign bit in d7
1970: negl d1
1971: negxl d0
1972: 1:
1973: exg d2,a0 | now we have the exponent in d2
1974: lsrw IMM (8),d2 | put it in the first byte
1975:
1976: | Now d0-d1 is positive and the sign bit is in d7.
1977:
1978: | Note that we do not have to normalize, since in the subtraction bit
1979: | #FLT_MANT_DIG+1 is never set, and denormalized numbers are handled by
1980: | the rounding routines themselves.
1981: lea Lsubsf$1,a0 | to return from rounding routine
1982: lea SYM (_fpCCR),a1 | check the rounding mode
1983: movew a1@(6),d6 | rounding mode in d6
1984: beq Lround$to$nearest
1985: cmpw IMM (ROUND_TO_PLUS),d6
1986: bhi Lround$to$minus
1987: blt Lround$to$zero
1988: bra Lround$to$plus
1989: Lsubsf$1:
1990: | Put back the exponent (we can't have overflow!). '
1991: bclr IMM (FLT_MANT_DIG-1),d0
1992: lslw IMM (7),d2
1993: swap d2
1994: orl d2,d0
1995: bra Laddsf$ret
1996:
1997: | If one of the numbers was too small (difference of exponents >=
1998: | FLT_MANT_DIG+2) we return the other (and now we don't have to '
1999: | check for finiteness or zero).
2000: Laddsf$a$small:
2001: movel a6@(12),d0
2002: lea SYM (_fpCCR),a0
2003: movew IMM (0),a0@
2004: moveml sp@+,d2-d7 | restore data registers
2005: unlk a6 | and return
2006: rts
2007:
2008: Laddsf$b$small:
2009: movel a6@(8),d0
2010: lea SYM (_fpCCR),a0
2011: movew IMM (0),a0@
2012: moveml sp@+,d2-d7 | restore data registers
2013: unlk a6 | and return
2014: rts
2015:
2016: | If the numbers are denormalized remember to put exponent equal to 1.
2017:
2018: Laddsf$a$den:
2019: movel d5,d6 | d5 contains 0x01000000
2020: swap d6
2021: bra Laddsf$1
2022:
2023: Laddsf$b$den:
2024: movel d5,d7
2025: swap d7
2026: notl d4 | make d4 into a mask for the fraction
2027: | (this was not executed after the jump)
2028: bra Laddsf$2
2029:
2030: | The rest is mainly code for the different results which can be
2031: | returned (checking always for +/-INFINITY and NaN).
2032:
2033: Laddsf$b:
2034: | Return b (if a is zero).
2035: movel a6@(12),d0
2036: bra 1f
2037: Laddsf$a:
2038: | Return a (if b is zero).
2039: movel a6@(8),d0
2040: 1:
2041: movew IMM (ADD),d5
2042: | We have to check for NaN and +/-infty.
2043: movel d0,d7
2044: andl IMM (0x80000000),d7 | put sign in d7
2045: bclr IMM (31),d0 | clear sign
2046: cmpl IMM (INFINITY),d0 | check for infty or NaN
2047: bge 2f
2048: movel d0,d0 | check for zero (we do this because we don't '
2049: bne Laddsf$ret | want to return -0 by mistake
2050: bclr IMM (31),d7 | if zero be sure to clear sign
2051: bra Laddsf$ret | if everything OK just return
2052: 2:
2053: | The value to be returned is either +/-infty or NaN
2054: andl IMM (0x007fffff),d0 | check for NaN
2055: bne Lf$inop | if mantissa not zero is NaN
2056: bra Lf$infty
2057:
2058: Laddsf$ret:
2059: | Normal exit (a and b nonzero, result is not NaN nor +/-infty).
2060: | We have to clear the exception flags (just the exception type).
2061: lea SYM (_fpCCR),a0
2062: movew IMM (0),a0@
2063: orl d7,d0 | put sign bit
2064: moveml sp@+,d2-d7 | restore data registers
2065: unlk a6 | and return
2066: rts
2067:
2068: Laddsf$ret$den:
2069: | Return a denormalized number (for addition we don't signal underflow) '
2070: lsrl IMM (1),d0 | remember to shift right back once
2071: bra Laddsf$ret | and return
2072:
2073: | Note: when adding two floats of the same sign if either one is
2074: | NaN we return NaN without regard to whether the other is finite or
2075: | not. When subtracting them (i.e., when adding two numbers of
2076: | opposite signs) things are more complicated: if both are INFINITY
2077: | we return NaN, if only one is INFINITY and the other is NaN we return
2078: | NaN, but if it is finite we return INFINITY with the corresponding sign.
2079:
2080: Laddsf$nf:
2081: movew IMM (ADD),d5
2082: | This could be faster but it is not worth the effort, since it is not
2083: | executed very often. We sacrifice speed for clarity here.
2084: movel a6@(8),d0 | get the numbers back (remember that we
2085: movel a6@(12),d1 | did some processing already)
2086: movel IMM (INFINITY),d4 | useful constant (INFINITY)
2087: movel d0,d2 | save sign bits
2088: movel d1,d3
2089: bclr IMM (31),d0 | clear sign bits
2090: bclr IMM (31),d1
2091: | We know that one of them is either NaN of +/-INFINITY
2092: | Check for NaN (if either one is NaN return NaN)
2093: cmpl d4,d0 | check first a (d0)
2094: bhi Lf$inop
2095: cmpl d4,d1 | check now b (d1)
2096: bhi Lf$inop
2097: | Now comes the check for +/-INFINITY. We know that both are (maybe not
2098: | finite) numbers, but we have to check if both are infinite whether we
2099: | are adding or subtracting them.
2100: eorl d3,d2 | to check sign bits
2101: bmi 1f
2102: movel d0,d7
2103: andl IMM (0x80000000),d7 | get (common) sign bit
2104: bra Lf$infty
2105: 1:
2106: | We know one (or both) are infinite, so we test for equality between the
2107: | two numbers (if they are equal they have to be infinite both, so we
2108: | return NaN).
2109: cmpl d1,d0 | are both infinite?
2110: beq Lf$inop | if so return NaN
2111:
2112: movel d0,d7
2113: andl IMM (0x80000000),d7 | get a's sign bit '
2114: cmpl d4,d0 | test now for infinity
2115: beq Lf$infty | if a is INFINITY return with this sign
2116: bchg IMM (31),d7 | else we know b is INFINITY and has
2117: bra Lf$infty | the opposite sign
2118:
2119: |=============================================================================
2120: | __mulsf3
2121: |=============================================================================
2122:
2123: | float __mulsf3(float, float);
2124: SYM (__mulsf3):
2125: link a6,IMM (0)
2126: moveml d2-d7,sp@-
2127: movel a6@(8),d0 | get a into d0
2128: movel a6@(12),d1 | and b into d1
2129: movel d0,d7 | d7 will hold the sign of the product
2130: eorl d1,d7 |
2131: andl IMM (0x80000000),d7
2132: movel IMM (INFINITY),d6 | useful constant (+INFINITY)
2133: movel d6,d5 | another (mask for fraction)
2134: notl d5 |
2135: movel IMM (0x00800000),d4 | this is to put hidden bit back
2136: bclr IMM (31),d0 | get rid of a's sign bit '
2137: movel d0,d2 |
2138: beq Lmulsf$a$0 | branch if a is zero
2139: bclr IMM (31),d1 | get rid of b's sign bit '
2140: movel d1,d3 |
2141: beq Lmulsf$b$0 | branch if b is zero
2142: cmpl d6,d0 | is a big?
2143: bhi Lmulsf$inop | if a is NaN return NaN
2144: beq Lmulsf$inf | if a is INFINITY we have to check b
2145: cmpl d6,d1 | now compare b with INFINITY
2146: bhi Lmulsf$inop | is b NaN?
2147: beq Lmulsf$overflow | is b INFINITY?
2148: | Here we have both numbers finite and nonzero (and with no sign bit).
2149: | Now we get the exponents into d2 and d3.
2150: andl d6,d2 | and isolate exponent in d2
2151: beq Lmulsf$a$den | if exponent is zero we have a denormalized
2152: andl d5,d0 | and isolate fraction
2153: orl d4,d0 | and put hidden bit back
2154: swap d2 | I like exponents in the first byte
2155: lsrw IMM (7),d2 |
2156: Lmulsf$1: | number
2157: andl d6,d3 |
2158: beq Lmulsf$b$den |
2159: andl d5,d1 |
2160: orl d4,d1 |
2161: swap d3 |
2162: lsrw IMM (7),d3 |
2163: Lmulsf$2: |
2164: addw d3,d2 | add exponents
2165: subw IMM (F_BIAS+1),d2 | and subtract bias (plus one)
2166:
2167: | We are now ready to do the multiplication. The situation is as follows:
2168: | both a and b have bit FLT_MANT_DIG-1 set (even if they were
2169: | denormalized to start with!), which means that in the product
2170: | bit 2*(FLT_MANT_DIG-1) (that is, bit 2*FLT_MANT_DIG-2-32 of the
2171: | high long) is set.
2172:
2173: | To do the multiplication let us move the number a little bit around ...
2174: movel d1,d6 | second operand in d6
2175: movel d0,d5 | first operand in d4-d5
2176: movel IMM (0),d4
2177: movel d4,d1 | the sums will go in d0-d1
2178: movel d4,d0
2179:
2180: | now bit FLT_MANT_DIG-1 becomes bit 31:
2181: lsll IMM (31-FLT_MANT_DIG+1),d6
2182:
2183: | Start the loop (we loop #FLT_MANT_DIG times):
2184: movew IMM (FLT_MANT_DIG-1),d3
2185: 1: addl d1,d1 | shift sum
2186: addxl d0,d0
2187: lsll IMM (1),d6 | get bit bn
2188: bcc 2f | if not set skip sum
2189: addl d5,d1 | add a
2190: addxl d4,d0
2191: 2: dbf d3,1b | loop back
2192:
2193: | Now we have the product in d0-d1, with bit (FLT_MANT_DIG - 1) + FLT_MANT_DIG
2194: | (mod 32) of d0 set. The first thing to do now is to normalize it so bit
2195: | FLT_MANT_DIG is set (to do the rounding).
2196: rorl IMM (6),d1
2197: swap d1
2198: movew d1,d3
2199: andw IMM (0x03ff),d3
2200: andw IMM (0xfd00),d1
2201: lsll IMM (8),d0
2202: addl d0,d0
2203: addl d0,d0
2204: orw d3,d0
2205:
2206: movew IMM (MULTIPLY),d5
2207:
2208: btst IMM (FLT_MANT_DIG+1),d0
2209: beq Lround$exit
2210: lsrl IMM (1),d0
2211: roxrl IMM (1),d1
2212: addw IMM (1),d2
2213: bra Lround$exit
2214:
2215: Lmulsf$inop:
2216: movew IMM (MULTIPLY),d5
2217: bra Lf$inop
2218:
2219: Lmulsf$overflow:
2220: movew IMM (MULTIPLY),d5
2221: bra Lf$overflow
2222:
2223: Lmulsf$inf:
2224: movew IMM (MULTIPLY),d5
2225: | If either is NaN return NaN; else both are (maybe infinite) numbers, so
2226: | return INFINITY with the correct sign (which is in d7).
2227: cmpl d6,d1 | is b NaN?
2228: bhi Lf$inop | if so return NaN
2229: bra Lf$overflow | else return +/-INFINITY
2230:
2231: | If either number is zero return zero, unless the other is +/-INFINITY,
2232: | or NaN, in which case we return NaN.
2233: Lmulsf$b$0:
2234: | Here d1 (==b) is zero.
2235: movel d1,d0 | put b into d0 (just a zero)
2236: movel a6@(8),d1 | get a again to check for non-finiteness
2237: bra 1f
2238: Lmulsf$a$0:
2239: movel a6@(12),d1 | get b again to check for non-finiteness
2240: 1: bclr IMM (31),d1 | clear sign bit
2241: cmpl IMM (INFINITY),d1 | and check for a large exponent
2242: bge Lf$inop | if b is +/-INFINITY or NaN return NaN
2243: lea SYM (_fpCCR),a0 | else return zero
2244: movew IMM (0),a0@ |
2245: moveml sp@+,d2-d7 |
2246: unlk a6 |
2247: rts |
2248:
2249: | If a number is denormalized we put an exponent of 1 but do not put the
2250: | hidden bit back into the fraction; instead we shift left until bit 23
2251: | (the hidden bit) is set, adjusting the exponent accordingly. We do this
2252: | to ensure that the product of the fractions is close to 1.
2253: Lmulsf$a$den:
2254: movel IMM (1),d2
2255: andl d5,d0
2256: 1: addl d0,d0 | shift a left (until bit 23 is set)
2257: subw IMM (1),d2 | and adjust exponent
2258: btst IMM (FLT_MANT_DIG-1),d0
2259: bne Lmulsf$1 |
2260: bra 1b | else loop back
2261:
2262: Lmulsf$b$den:
2263: movel IMM (1),d3
2264: andl d5,d1
2265: 1: addl d1,d1 | shift b left until bit 23 is set
2266: subw IMM (1),d3 | and adjust exponent
2267: btst IMM (FLT_MANT_DIG-1),d1
2268: bne Lmulsf$2 |
2269: bra 1b | else loop back
2270:
2271: |=============================================================================
2272: | __divsf3
2273: |=============================================================================
2274:
2275: | float __divsf3(float, float);
2276: SYM (__divsf3):
2277: link a6,IMM (0)
2278: moveml d2-d7,sp@-
2279: movel a6@(8),d0 | get a into d0
2280: movel a6@(12),d1 | and b into d1
2281: movel d0,d7 | d7 will hold the sign of the result
2282: eorl d1,d7 |
2283: andl IMM (0x80000000),d7 |
2284: movel IMM (INFINITY),d6 | useful constant (+INFINITY)
2285: movel d6,d5 | another (mask for fraction)
2286: notl d5 |
2287: movel IMM (0x00800000),d4 | this is to put hidden bit back
2288: bclr IMM (31),d0 | get rid of a's sign bit '
2289: movel d0,d2 |
2290: beq Ldivsf$a$0 | branch if a is zero
2291: bclr IMM (31),d1 | get rid of b's sign bit '
2292: movel d1,d3 |
2293: beq Ldivsf$b$0 | branch if b is zero
2294: cmpl d6,d0 | is a big?
2295: bhi Ldivsf$inop | if a is NaN return NaN
2296: beq Ldivsf$inf | if a is INFINITY we have to check b
2297: cmpl d6,d1 | now compare b with INFINITY
2298: bhi Ldivsf$inop | if b is NaN return NaN
2299: beq Ldivsf$underflow
2300: | Here we have both numbers finite and nonzero (and with no sign bit).
2301: | Now we get the exponents into d2 and d3 and normalize the numbers to
2302: | ensure that the ratio of the fractions is close to 1. We do this by
2303: | making sure that bit #FLT_MANT_DIG-1 (hidden bit) is set.
2304: andl d6,d2 | and isolate exponent in d2
2305: beq Ldivsf$a$den | if exponent is zero we have a denormalized
2306: andl d5,d0 | and isolate fraction
2307: orl d4,d0 | and put hidden bit back
2308: swap d2 | I like exponents in the first byte
2309: lsrw IMM (7),d2 |
2310: Ldivsf$1: |
2311: andl d6,d3 |
2312: beq Ldivsf$b$den |
2313: andl d5,d1 |
2314: orl d4,d1 |
2315: swap d3 |
2316: lsrw IMM (7),d3 |
2317: Ldivsf$2: |
2318: subw d3,d2 | subtract exponents
2319: addw IMM (F_BIAS),d2 | and add bias
2320:
2321: | We are now ready to do the division. We have prepared things in such a way
2322: | that the ratio of the fractions will be less than 2 but greater than 1/2.
2323: | At this point the registers in use are:
2324: | d0 holds a (first operand, bit FLT_MANT_DIG=0, bit FLT_MANT_DIG-1=1)
2325: | d1 holds b (second operand, bit FLT_MANT_DIG=1)
2326: | d2 holds the difference of the exponents, corrected by the bias
2327: | d7 holds the sign of the ratio
2328: | d4, d5, d6 hold some constants
2329: movel d7,a0 | d6-d7 will hold the ratio of the fractions
2330: movel IMM (0),d6 |
2331: movel d6,d7
2332:
2333: movew IMM (FLT_MANT_DIG+1),d3
2334: 1: cmpl d0,d1 | is a < b?
2335: bhi 2f |
2336: bset d3,d6 | set a bit in d6
2337: subl d1,d0 | if a >= b a <-- a-b
2338: beq 3f | if a is zero, exit
2339: 2: addl d0,d0 | multiply a by 2
2340: dbra d3,1b
2341:
2342: | Now we keep going to set the sticky bit ...
2343: movew IMM (FLT_MANT_DIG),d3
2344: 1: cmpl d0,d1
2345: ble 2f
2346: addl d0,d0
2347: dbra d3,1b
2348: movel IMM (0),d1
2349: bra 3f
2350: 2: movel IMM (0),d1
2351: subw IMM (FLT_MANT_DIG),d3
2352: addw IMM (31),d3
2353: bset d3,d1
2354: 3:
2355: movel d6,d0 | put the ratio in d0-d1
2356: movel a0,d7 | get sign back
2357:
2358: | Because of the normalization we did before we are guaranteed that
2359: | d0 is smaller than 2^26 but larger than 2^24. Thus bit 26 is not set,
2360: | bit 25 could be set, and if it is not set then bit 24 is necessarily set.
2361: btst IMM (FLT_MANT_DIG+1),d0
2362: beq 1f | if it is not set, then bit 24 is set
2363: lsrl IMM (1),d0 |
2364: addw IMM (1),d2 |
2365: 1:
2366: | Now round, check for over- and underflow, and exit.
2367: movew IMM (DIVIDE),d5
2368: bra Lround$exit
2369:
2370: Ldivsf$inop:
2371: movew IMM (DIVIDE),d5
2372: bra Lf$inop
2373:
2374: Ldivsf$overflow:
2375: movew IMM (DIVIDE),d5
2376: bra Lf$overflow
2377:
2378: Ldivsf$underflow:
2379: movew IMM (DIVIDE),d5
2380: bra Lf$underflow
2381:
2382: Ldivsf$a$0:
2383: movew IMM (DIVIDE),d5
2384: | If a is zero check to see whether b is zero also. In that case return
2385: | NaN; then check if b is NaN, and return NaN also in that case. Else
2386: | return zero.
2387: andl IMM (0x7fffffff),d1 | clear sign bit and test b
2388: beq Lf$inop | if b is also zero return NaN
2389: cmpl IMM (INFINITY),d1 | check for NaN
2390: bhi Lf$inop |
2391: movel IMM (0),d0 | else return zero
2392: lea SYM (_fpCCR),a0 |
2393: movew IMM (0),a0@ |
2394: moveml sp@+,d2-d7 |
2395: unlk a6 |
2396: rts |
2397:
2398: Ldivsf$b$0:
2399: movew IMM (DIVIDE),d5
2400: | If we got here a is not zero. Check if a is NaN; in that case return NaN,
2401: | else return +/-INFINITY. Remember that a is in d0 with the sign bit
2402: | cleared already.
2403: cmpl IMM (INFINITY),d0 | compare d0 with INFINITY
2404: bhi Lf$inop | if larger it is NaN
2405: bra Lf$div$0 | else signal DIVIDE_BY_ZERO
2406:
2407: Ldivsf$inf:
2408: movew IMM (DIVIDE),d5
2409: | If a is INFINITY we have to check b
2410: cmpl IMM (INFINITY),d1 | compare b with INFINITY
2411: bge Lf$inop | if b is NaN or INFINITY return NaN
2412: bra Lf$overflow | else return overflow
2413:
2414: | If a number is denormalized we put an exponent of 1 but do not put the
2415: | bit back into the fraction.
2416: Ldivsf$a$den:
2417: movel IMM (1),d2
2418: andl d5,d0
2419: 1: addl d0,d0 | shift a left until bit FLT_MANT_DIG-1 is set
2420: subw IMM (1),d2 | and adjust exponent
2421: btst IMM (FLT_MANT_DIG-1),d0
2422: bne Ldivsf$1
2423: bra 1b
2424:
2425: Ldivsf$b$den:
2426: movel IMM (1),d3
2427: andl d5,d1
2428: 1: addl d1,d1 | shift b left until bit FLT_MANT_DIG is set
2429: subw IMM (1),d3 | and adjust exponent
2430: btst IMM (FLT_MANT_DIG-1),d1
2431: bne Ldivsf$2
2432: bra 1b
2433:
2434: Lround$exit:
2435: | This is a common exit point for __mulsf3 and __divsf3.
2436:
2437: | First check for underlow in the exponent:
2438: cmpw IMM (-FLT_MANT_DIG-1),d2
2439: blt Lf$underflow
2440: | It could happen that the exponent is less than 1, in which case the
2441: | number is denormalized. In this case we shift right and adjust the
2442: | exponent until it becomes 1 or the fraction is zero (in the latter case
2443: | we signal underflow and return zero).
2444: movel IMM (0),d6 | d6 is used temporarily
2445: cmpw IMM (1),d2 | if the exponent is less than 1 we
2446: bge 2f | have to shift right (denormalize)
2447: 1: addw IMM (1),d2 | adjust the exponent
2448: lsrl IMM (1),d0 | shift right once
2449: roxrl IMM (1),d1 |
2450: roxrl IMM (1),d6 | d6 collect bits we would lose otherwise
2451: cmpw IMM (1),d2 | is the exponent 1 already?
2452: beq 2f | if not loop back
2453: bra 1b |
2454: bra Lf$underflow | safety check, shouldn't execute '
2455: 2: orl d6,d1 | this is a trick so we don't lose '
2456: | the extra bits which were flushed right
2457: | Now call the rounding routine (which takes care of denormalized numbers):
2458: lea Lround$0,a0 | to return from rounding routine
2459: lea SYM (_fpCCR),a1 | check the rounding mode
2460: movew a1@(6),d6 | rounding mode in d6
2461: beq Lround$to$nearest
2462: cmpw IMM (ROUND_TO_PLUS),d6
2463: bhi Lround$to$minus
2464: blt Lround$to$zero
2465: bra Lround$to$plus
2466: Lround$0:
2467: | Here we have a correctly rounded result (either normalized or denormalized).
2468:
2469: | Here we should have either a normalized number or a denormalized one, and
2470: | the exponent is necessarily larger or equal to 1 (so we don't have to '
2471: | check again for underflow!). We have to check for overflow or for a
2472: | denormalized number (which also signals underflow).
2473: | Check for overflow (i.e., exponent >= 255).
2474: cmpw IMM (0x00ff),d2
2475: bge Lf$overflow
2476: | Now check for a denormalized number (exponent==0).
2477: movew d2,d2
2478: beq Lf$den
2479: 1:
2480: | Put back the exponents and sign and return.
2481: lslw IMM (7),d2 | exponent back to fourth byte
2482: bclr IMM (FLT_MANT_DIG-1),d0
2483: swap d0 | and put back exponent
2484: orw d2,d0 |
2485: swap d0 |
2486: orl d7,d0 | and sign also
2487:
2488: lea SYM (_fpCCR),a0
2489: movew IMM (0),a0@
2490: moveml sp@+,d2-d7
2491: unlk a6
2492: rts
2493:
2494: |=============================================================================
2495: | __negsf2
2496: |=============================================================================
2497:
2498: | This is trivial and could be shorter if we didn't bother checking for NaN '
2499: | and +/-INFINITY.
2500:
2501: | float __negsf2(float);
2502: SYM (__negsf2):
2503: link a6,IMM (0)
2504: moveml d2-d7,sp@-
2505: movew IMM (NEGATE),d5
2506: movel a6@(8),d0 | get number to negate in d0
2507: bchg IMM (31),d0 | negate
2508: movel d0,d1 | make a positive copy
2509: bclr IMM (31),d1 |
2510: tstl d1 | check for zero
2511: beq 2f | if zero (either sign) return +zero
2512: cmpl IMM (INFINITY),d1 | compare to +INFINITY
2513: blt 1f |
2514: bhi Lf$inop | if larger (fraction not zero) is NaN
2515: movel d0,d7 | else get sign and return INFINITY
2516: andl IMM (0x80000000),d7
2517: bra Lf$infty
2518: 1: lea SYM (_fpCCR),a0
2519: movew IMM (0),a0@
2520: moveml sp@+,d2-d7
2521: unlk a6
2522: rts
2523: 2: bclr IMM (31),d0
2524: bra 1b
2525:
2526: |=============================================================================
2527: | __cmpsf2
2528: |=============================================================================
2529:
2530: GREATER = 1
2531: LESS = -1
2532: EQUAL = 0
2533:
2534: | int __cmpsf2(float, float);
2535: SYM (__cmpsf2):
2536: link a6,IMM (0)
2537: moveml d2-d7,sp@- | save registers
2538: movew IMM (COMPARE),d5
2539: movel a6@(8),d0 | get first operand
2540: movel a6@(12),d1 | get second operand
2541: | Check if either is NaN, and in that case return garbage and signal
2542: | INVALID_OPERATION. Check also if either is zero, and clear the signs
2543: | if necessary.
2544: movel d0,d6
2545: andl IMM (0x7fffffff),d0
2546: beq Lcmpsf$a$0
2547: cmpl IMM (0x7f800000),d0
2548: bhi Lf$inop
2549: Lcmpsf$1:
2550: movel d1,d7
2551: andl IMM (0x7fffffff),d1
2552: beq Lcmpsf$b$0
2553: cmpl IMM (0x7f800000),d1
2554: bhi Lf$inop
2555: Lcmpsf$2:
2556: | Check the signs
2557: eorl d6,d7
2558: bpl 1f
2559: | If the signs are not equal check if a >= 0
2560: tstl d6
2561: bpl Lcmpsf$a$gt$b | if (a >= 0 && b < 0) => a > b
2562: bmi Lcmpsf$b$gt$a | if (a < 0 && b >= 0) => a < b
2563: 1:
2564: | If the signs are equal check for < 0
2565: tstl d6
2566: bpl 1f
2567: | If both are negative exchange them
2568: exg d0,d1
2569: 1:
2570: | Now that they are positive we just compare them as longs (does this also
2571: | work for denormalized numbers?).
2572: cmpl d0,d1
2573: bhi Lcmpsf$b$gt$a | |b| > |a|
2574: bne Lcmpsf$a$gt$b | |b| < |a|
2575: | If we got here a == b.
2576: movel IMM (EQUAL),d0
2577: moveml sp@+,d2-d7 | put back the registers
2578: unlk a6
2579: rts
2580: Lcmpsf$a$gt$b:
2581: movel IMM (GREATER),d0
2582: moveml sp@+,d2-d7 | put back the registers
2583: unlk a6
2584: rts
2585: Lcmpsf$b$gt$a:
2586: movel IMM (LESS),d0
2587: moveml sp@+,d2-d7 | put back the registers
2588: unlk a6
2589: rts
2590:
2591: Lcmpsf$a$0:
2592: bclr IMM (31),d6
2593: bra Lcmpsf$1
2594: Lcmpsf$b$0:
2595: bclr IMM (31),d7
2596: bra Lcmpsf$2
2597:
2598: |=============================================================================
2599: | rounding routines
2600: |=============================================================================
2601:
2602: | The rounding routines expect the number to be normalized in registers
2603: | d0-d1, with the exponent in register d2. They assume that the
2604: | exponent is larger or equal to 1. They return a properly normalized number
2605: | if possible, and a denormalized number otherwise. The exponent is returned
2606: | in d2.
2607:
2608: Lround$to$nearest:
2609: | We now normalize as suggested by D. Knuth ("Seminumerical Algorithms"):
2610: | Here we assume that the exponent is not too small (this should be checked
2611: | before entering the rounding routine), but the number could be denormalized.
2612:
2613: | Check for denormalized numbers:
2614: 1: btst IMM (FLT_MANT_DIG),d0
2615: bne 2f | if set the number is normalized
2616: | Normalize shifting left until bit #FLT_MANT_DIG is set or the exponent
2617: | is one (remember that a denormalized number corresponds to an
2618: | exponent of -F_BIAS+1).
2619: cmpw IMM (1),d2 | remember that the exponent is at least one
2620: beq 2f | an exponent of one means denormalized
2621: addl d1,d1 | else shift and adjust the exponent
2622: addxl d0,d0 |
2623: dbra d2,1b |
2624: 2:
2625: | Now round: we do it as follows: after the shifting we can write the
2626: | fraction part as f + delta, where 1 < f < 2^25, and 0 <= delta <= 2.
2627: | If delta < 1, do nothing. If delta > 1, add 1 to f.
2628: | If delta == 1, we make sure the rounded number will be even (odd?)
2629: | (after shifting).
2630: btst IMM (0),d0 | is delta < 1?
2631: beq 2f | if so, do not do anything
2632: tstl d1 | is delta == 1?
2633: bne 1f | if so round to even
2634: movel d0,d1 |
2635: andl IMM (2),d1 | bit 1 is the last significant bit
2636: addl d1,d0 |
2637: bra 2f |
2638: 1: movel IMM (1),d1 | else add 1
2639: addl d1,d0 |
2640: | Shift right once (because we used bit #FLT_MANT_DIG!).
2641: 2: lsrl IMM (1),d0
2642: | Now check again bit #FLT_MANT_DIG (rounding could have produced a
2643: | 'fraction overflow' ...).
2644: btst IMM (FLT_MANT_DIG),d0
2645: beq 1f
2646: lsrl IMM (1),d0
2647: addw IMM (1),d2
2648: 1:
2649: | If bit #FLT_MANT_DIG-1 is clear we have a denormalized number, so we
2650: | have to put the exponent to zero and return a denormalized number.
2651: btst IMM (FLT_MANT_DIG-1),d0
2652: beq 1f
2653: jmp a0@
2654: 1: movel IMM (0),d2
2655: jmp a0@
2656:
2657: Lround$to$zero:
2658: Lround$to$plus:
2659: Lround$to$minus:
2660: jmp a0@
2661: #endif /* L_float */
2662:
2663: | gcc expects the routines __eqdf2, __nedf2, __gtdf2, __gedf2,
2664: | __ledf2, __ltdf2 to all return the same value as a direct call to
2665: | __cmpdf2 would. In this implementation, each of these routines
2666: | simply calls __cmpdf2. It would be more efficient to give the
2667: | __cmpdf2 routine several names, but separating them out will make it
2668: | easier to write efficient versions of these routines someday.
2669:
2670: #ifdef L_eqdf2
2671: LL0:
2672: .text
2673: .proc
2674: |#PROC# 04
2675: LF18 = 4
2676: LS18 = 128
2677: LFF18 = 0
2678: LSS18 = 0
2679: LV18 = 0
2680: .text
2681: .globl SYM (__eqdf2)
2682: SYM (__eqdf2):
2683: |#PROLOGUE# 0
2684: link a6,IMM (0)
2685: |#PROLOGUE# 1
2686: movl a6@(20),sp@-
2687: movl a6@(16),sp@-
2688: movl a6@(12),sp@-
2689: movl a6@(8),sp@-
2690: jbsr SYM (__cmpdf2)
2691: |#PROLOGUE# 2
2692: unlk a6
2693: |#PROLOGUE# 3
2694: rts
2695: #endif /* L_eqdf2 */
2696:
2697: #ifdef L_nedf2
2698: LL0:
2699: .text
2700: .proc
2701: |#PROC# 04
2702: LF18 = 8
2703: LS18 = 132
2704: LFF18 = 0
2705: LSS18 = 0
2706: LV18 = 0
2707: .text
2708: .globl SYM (__nedf2)
2709: SYM (__nedf2):
2710: |#PROLOGUE# 0
2711: link a6,IMM (0)
2712: |#PROLOGUE# 1
2713: movl a6@(20),sp@-
2714: movl a6@(16),sp@-
2715: movl a6@(12),sp@-
2716: movl a6@(8),sp@-
2717: jbsr SYM (__cmpdf2)
2718: |#PROLOGUE# 2
2719: unlk a6
2720: |#PROLOGUE# 3
2721: rts
2722: #endif /* L_nedf2 */
2723:
2724: #ifdef L_gtdf2
2725: .text
2726: .proc
2727: |#PROC# 04
2728: LF18 = 8
2729: LS18 = 132
2730: LFF18 = 0
2731: LSS18 = 0
2732: LV18 = 0
2733: .text
2734: .globl SYM (__gtdf2)
2735: SYM (__gtdf2):
2736: |#PROLOGUE# 0
2737: link a6,IMM (0)
2738: |#PROLOGUE# 1
2739: movl a6@(20),sp@-
2740: movl a6@(16),sp@-
2741: movl a6@(12),sp@-
2742: movl a6@(8),sp@-
2743: jbsr SYM (__cmpdf2)
2744: |#PROLOGUE# 2
2745: unlk a6
2746: |#PROLOGUE# 3
2747: rts
2748: #endif /* L_gtdf2 */
2749:
2750: #ifdef L_gedf2
2751: LL0:
2752: .text
2753: .proc
2754: |#PROC# 04
2755: LF18 = 8
2756: LS18 = 132
2757: LFF18 = 0
2758: LSS18 = 0
2759: LV18 = 0
2760: .text
2761: .globl SYM (__gedf2)
2762: SYM (__gedf2):
2763: |#PROLOGUE# 0
2764: link a6,IMM (0)
2765: |#PROLOGUE# 1
2766: movl a6@(20),sp@-
2767: movl a6@(16),sp@-
2768: movl a6@(12),sp@-
2769: movl a6@(8),sp@-
2770: jbsr SYM (__cmpdf2)
2771: |#PROLOGUE# 2
2772: unlk a6
2773: |#PROLOGUE# 3
2774: rts
2775: #endif /* L_gedf2 */
2776:
2777: #ifdef L_ltdf2
2778: LL0:
2779: .text
2780: .proc
2781: |#PROC# 04
2782: LF18 = 8
2783: LS18 = 132
2784: LFF18 = 0
2785: LSS18 = 0
2786: LV18 = 0
2787: .text
2788: .globl SYM (__ltdf2)
2789: SYM (__ltdf2):
2790: |#PROLOGUE# 0
2791: link a6,IMM (0)
2792: |#PROLOGUE# 1
2793: movl a6@(20),sp@-
2794: movl a6@(16),sp@-
2795: movl a6@(12),sp@-
2796: movl a6@(8),sp@-
2797: jbsr SYM (__cmpdf2)
2798: |#PROLOGUE# 2
2799: unlk a6
2800: |#PROLOGUE# 3
2801: rts
2802: #endif /* L_ltdf2 */
2803:
2804: #ifdef L_ledf2
2805: .text
2806: .proc
2807: |#PROC# 04
2808: LF18 = 8
2809: LS18 = 132
2810: LFF18 = 0
2811: LSS18 = 0
2812: LV18 = 0
2813: .text
2814: .globl SYM (__ledf2)
2815: SYM (__ledf2):
2816: |#PROLOGUE# 0
2817: link a6,IMM (0)
2818: |#PROLOGUE# 1
2819: movl a6@(20),sp@-
2820: movl a6@(16),sp@-
2821: movl a6@(12),sp@-
2822: movl a6@(8),sp@-
2823: jbsr SYM (__cmpdf2)
2824: |#PROLOGUE# 2
2825: unlk a6
2826: |#PROLOGUE# 3
2827: rts
2828: #endif /* L_ledf2 */
2829:
2830: | The comments above about __eqdf2, et. al., also apply to __eqsf2,
2831: | et. al., except that the latter call __cmpsf2 rather than __cmpdf2.
2832:
2833: #ifdef L_eqsf2
2834: .text
2835: .proc
2836: |#PROC# 04
2837: LF18 = 4
2838: LS18 = 128
2839: LFF18 = 0
2840: LSS18 = 0
2841: LV18 = 0
2842: .text
2843: .globl SYM (__eqsf2)
2844: SYM (__eqsf2):
2845: |#PROLOGUE# 0
2846: link a6,IMM (0)
2847: |#PROLOGUE# 1
2848: movl a6@(12),sp@-
2849: movl a6@(8),sp@-
2850: jbsr SYM (__cmpsf2)
2851: |#PROLOGUE# 2
2852: unlk a6
2853: |#PROLOGUE# 3
2854: rts
2855: #endif /* L_eqsf2 */
2856:
2857: #ifdef L_nesf2
2858: .text
2859: .proc
2860: |#PROC# 04
2861: LF18 = 8
2862: LS18 = 132
2863: LFF18 = 0
2864: LSS18 = 0
2865: LV18 = 0
2866: .text
2867: .globl SYM (__nesf2)
2868: SYM (__nesf2):
2869: |#PROLOGUE# 0
2870: link a6,IMM (0)
2871: |#PROLOGUE# 1
2872: movl a6@(12),sp@-
2873: movl a6@(8),sp@-
2874: jbsr SYM (__cmpsf2)
2875: |#PROLOGUE# 2
2876: unlk a6
2877: |#PROLOGUE# 3
2878: rts
2879: #endif /* L_nesf2 */
2880:
2881: #ifdef L_gtsf2
2882: .text
2883: .proc
2884: |#PROC# 04
2885: LF18 = 8
2886: LS18 = 132
2887: LFF18 = 0
2888: LSS18 = 0
2889: LV18 = 0
2890: .text
2891: .globl SYM (__gtsf2)
2892: SYM (__gtsf2):
2893: |#PROLOGUE# 0
2894: link a6,IMM (0)
2895: |#PROLOGUE# 1
2896: movl a6@(12),sp@-
2897: movl a6@(8),sp@-
2898: jbsr SYM (__cmpsf2)
2899: |#PROLOGUE# 2
2900: unlk a6
2901: |#PROLOGUE# 3
2902: rts
2903: #endif /* L_gtsf2 */
2904:
2905: #ifdef L_gesf2
2906: .text
2907: .proc
2908: |#PROC# 04
2909: LF18 = 8
2910: LS18 = 132
2911: LFF18 = 0
2912: LSS18 = 0
2913: LV18 = 0
2914: .text
2915: .globl SYM (__gesf2)
2916: SYM (__gesf2):
2917: |#PROLOGUE# 0
2918: link a6,IMM (0)
2919: |#PROLOGUE# 1
2920: movl a6@(12),sp@-
2921: movl a6@(8),sp@-
2922: jbsr SYM (__cmpsf2)
2923: |#PROLOGUE# 2
2924: unlk a6
2925: |#PROLOGUE# 3
2926: rts
2927: #endif /* L_gesf2 */
2928:
2929: #ifdef L_ltsf2
2930: .text
2931: .proc
2932: |#PROC# 04
2933: LF18 = 8
2934: LS18 = 132
2935: LFF18 = 0
2936: LSS18 = 0
2937: LV18 = 0
2938: .text
2939: .globl SYM (__ltsf2)
2940: SYM (__ltsf2):
2941: |#PROLOGUE# 0
2942: link a6,IMM (0)
2943: |#PROLOGUE# 1
2944: movl a6@(12),sp@-
2945: movl a6@(8),sp@-
2946: jbsr SYM (__cmpsf2)
2947: |#PROLOGUE# 2
2948: unlk a6
2949: |#PROLOGUE# 3
2950: rts
2951: #endif /* L_ltsf2 */
2952:
2953: #ifdef L_lesf2
2954: .text
2955: .proc
2956: |#PROC# 04
2957: LF18 = 8
2958: LS18 = 132
2959: LFF18 = 0
2960: LSS18 = 0
2961: LV18 = 0
2962: .text
2963: .globl SYM (__lesf2)
2964: SYM (__lesf2):
2965: |#PROLOGUE# 0
2966: link a6,IMM (0)
2967: |#PROLOGUE# 1
2968: movl a6@(12),sp@-
2969: movl a6@(8),sp@-
2970: jbsr SYM (__cmpsf2)
2971: |#PROLOGUE# 2
2972: unlk a6
2973: |#PROLOGUE# 3
2974: rts
2975: #endif /* L_lesf2 */
2976:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.