Added mcs51 assembly float lib functions (add, sub, mul, div
[fw/sdcc] / 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
154 union float_long
155   {
156     float f;
157     unsigned long l;
158   };
159
160 /* add two floats */
161 float __fsadd (float a1, float a2)
162 {
163   volatile long mant1, mant2;
164   volatile union float_long fl1, fl2;
165   volatile int exp1, exp2;
166   volatile unsigned long sign = 0;
167
168   fl1.f = a1;
169   fl2.f = a2;
170
171   /* check for zero args */
172   if (!fl1.l)
173     return (fl2.f);
174   if (!fl2.l)
175     return (fl1.f);
176
177   exp1 = EXP (fl1.l);
178   exp2 = EXP (fl2.l);
179
180   if (exp1 > exp2 + 25)
181     return (fl1.f);
182   if (exp2 > exp1 + 25)
183     return (fl2.f);
184
185   mant1 = MANT (fl1.l);
186   mant2 = MANT (fl2.l);
187
188   if (SIGN (fl1.l))
189     mant1 = -mant1;
190   if (SIGN (fl2.l))
191     mant2 = -mant2;
192
193   if (exp1 > exp2)
194     {
195       mant2 >>= exp1 - exp2;
196     }
197   else
198     {
199       mant1 >>= exp2 - exp1;
200       exp1 = exp2;
201     }
202   mant1 += mant2;
203
204   if (mant1 < 0)
205     {
206       mant1 = -mant1;
207       sign = SIGNBIT;
208     }
209   else if (!mant1)
210     return (0);
211
212   /* normalize */
213   while (mant1<HIDDEN) {
214     mant1 <<= 1;
215     exp1--;
216   }
217
218   /* round off */
219   while (mant1 & 0xff000000) {
220     if (mant1&1)
221       mant1 += 2;
222     mant1 >>= 1 ;
223     exp1++;
224   }
225
226   /* turn off hidden bit */
227   mant1 &= ~HIDDEN;
228
229   /* pack up and go home */
230   fl1.l = PACK (sign, (unsigned long) exp1, mant1);
231
232   return (fl1.f);
233 }
234
235 #endif
236