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.
23 #include <linux/config.h>
28 #include "fpmodule.inl"
30 #ifdef CONFIG_FPE_NWFPE_XP
31 extern flag floatx80_is_nan(floatx80);
33 extern flag float64_is_nan(float64);
34 extern flag float32_is_nan(float32);
36 unsigned int PerformFLT(const unsigned int opcode);
37 unsigned int PerformFIX(const unsigned int opcode);
39 static unsigned int PerformComparison(const unsigned int opcode);
41 unsigned int EmulateCPRT(const unsigned int opcode)
44 if (opcode & 0x800000) {
45 /* This is some variant of a comparison (PerformComparison
46 will sort out which one). Since most of the other CPRT
47 instructions are oddball cases of some sort or other it
48 makes sense to pull this out into a fast path. */
49 return PerformComparison(opcode);
52 /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
53 switch ((opcode & 0x700000) >> 20) {
55 return PerformFLT(opcode);
58 return PerformFIX(opcode);
62 writeFPSR(readRegister(getRd(opcode)));
65 writeRegister(getRd(opcode), readFPSR());
75 unsigned int PerformFLT(const unsigned int opcode)
77 FPA11 *fpa11 = GET_FPA11();
78 struct roundingData roundData;
80 roundData.mode = SetRoundingMode(opcode);
81 roundData.precision = SetRoundingPrecision(opcode);
82 roundData.exception = 0;
84 switch (opcode & MASK_ROUNDING_PRECISION) {
87 fpa11->fType[getFn(opcode)] = typeSingle;
88 fpa11->fpreg[getFn(opcode)].fSingle = int32_to_float32(&roundData, readRegister(getRd(opcode)));
94 fpa11->fType[getFn(opcode)] = typeDouble;
95 fpa11->fpreg[getFn(opcode)].fDouble = int32_to_float64(readRegister(getRd(opcode)));
99 #ifdef CONFIG_FPE_NWFPE_XP
102 fpa11->fType[getFn(opcode)] = typeExtended;
103 fpa11->fpreg[getFn(opcode)].fExtended = int32_to_floatx80(readRegister(getRd(opcode)));
112 if (roundData.exception)
113 float_raise(roundData.exception);
118 unsigned int PerformFIX(const unsigned int opcode)
120 FPA11 *fpa11 = GET_FPA11();
121 unsigned int Fn = getFm(opcode);
122 struct roundingData roundData;
124 roundData.mode = SetRoundingMode(opcode);
125 roundData.precision = SetRoundingPrecision(opcode);
126 roundData.exception = 0;
128 switch (fpa11->fType[Fn]) {
131 writeRegister(getRd(opcode), float32_to_int32(&roundData, fpa11->fpreg[Fn].fSingle));
137 writeRegister(getRd(opcode), float64_to_int32(&roundData, fpa11->fpreg[Fn].fDouble));
141 #ifdef CONFIG_FPE_NWFPE_XP
144 writeRegister(getRd(opcode), floatx80_to_int32(&roundData, fpa11->fpreg[Fn].fExtended));
153 if (roundData.exception)
154 float_raise(roundData.exception);
159 /* This instruction sets the flags N, Z, C, V in the FPSR. */
160 static unsigned int PerformComparison(const unsigned int opcode)
162 FPA11 *fpa11 = GET_FPA11();
163 unsigned int Fn = getFn(opcode), Fm = getFm(opcode);
164 int e_flag = opcode & 0x400000; /* 1 if CxFE */
165 int n_flag = opcode & 0x200000; /* 1 if CNxx */
166 unsigned int flags = 0;
168 #ifdef CONFIG_FPE_NWFPE_XP
171 /* Check for unordered condition and convert all operands to 80-bit
173 ?? Might be some mileage in avoiding this conversion if possible.
174 Eg, if both operands are 32-bit, detect this and do a 32-bit
175 comparison (cheaper than an 80-bit one). */
176 switch (fpa11->fType[Fn]) {
178 //printk("single.\n");
179 if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
181 rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
185 //printk("double.\n");
186 if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
188 rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
192 //printk("extended.\n");
193 if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
195 rFn = fpa11->fpreg[Fn].fExtended;
202 if (CONSTANT_FM(opcode)) {
203 //printk("Fm is a constant: #%d.\n",Fm);
204 rFm = getExtendedConstant(Fm);
205 if (floatx80_is_nan(rFm))
208 //printk("Fm = r%d which contains a ",Fm);
209 switch (fpa11->fType[Fm]) {
211 //printk("single.\n");
212 if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
214 rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
218 //printk("double.\n");
219 if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
221 rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble);
225 //printk("extended.\n");
226 if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
228 rFm = fpa11->fpreg[Fm].fExtended;
239 /* test for less than condition */
240 if (floatx80_lt(rFn, rFm))
241 flags |= CC_NEGATIVE;
243 /* test for equal condition */
244 if (floatx80_eq(rFn, rFm))
247 /* test for greater than or equal condition */
248 if (floatx80_lt(rFm, rFn))
252 if (CONSTANT_FM(opcode)) {
253 /* Fm is a constant. Do the comparison in whatever precision
254 Fn happens to be stored in. */
255 if (fpa11->fType[Fn] == typeSingle) {
256 float32 rFm = getSingleConstant(Fm);
257 float32 rFn = fpa11->fpreg[Fn].fSingle;
259 if (float32_is_nan(rFn))
265 /* test for less than condition */
266 if (float32_lt_nocheck(rFn, rFm))
267 flags |= CC_NEGATIVE;
269 /* test for equal condition */
270 if (float32_eq_nocheck(rFn, rFm))
273 /* test for greater than or equal condition */
274 if (float32_lt_nocheck(rFm, rFn))
277 float64 rFm = getDoubleConstant(Fm);
278 float64 rFn = fpa11->fpreg[Fn].fDouble;
280 if (float64_is_nan(rFn))
284 rFm ^= 0x8000000000000000ULL;
286 /* test for less than condition */
287 if (float64_lt_nocheck(rFn, rFm))
288 flags |= CC_NEGATIVE;
290 /* test for equal condition */
291 if (float64_eq_nocheck(rFn, rFm))
294 /* test for greater than or equal condition */
295 if (float64_lt_nocheck(rFm, rFn))
299 /* Both operands are in registers. */
300 if (fpa11->fType[Fn] == typeSingle
301 && fpa11->fType[Fm] == typeSingle) {
302 float32 rFm = fpa11->fpreg[Fm].fSingle;
303 float32 rFn = fpa11->fpreg[Fn].fSingle;
305 if (float32_is_nan(rFn)
306 || float32_is_nan(rFm))
312 /* test for less than condition */
313 if (float32_lt_nocheck(rFn, rFm))
314 flags |= CC_NEGATIVE;
316 /* test for equal condition */
317 if (float32_eq_nocheck(rFn, rFm))
320 /* test for greater than or equal condition */
321 if (float32_lt_nocheck(rFm, rFn))
324 /* Promote 32-bit operand to 64 bits. */
327 rFm = (fpa11->fType[Fm] == typeSingle) ?
328 float32_to_float64(fpa11->fpreg[Fm].fSingle)
329 : fpa11->fpreg[Fm].fDouble;
331 rFn = (fpa11->fType[Fn] == typeSingle) ?
332 float32_to_float64(fpa11->fpreg[Fn].fSingle)
333 : fpa11->fpreg[Fn].fDouble;
335 if (float64_is_nan(rFn)
336 || float64_is_nan(rFm))
340 rFm ^= 0x8000000000000000ULL;
342 /* test for less than condition */
343 if (float64_lt_nocheck(rFn, rFm))
344 flags |= CC_NEGATIVE;
346 /* test for equal condition */
347 if (float64_eq_nocheck(rFn, rFm))
350 /* test for greater than or equal condition */
351 if (float64_lt_nocheck(rFm, rFn))
358 writeConditionCodes(flags);
363 /* ?? The FPA data sheet is pretty vague about this, in particular
364 about whether the non-E comparisons can ever raise exceptions.
365 This implementation is based on a combination of what it says in
366 the data sheet, observation of how the Acorn emulator actually
367 behaves (and how programs expect it to) and guesswork. */
368 flags |= CC_OVERFLOW;
369 flags &= ~(CC_ZERO | CC_NEGATIVE);
371 if (BIT_AC & readFPSR())
375 float_raise(float_flag_invalid);
377 writeConditionCodes(flags);