1 /* $Id: softfloat.c,v 1.4 2009/07/29 12:32:34 ragge Exp $ */
4 * Copyright (c) 2008 Anders Magnusson. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 * Floating point emulation to be used when cross-compiling.
36 * Currently only supports F- and D-float, used in DEC machines.
37 * Should be trivial to add other emulations.
40 * - long long is (at least) 64 bits
41 * - int is at least 32 bits.
48 * Useful macros to manipulate the float.
50 #define DSIGN(w) (((w).fd1 >> 15) & 1)
51 #define DSIGNSET(w,s) ((w).fd1 = (s << 15) | ((w).fd1 & 077777))
52 #define DEXP(w) (((w).fd1 >> 7) & 0377)
53 #define DEXPSET(w,e) ((w).fd1 = (((e) & 0377) << 7) | ((w).fd1 & 0100177))
54 #define DMANTH(w) ((w).fd1 & 0177)
55 #define DMANTHSET(w,m) ((w).fd1 = ((m) & 0177) | ((w).fd1 & 0177600))
57 typedef unsigned int lword
;
58 typedef unsigned long long dword
;
60 #define MAXMANT 0x100000000000000LL
63 * Returns a zero dfloat.
70 rv
.fd1
= rv
.fd2
= rv
.fd3
= rv
.fd4
= 0;
75 * Convert a (u)longlong to dfloat.
76 * XXX - fails on too large (> 55 bits) numbers.
79 soft_cast(CONSZ ll
, TWORD t
)
86 return rv
; /* fp is zero */
88 DSIGNSET(rv
,1), ll
= -ll
;
89 for (i
= 0; ll
> 0; i
++, ll
<<= 1)
92 DMANTHSET(rv
, ll
>> 56);
100 * multiply two dfloat. Use chop, not round.
103 soft_mul(SF p1
, SF p2
)
106 lword a1
[2], a2
[2], res
[4];
109 res
[0] = res
[1] = res
[2] = res
[3] = 0;
111 /* move mantissa into lwords */
112 a1
[0] = p1
.fd4
| (p1
.fd3
<< 16);
113 a1
[1] = p1
.fd2
| DMANTH(p1
) << 16 | 0x800000;
115 a2
[0] = p2
.fd4
| (p2
.fd3
<< 16);
116 a2
[1] = p2
.fd2
| DMANTH(p2
) << 16 | 0x800000;
118 #define MULONE(x,y,r) sum += (dword)a1[x] * (dword)a2[y]; sum += res[r]; \
119 res[r] = sum; sum >>= 32;
131 DSIGNSET(rv
, DSIGN(p1
) ^ DSIGN(p2
));
132 DEXPSET(rv
, DEXP(p1
) + DEXP(p2
) - 128);
133 if (res
[3] & 0x8000) {
134 res
[3] = (res
[3] << 8) | (res
[2] >> 24);
135 res
[2] = (res
[2] << 8) | (res
[1] >> 24);
137 DEXPSET(rv
, DEXP(rv
) - 1);
138 res
[3] = (res
[3] << 9) | (res
[2] >> 23);
139 res
[2] = (res
[2] << 9) | (res
[1] >> 23);
141 DMANTHSET(rv
, res
[3] >> 16);
143 rv
.fd3
= res
[2] >> 16;
155 #define SHL(x,b) ((dword)(x) << b)
156 T
= SHL(1,55) | SHL(DMANTH(t
), 48) |
157 SHL(t
.fd2
, 32) | SHL(t
.fd3
, 16) | t
.fd4
;
158 N
= SHL(1,55) | SHL(DMANTH(n
), 48) |
159 SHL(n
.fd2
, 32) | SHL(n
.fd3
, 16) | n
.fd4
;
162 for (K
= 0; (K
& 0x80000000000000ULL
) == 0; ) {
171 DSIGNSET(rv
, DSIGN(t
) ^ DSIGN(n
));
172 DEXPSET(rv
, DEXP(t
) - DEXP(n
) + 128 + c
);
173 DMANTHSET(rv
, K
>> 48);
181 * Negate a float number. Easy.
186 int sign
= DSIGN(sf
) == 0;
192 * Return true if fp number is zero.
197 return (DEXP(sf
) == 0);
201 soft_cmp_eq(SF x1
, SF x2
)
203 cerror("soft_cmp_eq");
208 soft_cmp_ne(SF x1
, SF x2
)
210 cerror("soft_cmp_ne");
215 soft_cmp_le(SF x1
, SF x2
)
217 cerror("soft_cmp_le");
222 soft_cmp_lt(SF x1
, SF x2
)
224 cerror("soft_cmp_lt");
229 soft_cmp_ge(SF x1
, SF x2
)
231 cerror("soft_cmp_ge");
236 soft_cmp_gt(SF x1
, SF x2
)
238 cerror("soft_cmp_gt");
243 * Convert a fp number to a CONSZ.
249 int exp
= DEXP(sf
) - 128;
251 mant
= SHL(1,55) | SHL(DMANTH(sf
), 48) |
252 SHL(sf
.fd2
, 32) | SHL(sf
.fd3
, 16) | sf
.fd4
;
262 soft_plus(SF x1
, SF x2
)
269 soft_minus(SF x1
, SF x2
)
271 cerror("soft_minus");
276 * Convert a hex constant to floating point number.
286 * Convert a floating-point constant to D-float and store it in a NODE.
294 int exp
, negexp
, bexp
;
298 #define ADDTO(sum, val) sum = sum * 10 + val - '0'
299 for (; *s
>= '0' && *s
<= '9'; s
++) {
306 for (s
++; *s
>= '0' && *s
<= '9'; s
++) {
314 if ((*s
== 'E') || (*s
== 'e')) {
315 int eexp
= 0, sign
= 0;
322 for (; *s
>= '0' && *s
<= '9'; s
++)
336 flexp
= soft_cast(1, INT
);
337 exp5
= soft_cast(5, INT
);
339 fl
= soft_cast(mant
, INT
);
341 for (; exp
; exp
>>= 1) {
343 flexp
= soft_mul(flexp
, exp5
);
344 exp5
= soft_mul(exp5
, exp5
);
347 fl
= soft_div(fl
, flexp
);
349 fl
= soft_mul(fl
, flexp
);
351 DEXPSET(fl
, DEXP(fl
) + negexp
*bexp
);
352 p
= block(FCON
, NIL
, NIL
, DOUBLE
, 0, MKSUE(DOUBLE
)); /* XXX type */
357 #error missing softfloat definition