Fix FIQ bank switching.
[qemu/mini2440.git] / target-arm / nwfpe / fpa11_cprt.c
blobfe295e1aa7994ebcc7beef0b5d73d6f85e002381
1 /*
2 NetWinder Floating Point Emulator
3 (c) Rebel.COM, 1998,1999
4 (c) Philip Blundell, 1999
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 "fpa11.h"
24 #include "softfloat.h"
25 #include "fpopcode.h"
26 #include "fpa11.inl"
27 //#include "fpmodule.h"
28 //#include "fpmodule.inl"
30 extern flag floatx80_is_nan(floatx80);
31 extern flag float64_is_nan( float64);
32 extern flag float32_is_nan( float32);
34 void SetRoundingMode(const unsigned int opcode);
36 unsigned int PerformFLT(const unsigned int opcode);
37 unsigned int PerformFIX(const unsigned int opcode);
39 static unsigned int
40 PerformComparison(const unsigned int opcode);
42 unsigned int EmulateCPRT(const unsigned int opcode)
44 unsigned int nRc = 1;
46 //printk("EmulateCPRT(0x%08x)\n",opcode);
48 if (opcode & 0x800000)
50 /* This is some variant of a comparison (PerformComparison will
51 sort out which one). Since most of the other CPRT
52 instructions are oddball cases of some sort or other it makes
53 sense to pull this out into a fast path. */
54 return PerformComparison(opcode);
57 /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
58 switch ((opcode & 0x700000) >> 20)
60 case FLT_CODE >> 20: nRc = PerformFLT(opcode); break;
61 case FIX_CODE >> 20: nRc = PerformFIX(opcode); break;
63 case WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break;
64 case RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break;
66 #if 0 /* We currently have no use for the FPCR, so there's no point
67 in emulating it. */
68 case WFC_CODE >> 20: writeFPCR(readRegister(getRd(opcode)));
69 case RFC_CODE >> 20: writeRegister(getRd(opcode),readFPCR()); break;
70 #endif
72 default: nRc = 0;
75 return nRc;
78 unsigned int PerformFLT(const unsigned int opcode)
80 FPA11 *fpa11 = GET_FPA11();
82 unsigned int nRc = 1;
83 SetRoundingMode(opcode);
85 switch (opcode & MASK_ROUNDING_PRECISION)
87 case ROUND_SINGLE:
89 fpa11->fType[getFn(opcode)] = typeSingle;
90 fpa11->fpreg[getFn(opcode)].fSingle =
91 int32_to_float32(readRegister(getRd(opcode)), &fpa11->fp_status);
93 break;
95 case ROUND_DOUBLE:
97 fpa11->fType[getFn(opcode)] = typeDouble;
98 fpa11->fpreg[getFn(opcode)].fDouble =
99 int32_to_float64(readRegister(getRd(opcode)), &fpa11->fp_status);
101 break;
103 case ROUND_EXTENDED:
105 fpa11->fType[getFn(opcode)] = typeExtended;
106 fpa11->fpreg[getFn(opcode)].fExtended =
107 int32_to_floatx80(readRegister(getRd(opcode)), &fpa11->fp_status);
109 break;
111 default: nRc = 0;
114 return nRc;
117 unsigned int PerformFIX(const unsigned int opcode)
119 FPA11 *fpa11 = GET_FPA11();
120 unsigned int nRc = 1;
121 unsigned int Fn = getFm(opcode);
123 SetRoundingMode(opcode);
125 switch (fpa11->fType[Fn])
127 case typeSingle:
129 writeRegister(getRd(opcode),
130 float32_to_int32(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status));
132 break;
134 case typeDouble:
136 //printf("F%d is 0x%llx\n",Fn,fpa11->fpreg[Fn].fDouble);
137 writeRegister(getRd(opcode),
138 float64_to_int32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status));
140 break;
142 case typeExtended:
144 writeRegister(getRd(opcode),
145 floatx80_to_int32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status));
147 break;
149 default: nRc = 0;
152 return nRc;
156 static unsigned int __inline__
157 PerformComparisonOperation(floatx80 Fn, floatx80 Fm)
159 FPA11 *fpa11 = GET_FPA11();
160 unsigned int flags = 0;
162 /* test for less than condition */
163 if (floatx80_lt(Fn,Fm, &fpa11->fp_status))
165 flags |= CC_NEGATIVE;
168 /* test for equal condition */
169 if (floatx80_eq(Fn,Fm, &fpa11->fp_status))
171 flags |= CC_ZERO;
174 /* test for greater than or equal condition */
175 if (floatx80_lt(Fm,Fn, &fpa11->fp_status))
177 flags |= CC_CARRY;
180 writeConditionCodes(flags);
181 return 1;
184 /* This instruction sets the flags N, Z, C, V in the FPSR. */
186 static unsigned int PerformComparison(const unsigned int opcode)
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;
195 //printk("PerformComparison(0x%08x)\n",opcode);
197 Fn = getFn(opcode);
198 Fm = getFm(opcode);
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])
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, &fpa11->fp_status);
212 break;
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, &fpa11->fp_status);
219 break;
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;
228 default: return 0;
231 if (CONSTANT_FM(opcode))
233 //printk("Fm is a constant: #%d.\n",Fm);
234 rFm = getExtendedConstant(Fm);
235 if (floatx80_is_nan(rFm))
236 goto unordered;
238 else
240 //printk("Fm = r%d which contains a ",Fm);
241 switch (fpa11->fType[Fm])
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, &fpa11->fp_status);
248 break;
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, &fpa11->fp_status);
255 break;
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;
264 default: return 0;
268 if (n_flag)
270 rFm.high ^= 0x8000;
273 return PerformComparisonOperation(rFn,rFm);
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);
284 if (BIT_AC & readFPSR()) flags |= CC_CARRY;
286 if (e_flag) float_raise(float_flag_invalid, &fpa11->fp_status);
288 writeConditionCodes(flags);
289 return 1;