Commit 00406dff19893a4fb9fb582792a249b770eb1d11
1 parent
69de927c
added arm nwfpe support (initial patch by Ulrich Hecht)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@609 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
16 changed files
with
3914 additions
and
0 deletions
Too many changes to show.
To preserve performance only 16 of 18 files are displayed.
target-arm/nwfpe/ARM-gcc.h
0 → 100644
1 | +/* | |
2 | +------------------------------------------------------------------------------- | |
3 | +The macro `BITS64' can be defined to indicate that 64-bit integer types are | |
4 | +supported by the compiler. | |
5 | +------------------------------------------------------------------------------- | |
6 | +*/ | |
7 | +#define BITS64 | |
8 | + | |
9 | +/* | |
10 | +------------------------------------------------------------------------------- | |
11 | +Each of the following `typedef's defines the most convenient type that holds | |
12 | +integers of at least as many bits as specified. For example, `uint8' should | |
13 | +be the most convenient type that can hold unsigned integers of as many as | |
14 | +8 bits. The `flag' type must be able to hold either a 0 or 1. For most | |
15 | +implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed | |
16 | +to the same as `int'. | |
17 | +------------------------------------------------------------------------------- | |
18 | +*/ | |
19 | +typedef char flag; | |
20 | +typedef unsigned char uint8; | |
21 | +typedef signed char int8; | |
22 | +typedef int uint16; | |
23 | +typedef int int16; | |
24 | +typedef unsigned int uint32; | |
25 | +typedef signed int int32; | |
26 | +#ifdef BITS64 | |
27 | +typedef unsigned long long int bits64; | |
28 | +typedef signed long long int sbits64; | |
29 | +#endif | |
30 | + | |
31 | +/* | |
32 | +------------------------------------------------------------------------------- | |
33 | +Each of the following `typedef's defines a type that holds integers | |
34 | +of _exactly_ the number of bits specified. For instance, for most | |
35 | +implementation of C, `bits16' and `sbits16' should be `typedef'ed to | |
36 | +`unsigned short int' and `signed short int' (or `short int'), respectively. | |
37 | +------------------------------------------------------------------------------- | |
38 | +*/ | |
39 | +typedef unsigned char bits8; | |
40 | +typedef signed char sbits8; | |
41 | +typedef unsigned short int bits16; | |
42 | +typedef signed short int sbits16; | |
43 | +typedef unsigned int bits32; | |
44 | +typedef signed int sbits32; | |
45 | +#ifdef BITS64 | |
46 | +typedef unsigned long long int uint64; | |
47 | +typedef signed long long int int64; | |
48 | +#endif | |
49 | + | |
50 | +#ifdef BITS64 | |
51 | +/* | |
52 | +------------------------------------------------------------------------------- | |
53 | +The `LIT64' macro takes as its argument a textual integer literal and if | |
54 | +necessary ``marks'' the literal as having a 64-bit integer type. For | |
55 | +example, the Gnu C Compiler (`gcc') requires that 64-bit literals be | |
56 | +appended with the letters `LL' standing for `long long', which is `gcc's | |
57 | +name for the 64-bit integer type. Some compilers may allow `LIT64' to be | |
58 | +defined as the identity macro: `#define LIT64( a ) a'. | |
59 | +------------------------------------------------------------------------------- | |
60 | +*/ | |
61 | +#define LIT64( a ) a##LL | |
62 | +#endif | |
63 | + | |
64 | +/* | |
65 | +------------------------------------------------------------------------------- | |
66 | +The macro `INLINE' can be used before functions that should be inlined. If | |
67 | +a compiler does not support explicit inlining, this macro should be defined | |
68 | +to be `static'. | |
69 | +------------------------------------------------------------------------------- | |
70 | +*/ | |
71 | +#define INLINE extern __inline__ | |
72 | + | |
73 | + | |
74 | +/* For use as a GCC soft-float library we need some special function names. */ | |
75 | + | |
76 | +#ifdef __LIBFLOAT__ | |
77 | + | |
78 | +/* Some 32-bit ops can be mapped straight across by just changing the name. */ | |
79 | +#define float32_add __addsf3 | |
80 | +#define float32_sub __subsf3 | |
81 | +#define float32_mul __mulsf3 | |
82 | +#define float32_div __divsf3 | |
83 | +#define int32_to_float32 __floatsisf | |
84 | +#define float32_to_int32_round_to_zero __fixsfsi | |
85 | +#define float32_to_uint32_round_to_zero __fixunssfsi | |
86 | + | |
87 | +/* These ones go through the glue code. To avoid namespace pollution | |
88 | + we rename the internal functions too. */ | |
89 | +#define float32_eq ___float32_eq | |
90 | +#define float32_le ___float32_le | |
91 | +#define float32_lt ___float32_lt | |
92 | + | |
93 | +/* All the 64-bit ops have to go through the glue, so we pull the same | |
94 | + trick. */ | |
95 | +#define float64_add ___float64_add | |
96 | +#define float64_sub ___float64_sub | |
97 | +#define float64_mul ___float64_mul | |
98 | +#define float64_div ___float64_div | |
99 | +#define int32_to_float64 ___int32_to_float64 | |
100 | +#define float64_to_int32_round_to_zero ___float64_to_int32_round_to_zero | |
101 | +#define float64_to_uint32_round_to_zero ___float64_to_uint32_round_to_zero | |
102 | +#define float64_to_float32 ___float64_to_float32 | |
103 | +#define float32_to_float64 ___float32_to_float64 | |
104 | +#define float64_eq ___float64_eq | |
105 | +#define float64_le ___float64_le | |
106 | +#define float64_lt ___float64_lt | |
107 | + | |
108 | +#if 0 | |
109 | +#define float64_add __adddf3 | |
110 | +#define float64_sub __subdf3 | |
111 | +#define float64_mul __muldf3 | |
112 | +#define float64_div __divdf3 | |
113 | +#define int32_to_float64 __floatsidf | |
114 | +#define float64_to_int32_round_to_zero __fixdfsi | |
115 | +#define float64_to_uint32_round_to_zero __fixunsdfsi | |
116 | +#define float64_to_float32 __truncdfsf2 | |
117 | +#define float32_to_float64 __extendsfdf2 | |
118 | +#endif | |
119 | + | |
120 | +#endif | ... | ... |
target-arm/nwfpe/double_cpdo.c
0 → 100644
1 | +/* | |
2 | + NetWinder Floating Point Emulator | |
3 | + (c) Rebel.COM, 1998,1999 | |
4 | + | |
5 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | |
6 | + | |
7 | + This program is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 2 of the License, or | |
10 | + (at your option) any later version. | |
11 | + | |
12 | + This program is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with this program; if not, write to the Free Software | |
19 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 | +*/ | |
21 | + | |
22 | +#include "fpa11.h" | |
23 | +#include "softfloat.h" | |
24 | +#include "fpopcode.h" | |
25 | + | |
26 | +float64 float64_exp(float64 Fm); | |
27 | +float64 float64_ln(float64 Fm); | |
28 | +float64 float64_sin(float64 rFm); | |
29 | +float64 float64_cos(float64 rFm); | |
30 | +float64 float64_arcsin(float64 rFm); | |
31 | +float64 float64_arctan(float64 rFm); | |
32 | +float64 float64_log(float64 rFm); | |
33 | +float64 float64_tan(float64 rFm); | |
34 | +float64 float64_arccos(float64 rFm); | |
35 | +float64 float64_pow(float64 rFn,float64 rFm); | |
36 | +float64 float64_pol(float64 rFn,float64 rFm); | |
37 | + | |
38 | +unsigned int DoubleCPDO(const unsigned int opcode) | |
39 | +{ | |
40 | + FPA11 *fpa11 = GET_FPA11(); | |
41 | + float64 rFm, rFn; | |
42 | + unsigned int Fd, Fm, Fn, nRc = 1; | |
43 | + | |
44 | + //printk("DoubleCPDO(0x%08x)\n",opcode); | |
45 | + | |
46 | + Fm = getFm(opcode); | |
47 | + if (CONSTANT_FM(opcode)) | |
48 | + { | |
49 | + rFm = getDoubleConstant(Fm); | |
50 | + } | |
51 | + else | |
52 | + { | |
53 | + switch (fpa11->fType[Fm]) | |
54 | + { | |
55 | + case typeSingle: | |
56 | + rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle); | |
57 | + break; | |
58 | + | |
59 | + case typeDouble: | |
60 | + rFm = fpa11->fpreg[Fm].fDouble; | |
61 | + break; | |
62 | + | |
63 | + case typeExtended: | |
64 | + // !! patb | |
65 | + //printk("not implemented! why not?\n"); | |
66 | + //!! ScottB | |
67 | + // should never get here, if extended involved | |
68 | + // then other operand should be promoted then | |
69 | + // ExtendedCPDO called. | |
70 | + break; | |
71 | + | |
72 | + default: return 0; | |
73 | + } | |
74 | + } | |
75 | + | |
76 | + if (!MONADIC_INSTRUCTION(opcode)) | |
77 | + { | |
78 | + Fn = getFn(opcode); | |
79 | + switch (fpa11->fType[Fn]) | |
80 | + { | |
81 | + case typeSingle: | |
82 | + rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle); | |
83 | + break; | |
84 | + | |
85 | + case typeDouble: | |
86 | + rFn = fpa11->fpreg[Fn].fDouble; | |
87 | + break; | |
88 | + | |
89 | + default: return 0; | |
90 | + } | |
91 | + } | |
92 | + | |
93 | + Fd = getFd(opcode); | |
94 | + /* !! this switch isn't optimized; better (opcode & MASK_ARITHMETIC_OPCODE)>>24, sort of */ | |
95 | + switch (opcode & MASK_ARITHMETIC_OPCODE) | |
96 | + { | |
97 | + /* dyadic opcodes */ | |
98 | + case ADF_CODE: | |
99 | + fpa11->fpreg[Fd].fDouble = float64_add(rFn,rFm); | |
100 | + break; | |
101 | + | |
102 | + case MUF_CODE: | |
103 | + case FML_CODE: | |
104 | + fpa11->fpreg[Fd].fDouble = float64_mul(rFn,rFm); | |
105 | + break; | |
106 | + | |
107 | + case SUF_CODE: | |
108 | + fpa11->fpreg[Fd].fDouble = float64_sub(rFn,rFm); | |
109 | + break; | |
110 | + | |
111 | + case RSF_CODE: | |
112 | + fpa11->fpreg[Fd].fDouble = float64_sub(rFm,rFn); | |
113 | + break; | |
114 | + | |
115 | + case DVF_CODE: | |
116 | + case FDV_CODE: | |
117 | + fpa11->fpreg[Fd].fDouble = float64_div(rFn,rFm); | |
118 | + break; | |
119 | + | |
120 | + case RDF_CODE: | |
121 | + case FRD_CODE: | |
122 | + fpa11->fpreg[Fd].fDouble = float64_div(rFm,rFn); | |
123 | + break; | |
124 | + | |
125 | +#if 0 | |
126 | + case POW_CODE: | |
127 | + fpa11->fpreg[Fd].fDouble = float64_pow(rFn,rFm); | |
128 | + break; | |
129 | + | |
130 | + case RPW_CODE: | |
131 | + fpa11->fpreg[Fd].fDouble = float64_pow(rFm,rFn); | |
132 | + break; | |
133 | +#endif | |
134 | + | |
135 | + case RMF_CODE: | |
136 | + fpa11->fpreg[Fd].fDouble = float64_rem(rFn,rFm); | |
137 | + break; | |
138 | + | |
139 | +#if 0 | |
140 | + case POL_CODE: | |
141 | + fpa11->fpreg[Fd].fDouble = float64_pol(rFn,rFm); | |
142 | + break; | |
143 | +#endif | |
144 | + | |
145 | + /* monadic opcodes */ | |
146 | + case MVF_CODE: | |
147 | + fpa11->fpreg[Fd].fDouble = rFm; | |
148 | + break; | |
149 | + | |
150 | + case MNF_CODE: | |
151 | + { | |
152 | + unsigned int *p = (unsigned int*)&rFm; | |
153 | + p[1] ^= 0x80000000; | |
154 | + fpa11->fpreg[Fd].fDouble = rFm; | |
155 | + } | |
156 | + break; | |
157 | + | |
158 | + case ABS_CODE: | |
159 | + { | |
160 | + unsigned int *p = (unsigned int*)&rFm; | |
161 | + p[1] &= 0x7fffffff; | |
162 | + fpa11->fpreg[Fd].fDouble = rFm; | |
163 | + } | |
164 | + break; | |
165 | + | |
166 | + case RND_CODE: | |
167 | + case URD_CODE: | |
168 | + fpa11->fpreg[Fd].fDouble = float64_round_to_int(rFm); | |
169 | + break; | |
170 | + | |
171 | + case SQT_CODE: | |
172 | + fpa11->fpreg[Fd].fDouble = float64_sqrt(rFm); | |
173 | + break; | |
174 | + | |
175 | +#if 0 | |
176 | + case LOG_CODE: | |
177 | + fpa11->fpreg[Fd].fDouble = float64_log(rFm); | |
178 | + break; | |
179 | + | |
180 | + case LGN_CODE: | |
181 | + fpa11->fpreg[Fd].fDouble = float64_ln(rFm); | |
182 | + break; | |
183 | + | |
184 | + case EXP_CODE: | |
185 | + fpa11->fpreg[Fd].fDouble = float64_exp(rFm); | |
186 | + break; | |
187 | + | |
188 | + case SIN_CODE: | |
189 | + fpa11->fpreg[Fd].fDouble = float64_sin(rFm); | |
190 | + break; | |
191 | + | |
192 | + case COS_CODE: | |
193 | + fpa11->fpreg[Fd].fDouble = float64_cos(rFm); | |
194 | + break; | |
195 | + | |
196 | + case TAN_CODE: | |
197 | + fpa11->fpreg[Fd].fDouble = float64_tan(rFm); | |
198 | + break; | |
199 | + | |
200 | + case ASN_CODE: | |
201 | + fpa11->fpreg[Fd].fDouble = float64_arcsin(rFm); | |
202 | + break; | |
203 | + | |
204 | + case ACS_CODE: | |
205 | + fpa11->fpreg[Fd].fDouble = float64_arccos(rFm); | |
206 | + break; | |
207 | + | |
208 | + case ATN_CODE: | |
209 | + fpa11->fpreg[Fd].fDouble = float64_arctan(rFm); | |
210 | + break; | |
211 | +#endif | |
212 | + | |
213 | + case NRM_CODE: | |
214 | + break; | |
215 | + | |
216 | + default: | |
217 | + { | |
218 | + nRc = 0; | |
219 | + } | |
220 | + } | |
221 | + | |
222 | + if (0 != nRc) fpa11->fType[Fd] = typeDouble; | |
223 | + return nRc; | |
224 | +} | |
225 | + | |
226 | +#if 0 | |
227 | +float64 float64_exp(float64 rFm) | |
228 | +{ | |
229 | + return rFm; | |
230 | +//series | |
231 | +} | |
232 | + | |
233 | +float64 float64_ln(float64 rFm) | |
234 | +{ | |
235 | + return rFm; | |
236 | +//series | |
237 | +} | |
238 | + | |
239 | +float64 float64_sin(float64 rFm) | |
240 | +{ | |
241 | + return rFm; | |
242 | +//series | |
243 | +} | |
244 | + | |
245 | +float64 float64_cos(float64 rFm) | |
246 | +{ | |
247 | + return rFm; | |
248 | + //series | |
249 | +} | |
250 | + | |
251 | +#if 0 | |
252 | +float64 float64_arcsin(float64 rFm) | |
253 | +{ | |
254 | +//series | |
255 | +} | |
256 | + | |
257 | +float64 float64_arctan(float64 rFm) | |
258 | +{ | |
259 | + //series | |
260 | +} | |
261 | +#endif | |
262 | + | |
263 | +float64 float64_log(float64 rFm) | |
264 | +{ | |
265 | + return float64_div(float64_ln(rFm),getDoubleConstant(7)); | |
266 | +} | |
267 | + | |
268 | +float64 float64_tan(float64 rFm) | |
269 | +{ | |
270 | + return float64_div(float64_sin(rFm),float64_cos(rFm)); | |
271 | +} | |
272 | + | |
273 | +float64 float64_arccos(float64 rFm) | |
274 | +{ | |
275 | +return rFm; | |
276 | + //return float64_sub(halfPi,float64_arcsin(rFm)); | |
277 | +} | |
278 | + | |
279 | +float64 float64_pow(float64 rFn,float64 rFm) | |
280 | +{ | |
281 | + return float64_exp(float64_mul(rFm,float64_ln(rFn))); | |
282 | +} | |
283 | + | |
284 | +float64 float64_pol(float64 rFn,float64 rFm) | |
285 | +{ | |
286 | + return float64_arctan(float64_div(rFn,rFm)); | |
287 | +} | |
288 | +#endif | ... | ... |
target-arm/nwfpe/extended_cpdo.c
0 → 100644
1 | +/* | |
2 | + NetWinder Floating Point Emulator | |
3 | + (c) Rebel.COM, 1998,1999 | |
4 | + | |
5 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | |
6 | + | |
7 | + This program is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 2 of the License, or | |
10 | + (at your option) any later version. | |
11 | + | |
12 | + This program is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with this program; if not, write to the Free Software | |
19 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 | +*/ | |
21 | + | |
22 | +#include "fpa11.h" | |
23 | +#include "softfloat.h" | |
24 | +#include "fpopcode.h" | |
25 | + | |
26 | +floatx80 floatx80_exp(floatx80 Fm); | |
27 | +floatx80 floatx80_ln(floatx80 Fm); | |
28 | +floatx80 floatx80_sin(floatx80 rFm); | |
29 | +floatx80 floatx80_cos(floatx80 rFm); | |
30 | +floatx80 floatx80_arcsin(floatx80 rFm); | |
31 | +floatx80 floatx80_arctan(floatx80 rFm); | |
32 | +floatx80 floatx80_log(floatx80 rFm); | |
33 | +floatx80 floatx80_tan(floatx80 rFm); | |
34 | +floatx80 floatx80_arccos(floatx80 rFm); | |
35 | +floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm); | |
36 | +floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm); | |
37 | + | |
38 | +unsigned int ExtendedCPDO(const unsigned int opcode) | |
39 | +{ | |
40 | + FPA11 *fpa11 = GET_FPA11(); | |
41 | + floatx80 rFm, rFn; | |
42 | + unsigned int Fd, Fm, Fn, nRc = 1; | |
43 | + | |
44 | + //printk("ExtendedCPDO(0x%08x)\n",opcode); | |
45 | + | |
46 | + Fm = getFm(opcode); | |
47 | + if (CONSTANT_FM(opcode)) | |
48 | + { | |
49 | + rFm = getExtendedConstant(Fm); | |
50 | + } | |
51 | + else | |
52 | + { | |
53 | + switch (fpa11->fType[Fm]) | |
54 | + { | |
55 | + case typeSingle: | |
56 | + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle); | |
57 | + break; | |
58 | + | |
59 | + case typeDouble: | |
60 | + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble); | |
61 | + break; | |
62 | + | |
63 | + case typeExtended: | |
64 | + rFm = fpa11->fpreg[Fm].fExtended; | |
65 | + break; | |
66 | + | |
67 | + default: return 0; | |
68 | + } | |
69 | + } | |
70 | + | |
71 | + if (!MONADIC_INSTRUCTION(opcode)) | |
72 | + { | |
73 | + Fn = getFn(opcode); | |
74 | + switch (fpa11->fType[Fn]) | |
75 | + { | |
76 | + case typeSingle: | |
77 | + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); | |
78 | + break; | |
79 | + | |
80 | + case typeDouble: | |
81 | + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); | |
82 | + break; | |
83 | + | |
84 | + case typeExtended: | |
85 | + rFn = fpa11->fpreg[Fn].fExtended; | |
86 | + break; | |
87 | + | |
88 | + default: return 0; | |
89 | + } | |
90 | + } | |
91 | + | |
92 | + Fd = getFd(opcode); | |
93 | + switch (opcode & MASK_ARITHMETIC_OPCODE) | |
94 | + { | |
95 | + /* dyadic opcodes */ | |
96 | + case ADF_CODE: | |
97 | + fpa11->fpreg[Fd].fExtended = floatx80_add(rFn,rFm); | |
98 | + break; | |
99 | + | |
100 | + case MUF_CODE: | |
101 | + case FML_CODE: | |
102 | + fpa11->fpreg[Fd].fExtended = floatx80_mul(rFn,rFm); | |
103 | + break; | |
104 | + | |
105 | + case SUF_CODE: | |
106 | + fpa11->fpreg[Fd].fExtended = floatx80_sub(rFn,rFm); | |
107 | + break; | |
108 | + | |
109 | + case RSF_CODE: | |
110 | + fpa11->fpreg[Fd].fExtended = floatx80_sub(rFm,rFn); | |
111 | + break; | |
112 | + | |
113 | + case DVF_CODE: | |
114 | + case FDV_CODE: | |
115 | + fpa11->fpreg[Fd].fExtended = floatx80_div(rFn,rFm); | |
116 | + break; | |
117 | + | |
118 | + case RDF_CODE: | |
119 | + case FRD_CODE: | |
120 | + fpa11->fpreg[Fd].fExtended = floatx80_div(rFm,rFn); | |
121 | + break; | |
122 | + | |
123 | +#if 0 | |
124 | + case POW_CODE: | |
125 | + fpa11->fpreg[Fd].fExtended = floatx80_pow(rFn,rFm); | |
126 | + break; | |
127 | + | |
128 | + case RPW_CODE: | |
129 | + fpa11->fpreg[Fd].fExtended = floatx80_pow(rFm,rFn); | |
130 | + break; | |
131 | +#endif | |
132 | + | |
133 | + case RMF_CODE: | |
134 | + fpa11->fpreg[Fd].fExtended = floatx80_rem(rFn,rFm); | |
135 | + break; | |
136 | + | |
137 | +#if 0 | |
138 | + case POL_CODE: | |
139 | + fpa11->fpreg[Fd].fExtended = floatx80_pol(rFn,rFm); | |
140 | + break; | |
141 | +#endif | |
142 | + | |
143 | + /* monadic opcodes */ | |
144 | + case MVF_CODE: | |
145 | + fpa11->fpreg[Fd].fExtended = rFm; | |
146 | + break; | |
147 | + | |
148 | + case MNF_CODE: | |
149 | + rFm.high ^= 0x8000; | |
150 | + fpa11->fpreg[Fd].fExtended = rFm; | |
151 | + break; | |
152 | + | |
153 | + case ABS_CODE: | |
154 | + rFm.high &= 0x7fff; | |
155 | + fpa11->fpreg[Fd].fExtended = rFm; | |
156 | + break; | |
157 | + | |
158 | + case RND_CODE: | |
159 | + case URD_CODE: | |
160 | + fpa11->fpreg[Fd].fExtended = floatx80_round_to_int(rFm); | |
161 | + break; | |
162 | + | |
163 | + case SQT_CODE: | |
164 | + fpa11->fpreg[Fd].fExtended = floatx80_sqrt(rFm); | |
165 | + break; | |
166 | + | |
167 | +#if 0 | |
168 | + case LOG_CODE: | |
169 | + fpa11->fpreg[Fd].fExtended = floatx80_log(rFm); | |
170 | + break; | |
171 | + | |
172 | + case LGN_CODE: | |
173 | + fpa11->fpreg[Fd].fExtended = floatx80_ln(rFm); | |
174 | + break; | |
175 | + | |
176 | + case EXP_CODE: | |
177 | + fpa11->fpreg[Fd].fExtended = floatx80_exp(rFm); | |
178 | + break; | |
179 | + | |
180 | + case SIN_CODE: | |
181 | + fpa11->fpreg[Fd].fExtended = floatx80_sin(rFm); | |
182 | + break; | |
183 | + | |
184 | + case COS_CODE: | |
185 | + fpa11->fpreg[Fd].fExtended = floatx80_cos(rFm); | |
186 | + break; | |
187 | + | |
188 | + case TAN_CODE: | |
189 | + fpa11->fpreg[Fd].fExtended = floatx80_tan(rFm); | |
190 | + break; | |
191 | + | |
192 | + case ASN_CODE: | |
193 | + fpa11->fpreg[Fd].fExtended = floatx80_arcsin(rFm); | |
194 | + break; | |
195 | + | |
196 | + case ACS_CODE: | |
197 | + fpa11->fpreg[Fd].fExtended = floatx80_arccos(rFm); | |
198 | + break; | |
199 | + | |
200 | + case ATN_CODE: | |
201 | + fpa11->fpreg[Fd].fExtended = floatx80_arctan(rFm); | |
202 | + break; | |
203 | +#endif | |
204 | + | |
205 | + case NRM_CODE: | |
206 | + break; | |
207 | + | |
208 | + default: | |
209 | + { | |
210 | + nRc = 0; | |
211 | + } | |
212 | + } | |
213 | + | |
214 | + if (0 != nRc) fpa11->fType[Fd] = typeExtended; | |
215 | + return nRc; | |
216 | +} | |
217 | + | |
218 | +#if 0 | |
219 | +floatx80 floatx80_exp(floatx80 Fm) | |
220 | +{ | |
221 | +//series | |
222 | +} | |
223 | + | |
224 | +floatx80 floatx80_ln(floatx80 Fm) | |
225 | +{ | |
226 | +//series | |
227 | +} | |
228 | + | |
229 | +floatx80 floatx80_sin(floatx80 rFm) | |
230 | +{ | |
231 | +//series | |
232 | +} | |
233 | + | |
234 | +floatx80 floatx80_cos(floatx80 rFm) | |
235 | +{ | |
236 | +//series | |
237 | +} | |
238 | + | |
239 | +floatx80 floatx80_arcsin(floatx80 rFm) | |
240 | +{ | |
241 | +//series | |
242 | +} | |
243 | + | |
244 | +floatx80 floatx80_arctan(floatx80 rFm) | |
245 | +{ | |
246 | + //series | |
247 | +} | |
248 | + | |
249 | +floatx80 floatx80_log(floatx80 rFm) | |
250 | +{ | |
251 | + return floatx80_div(floatx80_ln(rFm),getExtendedConstant(7)); | |
252 | +} | |
253 | + | |
254 | +floatx80 floatx80_tan(floatx80 rFm) | |
255 | +{ | |
256 | + return floatx80_div(floatx80_sin(rFm),floatx80_cos(rFm)); | |
257 | +} | |
258 | + | |
259 | +floatx80 floatx80_arccos(floatx80 rFm) | |
260 | +{ | |
261 | + //return floatx80_sub(halfPi,floatx80_arcsin(rFm)); | |
262 | +} | |
263 | + | |
264 | +floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm) | |
265 | +{ | |
266 | + return floatx80_exp(floatx80_mul(rFm,floatx80_ln(rFn))); | |
267 | +} | |
268 | + | |
269 | +floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm) | |
270 | +{ | |
271 | + return floatx80_arctan(floatx80_div(rFn,rFm)); | |
272 | +} | |
273 | +#endif | ... | ... |
target-arm/nwfpe/fpa11.c
0 → 100644
1 | +/* | |
2 | + NetWinder Floating Point Emulator | |
3 | + (c) Rebel.COM, 1998,1999 | |
4 | + | |
5 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | |
6 | + | |
7 | + This program is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 2 of the License, or | |
10 | + (at your option) any later version. | |
11 | + | |
12 | + This program is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with this program; if not, write to the Free Software | |
19 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 | +*/ | |
21 | + | |
22 | +#include "fpa11.h" | |
23 | + | |
24 | +#include "fpopcode.h" | |
25 | + | |
26 | +//#include "fpmodule.h" | |
27 | +//#include "fpmodule.inl" | |
28 | + | |
29 | +//#include <asm/system.h> | |
30 | + | |
31 | +#include <stdio.h> | |
32 | + | |
33 | +/* forward declarations */ | |
34 | +unsigned int EmulateCPDO(const unsigned int); | |
35 | +unsigned int EmulateCPDT(const unsigned int); | |
36 | +unsigned int EmulateCPRT(const unsigned int); | |
37 | + | |
38 | +FPA11* qemufpa=0; | |
39 | +unsigned int* user_registers=0; | |
40 | + | |
41 | +/* Reset the FPA11 chip. Called to initialize and reset the emulator. */ | |
42 | +void resetFPA11(void) | |
43 | +{ | |
44 | + int i; | |
45 | + FPA11 *fpa11 = GET_FPA11(); | |
46 | + | |
47 | + /* initialize the register type array */ | |
48 | + for (i=0;i<=7;i++) | |
49 | + { | |
50 | + fpa11->fType[i] = typeNone; | |
51 | + } | |
52 | + | |
53 | + /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ | |
54 | + fpa11->fpsr = FP_EMULATOR | BIT_AC; | |
55 | + | |
56 | + /* FPCR: set SB, AB and DA bits, clear all others */ | |
57 | +#if MAINTAIN_FPCR | |
58 | + fpa11->fpcr = MASK_RESET; | |
59 | +#endif | |
60 | +} | |
61 | + | |
62 | +void SetRoundingMode(const unsigned int opcode) | |
63 | +{ | |
64 | +#if MAINTAIN_FPCR | |
65 | + FPA11 *fpa11 = GET_FPA11(); | |
66 | + fpa11->fpcr &= ~MASK_ROUNDING_MODE; | |
67 | +#endif | |
68 | + switch (opcode & MASK_ROUNDING_MODE) | |
69 | + { | |
70 | + default: | |
71 | + case ROUND_TO_NEAREST: | |
72 | + float_rounding_mode = float_round_nearest_even; | |
73 | +#if MAINTAIN_FPCR | |
74 | + fpa11->fpcr |= ROUND_TO_NEAREST; | |
75 | +#endif | |
76 | + break; | |
77 | + | |
78 | + case ROUND_TO_PLUS_INFINITY: | |
79 | + float_rounding_mode = float_round_up; | |
80 | +#if MAINTAIN_FPCR | |
81 | + fpa11->fpcr |= ROUND_TO_PLUS_INFINITY; | |
82 | +#endif | |
83 | + break; | |
84 | + | |
85 | + case ROUND_TO_MINUS_INFINITY: | |
86 | + float_rounding_mode = float_round_down; | |
87 | +#if MAINTAIN_FPCR | |
88 | + fpa11->fpcr |= ROUND_TO_MINUS_INFINITY; | |
89 | +#endif | |
90 | + break; | |
91 | + | |
92 | + case ROUND_TO_ZERO: | |
93 | + float_rounding_mode = float_round_to_zero; | |
94 | +#if MAINTAIN_FPCR | |
95 | + fpa11->fpcr |= ROUND_TO_ZERO; | |
96 | +#endif | |
97 | + break; | |
98 | + } | |
99 | +} | |
100 | + | |
101 | +void SetRoundingPrecision(const unsigned int opcode) | |
102 | +{ | |
103 | +#if MAINTAIN_FPCR | |
104 | + FPA11 *fpa11 = GET_FPA11(); | |
105 | + fpa11->fpcr &= ~MASK_ROUNDING_PRECISION; | |
106 | +#endif | |
107 | + switch (opcode & MASK_ROUNDING_PRECISION) | |
108 | + { | |
109 | + case ROUND_SINGLE: | |
110 | + floatx80_rounding_precision = 32; | |
111 | +#if MAINTAIN_FPCR | |
112 | + fpa11->fpcr |= ROUND_SINGLE; | |
113 | +#endif | |
114 | + break; | |
115 | + | |
116 | + case ROUND_DOUBLE: | |
117 | + floatx80_rounding_precision = 64; | |
118 | +#if MAINTAIN_FPCR | |
119 | + fpa11->fpcr |= ROUND_DOUBLE; | |
120 | +#endif | |
121 | + break; | |
122 | + | |
123 | + case ROUND_EXTENDED: | |
124 | + floatx80_rounding_precision = 80; | |
125 | +#if MAINTAIN_FPCR | |
126 | + fpa11->fpcr |= ROUND_EXTENDED; | |
127 | +#endif | |
128 | + break; | |
129 | + | |
130 | + default: floatx80_rounding_precision = 80; | |
131 | + } | |
132 | +} | |
133 | + | |
134 | +/* Emulate the instruction in the opcode. */ | |
135 | +unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, unsigned int* qregs) | |
136 | +{ | |
137 | + unsigned int nRc = 0; | |
138 | +// unsigned long flags; | |
139 | + FPA11 *fpa11; | |
140 | +// save_flags(flags); sti(); | |
141 | + | |
142 | + qemufpa=qfpa; | |
143 | + user_registers=qregs; | |
144 | + | |
145 | +#if 0 | |
146 | + fprintf(stderr,"emulating FP insn 0x%08x, PC=0x%08x\n", | |
147 | + opcode, qregs[REG_PC]); | |
148 | +#endif | |
149 | + fpa11 = GET_FPA11(); | |
150 | + | |
151 | + if (fpa11->initflag == 0) /* good place for __builtin_expect */ | |
152 | + { | |
153 | + resetFPA11(); | |
154 | + SetRoundingMode(ROUND_TO_NEAREST); | |
155 | + SetRoundingPrecision(ROUND_EXTENDED); | |
156 | + fpa11->initflag = 1; | |
157 | + } | |
158 | + | |
159 | + if (TEST_OPCODE(opcode,MASK_CPRT)) | |
160 | + { | |
161 | + //fprintf(stderr,"emulating CPRT\n"); | |
162 | + /* Emulate conversion opcodes. */ | |
163 | + /* Emulate register transfer opcodes. */ | |
164 | + /* Emulate comparison opcodes. */ | |
165 | + nRc = EmulateCPRT(opcode); | |
166 | + } | |
167 | + else if (TEST_OPCODE(opcode,MASK_CPDO)) | |
168 | + { | |
169 | + //fprintf(stderr,"emulating CPDO\n"); | |
170 | + /* Emulate monadic arithmetic opcodes. */ | |
171 | + /* Emulate dyadic arithmetic opcodes. */ | |
172 | + nRc = EmulateCPDO(opcode); | |
173 | + } | |
174 | + else if (TEST_OPCODE(opcode,MASK_CPDT)) | |
175 | + { | |
176 | + //fprintf(stderr,"emulating CPDT\n"); | |
177 | + /* Emulate load/store opcodes. */ | |
178 | + /* Emulate load/store multiple opcodes. */ | |
179 | + nRc = EmulateCPDT(opcode); | |
180 | + } | |
181 | + else | |
182 | + { | |
183 | + /* Invalid instruction detected. Return FALSE. */ | |
184 | + nRc = 0; | |
185 | + } | |
186 | + | |
187 | +// restore_flags(flags); | |
188 | + | |
189 | + //printf("returning %d\n",nRc); | |
190 | + return(nRc); | |
191 | +} | |
192 | + | |
193 | +#if 0 | |
194 | +unsigned int EmulateAll1(unsigned int opcode) | |
195 | +{ | |
196 | + switch ((opcode >> 24) & 0xf) | |
197 | + { | |
198 | + case 0xc: | |
199 | + case 0xd: | |
200 | + if ((opcode >> 20) & 0x1) | |
201 | + { | |
202 | + switch ((opcode >> 8) & 0xf) | |
203 | + { | |
204 | + case 0x1: return PerformLDF(opcode); break; | |
205 | + case 0x2: return PerformLFM(opcode); break; | |
206 | + default: return 0; | |
207 | + } | |
208 | + } | |
209 | + else | |
210 | + { | |
211 | + switch ((opcode >> 8) & 0xf) | |
212 | + { | |
213 | + case 0x1: return PerformSTF(opcode); break; | |
214 | + case 0x2: return PerformSFM(opcode); break; | |
215 | + default: return 0; | |
216 | + } | |
217 | + } | |
218 | + break; | |
219 | + | |
220 | + case 0xe: | |
221 | + if (opcode & 0x10) | |
222 | + return EmulateCPDO(opcode); | |
223 | + else | |
224 | + return EmulateCPRT(opcode); | |
225 | + break; | |
226 | + | |
227 | + default: return 0; | |
228 | + } | |
229 | +} | |
230 | +#endif | |
231 | + | ... | ... |
target-arm/nwfpe/fpa11.h
0 → 100644
1 | +/* | |
2 | + NetWinder Floating Point Emulator | |
3 | + (c) Rebel.com, 1998-1999 | |
4 | + | |
5 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | |
6 | + | |
7 | + This program is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 2 of the License, or | |
10 | + (at your option) any later version. | |
11 | + | |
12 | + This program is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with this program; if not, write to the Free Software | |
19 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 | +*/ | |
21 | + | |
22 | +#ifndef __FPA11_H__ | |
23 | +#define __FPA11_H__ | |
24 | + | |
25 | +#define GET_FPA11() (qemufpa) | |
26 | + | |
27 | +/* | |
28 | + * The processes registers are always at the very top of the 8K | |
29 | + * stack+task struct. Use the same method as 'current' uses to | |
30 | + * reach them. | |
31 | + */ | |
32 | +extern unsigned int *user_registers; | |
33 | + | |
34 | +#define GET_USERREG() (user_registers) | |
35 | + | |
36 | +/* Need task_struct */ | |
37 | +//#include <linux/sched.h> | |
38 | + | |
39 | +/* includes */ | |
40 | +#include "fpsr.h" /* FP control and status register definitions */ | |
41 | +#include "softfloat.h" | |
42 | + | |
43 | +#define typeNone 0x00 | |
44 | +#define typeSingle 0x01 | |
45 | +#define typeDouble 0x02 | |
46 | +#define typeExtended 0x03 | |
47 | + | |
48 | +/* | |
49 | + * This must be no more and no less than 12 bytes. | |
50 | + */ | |
51 | +typedef union tagFPREG { | |
52 | + floatx80 fExtended; | |
53 | + float64 fDouble; | |
54 | + float32 fSingle; | |
55 | +} FPREG; | |
56 | + | |
57 | +/* | |
58 | + * FPA11 device model. | |
59 | + * | |
60 | + * This structure is exported to user space. Do not re-order. | |
61 | + * Only add new stuff to the end, and do not change the size of | |
62 | + * any element. Elements of this structure are used by user | |
63 | + * space, and must match struct user_fp in include/asm-arm/user.h. | |
64 | + * We include the byte offsets below for documentation purposes. | |
65 | + * | |
66 | + * The size of this structure and FPREG are checked by fpmodule.c | |
67 | + * on initialisation. If the rules have been broken, NWFPE will | |
68 | + * not initialise. | |
69 | + */ | |
70 | +typedef struct tagFPA11 { | |
71 | +/* 0 */ FPREG fpreg[8]; /* 8 floating point registers */ | |
72 | +/* 96 */ FPSR fpsr; /* floating point status register */ | |
73 | +/* 100 */ FPCR fpcr; /* floating point control register */ | |
74 | +/* 104 */ unsigned char fType[8]; /* type of floating point value held in | |
75 | + floating point registers. One of none | |
76 | + single, double or extended. */ | |
77 | +/* 112 */ int initflag; /* this is special. The kernel guarantees | |
78 | + to set it to 0 when a thread is launched, | |
79 | + so we can use it to detect whether this | |
80 | + instance of the emulator needs to be | |
81 | + initialised. */ | |
82 | +} FPA11; | |
83 | + | |
84 | +extern FPA11* qemufpa; | |
85 | + | |
86 | +extern void resetFPA11(void); | |
87 | +extern void SetRoundingMode(const unsigned int); | |
88 | +extern void SetRoundingPrecision(const unsigned int); | |
89 | + | |
90 | +#define get_user(x,y) ((x)=*(y)) | |
91 | +#define put_user(x,y) (*(y)=(x)) | |
92 | +static inline unsigned int readRegister(unsigned int reg) | |
93 | +{ | |
94 | + return (user_registers[(reg)]); | |
95 | +} | |
96 | + | |
97 | +static inline void writeRegister(unsigned int x, unsigned int y) | |
98 | +{ | |
99 | +#if 0 | |
100 | + printf("writing %d to r%d\n",y,x); | |
101 | +#endif | |
102 | + user_registers[(x)]=(y); | |
103 | +} | |
104 | + | |
105 | +static inline void writeConditionCodes(unsigned int x) | |
106 | +{ | |
107 | +#if 0 | |
108 | +unsigned int y; | |
109 | +unsigned int ZF; | |
110 | + printf("setting flags to %x from %x\n",x,user_registers[16]); | |
111 | +#endif | |
112 | + user_registers[16]=(x); // cpsr | |
113 | + user_registers[17]=(x>>29)&1; // cf | |
114 | + user_registers[18]=(x<<3)&(1<<31); // vf | |
115 | + user_registers[19]=x&(1<<31); // nzf | |
116 | + if(!(x&(1<<30))) user_registers[19]++; // nzf must be non-zero for zf to be cleared | |
117 | + | |
118 | +#if 0 | |
119 | + ZF = (user_registers[19] == 0); | |
120 | + y=user_registers[16] | (user_registers[19] & 0x80000000) | (ZF << 30) | | |
121 | + (user_registers[17] << 29) | ((user_registers[18] & 0x80000000) >> 3); | |
122 | + if(y != x) | |
123 | + printf("GODDAM SHIIIIIIIIIIIIIIIIT! %x %x nzf %x zf %x\n",x,y,user_registers[19],ZF); | |
124 | +#endif | |
125 | +} | |
126 | + | |
127 | +#define REG_PC 15 | |
128 | + | |
129 | +unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, unsigned int* qregs); | |
130 | + | |
131 | +#endif | ... | ... |
target-arm/nwfpe/fpa11.inl
0 → 100644
1 | +/* | |
2 | + NetWinder Floating Point Emulator | |
3 | + (c) Rebel.COM, 1998,1999 | |
4 | + | |
5 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | |
6 | + | |
7 | + This program is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 2 of the License, or | |
10 | + (at your option) any later version. | |
11 | + | |
12 | + This program is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with this program; if not, write to the Free Software | |
19 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 | +*/ | |
21 | + | |
22 | +#include "fpa11.h" | |
23 | + | |
24 | +/* Read and write floating point status register */ | |
25 | +extern __inline__ unsigned int readFPSR(void) | |
26 | +{ | |
27 | + FPA11 *fpa11 = GET_FPA11(); | |
28 | + return(fpa11->fpsr); | |
29 | +} | |
30 | + | |
31 | +extern __inline__ void writeFPSR(FPSR reg) | |
32 | +{ | |
33 | + FPA11 *fpa11 = GET_FPA11(); | |
34 | + /* the sysid byte in the status register is readonly */ | |
35 | + fpa11->fpsr = (fpa11->fpsr & MASK_SYSID) | (reg & ~MASK_SYSID); | |
36 | +} | |
37 | + | |
38 | +/* Read and write floating point control register */ | |
39 | +extern __inline__ FPCR readFPCR(void) | |
40 | +{ | |
41 | + FPA11 *fpa11 = GET_FPA11(); | |
42 | + /* clear SB, AB and DA bits before returning FPCR */ | |
43 | + return(fpa11->fpcr & ~MASK_RFC); | |
44 | +} | |
45 | + | |
46 | +extern __inline__ void writeFPCR(FPCR reg) | |
47 | +{ | |
48 | + FPA11 *fpa11 = GET_FPA11(); | |
49 | + fpa11->fpcr &= ~MASK_WFC; /* clear SB, AB and DA bits */ | |
50 | + fpa11->fpcr |= (reg & MASK_WFC); /* write SB, AB and DA bits */ | |
51 | +} | ... | ... |
target-arm/nwfpe/fpa11_cpdo.c
0 → 100644
1 | +/* | |
2 | + NetWinder Floating Point Emulator | |
3 | + (c) Rebel.COM, 1998,1999 | |
4 | + | |
5 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | |
6 | + | |
7 | + This program is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 2 of the License, or | |
10 | + (at your option) any later version. | |
11 | + | |
12 | + This program is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with this program; if not, write to the Free Software | |
19 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 | +*/ | |
21 | + | |
22 | +#include "fpa11.h" | |
23 | +#include "fpopcode.h" | |
24 | + | |
25 | +unsigned int SingleCPDO(const unsigned int opcode); | |
26 | +unsigned int DoubleCPDO(const unsigned int opcode); | |
27 | +unsigned int ExtendedCPDO(const unsigned int opcode); | |
28 | + | |
29 | +unsigned int EmulateCPDO(const unsigned int opcode) | |
30 | +{ | |
31 | + FPA11 *fpa11 = GET_FPA11(); | |
32 | + unsigned int Fd, nType, nDest, nRc = 1; | |
33 | + | |
34 | + //printk("EmulateCPDO(0x%08x)\n",opcode); | |
35 | + | |
36 | + /* Get the destination size. If not valid let Linux perform | |
37 | + an invalid instruction trap. */ | |
38 | + nDest = getDestinationSize(opcode); | |
39 | + if (typeNone == nDest) return 0; | |
40 | + | |
41 | + SetRoundingMode(opcode); | |
42 | + | |
43 | + /* Compare the size of the operands in Fn and Fm. | |
44 | + Choose the largest size and perform operations in that size, | |
45 | + in order to make use of all the precision of the operands. | |
46 | + If Fm is a constant, we just grab a constant of a size | |
47 | + matching the size of the operand in Fn. */ | |
48 | + if (MONADIC_INSTRUCTION(opcode)) | |
49 | + nType = nDest; | |
50 | + else | |
51 | + nType = fpa11->fType[getFn(opcode)]; | |
52 | + | |
53 | + if (!CONSTANT_FM(opcode)) | |
54 | + { | |
55 | + register unsigned int Fm = getFm(opcode); | |
56 | + if (nType < fpa11->fType[Fm]) | |
57 | + { | |
58 | + nType = fpa11->fType[Fm]; | |
59 | + } | |
60 | + } | |
61 | + | |
62 | + switch (nType) | |
63 | + { | |
64 | + case typeSingle : nRc = SingleCPDO(opcode); break; | |
65 | + case typeDouble : nRc = DoubleCPDO(opcode); break; | |
66 | + case typeExtended : nRc = ExtendedCPDO(opcode); break; | |
67 | + default : nRc = 0; | |
68 | + } | |
69 | + | |
70 | + /* If the operation succeeded, check to see if the result in the | |
71 | + destination register is the correct size. If not force it | |
72 | + to be. */ | |
73 | + Fd = getFd(opcode); | |
74 | + nType = fpa11->fType[Fd]; | |
75 | + if ((0 != nRc) && (nDest != nType)) | |
76 | + { | |
77 | + switch (nDest) | |
78 | + { | |
79 | + case typeSingle: | |
80 | + { | |
81 | + if (typeDouble == nType) | |
82 | + fpa11->fpreg[Fd].fSingle = | |
83 | + float64_to_float32(fpa11->fpreg[Fd].fDouble); | |
84 | + else | |
85 | + fpa11->fpreg[Fd].fSingle = | |
86 | + floatx80_to_float32(fpa11->fpreg[Fd].fExtended); | |
87 | + } | |
88 | + break; | |
89 | + | |
90 | + case typeDouble: | |
91 | + { | |
92 | + if (typeSingle == nType) | |
93 | + fpa11->fpreg[Fd].fDouble = | |
94 | + float32_to_float64(fpa11->fpreg[Fd].fSingle); | |
95 | + else | |
96 | + fpa11->fpreg[Fd].fDouble = | |
97 | + floatx80_to_float64(fpa11->fpreg[Fd].fExtended); | |
98 | + } | |
99 | + break; | |
100 | + | |
101 | + case typeExtended: | |
102 | + { | |
103 | + if (typeSingle == nType) | |
104 | + fpa11->fpreg[Fd].fExtended = | |
105 | + float32_to_floatx80(fpa11->fpreg[Fd].fSingle); | |
106 | + else | |
107 | + fpa11->fpreg[Fd].fExtended = | |
108 | + float64_to_floatx80(fpa11->fpreg[Fd].fDouble); | |
109 | + } | |
110 | + break; | |
111 | + } | |
112 | + | |
113 | + fpa11->fType[Fd] = nDest; | |
114 | + } | |
115 | + | |
116 | + return nRc; | |
117 | +} | ... | ... |
target-arm/nwfpe/fpa11_cpdt.c
0 → 100644
1 | +/* | |
2 | + NetWinder Floating Point Emulator | |
3 | + (c) Rebel.com, 1998-1999 | |
4 | + (c) Philip Blundell, 1998 | |
5 | + | |
6 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | |
7 | + | |
8 | + This program is free software; you can redistribute it and/or modify | |
9 | + it under the terms of the GNU General Public License as published by | |
10 | + the Free Software Foundation; either version 2 of the License, or | |
11 | + (at your option) any later version. | |
12 | + | |
13 | + This program is distributed in the hope that it will be useful, | |
14 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | + GNU General Public License for more details. | |
17 | + | |
18 | + You should have received a copy of the GNU General Public License | |
19 | + along with this program; if not, write to the Free Software | |
20 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
21 | +*/ | |
22 | + | |
23 | +#include "fpa11.h" | |
24 | +#include "softfloat.h" | |
25 | +#include "fpopcode.h" | |
26 | +//#include "fpmodule.h" | |
27 | +//#include "fpmodule.inl" | |
28 | + | |
29 | +//#include <asm/uaccess.h> | |
30 | + | |
31 | +static inline | |
32 | +void loadSingle(const unsigned int Fn,const unsigned int *pMem) | |
33 | +{ | |
34 | + FPA11 *fpa11 = GET_FPA11(); | |
35 | + fpa11->fType[Fn] = typeSingle; | |
36 | + get_user(fpa11->fpreg[Fn].fSingle, pMem); | |
37 | +} | |
38 | + | |
39 | +static inline | |
40 | +void loadDouble(const unsigned int Fn,const unsigned int *pMem) | |
41 | +{ | |
42 | + FPA11 *fpa11 = GET_FPA11(); | |
43 | + unsigned int *p; | |
44 | + p = (unsigned int*)&fpa11->fpreg[Fn].fDouble; | |
45 | + fpa11->fType[Fn] = typeDouble; | |
46 | + get_user(p[0], &pMem[1]); | |
47 | + get_user(p[1], &pMem[0]); /* sign & exponent */ | |
48 | +} | |
49 | + | |
50 | +static inline | |
51 | +void loadExtended(const unsigned int Fn,const unsigned int *pMem) | |
52 | +{ | |
53 | + FPA11 *fpa11 = GET_FPA11(); | |
54 | + unsigned int *p; | |
55 | + p = (unsigned int*)&fpa11->fpreg[Fn].fExtended; | |
56 | + fpa11->fType[Fn] = typeExtended; | |
57 | + get_user(p[0], &pMem[0]); /* sign & exponent */ | |
58 | + get_user(p[1], &pMem[2]); /* ls bits */ | |
59 | + get_user(p[2], &pMem[1]); /* ms bits */ | |
60 | +} | |
61 | + | |
62 | +static inline | |
63 | +void loadMultiple(const unsigned int Fn,const unsigned int *pMem) | |
64 | +{ | |
65 | + FPA11 *fpa11 = GET_FPA11(); | |
66 | + register unsigned int *p; | |
67 | + unsigned long x; | |
68 | + | |
69 | + p = (unsigned int*)&(fpa11->fpreg[Fn]); | |
70 | + get_user(x, &pMem[0]); | |
71 | + fpa11->fType[Fn] = (x >> 14) & 0x00000003; | |
72 | + | |
73 | + switch (fpa11->fType[Fn]) | |
74 | + { | |
75 | + case typeSingle: | |
76 | + case typeDouble: | |
77 | + { | |
78 | + get_user(p[0], &pMem[2]); /* Single */ | |
79 | + get_user(p[1], &pMem[1]); /* double msw */ | |
80 | + p[2] = 0; /* empty */ | |
81 | + } | |
82 | + break; | |
83 | + | |
84 | + case typeExtended: | |
85 | + { | |
86 | + get_user(p[1], &pMem[2]); | |
87 | + get_user(p[2], &pMem[1]); /* msw */ | |
88 | + p[0] = (x & 0x80003fff); | |
89 | + } | |
90 | + break; | |
91 | + } | |
92 | +} | |
93 | + | |
94 | +static inline | |
95 | +void storeSingle(const unsigned int Fn,unsigned int *pMem) | |
96 | +{ | |
97 | + FPA11 *fpa11 = GET_FPA11(); | |
98 | + float32 val; | |
99 | + register unsigned int *p = (unsigned int*)&val; | |
100 | + | |
101 | + switch (fpa11->fType[Fn]) | |
102 | + { | |
103 | + case typeDouble: | |
104 | + val = float64_to_float32(fpa11->fpreg[Fn].fDouble); | |
105 | + break; | |
106 | + | |
107 | + case typeExtended: | |
108 | + val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended); | |
109 | + break; | |
110 | + | |
111 | + default: val = fpa11->fpreg[Fn].fSingle; | |
112 | + } | |
113 | + | |
114 | + put_user(p[0], pMem); | |
115 | +} | |
116 | + | |
117 | +static inline | |
118 | +void storeDouble(const unsigned int Fn,unsigned int *pMem) | |
119 | +{ | |
120 | + FPA11 *fpa11 = GET_FPA11(); | |
121 | + float64 val; | |
122 | + register unsigned int *p = (unsigned int*)&val; | |
123 | + | |
124 | + switch (fpa11->fType[Fn]) | |
125 | + { | |
126 | + case typeSingle: | |
127 | + val = float32_to_float64(fpa11->fpreg[Fn].fSingle); | |
128 | + break; | |
129 | + | |
130 | + case typeExtended: | |
131 | + val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended); | |
132 | + break; | |
133 | + | |
134 | + default: val = fpa11->fpreg[Fn].fDouble; | |
135 | + } | |
136 | + put_user(p[1], &pMem[0]); /* msw */ | |
137 | + put_user(p[0], &pMem[1]); /* lsw */ | |
138 | +} | |
139 | + | |
140 | +static inline | |
141 | +void storeExtended(const unsigned int Fn,unsigned int *pMem) | |
142 | +{ | |
143 | + FPA11 *fpa11 = GET_FPA11(); | |
144 | + floatx80 val; | |
145 | + register unsigned int *p = (unsigned int*)&val; | |
146 | + | |
147 | + switch (fpa11->fType[Fn]) | |
148 | + { | |
149 | + case typeSingle: | |
150 | + val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); | |
151 | + break; | |
152 | + | |
153 | + case typeDouble: | |
154 | + val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); | |
155 | + break; | |
156 | + | |
157 | + default: val = fpa11->fpreg[Fn].fExtended; | |
158 | + } | |
159 | + | |
160 | + put_user(p[0], &pMem[0]); /* sign & exp */ | |
161 | + put_user(p[1], &pMem[2]); | |
162 | + put_user(p[2], &pMem[1]); /* msw */ | |
163 | +} | |
164 | + | |
165 | +static inline | |
166 | +void storeMultiple(const unsigned int Fn,unsigned int *pMem) | |
167 | +{ | |
168 | + FPA11 *fpa11 = GET_FPA11(); | |
169 | + register unsigned int nType, *p; | |
170 | + | |
171 | + p = (unsigned int*)&(fpa11->fpreg[Fn]); | |
172 | + nType = fpa11->fType[Fn]; | |
173 | + | |
174 | + switch (nType) | |
175 | + { | |
176 | + case typeSingle: | |
177 | + case typeDouble: | |
178 | + { | |
179 | + put_user(p[0], &pMem[2]); /* single */ | |
180 | + put_user(p[1], &pMem[1]); /* double msw */ | |
181 | + put_user(nType << 14, &pMem[0]); | |
182 | + } | |
183 | + break; | |
184 | + | |
185 | + case typeExtended: | |
186 | + { | |
187 | + put_user(p[2], &pMem[1]); /* msw */ | |
188 | + put_user(p[1], &pMem[2]); | |
189 | + put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]); | |
190 | + } | |
191 | + break; | |
192 | + } | |
193 | +} | |
194 | + | |
195 | +unsigned int PerformLDF(const unsigned int opcode) | |
196 | +{ | |
197 | + unsigned int *pBase, *pAddress, *pFinal, nRc = 1, | |
198 | + write_back = WRITE_BACK(opcode); | |
199 | + | |
200 | + //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); | |
201 | + | |
202 | + pBase = (unsigned int*)readRegister(getRn(opcode)); | |
203 | + if (REG_PC == getRn(opcode)) | |
204 | + { | |
205 | + pBase += 2; | |
206 | + write_back = 0; | |
207 | + } | |
208 | + | |
209 | + pFinal = pBase; | |
210 | + if (BIT_UP_SET(opcode)) | |
211 | + pFinal += getOffset(opcode); | |
212 | + else | |
213 | + pFinal -= getOffset(opcode); | |
214 | + | |
215 | + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; | |
216 | + | |
217 | + switch (opcode & MASK_TRANSFER_LENGTH) | |
218 | + { | |
219 | + case TRANSFER_SINGLE : loadSingle(getFd(opcode),pAddress); break; | |
220 | + case TRANSFER_DOUBLE : loadDouble(getFd(opcode),pAddress); break; | |
221 | + case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break; | |
222 | + default: nRc = 0; | |
223 | + } | |
224 | + | |
225 | + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); | |
226 | + return nRc; | |
227 | +} | |
228 | + | |
229 | +unsigned int PerformSTF(const unsigned int opcode) | |
230 | +{ | |
231 | + unsigned int *pBase, *pAddress, *pFinal, nRc = 1, | |
232 | + write_back = WRITE_BACK(opcode); | |
233 | + | |
234 | + //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); | |
235 | + SetRoundingMode(ROUND_TO_NEAREST); | |
236 | + | |
237 | + pBase = (unsigned int*)readRegister(getRn(opcode)); | |
238 | + if (REG_PC == getRn(opcode)) | |
239 | + { | |
240 | + pBase += 2; | |
241 | + write_back = 0; | |
242 | + } | |
243 | + | |
244 | + pFinal = pBase; | |
245 | + if (BIT_UP_SET(opcode)) | |
246 | + pFinal += getOffset(opcode); | |
247 | + else | |
248 | + pFinal -= getOffset(opcode); | |
249 | + | |
250 | + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; | |
251 | + | |
252 | + switch (opcode & MASK_TRANSFER_LENGTH) | |
253 | + { | |
254 | + case TRANSFER_SINGLE : storeSingle(getFd(opcode),pAddress); break; | |
255 | + case TRANSFER_DOUBLE : storeDouble(getFd(opcode),pAddress); break; | |
256 | + case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break; | |
257 | + default: nRc = 0; | |
258 | + } | |
259 | + | |
260 | + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); | |
261 | + return nRc; | |
262 | +} | |
263 | + | |
264 | +unsigned int PerformLFM(const unsigned int opcode) | |
265 | +{ | |
266 | + unsigned int i, Fd, *pBase, *pAddress, *pFinal, | |
267 | + write_back = WRITE_BACK(opcode); | |
268 | + | |
269 | + pBase = (unsigned int*)readRegister(getRn(opcode)); | |
270 | + if (REG_PC == getRn(opcode)) | |
271 | + { | |
272 | + pBase += 2; | |
273 | + write_back = 0; | |
274 | + } | |
275 | + | |
276 | + pFinal = pBase; | |
277 | + if (BIT_UP_SET(opcode)) | |
278 | + pFinal += getOffset(opcode); | |
279 | + else | |
280 | + pFinal -= getOffset(opcode); | |
281 | + | |
282 | + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; | |
283 | + | |
284 | + Fd = getFd(opcode); | |
285 | + for (i=getRegisterCount(opcode);i>0;i--) | |
286 | + { | |
287 | + loadMultiple(Fd,pAddress); | |
288 | + pAddress += 3; Fd++; | |
289 | + if (Fd == 8) Fd = 0; | |
290 | + } | |
291 | + | |
292 | + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); | |
293 | + return 1; | |
294 | +} | |
295 | + | |
296 | +unsigned int PerformSFM(const unsigned int opcode) | |
297 | +{ | |
298 | + unsigned int i, Fd, *pBase, *pAddress, *pFinal, | |
299 | + write_back = WRITE_BACK(opcode); | |
300 | + | |
301 | + pBase = (unsigned int*)readRegister(getRn(opcode)); | |
302 | + if (REG_PC == getRn(opcode)) | |
303 | + { | |
304 | + pBase += 2; | |
305 | + write_back = 0; | |
306 | + } | |
307 | + | |
308 | + pFinal = pBase; | |
309 | + if (BIT_UP_SET(opcode)) | |
310 | + pFinal += getOffset(opcode); | |
311 | + else | |
312 | + pFinal -= getOffset(opcode); | |
313 | + | |
314 | + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; | |
315 | + | |
316 | + Fd = getFd(opcode); | |
317 | + for (i=getRegisterCount(opcode);i>0;i--) | |
318 | + { | |
319 | + storeMultiple(Fd,pAddress); | |
320 | + pAddress += 3; Fd++; | |
321 | + if (Fd == 8) Fd = 0; | |
322 | + } | |
323 | + | |
324 | + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); | |
325 | + return 1; | |
326 | +} | |
327 | + | |
328 | +#if 1 | |
329 | +unsigned int EmulateCPDT(const unsigned int opcode) | |
330 | +{ | |
331 | + unsigned int nRc = 0; | |
332 | + | |
333 | + //printk("EmulateCPDT(0x%08x)\n",opcode); | |
334 | + | |
335 | + if (LDF_OP(opcode)) | |
336 | + { | |
337 | + nRc = PerformLDF(opcode); | |
338 | + } | |
339 | + else if (LFM_OP(opcode)) | |
340 | + { | |
341 | + nRc = PerformLFM(opcode); | |
342 | + } | |
343 | + else if (STF_OP(opcode)) | |
344 | + { | |
345 | + nRc = PerformSTF(opcode); | |
346 | + } | |
347 | + else if (SFM_OP(opcode)) | |
348 | + { | |
349 | + nRc = PerformSFM(opcode); | |
350 | + } | |
351 | + else | |
352 | + { | |
353 | + nRc = 0; | |
354 | + } | |
355 | + | |
356 | + return nRc; | |
357 | +} | |
358 | +#endif | ... | ... |
target-arm/nwfpe/fpa11_cprt.c
0 → 100644
1 | +/* | |
2 | + NetWinder Floating Point Emulator | |
3 | + (c) Rebel.COM, 1998,1999 | |
4 | + (c) Philip Blundell, 1999 | |
5 | + | |
6 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | |
7 | + | |
8 | + This program is free software; you can redistribute it and/or modify | |
9 | + it under the terms of the GNU General Public License as published by | |
10 | + the Free Software Foundation; either version 2 of the License, or | |
11 | + (at your option) any later version. | |
12 | + | |
13 | + This program is distributed in the hope that it will be useful, | |
14 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | + GNU General Public License for more details. | |
17 | + | |
18 | + You should have received a copy of the GNU General Public License | |
19 | + along with this program; if not, write to the Free Software | |
20 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
21 | +*/ | |
22 | + | |
23 | +#include "fpa11.h" | |
24 | +#include "milieu.h" | |
25 | +#include "softfloat.h" | |
26 | +#include "fpopcode.h" | |
27 | +#include "fpa11.inl" | |
28 | +//#include "fpmodule.h" | |
29 | +//#include "fpmodule.inl" | |
30 | + | |
31 | +extern flag floatx80_is_nan(floatx80); | |
32 | +extern flag float64_is_nan( float64); | |
33 | +extern flag float32_is_nan( float32); | |
34 | + | |
35 | +void SetRoundingMode(const unsigned int opcode); | |
36 | + | |
37 | +unsigned int PerformFLT(const unsigned int opcode); | |
38 | +unsigned int PerformFIX(const unsigned int opcode); | |
39 | + | |
40 | +static unsigned int | |
41 | +PerformComparison(const unsigned int opcode); | |
42 | + | |
43 | +unsigned int EmulateCPRT(const unsigned int opcode) | |
44 | +{ | |
45 | + unsigned int nRc = 1; | |
46 | + | |
47 | + //printk("EmulateCPRT(0x%08x)\n",opcode); | |
48 | + | |
49 | + if (opcode & 0x800000) | |
50 | + { | |
51 | + /* This is some variant of a comparison (PerformComparison will | |
52 | + sort out which one). Since most of the other CPRT | |
53 | + instructions are oddball cases of some sort or other it makes | |
54 | + sense to pull this out into a fast path. */ | |
55 | + return PerformComparison(opcode); | |
56 | + } | |
57 | + | |
58 | + /* Hint to GCC that we'd like a jump table rather than a load of CMPs */ | |
59 | + switch ((opcode & 0x700000) >> 20) | |
60 | + { | |
61 | + case FLT_CODE >> 20: nRc = PerformFLT(opcode); break; | |
62 | + case FIX_CODE >> 20: nRc = PerformFIX(opcode); break; | |
63 | + | |
64 | + case WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break; | |
65 | + case RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break; | |
66 | + | |
67 | +#if 0 /* We currently have no use for the FPCR, so there's no point | |
68 | + in emulating it. */ | |
69 | + case WFC_CODE >> 20: writeFPCR(readRegister(getRd(opcode))); | |
70 | + case RFC_CODE >> 20: writeRegister(getRd(opcode),readFPCR()); break; | |
71 | +#endif | |
72 | + | |
73 | + default: nRc = 0; | |
74 | + } | |
75 | + | |
76 | + return nRc; | |
77 | +} | |
78 | + | |
79 | +unsigned int PerformFLT(const unsigned int opcode) | |
80 | +{ | |
81 | + FPA11 *fpa11 = GET_FPA11(); | |
82 | + | |
83 | + unsigned int nRc = 1; | |
84 | + SetRoundingMode(opcode); | |
85 | + | |
86 | + switch (opcode & MASK_ROUNDING_PRECISION) | |
87 | + { | |
88 | + case ROUND_SINGLE: | |
89 | + { | |
90 | + fpa11->fType[getFn(opcode)] = typeSingle; | |
91 | + fpa11->fpreg[getFn(opcode)].fSingle = | |
92 | + int32_to_float32(readRegister(getRd(opcode))); | |
93 | + } | |
94 | + break; | |
95 | + | |
96 | + case ROUND_DOUBLE: | |
97 | + { | |
98 | + fpa11->fType[getFn(opcode)] = typeDouble; | |
99 | + fpa11->fpreg[getFn(opcode)].fDouble = | |
100 | + int32_to_float64(readRegister(getRd(opcode))); | |
101 | + } | |
102 | + break; | |
103 | + | |
104 | + case ROUND_EXTENDED: | |
105 | + { | |
106 | + fpa11->fType[getFn(opcode)] = typeExtended; | |
107 | + fpa11->fpreg[getFn(opcode)].fExtended = | |
108 | + int32_to_floatx80(readRegister(getRd(opcode))); | |
109 | + } | |
110 | + break; | |
111 | + | |
112 | + default: nRc = 0; | |
113 | + } | |
114 | + | |
115 | + return nRc; | |
116 | +} | |
117 | + | |
118 | +unsigned int PerformFIX(const unsigned int opcode) | |
119 | +{ | |
120 | + FPA11 *fpa11 = GET_FPA11(); | |
121 | + unsigned int nRc = 1; | |
122 | + unsigned int Fn = getFm(opcode); | |
123 | + | |
124 | + SetRoundingMode(opcode); | |
125 | + | |
126 | + switch (fpa11->fType[Fn]) | |
127 | + { | |
128 | + case typeSingle: | |
129 | + { | |
130 | + writeRegister(getRd(opcode), | |
131 | + float32_to_int32(fpa11->fpreg[Fn].fSingle)); | |
132 | + } | |
133 | + break; | |
134 | + | |
135 | + case typeDouble: | |
136 | + { | |
137 | + //printf("F%d is 0x%llx\n",Fn,fpa11->fpreg[Fn].fDouble); | |
138 | + writeRegister(getRd(opcode), | |
139 | + float64_to_int32(fpa11->fpreg[Fn].fDouble)); | |
140 | + } | |
141 | + break; | |
142 | + | |
143 | + case typeExtended: | |
144 | + { | |
145 | + writeRegister(getRd(opcode), | |
146 | + floatx80_to_int32(fpa11->fpreg[Fn].fExtended)); | |
147 | + } | |
148 | + break; | |
149 | + | |
150 | + default: nRc = 0; | |
151 | + } | |
152 | + | |
153 | + return nRc; | |
154 | +} | |
155 | + | |
156 | + | |
157 | +static unsigned int __inline__ | |
158 | +PerformComparisonOperation(floatx80 Fn, floatx80 Fm) | |
159 | +{ | |
160 | + unsigned int flags = 0; | |
161 | + | |
162 | + /* test for less than condition */ | |
163 | + if (floatx80_lt(Fn,Fm)) | |
164 | + { | |
165 | + flags |= CC_NEGATIVE; | |
166 | + } | |
167 | + | |
168 | + /* test for equal condition */ | |
169 | + if (floatx80_eq(Fn,Fm)) | |
170 | + { | |
171 | + flags |= CC_ZERO; | |
172 | + } | |
173 | + | |
174 | + /* test for greater than or equal condition */ | |
175 | + if (floatx80_lt(Fm,Fn)) | |
176 | + { | |
177 | + flags |= CC_CARRY; | |
178 | + } | |
179 | + | |
180 | + writeConditionCodes(flags); | |
181 | + return 1; | |
182 | +} | |
183 | + | |
184 | +/* This instruction sets the flags N, Z, C, V in the FPSR. */ | |
185 | + | |
186 | +static unsigned int PerformComparison(const unsigned int opcode) | |
187 | +{ | |
188 | + FPA11 *fpa11 = GET_FPA11(); | |
189 | + unsigned int Fn, Fm; | |
190 | + floatx80 rFn, rFm; | |
191 | + int e_flag = opcode & 0x400000; /* 1 if CxFE */ | |
192 | + int n_flag = opcode & 0x200000; /* 1 if CNxx */ | |
193 | + unsigned int flags = 0; | |
194 | + | |
195 | + //printk("PerformComparison(0x%08x)\n",opcode); | |
196 | + | |
197 | + Fn = getFn(opcode); | |
198 | + Fm = getFm(opcode); | |
199 | + | |
200 | + /* Check for unordered condition and convert all operands to 80-bit | |
201 | + format. | |
202 | + ?? Might be some mileage in avoiding this conversion if possible. | |
203 | + Eg, if both operands are 32-bit, detect this and do a 32-bit | |
204 | + comparison (cheaper than an 80-bit one). */ | |
205 | + switch (fpa11->fType[Fn]) | |
206 | + { | |
207 | + case typeSingle: | |
208 | + //printk("single.\n"); | |
209 | + if (float32_is_nan(fpa11->fpreg[Fn].fSingle)) | |
210 | + goto unordered; | |
211 | + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); | |
212 | + break; | |
213 | + | |
214 | + case typeDouble: | |
215 | + //printk("double.\n"); | |
216 | + if (float64_is_nan(fpa11->fpreg[Fn].fDouble)) | |
217 | + goto unordered; | |
218 | + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); | |
219 | + break; | |
220 | + | |
221 | + case typeExtended: | |
222 | + //printk("extended.\n"); | |
223 | + if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended)) | |
224 | + goto unordered; | |
225 | + rFn = fpa11->fpreg[Fn].fExtended; | |
226 | + break; | |
227 | + | |
228 | + default: return 0; | |
229 | + } | |
230 | + | |
231 | + if (CONSTANT_FM(opcode)) | |
232 | + { | |
233 | + //printk("Fm is a constant: #%d.\n",Fm); | |
234 | + rFm = getExtendedConstant(Fm); | |
235 | + if (floatx80_is_nan(rFm)) | |
236 | + goto unordered; | |
237 | + } | |
238 | + else | |
239 | + { | |
240 | + //printk("Fm = r%d which contains a ",Fm); | |
241 | + switch (fpa11->fType[Fm]) | |
242 | + { | |
243 | + case typeSingle: | |
244 | + //printk("single.\n"); | |
245 | + if (float32_is_nan(fpa11->fpreg[Fm].fSingle)) | |
246 | + goto unordered; | |
247 | + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle); | |
248 | + break; | |
249 | + | |
250 | + case typeDouble: | |
251 | + //printk("double.\n"); | |
252 | + if (float64_is_nan(fpa11->fpreg[Fm].fDouble)) | |
253 | + goto unordered; | |
254 | + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble); | |
255 | + break; | |
256 | + | |
257 | + case typeExtended: | |
258 | + //printk("extended.\n"); | |
259 | + if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended)) | |
260 | + goto unordered; | |
261 | + rFm = fpa11->fpreg[Fm].fExtended; | |
262 | + break; | |
263 | + | |
264 | + default: return 0; | |
265 | + } | |
266 | + } | |
267 | + | |
268 | + if (n_flag) | |
269 | + { | |
270 | + rFm.high ^= 0x8000; | |
271 | + } | |
272 | + | |
273 | + return PerformComparisonOperation(rFn,rFm); | |
274 | + | |
275 | + unordered: | |
276 | + /* ?? The FPA data sheet is pretty vague about this, in particular | |
277 | + about whether the non-E comparisons can ever raise exceptions. | |
278 | + This implementation is based on a combination of what it says in | |
279 | + the data sheet, observation of how the Acorn emulator actually | |
280 | + behaves (and how programs expect it to) and guesswork. */ | |
281 | + flags |= CC_OVERFLOW; | |
282 | + flags &= ~(CC_ZERO | CC_NEGATIVE); | |
283 | + | |
284 | + if (BIT_AC & readFPSR()) flags |= CC_CARRY; | |
285 | + | |
286 | + if (e_flag) float_raise(float_flag_invalid); | |
287 | + | |
288 | + writeConditionCodes(flags); | |
289 | + return 1; | |
290 | +} | ... | ... |
target-arm/nwfpe/fpopcode.c
0 → 100644
1 | +/* | |
2 | + NetWinder Floating Point Emulator | |
3 | + (c) Rebel.COM, 1998,1999 | |
4 | + | |
5 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | |
6 | + | |
7 | + This program is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 2 of the License, or | |
10 | + (at your option) any later version. | |
11 | + | |
12 | + This program is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with this program; if not, write to the Free Software | |
19 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 | +*/ | |
21 | + | |
22 | +#include "fpa11.h" | |
23 | +#include "softfloat.h" | |
24 | +#include "fpopcode.h" | |
25 | +#include "fpsr.h" | |
26 | +//#include "fpmodule.h" | |
27 | +//#include "fpmodule.inl" | |
28 | + | |
29 | +const floatx80 floatx80Constant[] = { | |
30 | + { 0x0000, 0x0000000000000000ULL}, /* extended 0.0 */ | |
31 | + { 0x3fff, 0x8000000000000000ULL}, /* extended 1.0 */ | |
32 | + { 0x4000, 0x8000000000000000ULL}, /* extended 2.0 */ | |
33 | + { 0x4000, 0xc000000000000000ULL}, /* extended 3.0 */ | |
34 | + { 0x4001, 0x8000000000000000ULL}, /* extended 4.0 */ | |
35 | + { 0x4001, 0xa000000000000000ULL}, /* extended 5.0 */ | |
36 | + { 0x3ffe, 0x8000000000000000ULL}, /* extended 0.5 */ | |
37 | + { 0x4002, 0xa000000000000000ULL} /* extended 10.0 */ | |
38 | +}; | |
39 | + | |
40 | +const float64 float64Constant[] = { | |
41 | + 0x0000000000000000ULL, /* double 0.0 */ | |
42 | + 0x3ff0000000000000ULL, /* double 1.0 */ | |
43 | + 0x4000000000000000ULL, /* double 2.0 */ | |
44 | + 0x4008000000000000ULL, /* double 3.0 */ | |
45 | + 0x4010000000000000ULL, /* double 4.0 */ | |
46 | + 0x4014000000000000ULL, /* double 5.0 */ | |
47 | + 0x3fe0000000000000ULL, /* double 0.5 */ | |
48 | + 0x4024000000000000ULL /* double 10.0 */ | |
49 | +}; | |
50 | + | |
51 | +const float32 float32Constant[] = { | |
52 | + 0x00000000, /* single 0.0 */ | |
53 | + 0x3f800000, /* single 1.0 */ | |
54 | + 0x40000000, /* single 2.0 */ | |
55 | + 0x40400000, /* single 3.0 */ | |
56 | + 0x40800000, /* single 4.0 */ | |
57 | + 0x40a00000, /* single 5.0 */ | |
58 | + 0x3f000000, /* single 0.5 */ | |
59 | + 0x41200000 /* single 10.0 */ | |
60 | +}; | |
61 | + | |
62 | +unsigned int getTransferLength(const unsigned int opcode) | |
63 | +{ | |
64 | + unsigned int nRc; | |
65 | + | |
66 | + switch (opcode & MASK_TRANSFER_LENGTH) | |
67 | + { | |
68 | + case 0x00000000: nRc = 1; break; /* single precision */ | |
69 | + case 0x00008000: nRc = 2; break; /* double precision */ | |
70 | + case 0x00400000: nRc = 3; break; /* extended precision */ | |
71 | + default: nRc = 0; | |
72 | + } | |
73 | + | |
74 | + return(nRc); | |
75 | +} | |
76 | + | |
77 | +unsigned int getRegisterCount(const unsigned int opcode) | |
78 | +{ | |
79 | + unsigned int nRc; | |
80 | + | |
81 | + switch (opcode & MASK_REGISTER_COUNT) | |
82 | + { | |
83 | + case 0x00000000: nRc = 4; break; | |
84 | + case 0x00008000: nRc = 1; break; | |
85 | + case 0x00400000: nRc = 2; break; | |
86 | + case 0x00408000: nRc = 3; break; | |
87 | + default: nRc = 0; | |
88 | + } | |
89 | + | |
90 | + return(nRc); | |
91 | +} | |
92 | + | |
93 | +unsigned int getRoundingPrecision(const unsigned int opcode) | |
94 | +{ | |
95 | + unsigned int nRc; | |
96 | + | |
97 | + switch (opcode & MASK_ROUNDING_PRECISION) | |
98 | + { | |
99 | + case 0x00000000: nRc = 1; break; | |
100 | + case 0x00000080: nRc = 2; break; | |
101 | + case 0x00080000: nRc = 3; break; | |
102 | + default: nRc = 0; | |
103 | + } | |
104 | + | |
105 | + return(nRc); | |
106 | +} | |
107 | + | |
108 | +unsigned int getDestinationSize(const unsigned int opcode) | |
109 | +{ | |
110 | + unsigned int nRc; | |
111 | + | |
112 | + switch (opcode & MASK_DESTINATION_SIZE) | |
113 | + { | |
114 | + case 0x00000000: nRc = typeSingle; break; | |
115 | + case 0x00000080: nRc = typeDouble; break; | |
116 | + case 0x00080000: nRc = typeExtended; break; | |
117 | + default: nRc = typeNone; | |
118 | + } | |
119 | + | |
120 | + return(nRc); | |
121 | +} | |
122 | + | |
123 | +/* condition code lookup table | |
124 | + index into the table is test code: EQ, NE, ... LT, GT, AL, NV | |
125 | + bit position in short is condition code: NZCV */ | |
126 | +static const unsigned short aCC[16] = { | |
127 | + 0xF0F0, // EQ == Z set | |
128 | + 0x0F0F, // NE | |
129 | + 0xCCCC, // CS == C set | |
130 | + 0x3333, // CC | |
131 | + 0xFF00, // MI == N set | |
132 | + 0x00FF, // PL | |
133 | + 0xAAAA, // VS == V set | |
134 | + 0x5555, // VC | |
135 | + 0x0C0C, // HI == C set && Z clear | |
136 | + 0xF3F3, // LS == C clear || Z set | |
137 | + 0xAA55, // GE == (N==V) | |
138 | + 0x55AA, // LT == (N!=V) | |
139 | + 0x0A05, // GT == (!Z && (N==V)) | |
140 | + 0xF5FA, // LE == (Z || (N!=V)) | |
141 | + 0xFFFF, // AL always | |
142 | + 0 // NV | |
143 | +}; | |
144 | + | |
145 | +unsigned int checkCondition(const unsigned int opcode, const unsigned int ccodes) | |
146 | +{ | |
147 | + return (aCC[opcode>>28] >> (ccodes>>28)) & 1; | |
148 | +} | ... | ... |
target-arm/nwfpe/fpopcode.h
0 → 100644
1 | +/* | |
2 | + NetWinder Floating Point Emulator | |
3 | + (c) Rebel.COM, 1998,1999 | |
4 | + | |
5 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | |
6 | + | |
7 | + This program is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 2 of the License, or | |
10 | + (at your option) any later version. | |
11 | + | |
12 | + This program is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with this program; if not, write to the Free Software | |
19 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 | +*/ | |
21 | + | |
22 | +#ifndef __FPOPCODE_H__ | |
23 | +#define __FPOPCODE_H__ | |
24 | + | |
25 | +/* | |
26 | +ARM Floating Point Instruction Classes | |
27 | +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
28 | +|c o n d|1 1 0 P|U|u|W|L| Rn |v| Fd |0|0|0|1| o f f s e t | CPDT | |
29 | +|c o n d|1 1 0 P|U|w|W|L| Rn |x| Fd |0|0|0|1| o f f s e t | CPDT | |
30 | +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
31 | +|c o n d|1 1 1 0|a|b|c|d|e| Fn |j| Fd |0|0|0|1|f|g|h|0|i| Fm | CPDO | |
32 | +|c o n d|1 1 1 0|a|b|c|L|e| Fn | Rd |0|0|0|1|f|g|h|1|i| Fm | CPRT | |
33 | +|c o n d|1 1 1 0|a|b|c|1|e| Fn |1|1|1|1|0|0|0|1|f|g|h|1|i| Fm | comparisons | |
34 | +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
35 | + | |
36 | +CPDT data transfer instructions | |
37 | + LDF, STF, LFM, SFM | |
38 | + | |
39 | +CPDO dyadic arithmetic instructions | |
40 | + ADF, MUF, SUF, RSF, DVF, RDF, | |
41 | + POW, RPW, RMF, FML, FDV, FRD, POL | |
42 | + | |
43 | +CPDO monadic arithmetic instructions | |
44 | + MVF, MNF, ABS, RND, SQT, LOG, LGN, EXP, | |
45 | + SIN, COS, TAN, ASN, ACS, ATN, URD, NRM | |
46 | + | |
47 | +CPRT joint arithmetic/data transfer instructions | |
48 | + FIX (arithmetic followed by load/store) | |
49 | + FLT (load/store followed by arithmetic) | |
50 | + CMF, CNF CMFE, CNFE (comparisons) | |
51 | + WFS, RFS (write/read floating point status register) | |
52 | + WFC, RFC (write/read floating point control register) | |
53 | + | |
54 | +cond condition codes | |
55 | +P pre/post index bit: 0 = postindex, 1 = preindex | |
56 | +U up/down bit: 0 = stack grows down, 1 = stack grows up | |
57 | +W write back bit: 1 = update base register (Rn) | |
58 | +L load/store bit: 0 = store, 1 = load | |
59 | +Rn base register | |
60 | +Rd destination/source register | |
61 | +Fd floating point destination register | |
62 | +Fn floating point source register | |
63 | +Fm floating point source register or floating point constant | |
64 | + | |
65 | +uv transfer length (TABLE 1) | |
66 | +wx register count (TABLE 2) | |
67 | +abcd arithmetic opcode (TABLES 3 & 4) | |
68 | +ef destination size (rounding precision) (TABLE 5) | |
69 | +gh rounding mode (TABLE 6) | |
70 | +j dyadic/monadic bit: 0 = dyadic, 1 = monadic | |
71 | +i constant bit: 1 = constant (TABLE 6) | |
72 | +*/ | |
73 | + | |
74 | +/* | |
75 | +TABLE 1 | |
76 | ++-------------------------+---+---+---------+---------+ | |
77 | +| Precision | u | v | FPSR.EP | length | | |
78 | ++-------------------------+---+---+---------+---------+ | |
79 | +| Single | 0 ü 0 | x | 1 words | | |
80 | +| Double | 1 ü 1 | x | 2 words | | |
81 | +| Extended | 1 ü 1 | x | 3 words | | |
82 | +| Packed decimal | 1 ü 1 | 0 | 3 words | | |
83 | +| Expanded packed decimal | 1 ü 1 | 1 | 4 words | | |
84 | ++-------------------------+---+---+---------+---------+ | |
85 | +Note: x = don't care | |
86 | +*/ | |
87 | + | |
88 | +/* | |
89 | +TABLE 2 | |
90 | ++---+---+---------------------------------+ | |
91 | +| w | x | Number of registers to transfer | | |
92 | ++---+---+---------------------------------+ | |
93 | +| 0 ü 1 | 1 | | |
94 | +| 1 ü 0 | 2 | | |
95 | +| 1 ü 1 | 3 | | |
96 | +| 0 ü 0 | 4 | | |
97 | ++---+---+---------------------------------+ | |
98 | +*/ | |
99 | + | |
100 | +/* | |
101 | +TABLE 3: Dyadic Floating Point Opcodes | |
102 | ++---+---+---+---+----------+-----------------------+-----------------------+ | |
103 | +| a | b | c | d | Mnemonic | Description | Operation | | |
104 | ++---+---+---+---+----------+-----------------------+-----------------------+ | |
105 | +| 0 | 0 | 0 | 0 | ADF | Add | Fd := Fn + Fm | | |
106 | +| 0 | 0 | 0 | 1 | MUF | Multiply | Fd := Fn * Fm | | |
107 | +| 0 | 0 | 1 | 0 | SUF | Subtract | Fd := Fn - Fm | | |
108 | +| 0 | 0 | 1 | 1 | RSF | Reverse subtract | Fd := Fm - Fn | | |
109 | +| 0 | 1 | 0 | 0 | DVF | Divide | Fd := Fn / Fm | | |
110 | +| 0 | 1 | 0 | 1 | RDF | Reverse divide | Fd := Fm / Fn | | |
111 | +| 0 | 1 | 1 | 0 | POW | Power | Fd := Fn ^ Fm | | |
112 | +| 0 | 1 | 1 | 1 | RPW | Reverse power | Fd := Fm ^ Fn | | |
113 | +| 1 | 0 | 0 | 0 | RMF | Remainder | Fd := IEEE rem(Fn/Fm) | | |
114 | +| 1 | 0 | 0 | 1 | FML | Fast Multiply | Fd := Fn * Fm | | |
115 | +| 1 | 0 | 1 | 0 | FDV | Fast Divide | Fd := Fn / Fm | | |
116 | +| 1 | 0 | 1 | 1 | FRD | Fast reverse divide | Fd := Fm / Fn | | |
117 | +| 1 | 1 | 0 | 0 | POL | Polar angle (ArcTan2) | Fd := arctan2(Fn,Fm) | | |
118 | +| 1 | 1 | 0 | 1 | | undefined instruction | trap | | |
119 | +| 1 | 1 | 1 | 0 | | undefined instruction | trap | | |
120 | +| 1 | 1 | 1 | 1 | | undefined instruction | trap | | |
121 | ++---+---+---+---+----------+-----------------------+-----------------------+ | |
122 | +Note: POW, RPW, POL are deprecated, and are available for backwards | |
123 | + compatibility only. | |
124 | +*/ | |
125 | + | |
126 | +/* | |
127 | +TABLE 4: Monadic Floating Point Opcodes | |
128 | ++---+---+---+---+----------+-----------------------+-----------------------+ | |
129 | +| a | b | c | d | Mnemonic | Description | Operation | | |
130 | ++---+---+---+---+----------+-----------------------+-----------------------+ | |
131 | +| 0 | 0 | 0 | 0 | MVF | Move | Fd := Fm | | |
132 | +| 0 | 0 | 0 | 1 | MNF | Move negated | Fd := - Fm | | |
133 | +| 0 | 0 | 1 | 0 | ABS | Absolute value | Fd := abs(Fm) | | |
134 | +| 0 | 0 | 1 | 1 | RND | Round to integer | Fd := int(Fm) | | |
135 | +| 0 | 1 | 0 | 0 | SQT | Square root | Fd := sqrt(Fm) | | |
136 | +| 0 | 1 | 0 | 1 | LOG | Log base 10 | Fd := log10(Fm) | | |
137 | +| 0 | 1 | 1 | 0 | LGN | Log base e | Fd := ln(Fm) | | |
138 | +| 0 | 1 | 1 | 1 | EXP | Exponent | Fd := e ^ Fm | | |
139 | +| 1 | 0 | 0 | 0 | SIN | Sine | Fd := sin(Fm) | | |
140 | +| 1 | 0 | 0 | 1 | COS | Cosine | Fd := cos(Fm) | | |
141 | +| 1 | 0 | 1 | 0 | TAN | Tangent | Fd := tan(Fm) | | |
142 | +| 1 | 0 | 1 | 1 | ASN | Arc Sine | Fd := arcsin(Fm) | | |
143 | +| 1 | 1 | 0 | 0 | ACS | Arc Cosine | Fd := arccos(Fm) | | |
144 | +| 1 | 1 | 0 | 1 | ATN | Arc Tangent | Fd := arctan(Fm) | | |
145 | +| 1 | 1 | 1 | 0 | URD | Unnormalized round | Fd := int(Fm) | | |
146 | +| 1 | 1 | 1 | 1 | NRM | Normalize | Fd := norm(Fm) | | |
147 | ++---+---+---+---+----------+-----------------------+-----------------------+ | |
148 | +Note: LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN are deprecated, and are | |
149 | + available for backwards compatibility only. | |
150 | +*/ | |
151 | + | |
152 | +/* | |
153 | +TABLE 5 | |
154 | ++-------------------------+---+---+ | |
155 | +| Rounding Precision | e | f | | |
156 | ++-------------------------+---+---+ | |
157 | +| IEEE Single precision | 0 ü 0 | | |
158 | +| IEEE Double precision | 0 ü 1 | | |
159 | +| IEEE Extended precision | 1 ü 0 | | |
160 | +| undefined (trap) | 1 ü 1 | | |
161 | ++-------------------------+---+---+ | |
162 | +*/ | |
163 | + | |
164 | +/* | |
165 | +TABLE 5 | |
166 | ++---------------------------------+---+---+ | |
167 | +| Rounding Mode | g | h | | |
168 | ++---------------------------------+---+---+ | |
169 | +| Round to nearest (default) | 0 ü 0 | | |
170 | +| Round toward plus infinity | 0 ü 1 | | |
171 | +| Round toward negative infinity | 1 ü 0 | | |
172 | +| Round toward zero | 1 ü 1 | | |
173 | ++---------------------------------+---+---+ | |
174 | +*/ | |
175 | + | |
176 | +/* | |
177 | +=== | |
178 | +=== Definitions for load and store instructions | |
179 | +=== | |
180 | +*/ | |
181 | + | |
182 | +/* bit masks */ | |
183 | +#define BIT_PREINDEX 0x01000000 | |
184 | +#define BIT_UP 0x00800000 | |
185 | +#define BIT_WRITE_BACK 0x00200000 | |
186 | +#define BIT_LOAD 0x00100000 | |
187 | + | |
188 | +/* masks for load/store */ | |
189 | +#define MASK_CPDT 0x0c000000 /* data processing opcode */ | |
190 | +#define MASK_OFFSET 0x000000ff | |
191 | +#define MASK_TRANSFER_LENGTH 0x00408000 | |
192 | +#define MASK_REGISTER_COUNT MASK_TRANSFER_LENGTH | |
193 | +#define MASK_COPROCESSOR 0x00000f00 | |
194 | + | |
195 | +/* Tests for transfer length */ | |
196 | +#define TRANSFER_SINGLE 0x00000000 | |
197 | +#define TRANSFER_DOUBLE 0x00008000 | |
198 | +#define TRANSFER_EXTENDED 0x00400000 | |
199 | +#define TRANSFER_PACKED MASK_TRANSFER_LENGTH | |
200 | + | |
201 | +/* Get the coprocessor number from the opcode. */ | |
202 | +#define getCoprocessorNumber(opcode) ((opcode & MASK_COPROCESSOR) >> 8) | |
203 | + | |
204 | +/* Get the offset from the opcode. */ | |
205 | +#define getOffset(opcode) (opcode & MASK_OFFSET) | |
206 | + | |
207 | +/* Tests for specific data transfer load/store opcodes. */ | |
208 | +#define TEST_OPCODE(opcode,mask) (((opcode) & (mask)) == (mask)) | |
209 | + | |
210 | +#define LOAD_OP(opcode) TEST_OPCODE((opcode),MASK_CPDT | BIT_LOAD) | |
211 | +#define STORE_OP(opcode) ((opcode & (MASK_CPDT | BIT_LOAD)) == MASK_CPDT) | |
212 | + | |
213 | +#define LDF_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 1)) | |
214 | +#define LFM_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 2)) | |
215 | +#define STF_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 1)) | |
216 | +#define SFM_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 2)) | |
217 | + | |
218 | +#define PREINDEXED(opcode) ((opcode & BIT_PREINDEX) != 0) | |
219 | +#define POSTINDEXED(opcode) ((opcode & BIT_PREINDEX) == 0) | |
220 | +#define BIT_UP_SET(opcode) ((opcode & BIT_UP) != 0) | |
221 | +#define BIT_UP_CLEAR(opcode) ((opcode & BIT_DOWN) == 0) | |
222 | +#define WRITE_BACK(opcode) ((opcode & BIT_WRITE_BACK) != 0) | |
223 | +#define LOAD(opcode) ((opcode & BIT_LOAD) != 0) | |
224 | +#define STORE(opcode) ((opcode & BIT_LOAD) == 0) | |
225 | + | |
226 | +/* | |
227 | +=== | |
228 | +=== Definitions for arithmetic instructions | |
229 | +=== | |
230 | +*/ | |
231 | +/* bit masks */ | |
232 | +#define BIT_MONADIC 0x00008000 | |
233 | +#define BIT_CONSTANT 0x00000008 | |
234 | + | |
235 | +#define CONSTANT_FM(opcode) ((opcode & BIT_CONSTANT) != 0) | |
236 | +#define MONADIC_INSTRUCTION(opcode) ((opcode & BIT_MONADIC) != 0) | |
237 | + | |
238 | +/* instruction identification masks */ | |
239 | +#define MASK_CPDO 0x0e000000 /* arithmetic opcode */ | |
240 | +#define MASK_ARITHMETIC_OPCODE 0x00f08000 | |
241 | +#define MASK_DESTINATION_SIZE 0x00080080 | |
242 | + | |
243 | +/* dyadic arithmetic opcodes. */ | |
244 | +#define ADF_CODE 0x00000000 | |
245 | +#define MUF_CODE 0x00100000 | |
246 | +#define SUF_CODE 0x00200000 | |
247 | +#define RSF_CODE 0x00300000 | |
248 | +#define DVF_CODE 0x00400000 | |
249 | +#define RDF_CODE 0x00500000 | |
250 | +#define POW_CODE 0x00600000 | |
251 | +#define RPW_CODE 0x00700000 | |
252 | +#define RMF_CODE 0x00800000 | |
253 | +#define FML_CODE 0x00900000 | |
254 | +#define FDV_CODE 0x00a00000 | |
255 | +#define FRD_CODE 0x00b00000 | |
256 | +#define POL_CODE 0x00c00000 | |
257 | +/* 0x00d00000 is an invalid dyadic arithmetic opcode */ | |
258 | +/* 0x00e00000 is an invalid dyadic arithmetic opcode */ | |
259 | +/* 0x00f00000 is an invalid dyadic arithmetic opcode */ | |
260 | + | |
261 | +/* monadic arithmetic opcodes. */ | |
262 | +#define MVF_CODE 0x00008000 | |
263 | +#define MNF_CODE 0x00108000 | |
264 | +#define ABS_CODE 0x00208000 | |
265 | +#define RND_CODE 0x00308000 | |
266 | +#define SQT_CODE 0x00408000 | |
267 | +#define LOG_CODE 0x00508000 | |
268 | +#define LGN_CODE 0x00608000 | |
269 | +#define EXP_CODE 0x00708000 | |
270 | +#define SIN_CODE 0x00808000 | |
271 | +#define COS_CODE 0x00908000 | |
272 | +#define TAN_CODE 0x00a08000 | |
273 | +#define ASN_CODE 0x00b08000 | |
274 | +#define ACS_CODE 0x00c08000 | |
275 | +#define ATN_CODE 0x00d08000 | |
276 | +#define URD_CODE 0x00e08000 | |
277 | +#define NRM_CODE 0x00f08000 | |
278 | + | |
279 | +/* | |
280 | +=== | |
281 | +=== Definitions for register transfer and comparison instructions | |
282 | +=== | |
283 | +*/ | |
284 | + | |
285 | +#define MASK_CPRT 0x0e000010 /* register transfer opcode */ | |
286 | +#define MASK_CPRT_CODE 0x00f00000 | |
287 | +#define FLT_CODE 0x00000000 | |
288 | +#define FIX_CODE 0x00100000 | |
289 | +#define WFS_CODE 0x00200000 | |
290 | +#define RFS_CODE 0x00300000 | |
291 | +#define WFC_CODE 0x00400000 | |
292 | +#define RFC_CODE 0x00500000 | |
293 | +#define CMF_CODE 0x00900000 | |
294 | +#define CNF_CODE 0x00b00000 | |
295 | +#define CMFE_CODE 0x00d00000 | |
296 | +#define CNFE_CODE 0x00f00000 | |
297 | + | |
298 | +/* | |
299 | +=== | |
300 | +=== Common definitions | |
301 | +=== | |
302 | +*/ | |
303 | + | |
304 | +/* register masks */ | |
305 | +#define MASK_Rd 0x0000f000 | |
306 | +#define MASK_Rn 0x000f0000 | |
307 | +#define MASK_Fd 0x00007000 | |
308 | +#define MASK_Fm 0x00000007 | |
309 | +#define MASK_Fn 0x00070000 | |
310 | + | |
311 | +/* condition code masks */ | |
312 | +#define CC_MASK 0xf0000000 | |
313 | +#define CC_NEGATIVE 0x80000000 | |
314 | +#define CC_ZERO 0x40000000 | |
315 | +#define CC_CARRY 0x20000000 | |
316 | +#define CC_OVERFLOW 0x10000000 | |
317 | +#define CC_EQ 0x00000000 | |
318 | +#define CC_NE 0x10000000 | |
319 | +#define CC_CS 0x20000000 | |
320 | +#define CC_HS CC_CS | |
321 | +#define CC_CC 0x30000000 | |
322 | +#define CC_LO CC_CC | |
323 | +#define CC_MI 0x40000000 | |
324 | +#define CC_PL 0x50000000 | |
325 | +#define CC_VS 0x60000000 | |
326 | +#define CC_VC 0x70000000 | |
327 | +#define CC_HI 0x80000000 | |
328 | +#define CC_LS 0x90000000 | |
329 | +#define CC_GE 0xa0000000 | |
330 | +#define CC_LT 0xb0000000 | |
331 | +#define CC_GT 0xc0000000 | |
332 | +#define CC_LE 0xd0000000 | |
333 | +#define CC_AL 0xe0000000 | |
334 | +#define CC_NV 0xf0000000 | |
335 | + | |
336 | +/* rounding masks/values */ | |
337 | +#define MASK_ROUNDING_MODE 0x00000060 | |
338 | +#define ROUND_TO_NEAREST 0x00000000 | |
339 | +#define ROUND_TO_PLUS_INFINITY 0x00000020 | |
340 | +#define ROUND_TO_MINUS_INFINITY 0x00000040 | |
341 | +#define ROUND_TO_ZERO 0x00000060 | |
342 | + | |
343 | +#define MASK_ROUNDING_PRECISION 0x00080080 | |
344 | +#define ROUND_SINGLE 0x00000000 | |
345 | +#define ROUND_DOUBLE 0x00000080 | |
346 | +#define ROUND_EXTENDED 0x00080000 | |
347 | + | |
348 | +/* Get the condition code from the opcode. */ | |
349 | +#define getCondition(opcode) (opcode >> 28) | |
350 | + | |
351 | +/* Get the source register from the opcode. */ | |
352 | +#define getRn(opcode) ((opcode & MASK_Rn) >> 16) | |
353 | + | |
354 | +/* Get the destination floating point register from the opcode. */ | |
355 | +#define getFd(opcode) ((opcode & MASK_Fd) >> 12) | |
356 | + | |
357 | +/* Get the first source floating point register from the opcode. */ | |
358 | +#define getFn(opcode) ((opcode & MASK_Fn) >> 16) | |
359 | + | |
360 | +/* Get the second source floating point register from the opcode. */ | |
361 | +#define getFm(opcode) (opcode & MASK_Fm) | |
362 | + | |
363 | +/* Get the destination register from the opcode. */ | |
364 | +#define getRd(opcode) ((opcode & MASK_Rd) >> 12) | |
365 | + | |
366 | +/* Get the rounding mode from the opcode. */ | |
367 | +#define getRoundingMode(opcode) ((opcode & MASK_ROUNDING_MODE) >> 5) | |
368 | + | |
369 | +static inline const floatx80 getExtendedConstant(const unsigned int nIndex) | |
370 | +{ | |
371 | + extern const floatx80 floatx80Constant[]; | |
372 | + return floatx80Constant[nIndex]; | |
373 | +} | |
374 | + | |
375 | +static inline const float64 getDoubleConstant(const unsigned int nIndex) | |
376 | +{ | |
377 | + extern const float64 float64Constant[]; | |
378 | + return float64Constant[nIndex]; | |
379 | +} | |
380 | + | |
381 | +static inline const float32 getSingleConstant(const unsigned int nIndex) | |
382 | +{ | |
383 | + extern const float32 float32Constant[]; | |
384 | + return float32Constant[nIndex]; | |
385 | +} | |
386 | + | |
387 | +extern unsigned int getRegisterCount(const unsigned int opcode); | |
388 | +extern unsigned int getDestinationSize(const unsigned int opcode); | |
389 | + | |
390 | +#endif | ... | ... |
target-arm/nwfpe/fpsr.h
0 → 100644
1 | +/* | |
2 | + NetWinder Floating Point Emulator | |
3 | + (c) Rebel.com, 1998-1999 | |
4 | + | |
5 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | |
6 | + | |
7 | + This program is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 2 of the License, or | |
10 | + (at your option) any later version. | |
11 | + | |
12 | + This program is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with this program; if not, write to the Free Software | |
19 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 | +*/ | |
21 | + | |
22 | +#ifndef __FPSR_H__ | |
23 | +#define __FPSR_H__ | |
24 | + | |
25 | +/* | |
26 | +The FPSR is a 32 bit register consisting of 4 parts, each exactly | |
27 | +one byte. | |
28 | + | |
29 | + SYSTEM ID | |
30 | + EXCEPTION TRAP ENABLE BYTE | |
31 | + SYSTEM CONTROL BYTE | |
32 | + CUMULATIVE EXCEPTION FLAGS BYTE | |
33 | + | |
34 | +The FPCR is a 32 bit register consisting of bit flags. | |
35 | +*/ | |
36 | + | |
37 | +/* SYSTEM ID | |
38 | +------------ | |
39 | +Note: the system id byte is read only */ | |
40 | + | |
41 | +typedef unsigned int FPSR; /* type for floating point status register */ | |
42 | +typedef unsigned int FPCR; /* type for floating point control register */ | |
43 | + | |
44 | +#define MASK_SYSID 0xff000000 | |
45 | +#define BIT_HARDWARE 0x80000000 | |
46 | +#define FP_EMULATOR 0x01000000 /* System ID for emulator */ | |
47 | +#define FP_ACCELERATOR 0x81000000 /* System ID for FPA11 */ | |
48 | + | |
49 | +/* EXCEPTION TRAP ENABLE BYTE | |
50 | +----------------------------- */ | |
51 | + | |
52 | +#define MASK_TRAP_ENABLE 0x00ff0000 | |
53 | +#define MASK_TRAP_ENABLE_STRICT 0x001f0000 | |
54 | +#define BIT_IXE 0x00100000 /* inexact exception enable */ | |
55 | +#define BIT_UFE 0x00080000 /* underflow exception enable */ | |
56 | +#define BIT_OFE 0x00040000 /* overflow exception enable */ | |
57 | +#define BIT_DZE 0x00020000 /* divide by zero exception enable */ | |
58 | +#define BIT_IOE 0x00010000 /* invalid operation exception enable */ | |
59 | + | |
60 | +/* SYSTEM CONTROL BYTE | |
61 | +---------------------- */ | |
62 | + | |
63 | +#define MASK_SYSTEM_CONTROL 0x0000ff00 | |
64 | +#define MASK_TRAP_STRICT 0x00001f00 | |
65 | + | |
66 | +#define BIT_AC 0x00001000 /* use alternative C-flag definition | |
67 | + for compares */ | |
68 | +#define BIT_EP 0x00000800 /* use expanded packed decimal format */ | |
69 | +#define BIT_SO 0x00000400 /* select synchronous operation of FPA */ | |
70 | +#define BIT_NE 0x00000200 /* NaN exception bit */ | |
71 | +#define BIT_ND 0x00000100 /* no denormalized numbers bit */ | |
72 | + | |
73 | +/* CUMULATIVE EXCEPTION FLAGS BYTE | |
74 | +---------------------------------- */ | |
75 | + | |
76 | +#define MASK_EXCEPTION_FLAGS 0x000000ff | |
77 | +#define MASK_EXCEPTION_FLAGS_STRICT 0x0000001f | |
78 | + | |
79 | +#define BIT_IXC 0x00000010 /* inexact exception flag */ | |
80 | +#define BIT_UFC 0x00000008 /* underflow exception flag */ | |
81 | +#define BIT_OFC 0x00000004 /* overfloat exception flag */ | |
82 | +#define BIT_DZC 0x00000002 /* divide by zero exception flag */ | |
83 | +#define BIT_IOC 0x00000001 /* invalid operation exception flag */ | |
84 | + | |
85 | +/* Floating Point Control Register | |
86 | +----------------------------------*/ | |
87 | + | |
88 | +#define BIT_RU 0x80000000 /* rounded up bit */ | |
89 | +#define BIT_IE 0x10000000 /* inexact bit */ | |
90 | +#define BIT_MO 0x08000000 /* mantissa overflow bit */ | |
91 | +#define BIT_EO 0x04000000 /* exponent overflow bit */ | |
92 | +#define BIT_SB 0x00000800 /* store bounce */ | |
93 | +#define BIT_AB 0x00000400 /* arithmetic bounce */ | |
94 | +#define BIT_RE 0x00000200 /* rounding exception */ | |
95 | +#define BIT_DA 0x00000100 /* disable FPA */ | |
96 | + | |
97 | +#define MASK_OP 0x00f08010 /* AU operation code */ | |
98 | +#define MASK_PR 0x00080080 /* AU precision */ | |
99 | +#define MASK_S1 0x00070000 /* AU source register 1 */ | |
100 | +#define MASK_S2 0x00000007 /* AU source register 2 */ | |
101 | +#define MASK_DS 0x00007000 /* AU destination register */ | |
102 | +#define MASK_RM 0x00000060 /* AU rounding mode */ | |
103 | +#define MASK_ALU 0x9cfff2ff /* only ALU can write these bits */ | |
104 | +#define MASK_RESET 0x00000d00 /* bits set on reset, all others cleared */ | |
105 | +#define MASK_WFC MASK_RESET | |
106 | +#define MASK_RFC ~MASK_RESET | |
107 | + | |
108 | +#endif | ... | ... |
target-arm/nwfpe/milieu.h
0 → 100644
1 | + | |
2 | +/* | |
3 | +=============================================================================== | |
4 | + | |
5 | +This C header file is part of the SoftFloat IEC/IEEE Floating-point | |
6 | +Arithmetic Package, Release 2. | |
7 | + | |
8 | +Written by John R. Hauser. This work was made possible in part by the | |
9 | +International Computer Science Institute, located at Suite 600, 1947 Center | |
10 | +Street, Berkeley, California 94704. Funding was partially provided by the | |
11 | +National Science Foundation under grant MIP-9311980. The original version | |
12 | +of this code was written as part of a project to build a fixed-point vector | |
13 | +processor in collaboration with the University of California at Berkeley, | |
14 | +overseen by Profs. Nelson Morgan and John Wawrzynek. More information | |
15 | +is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ | |
16 | +arithmetic/softfloat.html'. | |
17 | + | |
18 | +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort | |
19 | +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT | |
20 | +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO | |
21 | +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY | |
22 | +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. | |
23 | + | |
24 | +Derivative works are acceptable, even for commercial purposes, so long as | |
25 | +(1) they include prominent notice that the work is derivative, and (2) they | |
26 | +include prominent notice akin to these three paragraphs for those parts of | |
27 | +this code that are retained. | |
28 | + | |
29 | +=============================================================================== | |
30 | +*/ | |
31 | + | |
32 | +/* | |
33 | +------------------------------------------------------------------------------- | |
34 | +Include common integer types and flags. | |
35 | +------------------------------------------------------------------------------- | |
36 | +*/ | |
37 | +#include "ARM-gcc.h" | |
38 | + | |
39 | +/* | |
40 | +------------------------------------------------------------------------------- | |
41 | +Symbolic Boolean literals. | |
42 | +------------------------------------------------------------------------------- | |
43 | +*/ | |
44 | +enum { | |
45 | + FALSE = 0, | |
46 | + TRUE = 1 | |
47 | +}; | |
48 | + | ... | ... |
target-arm/nwfpe/single_cpdo.c
0 → 100644
1 | +/* | |
2 | + NetWinder Floating Point Emulator | |
3 | + (c) Rebel.COM, 1998,1999 | |
4 | + | |
5 | + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> | |
6 | + | |
7 | + This program is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 2 of the License, or | |
10 | + (at your option) any later version. | |
11 | + | |
12 | + This program is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with this program; if not, write to the Free Software | |
19 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 | +*/ | |
21 | + | |
22 | +#include "fpa11.h" | |
23 | +#include "softfloat.h" | |
24 | +#include "fpopcode.h" | |
25 | + | |
26 | +float32 float32_exp(float32 Fm); | |
27 | +float32 float32_ln(float32 Fm); | |
28 | +float32 float32_sin(float32 rFm); | |
29 | +float32 float32_cos(float32 rFm); | |
30 | +float32 float32_arcsin(float32 rFm); | |
31 | +float32 float32_arctan(float32 rFm); | |
32 | +float32 float32_log(float32 rFm); | |
33 | +float32 float32_tan(float32 rFm); | |
34 | +float32 float32_arccos(float32 rFm); | |
35 | +float32 float32_pow(float32 rFn,float32 rFm); | |
36 | +float32 float32_pol(float32 rFn,float32 rFm); | |
37 | + | |
38 | +unsigned int SingleCPDO(const unsigned int opcode) | |
39 | +{ | |
40 | + FPA11 *fpa11 = GET_FPA11(); | |
41 | + float32 rFm, rFn; | |
42 | + unsigned int Fd, Fm, Fn, nRc = 1; | |
43 | + | |
44 | + Fm = getFm(opcode); | |
45 | + if (CONSTANT_FM(opcode)) | |
46 | + { | |
47 | + rFm = getSingleConstant(Fm); | |
48 | + } | |
49 | + else | |
50 | + { | |
51 | + switch (fpa11->fType[Fm]) | |
52 | + { | |
53 | + case typeSingle: | |
54 | + rFm = fpa11->fpreg[Fm].fSingle; | |
55 | + break; | |
56 | + | |
57 | + default: return 0; | |
58 | + } | |
59 | + } | |
60 | + | |
61 | + if (!MONADIC_INSTRUCTION(opcode)) | |
62 | + { | |
63 | + Fn = getFn(opcode); | |
64 | + switch (fpa11->fType[Fn]) | |
65 | + { | |
66 | + case typeSingle: | |
67 | + rFn = fpa11->fpreg[Fn].fSingle; | |
68 | + break; | |
69 | + | |
70 | + default: return 0; | |
71 | + } | |
72 | + } | |
73 | + | |
74 | + Fd = getFd(opcode); | |
75 | + switch (opcode & MASK_ARITHMETIC_OPCODE) | |
76 | + { | |
77 | + /* dyadic opcodes */ | |
78 | + case ADF_CODE: | |
79 | + fpa11->fpreg[Fd].fSingle = float32_add(rFn,rFm); | |
80 | + break; | |
81 | + | |
82 | + case MUF_CODE: | |
83 | + case FML_CODE: | |
84 | + fpa11->fpreg[Fd].fSingle = float32_mul(rFn,rFm); | |
85 | + break; | |
86 | + | |
87 | + case SUF_CODE: | |
88 | + fpa11->fpreg[Fd].fSingle = float32_sub(rFn,rFm); | |
89 | + break; | |
90 | + | |
91 | + case RSF_CODE: | |
92 | + fpa11->fpreg[Fd].fSingle = float32_sub(rFm,rFn); | |
93 | + break; | |
94 | + | |
95 | + case DVF_CODE: | |
96 | + case FDV_CODE: | |
97 | + fpa11->fpreg[Fd].fSingle = float32_div(rFn,rFm); | |
98 | + break; | |
99 | + | |
100 | + case RDF_CODE: | |
101 | + case FRD_CODE: | |
102 | + fpa11->fpreg[Fd].fSingle = float32_div(rFm,rFn); | |
103 | + break; | |
104 | + | |
105 | +#if 0 | |
106 | + case POW_CODE: | |
107 | + fpa11->fpreg[Fd].fSingle = float32_pow(rFn,rFm); | |
108 | + break; | |
109 | + | |
110 | + case RPW_CODE: | |
111 | + fpa11->fpreg[Fd].fSingle = float32_pow(rFm,rFn); | |
112 | + break; | |
113 | +#endif | |
114 | + | |
115 | + case RMF_CODE: | |
116 | + fpa11->fpreg[Fd].fSingle = float32_rem(rFn,rFm); | |
117 | + break; | |
118 | + | |
119 | +#if 0 | |
120 | + case POL_CODE: | |
121 | + fpa11->fpreg[Fd].fSingle = float32_pol(rFn,rFm); | |
122 | + break; | |
123 | +#endif | |
124 | + | |
125 | + /* monadic opcodes */ | |
126 | + case MVF_CODE: | |
127 | + fpa11->fpreg[Fd].fSingle = rFm; | |
128 | + break; | |
129 | + | |
130 | + case MNF_CODE: | |
131 | + rFm ^= 0x80000000; | |
132 | + fpa11->fpreg[Fd].fSingle = rFm; | |
133 | + break; | |
134 | + | |
135 | + case ABS_CODE: | |
136 | + rFm &= 0x7fffffff; | |
137 | + fpa11->fpreg[Fd].fSingle = rFm; | |
138 | + break; | |
139 | + | |
140 | + case RND_CODE: | |
141 | + case URD_CODE: | |
142 | + fpa11->fpreg[Fd].fSingle = float32_round_to_int(rFm); | |
143 | + break; | |
144 | + | |
145 | + case SQT_CODE: | |
146 | + fpa11->fpreg[Fd].fSingle = float32_sqrt(rFm); | |
147 | + break; | |
148 | + | |
149 | +#if 0 | |
150 | + case LOG_CODE: | |
151 | + fpa11->fpreg[Fd].fSingle = float32_log(rFm); | |
152 | + break; | |
153 | + | |
154 | + case LGN_CODE: | |
155 | + fpa11->fpreg[Fd].fSingle = float32_ln(rFm); | |
156 | + break; | |
157 | + | |
158 | + case EXP_CODE: | |
159 | + fpa11->fpreg[Fd].fSingle = float32_exp(rFm); | |
160 | + break; | |
161 | + | |
162 | + case SIN_CODE: | |
163 | + fpa11->fpreg[Fd].fSingle = float32_sin(rFm); | |
164 | + break; | |
165 | + | |
166 | + case COS_CODE: | |
167 | + fpa11->fpreg[Fd].fSingle = float32_cos(rFm); | |
168 | + break; | |
169 | + | |
170 | + case TAN_CODE: | |
171 | + fpa11->fpreg[Fd].fSingle = float32_tan(rFm); | |
172 | + break; | |
173 | + | |
174 | + case ASN_CODE: | |
175 | + fpa11->fpreg[Fd].fSingle = float32_arcsin(rFm); | |
176 | + break; | |
177 | + | |
178 | + case ACS_CODE: | |
179 | + fpa11->fpreg[Fd].fSingle = float32_arccos(rFm); | |
180 | + break; | |
181 | + | |
182 | + case ATN_CODE: | |
183 | + fpa11->fpreg[Fd].fSingle = float32_arctan(rFm); | |
184 | + break; | |
185 | +#endif | |
186 | + | |
187 | + case NRM_CODE: | |
188 | + break; | |
189 | + | |
190 | + default: | |
191 | + { | |
192 | + nRc = 0; | |
193 | + } | |
194 | + } | |
195 | + | |
196 | + if (0 != nRc) fpa11->fType[Fd] = typeSingle; | |
197 | + return nRc; | |
198 | +} | |
199 | + | |
200 | +#if 0 | |
201 | +float32 float32_exp(float32 Fm) | |
202 | +{ | |
203 | +//series | |
204 | +} | |
205 | + | |
206 | +float32 float32_ln(float32 Fm) | |
207 | +{ | |
208 | +//series | |
209 | +} | |
210 | + | |
211 | +float32 float32_sin(float32 rFm) | |
212 | +{ | |
213 | +//series | |
214 | +} | |
215 | + | |
216 | +float32 float32_cos(float32 rFm) | |
217 | +{ | |
218 | +//series | |
219 | +} | |
220 | + | |
221 | +float32 float32_arcsin(float32 rFm) | |
222 | +{ | |
223 | +//series | |
224 | +} | |
225 | + | |
226 | +float32 float32_arctan(float32 rFm) | |
227 | +{ | |
228 | + //series | |
229 | +} | |
230 | + | |
231 | +float32 float32_arccos(float32 rFm) | |
232 | +{ | |
233 | + //return float32_sub(halfPi,float32_arcsin(rFm)); | |
234 | +} | |
235 | + | |
236 | +float32 float32_log(float32 rFm) | |
237 | +{ | |
238 | + return float32_div(float32_ln(rFm),getSingleConstant(7)); | |
239 | +} | |
240 | + | |
241 | +float32 float32_tan(float32 rFm) | |
242 | +{ | |
243 | + return float32_div(float32_sin(rFm),float32_cos(rFm)); | |
244 | +} | |
245 | + | |
246 | +float32 float32_pow(float32 rFn,float32 rFm) | |
247 | +{ | |
248 | + return float32_exp(float32_mul(rFm,float32_ln(rFn))); | |
249 | +} | |
250 | + | |
251 | +float32 float32_pol(float32 rFn,float32 rFm) | |
252 | +{ | |
253 | + return float32_arctan(float32_div(rFn,rFm)); | |
254 | +} | |
255 | +#endif | ... | ... |
target-arm/nwfpe/softfloat-macros
0 → 100644
1 | + | |
2 | +/* | |
3 | +=============================================================================== | |
4 | + | |
5 | +This C source fragment is part of the SoftFloat IEC/IEEE Floating-point | |
6 | +Arithmetic Package, Release 2. | |
7 | + | |
8 | +Written by John R. Hauser. This work was made possible in part by the | |
9 | +International Computer Science Institute, located at Suite 600, 1947 Center | |
10 | +Street, Berkeley, California 94704. Funding was partially provided by the | |
11 | +National Science Foundation under grant MIP-9311980. The original version | |
12 | +of this code was written as part of a project to build a fixed-point vector | |
13 | +processor in collaboration with the University of California at Berkeley, | |
14 | +overseen by Profs. Nelson Morgan and John Wawrzynek. More information | |
15 | +is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ | |
16 | +arithmetic/softfloat.html'. | |
17 | + | |
18 | +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort | |
19 | +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT | |
20 | +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO | |
21 | +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY | |
22 | +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. | |
23 | + | |
24 | +Derivative works are acceptable, even for commercial purposes, so long as | |
25 | +(1) they include prominent notice that the work is derivative, and (2) they | |
26 | +include prominent notice akin to these three paragraphs for those parts of | |
27 | +this code that are retained. | |
28 | + | |
29 | +=============================================================================== | |
30 | +*/ | |
31 | + | |
32 | +/* | |
33 | +------------------------------------------------------------------------------- | |
34 | +Shifts `a' right by the number of bits given in `count'. If any nonzero | |
35 | +bits are shifted off, they are ``jammed'' into the least significant bit of | |
36 | +the result by setting the least significant bit to 1. The value of `count' | |
37 | +can be arbitrarily large; in particular, if `count' is greater than 32, the | |
38 | +result will be either 0 or 1, depending on whether `a' is zero or nonzero. | |
39 | +The result is stored in the location pointed to by `zPtr'. | |
40 | +------------------------------------------------------------------------------- | |
41 | +*/ | |
42 | +INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr ) | |
43 | +{ | |
44 | + bits32 z; | |
45 | + if ( count == 0 ) { | |
46 | + z = a; | |
47 | + } | |
48 | + else if ( count < 32 ) { | |
49 | + z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 ); | |
50 | + } | |
51 | + else { | |
52 | + z = ( a != 0 ); | |
53 | + } | |
54 | + *zPtr = z; | |
55 | +} | |
56 | + | |
57 | +/* | |
58 | +------------------------------------------------------------------------------- | |
59 | +Shifts `a' right by the number of bits given in `count'. If any nonzero | |
60 | +bits are shifted off, they are ``jammed'' into the least significant bit of | |
61 | +the result by setting the least significant bit to 1. The value of `count' | |
62 | +can be arbitrarily large; in particular, if `count' is greater than 64, the | |
63 | +result will be either 0 or 1, depending on whether `a' is zero or nonzero. | |
64 | +The result is stored in the location pointed to by `zPtr'. | |
65 | +------------------------------------------------------------------------------- | |
66 | +*/ | |
67 | +INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr ) | |
68 | +{ | |
69 | + bits64 z; | |
70 | + | |
71 | +// __asm__("@shift64RightJamming -- start"); | |
72 | + if ( count == 0 ) { | |
73 | + z = a; | |
74 | + } | |
75 | + else if ( count < 64 ) { | |
76 | + z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 ); | |
77 | + } | |
78 | + else { | |
79 | + z = ( a != 0 ); | |
80 | + } | |
81 | +// __asm__("@shift64RightJamming -- end"); | |
82 | + *zPtr = z; | |
83 | +} | |
84 | + | |
85 | +/* | |
86 | +------------------------------------------------------------------------------- | |
87 | +Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64 | |
88 | +_plus_ the number of bits given in `count'. The shifted result is at most | |
89 | +64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The | |
90 | +bits shifted off form a second 64-bit result as follows: The _last_ bit | |
91 | +shifted off is the most-significant bit of the extra result, and the other | |
92 | +63 bits of the extra result are all zero if and only if _all_but_the_last_ | |
93 | +bits shifted off were all zero. This extra result is stored in the location | |
94 | +pointed to by `z1Ptr'. The value of `count' can be arbitrarily large. | |
95 | + (This routine makes more sense if `a0' and `a1' are considered to form a | |
96 | +fixed-point value with binary point between `a0' and `a1'. This fixed-point | |
97 | +value is shifted right by the number of bits given in `count', and the | |
98 | +integer part of the result is returned at the location pointed to by | |
99 | +`z0Ptr'. The fractional part of the result may be slightly corrupted as | |
100 | +described above, and is returned at the location pointed to by `z1Ptr'.) | |
101 | +------------------------------------------------------------------------------- | |
102 | +*/ | |
103 | +INLINE void | |
104 | + shift64ExtraRightJamming( | |
105 | + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) | |
106 | +{ | |
107 | + bits64 z0, z1; | |
108 | + int8 negCount = ( - count ) & 63; | |
109 | + | |
110 | + if ( count == 0 ) { | |
111 | + z1 = a1; | |
112 | + z0 = a0; | |
113 | + } | |
114 | + else if ( count < 64 ) { | |
115 | + z1 = ( a0<<negCount ) | ( a1 != 0 ); | |
116 | + z0 = a0>>count; | |
117 | + } | |
118 | + else { | |
119 | + if ( count == 64 ) { | |
120 | + z1 = a0 | ( a1 != 0 ); | |
121 | + } | |
122 | + else { | |
123 | + z1 = ( ( a0 | a1 ) != 0 ); | |
124 | + } | |
125 | + z0 = 0; | |
126 | + } | |
127 | + *z1Ptr = z1; | |
128 | + *z0Ptr = z0; | |
129 | + | |
130 | +} | |
131 | + | |
132 | +/* | |
133 | +------------------------------------------------------------------------------- | |
134 | +Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the | |
135 | +number of bits given in `count'. Any bits shifted off are lost. The value | |
136 | +of `count' can be arbitrarily large; in particular, if `count' is greater | |
137 | +than 128, the result will be 0. The result is broken into two 64-bit pieces | |
138 | +which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. | |
139 | +------------------------------------------------------------------------------- | |
140 | +*/ | |
141 | +INLINE void | |
142 | + shift128Right( | |
143 | + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) | |
144 | +{ | |
145 | + bits64 z0, z1; | |
146 | + int8 negCount = ( - count ) & 63; | |
147 | + | |
148 | + if ( count == 0 ) { | |
149 | + z1 = a1; | |
150 | + z0 = a0; | |
151 | + } | |
152 | + else if ( count < 64 ) { | |
153 | + z1 = ( a0<<negCount ) | ( a1>>count ); | |
154 | + z0 = a0>>count; | |
155 | + } | |
156 | + else { | |
157 | + z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0; | |
158 | + z0 = 0; | |
159 | + } | |
160 | + *z1Ptr = z1; | |
161 | + *z0Ptr = z0; | |
162 | + | |
163 | +} | |
164 | + | |
165 | +/* | |
166 | +------------------------------------------------------------------------------- | |
167 | +Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the | |
168 | +number of bits given in `count'. If any nonzero bits are shifted off, they | |
169 | +are ``jammed'' into the least significant bit of the result by setting the | |
170 | +least significant bit to 1. The value of `count' can be arbitrarily large; | |
171 | +in particular, if `count' is greater than 128, the result will be either 0 | |
172 | +or 1, depending on whether the concatenation of `a0' and `a1' is zero or | |
173 | +nonzero. The result is broken into two 64-bit pieces which are stored at | |
174 | +the locations pointed to by `z0Ptr' and `z1Ptr'. | |
175 | +------------------------------------------------------------------------------- | |
176 | +*/ | |
177 | +INLINE void | |
178 | + shift128RightJamming( | |
179 | + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) | |
180 | +{ | |
181 | + bits64 z0, z1; | |
182 | + int8 negCount = ( - count ) & 63; | |
183 | + | |
184 | + if ( count == 0 ) { | |
185 | + z1 = a1; | |
186 | + z0 = a0; | |
187 | + } | |
188 | + else if ( count < 64 ) { | |
189 | + z1 = ( a0<<negCount ) | ( a1>>count ) | ( ( a1<<negCount ) != 0 ); | |
190 | + z0 = a0>>count; | |
191 | + } | |
192 | + else { | |
193 | + if ( count == 64 ) { | |
194 | + z1 = a0 | ( a1 != 0 ); | |
195 | + } | |
196 | + else if ( count < 128 ) { | |
197 | + z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<<negCount ) | a1 ) != 0 ); | |
198 | + } | |
199 | + else { | |
200 | + z1 = ( ( a0 | a1 ) != 0 ); | |
201 | + } | |
202 | + z0 = 0; | |
203 | + } | |
204 | + *z1Ptr = z1; | |
205 | + *z0Ptr = z0; | |
206 | + | |
207 | +} | |
208 | + | |
209 | +/* | |
210 | +------------------------------------------------------------------------------- | |
211 | +Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' right | |
212 | +by 64 _plus_ the number of bits given in `count'. The shifted result is | |
213 | +at most 128 nonzero bits; these are broken into two 64-bit pieces which are | |
214 | +stored at the locations pointed to by `z0Ptr' and `z1Ptr'. The bits shifted | |
215 | +off form a third 64-bit result as follows: The _last_ bit shifted off is | |
216 | +the most-significant bit of the extra result, and the other 63 bits of the | |
217 | +extra result are all zero if and only if _all_but_the_last_ bits shifted off | |
218 | +were all zero. This extra result is stored in the location pointed to by | |
219 | +`z2Ptr'. The value of `count' can be arbitrarily large. | |
220 | + (This routine makes more sense if `a0', `a1', and `a2' are considered | |
221 | +to form a fixed-point value with binary point between `a1' and `a2'. This | |
222 | +fixed-point value is shifted right by the number of bits given in `count', | |
223 | +and the integer part of the result is returned at the locations pointed to | |
224 | +by `z0Ptr' and `z1Ptr'. The fractional part of the result may be slightly | |
225 | +corrupted as described above, and is returned at the location pointed to by | |
226 | +`z2Ptr'.) | |
227 | +------------------------------------------------------------------------------- | |
228 | +*/ | |
229 | +INLINE void | |
230 | + shift128ExtraRightJamming( | |
231 | + bits64 a0, | |
232 | + bits64 a1, | |
233 | + bits64 a2, | |
234 | + int16 count, | |
235 | + bits64 *z0Ptr, | |
236 | + bits64 *z1Ptr, | |
237 | + bits64 *z2Ptr | |
238 | + ) | |
239 | +{ | |
240 | + bits64 z0, z1, z2; | |
241 | + int8 negCount = ( - count ) & 63; | |
242 | + | |
243 | + if ( count == 0 ) { | |
244 | + z2 = a2; | |
245 | + z1 = a1; | |
246 | + z0 = a0; | |
247 | + } | |
248 | + else { | |
249 | + if ( count < 64 ) { | |
250 | + z2 = a1<<negCount; | |
251 | + z1 = ( a0<<negCount ) | ( a1>>count ); | |
252 | + z0 = a0>>count; | |
253 | + } | |
254 | + else { | |
255 | + if ( count == 64 ) { | |
256 | + z2 = a1; | |
257 | + z1 = a0; | |
258 | + } | |
259 | + else { | |
260 | + a2 |= a1; | |
261 | + if ( count < 128 ) { | |
262 | + z2 = a0<<negCount; | |
263 | + z1 = a0>>( count & 63 ); | |
264 | + } | |
265 | + else { | |
266 | + z2 = ( count == 128 ) ? a0 : ( a0 != 0 ); | |
267 | + z1 = 0; | |
268 | + } | |
269 | + } | |
270 | + z0 = 0; | |
271 | + } | |
272 | + z2 |= ( a2 != 0 ); | |
273 | + } | |
274 | + *z2Ptr = z2; | |
275 | + *z1Ptr = z1; | |
276 | + *z0Ptr = z0; | |
277 | + | |
278 | +} | |
279 | + | |
280 | +/* | |
281 | +------------------------------------------------------------------------------- | |
282 | +Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the | |
283 | +number of bits given in `count'. Any bits shifted off are lost. The value | |
284 | +of `count' must be less than 64. The result is broken into two 64-bit | |
285 | +pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. | |
286 | +------------------------------------------------------------------------------- | |
287 | +*/ | |
288 | +INLINE void | |
289 | + shortShift128Left( | |
290 | + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) | |
291 | +{ | |
292 | + | |
293 | + *z1Ptr = a1<<count; | |
294 | + *z0Ptr = | |
295 | + ( count == 0 ) ? a0 : ( a0<<count ) | ( a1>>( ( - count ) & 63 ) ); | |
296 | + | |
297 | +} | |
298 | + | |
299 | +/* | |
300 | +------------------------------------------------------------------------------- | |
301 | +Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left | |
302 | +by the number of bits given in `count'. Any bits shifted off are lost. | |
303 | +The value of `count' must be less than 64. The result is broken into three | |
304 | +64-bit pieces which are stored at the locations pointed to by `z0Ptr', | |
305 | +`z1Ptr', and `z2Ptr'. | |
306 | +------------------------------------------------------------------------------- | |
307 | +*/ | |
308 | +INLINE void | |
309 | + shortShift192Left( | |
310 | + bits64 a0, | |
311 | + bits64 a1, | |
312 | + bits64 a2, | |
313 | + int16 count, | |
314 | + bits64 *z0Ptr, | |
315 | + bits64 *z1Ptr, | |
316 | + bits64 *z2Ptr | |
317 | + ) | |
318 | +{ | |
319 | + bits64 z0, z1, z2; | |
320 | + int8 negCount; | |
321 | + | |
322 | + z2 = a2<<count; | |
323 | + z1 = a1<<count; | |
324 | + z0 = a0<<count; | |
325 | + if ( 0 < count ) { | |
326 | + negCount = ( ( - count ) & 63 ); | |
327 | + z1 |= a2>>negCount; | |
328 | + z0 |= a1>>negCount; | |
329 | + } | |
330 | + *z2Ptr = z2; | |
331 | + *z1Ptr = z1; | |
332 | + *z0Ptr = z0; | |
333 | + | |
334 | +} | |
335 | + | |
336 | +/* | |
337 | +------------------------------------------------------------------------------- | |
338 | +Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit | |
339 | +value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so | |
340 | +any carry out is lost. The result is broken into two 64-bit pieces which | |
341 | +are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. | |
342 | +------------------------------------------------------------------------------- | |
343 | +*/ | |
344 | +INLINE void | |
345 | + add128( | |
346 | + bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) | |
347 | +{ | |
348 | + bits64 z1; | |
349 | + | |
350 | + z1 = a1 + b1; | |
351 | + *z1Ptr = z1; | |
352 | + *z0Ptr = a0 + b0 + ( z1 < a1 ); | |
353 | + | |
354 | +} | |
355 | + | |
356 | +/* | |
357 | +------------------------------------------------------------------------------- | |
358 | +Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the | |
359 | +192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is | |
360 | +modulo 2^192, so any carry out is lost. The result is broken into three | |
361 | +64-bit pieces which are stored at the locations pointed to by `z0Ptr', | |
362 | +`z1Ptr', and `z2Ptr'. | |
363 | +------------------------------------------------------------------------------- | |
364 | +*/ | |
365 | +INLINE void | |
366 | + add192( | |
367 | + bits64 a0, | |
368 | + bits64 a1, | |
369 | + bits64 a2, | |
370 | + bits64 b0, | |
371 | + bits64 b1, | |
372 | + bits64 b2, | |
373 | + bits64 *z0Ptr, | |
374 | + bits64 *z1Ptr, | |
375 | + bits64 *z2Ptr | |
376 | + ) | |
377 | +{ | |
378 | + bits64 z0, z1, z2; | |
379 | + int8 carry0, carry1; | |
380 | + | |
381 | + z2 = a2 + b2; | |
382 | + carry1 = ( z2 < a2 ); | |
383 | + z1 = a1 + b1; | |
384 | + carry0 = ( z1 < a1 ); | |
385 | + z0 = a0 + b0; | |
386 | + z1 += carry1; | |
387 | + z0 += ( z1 < carry1 ); | |
388 | + z0 += carry0; | |
389 | + *z2Ptr = z2; | |
390 | + *z1Ptr = z1; | |
391 | + *z0Ptr = z0; | |
392 | + | |
393 | +} | |
394 | + | |
395 | +/* | |
396 | +------------------------------------------------------------------------------- | |
397 | +Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the | |
398 | +128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo | |
399 | +2^128, so any borrow out (carry out) is lost. The result is broken into two | |
400 | +64-bit pieces which are stored at the locations pointed to by `z0Ptr' and | |
401 | +`z1Ptr'. | |
402 | +------------------------------------------------------------------------------- | |
403 | +*/ | |
404 | +INLINE void | |
405 | + sub128( | |
406 | + bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) | |
407 | +{ | |
408 | + | |
409 | + *z1Ptr = a1 - b1; | |
410 | + *z0Ptr = a0 - b0 - ( a1 < b1 ); | |
411 | + | |
412 | +} | |
413 | + | |
414 | +/* | |
415 | +------------------------------------------------------------------------------- | |
416 | +Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2' | |
417 | +from the 192-bit value formed by concatenating `a0', `a1', and `a2'. | |
418 | +Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The | |
419 | +result is broken into three 64-bit pieces which are stored at the locations | |
420 | +pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'. | |
421 | +------------------------------------------------------------------------------- | |
422 | +*/ | |
423 | +INLINE void | |
424 | + sub192( | |
425 | + bits64 a0, | |
426 | + bits64 a1, | |
427 | + bits64 a2, | |
428 | + bits64 b0, | |
429 | + bits64 b1, | |
430 | + bits64 b2, | |
431 | + bits64 *z0Ptr, | |
432 | + bits64 *z1Ptr, | |
433 | + bits64 *z2Ptr | |
434 | + ) | |
435 | +{ | |
436 | + bits64 z0, z1, z2; | |
437 | + int8 borrow0, borrow1; | |
438 | + | |
439 | + z2 = a2 - b2; | |
440 | + borrow1 = ( a2 < b2 ); | |
441 | + z1 = a1 - b1; | |
442 | + borrow0 = ( a1 < b1 ); | |
443 | + z0 = a0 - b0; | |
444 | + z0 -= ( z1 < borrow1 ); | |
445 | + z1 -= borrow1; | |
446 | + z0 -= borrow0; | |
447 | + *z2Ptr = z2; | |
448 | + *z1Ptr = z1; | |
449 | + *z0Ptr = z0; | |
450 | + | |
451 | +} | |
452 | + | |
453 | +/* | |
454 | +------------------------------------------------------------------------------- | |
455 | +Multiplies `a' by `b' to obtain a 128-bit product. The product is broken | |
456 | +into two 64-bit pieces which are stored at the locations pointed to by | |
457 | +`z0Ptr' and `z1Ptr'. | |
458 | +------------------------------------------------------------------------------- | |
459 | +*/ | |
460 | +INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr ) | |
461 | +{ | |
462 | + bits32 aHigh, aLow, bHigh, bLow; | |
463 | + bits64 z0, zMiddleA, zMiddleB, z1; | |
464 | + | |
465 | + aLow = a; | |
466 | + aHigh = a>>32; | |
467 | + bLow = b; | |
468 | + bHigh = b>>32; | |
469 | + z1 = ( (bits64) aLow ) * bLow; | |
470 | + zMiddleA = ( (bits64) aLow ) * bHigh; | |
471 | + zMiddleB = ( (bits64) aHigh ) * bLow; | |
472 | + z0 = ( (bits64) aHigh ) * bHigh; | |
473 | + zMiddleA += zMiddleB; | |
474 | + z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 ); | |
475 | + zMiddleA <<= 32; | |
476 | + z1 += zMiddleA; | |
477 | + z0 += ( z1 < zMiddleA ); | |
478 | + *z1Ptr = z1; | |
479 | + *z0Ptr = z0; | |
480 | + | |
481 | +} | |
482 | + | |
483 | +/* | |
484 | +------------------------------------------------------------------------------- | |
485 | +Multiplies the 128-bit value formed by concatenating `a0' and `a1' by `b' to | |
486 | +obtain a 192-bit product. The product is broken into three 64-bit pieces | |
487 | +which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and | |
488 | +`z2Ptr'. | |
489 | +------------------------------------------------------------------------------- | |
490 | +*/ | |
491 | +INLINE void | |
492 | + mul128By64To192( | |
493 | + bits64 a0, | |
494 | + bits64 a1, | |
495 | + bits64 b, | |
496 | + bits64 *z0Ptr, | |
497 | + bits64 *z1Ptr, | |
498 | + bits64 *z2Ptr | |
499 | + ) | |
500 | +{ | |
501 | + bits64 z0, z1, z2, more1; | |
502 | + | |
503 | + mul64To128( a1, b, &z1, &z2 ); | |
504 | + mul64To128( a0, b, &z0, &more1 ); | |
505 | + add128( z0, more1, 0, z1, &z0, &z1 ); | |
506 | + *z2Ptr = z2; | |
507 | + *z1Ptr = z1; | |
508 | + *z0Ptr = z0; | |
509 | + | |
510 | +} | |
511 | + | |
512 | +/* | |
513 | +------------------------------------------------------------------------------- | |
514 | +Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the | |
515 | +128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit | |
516 | +product. The product is broken into four 64-bit pieces which are stored at | |
517 | +the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'. | |
518 | +------------------------------------------------------------------------------- | |
519 | +*/ | |
520 | +INLINE void | |
521 | + mul128To256( | |
522 | + bits64 a0, | |
523 | + bits64 a1, | |
524 | + bits64 b0, | |
525 | + bits64 b1, | |
526 | + bits64 *z0Ptr, | |
527 | + bits64 *z1Ptr, | |
528 | + bits64 *z2Ptr, | |
529 | + bits64 *z3Ptr | |
530 | + ) | |
531 | +{ | |
532 | + bits64 z0, z1, z2, z3; | |
533 | + bits64 more1, more2; | |
534 | + | |
535 | + mul64To128( a1, b1, &z2, &z3 ); | |
536 | + mul64To128( a1, b0, &z1, &more2 ); | |
537 | + add128( z1, more2, 0, z2, &z1, &z2 ); | |
538 | + mul64To128( a0, b0, &z0, &more1 ); | |
539 | + add128( z0, more1, 0, z1, &z0, &z1 ); | |
540 | + mul64To128( a0, b1, &more1, &more2 ); | |
541 | + add128( more1, more2, 0, z2, &more1, &z2 ); | |
542 | + add128( z0, z1, 0, more1, &z0, &z1 ); | |
543 | + *z3Ptr = z3; | |
544 | + *z2Ptr = z2; | |
545 | + *z1Ptr = z1; | |
546 | + *z0Ptr = z0; | |
547 | + | |
548 | +} | |
549 | + | |
550 | +/* | |
551 | +------------------------------------------------------------------------------- | |
552 | +Returns an approximation to the 64-bit integer quotient obtained by dividing | |
553 | +`b' into the 128-bit value formed by concatenating `a0' and `a1'. The | |
554 | +divisor `b' must be at least 2^63. If q is the exact quotient truncated | |
555 | +toward zero, the approximation returned lies between q and q + 2 inclusive. | |
556 | +If the exact quotient q is larger than 64 bits, the maximum positive 64-bit | |
557 | +unsigned integer is returned. | |
558 | +------------------------------------------------------------------------------- | |
559 | +*/ | |
560 | +static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b ) | |
561 | +{ | |
562 | + bits64 b0, b1; | |
563 | + bits64 rem0, rem1, term0, term1; | |
564 | + bits64 z; | |
565 | + if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF ); | |
566 | + b0 = b>>32; | |
567 | + z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32; | |
568 | + mul64To128( b, z, &term0, &term1 ); | |
569 | + sub128( a0, a1, term0, term1, &rem0, &rem1 ); | |
570 | + while ( ( (sbits64) rem0 ) < 0 ) { | |
571 | + z -= LIT64( 0x100000000 ); | |
572 | + b1 = b<<32; | |
573 | + add128( rem0, rem1, b0, b1, &rem0, &rem1 ); | |
574 | + } | |
575 | + rem0 = ( rem0<<32 ) | ( rem1>>32 ); | |
576 | + z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0; | |
577 | + return z; | |
578 | + | |
579 | +} | |
580 | + | |
581 | +/* | |
582 | +------------------------------------------------------------------------------- | |
583 | +Returns an approximation to the square root of the 32-bit significand given | |
584 | +by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of | |
585 | +`aExp' (the least significant bit) is 1, the integer returned approximates | |
586 | +2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp' | |
587 | +is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either | |
588 | +case, the approximation returned lies strictly within +/-2 of the exact | |
589 | +value. | |
590 | +------------------------------------------------------------------------------- | |
591 | +*/ | |
592 | +static bits32 estimateSqrt32( int16 aExp, bits32 a ) | |
593 | +{ | |
594 | + static const bits16 sqrtOddAdjustments[] = { | |
595 | + 0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0, | |
596 | + 0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67 | |
597 | + }; | |
598 | + static const bits16 sqrtEvenAdjustments[] = { | |
599 | + 0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E, | |
600 | + 0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002 | |
601 | + }; | |
602 | + int8 index; | |
603 | + bits32 z; | |
604 | + | |
605 | + index = ( a>>27 ) & 15; | |
606 | + if ( aExp & 1 ) { | |
607 | + z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ]; | |
608 | + z = ( ( a / z )<<14 ) + ( z<<15 ); | |
609 | + a >>= 1; | |
610 | + } | |
611 | + else { | |
612 | + z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ]; | |
613 | + z = a / z + z; | |
614 | + z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 ); | |
615 | + if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 ); | |
616 | + } | |
617 | + return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 ); | |
618 | + | |
619 | +} | |
620 | + | |
621 | +/* | |
622 | +------------------------------------------------------------------------------- | |
623 | +Returns the number of leading 0 bits before the most-significant 1 bit | |
624 | +of `a'. If `a' is zero, 32 is returned. | |
625 | +------------------------------------------------------------------------------- | |
626 | +*/ | |
627 | +static int8 countLeadingZeros32( bits32 a ) | |
628 | +{ | |
629 | + static const int8 countLeadingZerosHigh[] = { | |
630 | + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, | |
631 | + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | |
632 | + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | |
633 | + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | |
634 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
635 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
636 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
637 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
638 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
639 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
640 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
641 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
642 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
643 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
644 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
645 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | |
646 | + }; | |
647 | + int8 shiftCount; | |
648 | + | |
649 | + shiftCount = 0; | |
650 | + if ( a < 0x10000 ) { | |
651 | + shiftCount += 16; | |
652 | + a <<= 16; | |
653 | + } | |
654 | + if ( a < 0x1000000 ) { | |
655 | + shiftCount += 8; | |
656 | + a <<= 8; | |
657 | + } | |
658 | + shiftCount += countLeadingZerosHigh[ a>>24 ]; | |
659 | + return shiftCount; | |
660 | + | |
661 | +} | |
662 | + | |
663 | +/* | |
664 | +------------------------------------------------------------------------------- | |
665 | +Returns the number of leading 0 bits before the most-significant 1 bit | |
666 | +of `a'. If `a' is zero, 64 is returned. | |
667 | +------------------------------------------------------------------------------- | |
668 | +*/ | |
669 | +static int8 countLeadingZeros64( bits64 a ) | |
670 | +{ | |
671 | + int8 shiftCount; | |
672 | + | |
673 | + shiftCount = 0; | |
674 | + if ( a < ( (bits64) 1 )<<32 ) { | |
675 | + shiftCount += 32; | |
676 | + } | |
677 | + else { | |
678 | + a >>= 32; | |
679 | + } | |
680 | + shiftCount += countLeadingZeros32( a ); | |
681 | + return shiftCount; | |
682 | + | |
683 | +} | |
684 | + | |
685 | +/* | |
686 | +------------------------------------------------------------------------------- | |
687 | +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' | |
688 | +is equal to the 128-bit value formed by concatenating `b0' and `b1'. | |
689 | +Otherwise, returns 0. | |
690 | +------------------------------------------------------------------------------- | |
691 | +*/ | |
692 | +INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) | |
693 | +{ | |
694 | + | |
695 | + return ( a0 == b0 ) && ( a1 == b1 ); | |
696 | + | |
697 | +} | |
698 | + | |
699 | +/* | |
700 | +------------------------------------------------------------------------------- | |
701 | +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less | |
702 | +than or equal to the 128-bit value formed by concatenating `b0' and `b1'. | |
703 | +Otherwise, returns 0. | |
704 | +------------------------------------------------------------------------------- | |
705 | +*/ | |
706 | +INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) | |
707 | +{ | |
708 | + | |
709 | + return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) ); | |
710 | + | |
711 | +} | |
712 | + | |
713 | +/* | |
714 | +------------------------------------------------------------------------------- | |
715 | +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less | |
716 | +than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise, | |
717 | +returns 0. | |
718 | +------------------------------------------------------------------------------- | |
719 | +*/ | |
720 | +INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) | |
721 | +{ | |
722 | + | |
723 | + return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) ); | |
724 | + | |
725 | +} | |
726 | + | |
727 | +/* | |
728 | +------------------------------------------------------------------------------- | |
729 | +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is | |
730 | +not equal to the 128-bit value formed by concatenating `b0' and `b1'. | |
731 | +Otherwise, returns 0. | |
732 | +------------------------------------------------------------------------------- | |
733 | +*/ | |
734 | +INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) | |
735 | +{ | |
736 | + | |
737 | + return ( a0 != b0 ) || ( a1 != b1 ); | |
738 | + | |
739 | +} | |
740 | + | ... | ... |
target-arm/nwfpe/softfloat-specialize
0 → 100644
1 | + | |
2 | +/* | |
3 | +=============================================================================== | |
4 | + | |
5 | +This C source fragment is part of the SoftFloat IEC/IEEE Floating-point | |
6 | +Arithmetic Package, Release 2. | |
7 | + | |
8 | +Written by John R. Hauser. This work was made possible in part by the | |
9 | +International Computer Science Institute, located at Suite 600, 1947 Center | |
10 | +Street, Berkeley, California 94704. Funding was partially provided by the | |
11 | +National Science Foundation under grant MIP-9311980. The original version | |
12 | +of this code was written as part of a project to build a fixed-point vector | |
13 | +processor in collaboration with the University of California at Berkeley, | |
14 | +overseen by Profs. Nelson Morgan and John Wawrzynek. More information | |
15 | +is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ | |
16 | +arithmetic/softfloat.html'. | |
17 | + | |
18 | +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort | |
19 | +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT | |
20 | +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO | |
21 | +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY | |
22 | +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. | |
23 | + | |
24 | +Derivative works are acceptable, even for commercial purposes, so long as | |
25 | +(1) they include prominent notice that the work is derivative, and (2) they | |
26 | +include prominent notice akin to these three paragraphs for those parts of | |
27 | +this code that are retained. | |
28 | + | |
29 | +=============================================================================== | |
30 | +*/ | |
31 | + | |
32 | +/* | |
33 | +------------------------------------------------------------------------------- | |
34 | +Underflow tininess-detection mode, statically initialized to default value. | |
35 | +(The declaration in `softfloat.h' must match the `int8' type here.) | |
36 | +------------------------------------------------------------------------------- | |
37 | +*/ | |
38 | +int8 float_detect_tininess = float_tininess_after_rounding; | |
39 | + | |
40 | +/* | |
41 | +------------------------------------------------------------------------------- | |
42 | +Raises the exceptions specified by `flags'. Floating-point traps can be | |
43 | +defined here if desired. It is currently not possible for such a trap to | |
44 | +substitute a result value. If traps are not implemented, this routine | |
45 | +should be simply `float_exception_flags |= flags;'. | |
46 | + | |
47 | +ScottB: November 4, 1998 | |
48 | +Moved this function out of softfloat-specialize into fpmodule.c. | |
49 | +This effectively isolates all the changes required for integrating with the | |
50 | +Linux kernel into fpmodule.c. Porting to NetBSD should only require modifying | |
51 | +fpmodule.c to integrate with the NetBSD kernel (I hope!). | |
52 | +------------------------------------------------------------------------------- | |
53 | +*/ | |
54 | +void float_raise( int8 flags ) | |
55 | +{ | |
56 | + float_exception_flags |= flags; | |
57 | +} | |
58 | + | |
59 | +/* | |
60 | +------------------------------------------------------------------------------- | |
61 | +Internal canonical NaN format. | |
62 | +------------------------------------------------------------------------------- | |
63 | +*/ | |
64 | +typedef struct { | |
65 | + flag sign; | |
66 | + bits64 high, low; | |
67 | +} commonNaNT; | |
68 | + | |
69 | +/* | |
70 | +------------------------------------------------------------------------------- | |
71 | +The pattern for a default generated single-precision NaN. | |
72 | +------------------------------------------------------------------------------- | |
73 | +*/ | |
74 | +#define float32_default_nan 0xFFFFFFFF | |
75 | + | |
76 | +/* | |
77 | +------------------------------------------------------------------------------- | |
78 | +Returns 1 if the single-precision floating-point value `a' is a NaN; | |
79 | +otherwise returns 0. | |
80 | +------------------------------------------------------------------------------- | |
81 | +*/ | |
82 | +flag float32_is_nan( float32 a ) | |
83 | +{ | |
84 | + | |
85 | + return ( 0xFF000000 < (bits32) ( a<<1 ) ); | |
86 | + | |
87 | +} | |
88 | + | |
89 | +/* | |
90 | +------------------------------------------------------------------------------- | |
91 | +Returns 1 if the single-precision floating-point value `a' is a signaling | |
92 | +NaN; otherwise returns 0. | |
93 | +------------------------------------------------------------------------------- | |
94 | +*/ | |
95 | +flag float32_is_signaling_nan( float32 a ) | |
96 | +{ | |
97 | + | |
98 | + return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); | |
99 | + | |
100 | +} | |
101 | + | |
102 | +/* | |
103 | +------------------------------------------------------------------------------- | |
104 | +Returns the result of converting the single-precision floating-point NaN | |
105 | +`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid | |
106 | +exception is raised. | |
107 | +------------------------------------------------------------------------------- | |
108 | +*/ | |
109 | +static commonNaNT float32ToCommonNaN( float32 a ) | |
110 | +{ | |
111 | + commonNaNT z; | |
112 | + | |
113 | + if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); | |
114 | + z.sign = a>>31; | |
115 | + z.low = 0; | |
116 | + z.high = ( (bits64) a )<<41; | |
117 | + return z; | |
118 | + | |
119 | +} | |
120 | + | |
121 | +/* | |
122 | +------------------------------------------------------------------------------- | |
123 | +Returns the result of converting the canonical NaN `a' to the single- | |
124 | +precision floating-point format. | |
125 | +------------------------------------------------------------------------------- | |
126 | +*/ | |
127 | +static float32 commonNaNToFloat32( commonNaNT a ) | |
128 | +{ | |
129 | + | |
130 | + return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 ); | |
131 | + | |
132 | +} | |
133 | + | |
134 | +/* | |
135 | +------------------------------------------------------------------------------- | |
136 | +Takes two single-precision floating-point values `a' and `b', one of which | |
137 | +is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a | |
138 | +signaling NaN, the invalid exception is raised. | |
139 | +------------------------------------------------------------------------------- | |
140 | +*/ | |
141 | +static float32 propagateFloat32NaN( float32 a, float32 b ) | |
142 | +{ | |
143 | + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; | |
144 | + | |
145 | + aIsNaN = float32_is_nan( a ); | |
146 | + aIsSignalingNaN = float32_is_signaling_nan( a ); | |
147 | + bIsNaN = float32_is_nan( b ); | |
148 | + bIsSignalingNaN = float32_is_signaling_nan( b ); | |
149 | + a |= 0x00400000; | |
150 | + b |= 0x00400000; | |
151 | + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); | |
152 | + if ( aIsNaN ) { | |
153 | + return ( aIsSignalingNaN & bIsNaN ) ? b : a; | |
154 | + } | |
155 | + else { | |
156 | + return b; | |
157 | + } | |
158 | + | |
159 | +} | |
160 | + | |
161 | +/* | |
162 | +------------------------------------------------------------------------------- | |
163 | +The pattern for a default generated double-precision NaN. | |
164 | +------------------------------------------------------------------------------- | |
165 | +*/ | |
166 | +#define float64_default_nan LIT64( 0xFFFFFFFFFFFFFFFF ) | |
167 | + | |
168 | +/* | |
169 | +------------------------------------------------------------------------------- | |
170 | +Returns 1 if the double-precision floating-point value `a' is a NaN; | |
171 | +otherwise returns 0. | |
172 | +------------------------------------------------------------------------------- | |
173 | +*/ | |
174 | +flag float64_is_nan( float64 a ) | |
175 | +{ | |
176 | + | |
177 | + return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) ); | |
178 | + | |
179 | +} | |
180 | + | |
181 | +/* | |
182 | +------------------------------------------------------------------------------- | |
183 | +Returns 1 if the double-precision floating-point value `a' is a signaling | |
184 | +NaN; otherwise returns 0. | |
185 | +------------------------------------------------------------------------------- | |
186 | +*/ | |
187 | +flag float64_is_signaling_nan( float64 a ) | |
188 | +{ | |
189 | + | |
190 | + return | |
191 | + ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) | |
192 | + && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); | |
193 | + | |
194 | +} | |
195 | + | |
196 | +/* | |
197 | +------------------------------------------------------------------------------- | |
198 | +Returns the result of converting the double-precision floating-point NaN | |
199 | +`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid | |
200 | +exception is raised. | |
201 | +------------------------------------------------------------------------------- | |
202 | +*/ | |
203 | +static commonNaNT float64ToCommonNaN( float64 a ) | |
204 | +{ | |
205 | + commonNaNT z; | |
206 | + | |
207 | + if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); | |
208 | + z.sign = a>>63; | |
209 | + z.low = 0; | |
210 | + z.high = a<<12; | |
211 | + return z; | |
212 | + | |
213 | +} | |
214 | + | |
215 | +/* | |
216 | +------------------------------------------------------------------------------- | |
217 | +Returns the result of converting the canonical NaN `a' to the double- | |
218 | +precision floating-point format. | |
219 | +------------------------------------------------------------------------------- | |
220 | +*/ | |
221 | +static float64 commonNaNToFloat64( commonNaNT a ) | |
222 | +{ | |
223 | + | |
224 | + return | |
225 | + ( ( (bits64) a.sign )<<63 ) | |
226 | + | LIT64( 0x7FF8000000000000 ) | |
227 | + | ( a.high>>12 ); | |
228 | + | |
229 | +} | |
230 | + | |
231 | +/* | |
232 | +------------------------------------------------------------------------------- | |
233 | +Takes two double-precision floating-point values `a' and `b', one of which | |
234 | +is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a | |
235 | +signaling NaN, the invalid exception is raised. | |
236 | +------------------------------------------------------------------------------- | |
237 | +*/ | |
238 | +static float64 propagateFloat64NaN( float64 a, float64 b ) | |
239 | +{ | |
240 | + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; | |
241 | + | |
242 | + aIsNaN = float64_is_nan( a ); | |
243 | + aIsSignalingNaN = float64_is_signaling_nan( a ); | |
244 | + bIsNaN = float64_is_nan( b ); | |
245 | + bIsSignalingNaN = float64_is_signaling_nan( b ); | |
246 | + a |= LIT64( 0x0008000000000000 ); | |
247 | + b |= LIT64( 0x0008000000000000 ); | |
248 | + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); | |
249 | + if ( aIsNaN ) { | |
250 | + return ( aIsSignalingNaN & bIsNaN ) ? b : a; | |
251 | + } | |
252 | + else { | |
253 | + return b; | |
254 | + } | |
255 | + | |
256 | +} | |
257 | + | |
258 | +#ifdef FLOATX80 | |
259 | + | |
260 | +/* | |
261 | +------------------------------------------------------------------------------- | |
262 | +The pattern for a default generated extended double-precision NaN. The | |
263 | +`high' and `low' values hold the most- and least-significant bits, | |
264 | +respectively. | |
265 | +------------------------------------------------------------------------------- | |
266 | +*/ | |
267 | +#define floatx80_default_nan_high 0xFFFF | |
268 | +#define floatx80_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF ) | |
269 | + | |
270 | +/* | |
271 | +------------------------------------------------------------------------------- | |
272 | +Returns 1 if the extended double-precision floating-point value `a' is a | |
273 | +NaN; otherwise returns 0. | |
274 | +------------------------------------------------------------------------------- | |
275 | +*/ | |
276 | +flag floatx80_is_nan( floatx80 a ) | |
277 | +{ | |
278 | + | |
279 | + return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 ); | |
280 | + | |
281 | +} | |
282 | + | |
283 | +/* | |
284 | +------------------------------------------------------------------------------- | |
285 | +Returns 1 if the extended double-precision floating-point value `a' is a | |
286 | +signaling NaN; otherwise returns 0. | |
287 | +------------------------------------------------------------------------------- | |
288 | +*/ | |
289 | +flag floatx80_is_signaling_nan( floatx80 a ) | |
290 | +{ | |
291 | + //register int lr; | |
292 | + bits64 aLow; | |
293 | + | |
294 | + //__asm__("mov %0, lr" : : "g" (lr)); | |
295 | + //fp_printk("floatx80_is_signalling_nan() called from 0x%08x\n",lr); | |
296 | + aLow = a.low & ~ LIT64( 0x4000000000000000 ); | |
297 | + return | |
298 | + ( ( a.high & 0x7FFF ) == 0x7FFF ) | |
299 | + && (bits64) ( aLow<<1 ) | |
300 | + && ( a.low == aLow ); | |
301 | + | |
302 | +} | |
303 | + | |
304 | +/* | |
305 | +------------------------------------------------------------------------------- | |
306 | +Returns the result of converting the extended double-precision floating- | |
307 | +point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the | |
308 | +invalid exception is raised. | |
309 | +------------------------------------------------------------------------------- | |
310 | +*/ | |
311 | +static commonNaNT floatx80ToCommonNaN( floatx80 a ) | |
312 | +{ | |
313 | + commonNaNT z; | |
314 | + | |
315 | + if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); | |
316 | + z.sign = a.high>>15; | |
317 | + z.low = 0; | |
318 | + z.high = a.low<<1; | |
319 | + return z; | |
320 | + | |
321 | +} | |
322 | + | |
323 | +/* | |
324 | +------------------------------------------------------------------------------- | |
325 | +Returns the result of converting the canonical NaN `a' to the extended | |
326 | +double-precision floating-point format. | |
327 | +------------------------------------------------------------------------------- | |
328 | +*/ | |
329 | +static floatx80 commonNaNToFloatx80( commonNaNT a ) | |
330 | +{ | |
331 | + floatx80 z; | |
332 | + | |
333 | + z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 ); | |
334 | + z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF; | |
335 | + return z; | |
336 | + | |
337 | +} | |
338 | + | |
339 | +/* | |
340 | +------------------------------------------------------------------------------- | |
341 | +Takes two extended double-precision floating-point values `a' and `b', one | |
342 | +of which is a NaN, and returns the appropriate NaN result. If either `a' or | |
343 | +`b' is a signaling NaN, the invalid exception is raised. | |
344 | +------------------------------------------------------------------------------- | |
345 | +*/ | |
346 | +static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b ) | |
347 | +{ | |
348 | + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; | |
349 | + | |
350 | + aIsNaN = floatx80_is_nan( a ); | |
351 | + aIsSignalingNaN = floatx80_is_signaling_nan( a ); | |
352 | + bIsNaN = floatx80_is_nan( b ); | |
353 | + bIsSignalingNaN = floatx80_is_signaling_nan( b ); | |
354 | + a.low |= LIT64( 0xC000000000000000 ); | |
355 | + b.low |= LIT64( 0xC000000000000000 ); | |
356 | + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); | |
357 | + if ( aIsNaN ) { | |
358 | + return ( aIsSignalingNaN & bIsNaN ) ? b : a; | |
359 | + } | |
360 | + else { | |
361 | + return b; | |
362 | + } | |
363 | + | |
364 | +} | |
365 | + | |
366 | +#endif | ... | ... |