Imported Upstream version 2.9.0
[debian/cc1111] / device / lib / _fsadd.c
1 /* Floating point library in optimized assembly for 8051
2  * Copyright (c) 2004, Paul Stoffregen, paul@pjrc.com
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  */
18
19
20 #define SDCC_FLOAT_LIB
21 #include <float.h>
22
23
24 #ifdef FLOAT_ASM_MCS51
25
26 // float __fsadd (float a, float b) __reentrant
27 static void dummy(void) __naked
28 {
29         __asm
30
31         // extract the two inputs, placing them into:
32         //      sign     exponent   mantiassa
33         //      ----     --------   ---------
34         //  a:  sign_a   exp_a      r4/r3/r2
35         //  b:  sign_b   exp_b      r7/r6/r5
36         //
37         // r1: used to extend precision of a's mantissa
38         // r0: general purpose loop counter
39
40         .globl  ___fsadd
41 ___fsadd:
42         lcall   fsgetargs
43
44         .globl  fsadd_direct_entry
45 fsadd_direct_entry:
46         // we're going to extend mantissa to 32 bits temporarily
47         mov     r1, #0
48
49         // which exponent is greater?
50         mov     a, exp_b
51         cjne    a, exp_a, 00005$
52         sjmp    00011$
53 00005$: jnc     00010$
54
55         // a's exponent was greater, so shift b's mantissa
56         lcall   fs_swap_a_b
57
58 00010$:
59         // b's exponent was greater, so shift a's mantissa
60         mov     a, exp_b
61         clr     c
62         subb    a, exp_a
63         lcall   fs_rshift_a     // acc has # of shifts to do
64
65 00011$:
66         // decide if we need to add or subtract
67         // sign_a and sign_b are stored in the flag bits of psw,
68         // so this little trick checks if the arguements ave the
69         // same sign.
70         mov     a, psw
71         swap    a
72         xrl     a, psw
73         jb      acc.1, 00022$
74
75 00020$:
76         // add the mantissas (both positive or both negative)
77         mov     a, r2
78         add     a, r5
79         mov     r2, a
80         mov     a, r3
81         addc    a, r6
82         mov     r3, a
83         mov     a, r4
84         addc    a, r7
85         mov     r4, a
86         // check for overflow past 24 bits
87         jnc     00021$
88         mov     a, #1
89         lcall   fs_rshift_a
90         mov     a, r4
91         orl     a, #0x80
92         mov     r4, a
93 00021$:
94         ljmp    fs_round_and_return
95
96
97
98 00022$:
99         // subtract the mantissas (one of them is negative)
100         clr     c
101         mov     a, r2
102         subb    a, r5
103         mov     r2, a
104         mov     a, r3
105         subb    a, r6
106         mov     r3, a
107         mov     a, r4
108         subb    a, r7
109         mov     r4, a
110         jnc     00025$
111         // if we get a negative result, turn it positive and
112         // flip the sign bit
113         clr     c
114         clr     a
115         subb    a, r1
116         mov     r1, a
117         clr     a
118         subb    a, r2
119         mov     r2, a
120         clr     a
121         subb    a, r3
122         mov     r3, a
123         clr     a
124         subb    a, r4
125         mov     r4, a
126         cpl     sign_a
127 00025$:
128         lcall   fs_normalize_a
129         ljmp    fs_round_and_return
130
131         __endasm;
132 }
133
134 #else
135
136
137 /*
138 ** libgcc support for software floating point.
139 ** Copyright (C) 1991 by Pipeline Associates, Inc.  All rights reserved.
140 ** Permission is granted to do *anything* you want with this file,
141 ** commercial or otherwise, provided this message remains intact.  So there!
142 ** I would appreciate receiving any updates/patches/changes that anyone
143 ** makes, and am willing to be the repository for said changes (am I
144 ** making a big mistake?).
145 **
146 ** Pat Wood
147 ** Pipeline Associates, Inc.
148 ** pipeline!phw@motown.com or
149 ** sun!pipeline!phw or
150 ** uunet!motown!pipeline!phw
151 */
152
153 union float_long
154   {
155     float f;
156     unsigned long l;
157   };
158
159 /* add two floats */
160 float __fsadd (float a1, float a2)
161 {
162   volatile long mant1, mant2;
163   volatile union float_long fl1, fl2;
164   volatile int exp1, exp2;
165   char sign = 0;
166
167   fl1.f = a1;
168   fl2.f = a2;
169
170   /* check for zero args */
171   if (!fl1.l)
172     return (fl2.f);
173   if (!fl2.l)
174     return (fl1.f);
175
176   exp1 = EXP (fl1.l);
177   exp2 = EXP (fl2.l);
178
179   if (exp1 > exp2 + 25)
180     return (fl1.f);
181   if (exp2 > exp1 + 25)
182     return (fl2.f);
183
184   mant1 = MANT (fl1.l);
185   mant2 = MANT (fl2.l);
186
187   if (SIGN (fl1.l))
188     mant1 = -mant1;
189   if (SIGN (fl2.l))
190     mant2 = -mant2;
191
192   if (exp1 > exp2)
193     {
194       mant2 >>= exp1 - exp2;
195     }
196   else
197     {
198       mant1 >>= exp2 - exp1;
199       exp1 = exp2;
200     }
201   mant1 += mant2;
202
203   if (mant1 < 0)
204     {
205       mant1 = -mant1;
206       sign = 1;
207     }
208   else if (!mant1)
209     return (0);
210
211   /* normalize */
212   while (mant1<HIDDEN) {
213     mant1 <<= 1;
214     exp1--;
215   }
216
217   /* round off */
218   while (mant1 & 0xff000000) {
219     if (mant1&1)
220       mant1 += 2;
221     mant1 >>= 1;
222     exp1++;
223   }
224
225   /* turn off hidden bit */
226   mant1 &= ~HIDDEN;
227
228   /* pack up and go home */
229   if (exp1 >= 0x100)
230     fl1.l = (sign ? SIGNBIT : 0) | __INFINITY;
231   else if (exp1 < 0)
232     fl1.l = 0;
233   else
234     fl1.l = PACK (sign ? SIGNBIT : 0 , exp1, mant1);
235   return (fl1.f);
236 }
237
238 #endif