[PATCH] page migration cleanup: rename "ignrefs" to "migration"
[linux-2.6/suspend2-2.6.18.git] / arch / arm / nwfpe / fpa11_cprt.c
blob7c67023655e41c6543fb1b31a246f91fbd91499f
1 /*
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>
24 #include "fpa11.h"
25 #include "fpopcode.h"
26 #include "fpa11.inl"
27 #include "fpmodule.h"
28 #include "fpmodule.inl"
29 #include "softfloat.h"
31 #ifdef CONFIG_FPE_NWFPE_XP
32 extern flag floatx80_is_nan(floatx80);
33 #endif
35 unsigned int PerformFLT(const unsigned int opcode);
36 unsigned int PerformFIX(const unsigned int opcode);
38 static unsigned int PerformComparison(const unsigned int opcode);
40 unsigned int EmulateCPRT(const unsigned int opcode)
43 if (opcode & 0x800000) {
44 /* This is some variant of a comparison (PerformComparison
45 will sort out which one). Since most of the other CPRT
46 instructions are oddball cases of some sort or other it
47 makes sense to pull this out into a fast path. */
48 return PerformComparison(opcode);
51 /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
52 switch ((opcode & 0x700000) >> 20) {
53 case FLT_CODE >> 20:
54 return PerformFLT(opcode);
55 break;
56 case FIX_CODE >> 20:
57 return PerformFIX(opcode);
58 break;
60 case WFS_CODE >> 20:
61 writeFPSR(readRegister(getRd(opcode)));
62 break;
63 case RFS_CODE >> 20:
64 writeRegister(getRd(opcode), readFPSR());
65 break;
67 default:
68 return 0;
71 return 1;
74 unsigned int PerformFLT(const unsigned int opcode)
76 FPA11 *fpa11 = GET_FPA11();
77 struct roundingData roundData;
79 roundData.mode = SetRoundingMode(opcode);
80 roundData.precision = SetRoundingPrecision(opcode);
81 roundData.exception = 0;
83 switch (opcode & MASK_ROUNDING_PRECISION) {
84 case ROUND_SINGLE:
86 fpa11->fType[getFn(opcode)] = typeSingle;
87 fpa11->fpreg[getFn(opcode)].fSingle = int32_to_float32(&roundData, readRegister(getRd(opcode)));
89 break;
91 case ROUND_DOUBLE:
93 fpa11->fType[getFn(opcode)] = typeDouble;
94 fpa11->fpreg[getFn(opcode)].fDouble = int32_to_float64(readRegister(getRd(opcode)));
96 break;
98 #ifdef CONFIG_FPE_NWFPE_XP
99 case ROUND_EXTENDED:
101 fpa11->fType[getFn(opcode)] = typeExtended;
102 fpa11->fpreg[getFn(opcode)].fExtended = int32_to_floatx80(readRegister(getRd(opcode)));
104 break;
105 #endif
107 default:
108 return 0;
111 if (roundData.exception)
112 float_raise(roundData.exception);
114 return 1;
117 unsigned int PerformFIX(const unsigned int opcode)
119 FPA11 *fpa11 = GET_FPA11();
120 unsigned int Fn = getFm(opcode);
121 struct roundingData roundData;
123 roundData.mode = SetRoundingMode(opcode);
124 roundData.precision = SetRoundingPrecision(opcode);
125 roundData.exception = 0;
127 switch (fpa11->fType[Fn]) {
128 case typeSingle:
130 writeRegister(getRd(opcode), float32_to_int32(&roundData, fpa11->fpreg[Fn].fSingle));
132 break;
134 case typeDouble:
136 writeRegister(getRd(opcode), float64_to_int32(&roundData, fpa11->fpreg[Fn].fDouble));
138 break;
140 #ifdef CONFIG_FPE_NWFPE_XP
141 case typeExtended:
143 writeRegister(getRd(opcode), floatx80_to_int32(&roundData, fpa11->fpreg[Fn].fExtended));
145 break;
146 #endif
148 default:
149 return 0;
152 if (roundData.exception)
153 float_raise(roundData.exception);
155 return 1;
158 /* This instruction sets the flags N, Z, C, V in the FPSR. */
159 static unsigned int PerformComparison(const unsigned int opcode)
161 FPA11 *fpa11 = GET_FPA11();
162 unsigned int Fn = getFn(opcode), Fm = getFm(opcode);
163 int e_flag = opcode & 0x400000; /* 1 if CxFE */
164 int n_flag = opcode & 0x200000; /* 1 if CNxx */
165 unsigned int flags = 0;
167 #ifdef CONFIG_FPE_NWFPE_XP
168 floatx80 rFn, rFm;
170 /* Check for unordered condition and convert all operands to 80-bit
171 format.
172 ?? Might be some mileage in avoiding this conversion if possible.
173 Eg, if both operands are 32-bit, detect this and do a 32-bit
174 comparison (cheaper than an 80-bit one). */
175 switch (fpa11->fType[Fn]) {
176 case typeSingle:
177 //printk("single.\n");
178 if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
179 goto unordered;
180 rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
181 break;
183 case typeDouble:
184 //printk("double.\n");
185 if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
186 goto unordered;
187 rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
188 break;
190 case typeExtended:
191 //printk("extended.\n");
192 if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
193 goto unordered;
194 rFn = fpa11->fpreg[Fn].fExtended;
195 break;
197 default:
198 return 0;
201 if (CONSTANT_FM(opcode)) {
202 //printk("Fm is a constant: #%d.\n",Fm);
203 rFm = getExtendedConstant(Fm);
204 if (floatx80_is_nan(rFm))
205 goto unordered;
206 } else {
207 //printk("Fm = r%d which contains a ",Fm);
208 switch (fpa11->fType[Fm]) {
209 case typeSingle:
210 //printk("single.\n");
211 if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
212 goto unordered;
213 rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
214 break;
216 case typeDouble:
217 //printk("double.\n");
218 if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
219 goto unordered;
220 rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble);
221 break;
223 case typeExtended:
224 //printk("extended.\n");
225 if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
226 goto unordered;
227 rFm = fpa11->fpreg[Fm].fExtended;
228 break;
230 default:
231 return 0;
235 if (n_flag)
236 rFm.high ^= 0x8000;
238 /* test for less than condition */
239 if (floatx80_lt(rFn, rFm))
240 flags |= CC_NEGATIVE;
242 /* test for equal condition */
243 if (floatx80_eq(rFn, rFm))
244 flags |= CC_ZERO;
246 /* test for greater than or equal condition */
247 if (floatx80_lt(rFm, rFn))
248 flags |= CC_CARRY;
250 #else
251 if (CONSTANT_FM(opcode)) {
252 /* Fm is a constant. Do the comparison in whatever precision
253 Fn happens to be stored in. */
254 if (fpa11->fType[Fn] == typeSingle) {
255 float32 rFm = getSingleConstant(Fm);
256 float32 rFn = fpa11->fpreg[Fn].fSingle;
258 if (float32_is_nan(rFn))
259 goto unordered;
261 if (n_flag)
262 rFm ^= 0x80000000;
264 /* test for less than condition */
265 if (float32_lt_nocheck(rFn, rFm))
266 flags |= CC_NEGATIVE;
268 /* test for equal condition */
269 if (float32_eq_nocheck(rFn, rFm))
270 flags |= CC_ZERO;
272 /* test for greater than or equal condition */
273 if (float32_lt_nocheck(rFm, rFn))
274 flags |= CC_CARRY;
275 } else {
276 float64 rFm = getDoubleConstant(Fm);
277 float64 rFn = fpa11->fpreg[Fn].fDouble;
279 if (float64_is_nan(rFn))
280 goto unordered;
282 if (n_flag)
283 rFm ^= 0x8000000000000000ULL;
285 /* test for less than condition */
286 if (float64_lt_nocheck(rFn, rFm))
287 flags |= CC_NEGATIVE;
289 /* test for equal condition */
290 if (float64_eq_nocheck(rFn, rFm))
291 flags |= CC_ZERO;
293 /* test for greater than or equal condition */
294 if (float64_lt_nocheck(rFm, rFn))
295 flags |= CC_CARRY;
297 } else {
298 /* Both operands are in registers. */
299 if (fpa11->fType[Fn] == typeSingle
300 && fpa11->fType[Fm] == typeSingle) {
301 float32 rFm = fpa11->fpreg[Fm].fSingle;
302 float32 rFn = fpa11->fpreg[Fn].fSingle;
304 if (float32_is_nan(rFn)
305 || float32_is_nan(rFm))
306 goto unordered;
308 if (n_flag)
309 rFm ^= 0x80000000;
311 /* test for less than condition */
312 if (float32_lt_nocheck(rFn, rFm))
313 flags |= CC_NEGATIVE;
315 /* test for equal condition */
316 if (float32_eq_nocheck(rFn, rFm))
317 flags |= CC_ZERO;
319 /* test for greater than or equal condition */
320 if (float32_lt_nocheck(rFm, rFn))
321 flags |= CC_CARRY;
322 } else {
323 /* Promote 32-bit operand to 64 bits. */
324 float64 rFm, rFn;
326 rFm = (fpa11->fType[Fm] == typeSingle) ?
327 float32_to_float64(fpa11->fpreg[Fm].fSingle)
328 : fpa11->fpreg[Fm].fDouble;
330 rFn = (fpa11->fType[Fn] == typeSingle) ?
331 float32_to_float64(fpa11->fpreg[Fn].fSingle)
332 : fpa11->fpreg[Fn].fDouble;
334 if (float64_is_nan(rFn)
335 || float64_is_nan(rFm))
336 goto unordered;
338 if (n_flag)
339 rFm ^= 0x8000000000000000ULL;
341 /* test for less than condition */
342 if (float64_lt_nocheck(rFn, rFm))
343 flags |= CC_NEGATIVE;
345 /* test for equal condition */
346 if (float64_eq_nocheck(rFn, rFm))
347 flags |= CC_ZERO;
349 /* test for greater than or equal condition */
350 if (float64_lt_nocheck(rFm, rFn))
351 flags |= CC_CARRY;
355 #endif
357 writeConditionCodes(flags);
359 return 1;
361 unordered:
362 /* ?? The FPA data sheet is pretty vague about this, in particular
363 about whether the non-E comparisons can ever raise exceptions.
364 This implementation is based on a combination of what it says in
365 the data sheet, observation of how the Acorn emulator actually
366 behaves (and how programs expect it to) and guesswork. */
367 flags |= CC_OVERFLOW;
368 flags &= ~(CC_ZERO | CC_NEGATIVE);
370 if (BIT_AC & readFPSR())
371 flags |= CC_CARRY;
373 if (e_flag)
374 float_raise(float_flag_invalid);
376 writeConditionCodes(flags);
377 return 1;