2 NetWinder Floating Point Emulator
3 (c) Rebel.COM, 1998,1999
4 (c) Philip Blundell, 1999, 2001
6 Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
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.
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.
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.
27 #include "fpmodule.inl"
28 #include "softfloat.h"
30 #ifdef CONFIG_FPE_NWFPE_XP
31 extern flag
floatx80_is_nan(floatx80
);
34 unsigned int PerformFLT(const unsigned int opcode
);
35 unsigned int PerformFIX(const unsigned int opcode
);
37 static unsigned int PerformComparison(const unsigned int opcode
);
39 unsigned int EmulateCPRT(const unsigned int opcode
)
42 if (opcode
& 0x800000) {
43 /* This is some variant of a comparison (PerformComparison
44 will sort out which one). Since most of the other CPRT
45 instructions are oddball cases of some sort or other it
46 makes sense to pull this out into a fast path. */
47 return PerformComparison(opcode
);
50 /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
51 switch ((opcode
& 0x700000) >> 20) {
53 return PerformFLT(opcode
);
56 return PerformFIX(opcode
);
60 writeFPSR(readRegister(getRd(opcode
)));
63 writeRegister(getRd(opcode
), readFPSR());
73 unsigned int PerformFLT(const unsigned int opcode
)
75 FPA11
*fpa11
= GET_FPA11();
76 struct roundingData roundData
;
78 roundData
.mode
= SetRoundingMode(opcode
);
79 roundData
.precision
= SetRoundingPrecision(opcode
);
80 roundData
.exception
= 0;
82 switch (opcode
& MASK_ROUNDING_PRECISION
) {
85 fpa11
->fType
[getFn(opcode
)] = typeSingle
;
86 fpa11
->fpreg
[getFn(opcode
)].fSingle
= int32_to_float32(&roundData
, readRegister(getRd(opcode
)));
92 fpa11
->fType
[getFn(opcode
)] = typeDouble
;
93 fpa11
->fpreg
[getFn(opcode
)].fDouble
= int32_to_float64(readRegister(getRd(opcode
)));
97 #ifdef CONFIG_FPE_NWFPE_XP
100 fpa11
->fType
[getFn(opcode
)] = typeExtended
;
101 fpa11
->fpreg
[getFn(opcode
)].fExtended
= int32_to_floatx80(readRegister(getRd(opcode
)));
110 if (roundData
.exception
)
111 float_raise(roundData
.exception
);
116 unsigned int PerformFIX(const unsigned int opcode
)
118 FPA11
*fpa11
= GET_FPA11();
119 unsigned int Fn
= getFm(opcode
);
120 struct roundingData roundData
;
122 roundData
.mode
= SetRoundingMode(opcode
);
123 roundData
.precision
= SetRoundingPrecision(opcode
);
124 roundData
.exception
= 0;
126 switch (fpa11
->fType
[Fn
]) {
129 writeRegister(getRd(opcode
), float32_to_int32(&roundData
, fpa11
->fpreg
[Fn
].fSingle
));
135 writeRegister(getRd(opcode
), float64_to_int32(&roundData
, fpa11
->fpreg
[Fn
].fDouble
));
139 #ifdef CONFIG_FPE_NWFPE_XP
142 writeRegister(getRd(opcode
), floatx80_to_int32(&roundData
, fpa11
->fpreg
[Fn
].fExtended
));
151 if (roundData
.exception
)
152 float_raise(roundData
.exception
);
157 /* This instruction sets the flags N, Z, C, V in the FPSR. */
158 static unsigned int PerformComparison(const unsigned int opcode
)
160 FPA11
*fpa11
= GET_FPA11();
161 unsigned int Fn
= getFn(opcode
), Fm
= getFm(opcode
);
162 int e_flag
= opcode
& 0x400000; /* 1 if CxFE */
163 int n_flag
= opcode
& 0x200000; /* 1 if CNxx */
164 unsigned int flags
= 0;
166 #ifdef CONFIG_FPE_NWFPE_XP
169 /* Check for unordered condition and convert all operands to 80-bit
171 ?? Might be some mileage in avoiding this conversion if possible.
172 Eg, if both operands are 32-bit, detect this and do a 32-bit
173 comparison (cheaper than an 80-bit one). */
174 switch (fpa11
->fType
[Fn
]) {
176 //printk("single.\n");
177 if (float32_is_nan(fpa11
->fpreg
[Fn
].fSingle
))
179 rFn
= float32_to_floatx80(fpa11
->fpreg
[Fn
].fSingle
);
183 //printk("double.\n");
184 if (float64_is_nan(fpa11
->fpreg
[Fn
].fDouble
))
186 rFn
= float64_to_floatx80(fpa11
->fpreg
[Fn
].fDouble
);
190 //printk("extended.\n");
191 if (floatx80_is_nan(fpa11
->fpreg
[Fn
].fExtended
))
193 rFn
= fpa11
->fpreg
[Fn
].fExtended
;
200 if (CONSTANT_FM(opcode
)) {
201 //printk("Fm is a constant: #%d.\n",Fm);
202 rFm
= getExtendedConstant(Fm
);
203 if (floatx80_is_nan(rFm
))
206 //printk("Fm = r%d which contains a ",Fm);
207 switch (fpa11
->fType
[Fm
]) {
209 //printk("single.\n");
210 if (float32_is_nan(fpa11
->fpreg
[Fm
].fSingle
))
212 rFm
= float32_to_floatx80(fpa11
->fpreg
[Fm
].fSingle
);
216 //printk("double.\n");
217 if (float64_is_nan(fpa11
->fpreg
[Fm
].fDouble
))
219 rFm
= float64_to_floatx80(fpa11
->fpreg
[Fm
].fDouble
);
223 //printk("extended.\n");
224 if (floatx80_is_nan(fpa11
->fpreg
[Fm
].fExtended
))
226 rFm
= fpa11
->fpreg
[Fm
].fExtended
;
237 /* test for less than condition */
238 if (floatx80_lt(rFn
, rFm
))
239 flags
|= CC_NEGATIVE
;
241 /* test for equal condition */
242 if (floatx80_eq(rFn
, rFm
))
245 /* test for greater than or equal condition */
246 if (floatx80_lt(rFm
, rFn
))
250 if (CONSTANT_FM(opcode
)) {
251 /* Fm is a constant. Do the comparison in whatever precision
252 Fn happens to be stored in. */
253 if (fpa11
->fType
[Fn
] == typeSingle
) {
254 float32 rFm
= getSingleConstant(Fm
);
255 float32 rFn
= fpa11
->fpreg
[Fn
].fSingle
;
257 if (float32_is_nan(rFn
))
263 /* test for less than condition */
264 if (float32_lt_nocheck(rFn
, rFm
))
265 flags
|= CC_NEGATIVE
;
267 /* test for equal condition */
268 if (float32_eq_nocheck(rFn
, rFm
))
271 /* test for greater than or equal condition */
272 if (float32_lt_nocheck(rFm
, rFn
))
275 float64 rFm
= getDoubleConstant(Fm
);
276 float64 rFn
= fpa11
->fpreg
[Fn
].fDouble
;
278 if (float64_is_nan(rFn
))
282 rFm
^= 0x8000000000000000ULL
;
284 /* test for less than condition */
285 if (float64_lt_nocheck(rFn
, rFm
))
286 flags
|= CC_NEGATIVE
;
288 /* test for equal condition */
289 if (float64_eq_nocheck(rFn
, rFm
))
292 /* test for greater than or equal condition */
293 if (float64_lt_nocheck(rFm
, rFn
))
297 /* Both operands are in registers. */
298 if (fpa11
->fType
[Fn
] == typeSingle
299 && fpa11
->fType
[Fm
] == typeSingle
) {
300 float32 rFm
= fpa11
->fpreg
[Fm
].fSingle
;
301 float32 rFn
= fpa11
->fpreg
[Fn
].fSingle
;
303 if (float32_is_nan(rFn
)
304 || float32_is_nan(rFm
))
310 /* test for less than condition */
311 if (float32_lt_nocheck(rFn
, rFm
))
312 flags
|= CC_NEGATIVE
;
314 /* test for equal condition */
315 if (float32_eq_nocheck(rFn
, rFm
))
318 /* test for greater than or equal condition */
319 if (float32_lt_nocheck(rFm
, rFn
))
322 /* Promote 32-bit operand to 64 bits. */
325 rFm
= (fpa11
->fType
[Fm
] == typeSingle
) ?
326 float32_to_float64(fpa11
->fpreg
[Fm
].fSingle
)
327 : fpa11
->fpreg
[Fm
].fDouble
;
329 rFn
= (fpa11
->fType
[Fn
] == typeSingle
) ?
330 float32_to_float64(fpa11
->fpreg
[Fn
].fSingle
)
331 : fpa11
->fpreg
[Fn
].fDouble
;
333 if (float64_is_nan(rFn
)
334 || float64_is_nan(rFm
))
338 rFm
^= 0x8000000000000000ULL
;
340 /* test for less than condition */
341 if (float64_lt_nocheck(rFn
, rFm
))
342 flags
|= CC_NEGATIVE
;
344 /* test for equal condition */
345 if (float64_eq_nocheck(rFn
, rFm
))
348 /* test for greater than or equal condition */
349 if (float64_lt_nocheck(rFm
, rFn
))
356 writeConditionCodes(flags
);
361 /* ?? The FPA data sheet is pretty vague about this, in particular
362 about whether the non-E comparisons can ever raise exceptions.
363 This implementation is based on a combination of what it says in
364 the data sheet, observation of how the Acorn emulator actually
365 behaves (and how programs expect it to) and guesswork. */
366 flags
|= CC_OVERFLOW
;
367 flags
&= ~(CC_ZERO
| CC_NEGATIVE
);
369 if (BIT_AC
& readFPSR())
373 float_raise(float_flag_invalid
);
375 writeConditionCodes(flags
);