~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/nwfpe/fpa11_cprt.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3     NetWinder Floating Point Emulator
  4     (c) Rebel.COM, 1998,1999
  5     (c) Philip Blundell, 1999, 2001
  6 
  7     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
  8 
  9 */
 10 
 11 #include "fpa11.h"
 12 #include "fpopcode.h"
 13 #include "fpa11.inl"
 14 #include "fpmodule.h"
 15 #include "fpmodule.inl"
 16 #include "softfloat.h"
 17 
 18 unsigned int PerformFLT(const unsigned int opcode);
 19 unsigned int PerformFIX(const unsigned int opcode);
 20 
 21 static unsigned int PerformComparison(const unsigned int opcode);
 22 
 23 unsigned int EmulateCPRT(const unsigned int opcode)
 24 {
 25 
 26         if (opcode & 0x800000) {
 27                 /* This is some variant of a comparison (PerformComparison
 28                    will sort out which one).  Since most of the other CPRT
 29                    instructions are oddball cases of some sort or other it
 30                    makes sense to pull this out into a fast path.  */
 31                 return PerformComparison(opcode);
 32         }
 33 
 34         /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
 35         switch ((opcode & 0x700000) >> 20) {
 36         case FLT_CODE >> 20:
 37                 return PerformFLT(opcode);
 38                 break;
 39         case FIX_CODE >> 20:
 40                 return PerformFIX(opcode);
 41                 break;
 42 
 43         case WFS_CODE >> 20:
 44                 writeFPSR(readRegister(getRd(opcode)));
 45                 break;
 46         case RFS_CODE >> 20:
 47                 writeRegister(getRd(opcode), readFPSR());
 48                 break;
 49 
 50         default:
 51                 return 0;
 52         }
 53 
 54         return 1;
 55 }
 56 
 57 unsigned int PerformFLT(const unsigned int opcode)
 58 {
 59         FPA11 *fpa11 = GET_FPA11();
 60         struct roundingData roundData;
 61 
 62         roundData.mode = SetRoundingMode(opcode);
 63         roundData.precision = SetRoundingPrecision(opcode);
 64         roundData.exception = 0;
 65 
 66         switch (opcode & MASK_ROUNDING_PRECISION) {
 67         case ROUND_SINGLE:
 68                 {
 69                         fpa11->fType[getFn(opcode)] = typeSingle;
 70                         fpa11->fpreg[getFn(opcode)].fSingle = int32_to_float32(&roundData, readRegister(getRd(opcode)));
 71                 }
 72                 break;
 73 
 74         case ROUND_DOUBLE:
 75                 {
 76                         fpa11->fType[getFn(opcode)] = typeDouble;
 77                         fpa11->fpreg[getFn(opcode)].fDouble = int32_to_float64(readRegister(getRd(opcode)));
 78                 }
 79                 break;
 80 
 81 #ifdef CONFIG_FPE_NWFPE_XP
 82         case ROUND_EXTENDED:
 83                 {
 84                         fpa11->fType[getFn(opcode)] = typeExtended;
 85                         fpa11->fpreg[getFn(opcode)].fExtended = int32_to_floatx80(readRegister(getRd(opcode)));
 86                 }
 87                 break;
 88 #endif
 89 
 90         default:
 91                 return 0;
 92         }
 93 
 94         if (roundData.exception)
 95                 float_raise(roundData.exception);
 96 
 97         return 1;
 98 }
 99 
100 unsigned int PerformFIX(const unsigned int opcode)
101 {
102         FPA11 *fpa11 = GET_FPA11();
103         unsigned int Fn = getFm(opcode);
104         struct roundingData roundData;
105 
106         roundData.mode = SetRoundingMode(opcode);
107         roundData.precision = SetRoundingPrecision(opcode);
108         roundData.exception = 0;
109 
110         switch (fpa11->fType[Fn]) {
111         case typeSingle:
112                 {
113                         writeRegister(getRd(opcode), float32_to_int32(&roundData, fpa11->fpreg[Fn].fSingle));
114                 }
115                 break;
116 
117         case typeDouble:
118                 {
119                         writeRegister(getRd(opcode), float64_to_int32(&roundData, fpa11->fpreg[Fn].fDouble));
120                 }
121                 break;
122 
123 #ifdef CONFIG_FPE_NWFPE_XP
124         case typeExtended:
125                 {
126                         writeRegister(getRd(opcode), floatx80_to_int32(&roundData, fpa11->fpreg[Fn].fExtended));
127                 }
128                 break;
129 #endif
130 
131         default:
132                 return 0;
133         }
134 
135         if (roundData.exception)
136                 float_raise(roundData.exception);
137 
138         return 1;
139 }
140 
141 /* This instruction sets the flags N, Z, C, V in the FPSR. */
142 static unsigned int PerformComparison(const unsigned int opcode)
143 {
144         FPA11 *fpa11 = GET_FPA11();
145         unsigned int Fn = getFn(opcode), Fm = getFm(opcode);
146         int e_flag = opcode & 0x400000; /* 1 if CxFE */
147         int n_flag = opcode & 0x200000; /* 1 if CNxx */
148         unsigned int flags = 0;
149 
150 #ifdef CONFIG_FPE_NWFPE_XP
151         floatx80 rFn, rFm;
152 
153         /* Check for unordered condition and convert all operands to 80-bit
154            format.
155            ?? Might be some mileage in avoiding this conversion if possible.
156            Eg, if both operands are 32-bit, detect this and do a 32-bit
157            comparison (cheaper than an 80-bit one).  */
158         switch (fpa11->fType[Fn]) {
159         case typeSingle:
160                 //printk("single.\n");
161                 if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
162                         goto unordered;
163                 rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
164                 break;
165 
166         case typeDouble:
167                 //printk("double.\n");
168                 if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
169                         goto unordered;
170                 rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
171                 break;
172 
173         case typeExtended:
174                 //printk("extended.\n");
175                 if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
176                         goto unordered;
177                 rFn = fpa11->fpreg[Fn].fExtended;
178                 break;
179 
180         default:
181                 return 0;
182         }
183 
184         if (CONSTANT_FM(opcode)) {
185                 //printk("Fm is a constant: #%d.\n",Fm);
186                 rFm = getExtendedConstant(Fm);
187                 if (floatx80_is_nan(rFm))
188                         goto unordered;
189         } else {
190                 //printk("Fm = r%d which contains a ",Fm);
191                 switch (fpa11->fType[Fm]) {
192                 case typeSingle:
193                         //printk("single.\n");
194                         if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
195                                 goto unordered;
196                         rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
197                         break;
198 
199                 case typeDouble:
200                         //printk("double.\n");
201                         if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
202                                 goto unordered;
203                         rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble);
204                         break;
205 
206                 case typeExtended:
207                         //printk("extended.\n");
208                         if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
209                                 goto unordered;
210                         rFm = fpa11->fpreg[Fm].fExtended;
211                         break;
212 
213                 default:
214                         return 0;
215                 }
216         }
217 
218         if (n_flag)
219                 rFm.high ^= 0x8000;
220 
221         /* test for less than condition */
222         if (floatx80_lt(rFn, rFm))
223                 flags |= CC_NEGATIVE;
224 
225         /* test for equal condition */
226         if (floatx80_eq(rFn, rFm))
227                 flags |= CC_ZERO;
228 
229         /* test for greater than or equal condition */
230         if (floatx80_lt(rFm, rFn))
231                 flags |= CC_CARRY;
232 
233 #else
234         if (CONSTANT_FM(opcode)) {
235                 /* Fm is a constant.  Do the comparison in whatever precision
236                    Fn happens to be stored in.  */
237                 if (fpa11->fType[Fn] == typeSingle) {
238                         float32 rFm = getSingleConstant(Fm);
239                         float32 rFn = fpa11->fpreg[Fn].fSingle;
240 
241                         if (float32_is_nan(rFn))
242                                 goto unordered;
243 
244                         if (n_flag)
245                                 rFm ^= 0x80000000;
246 
247                         /* test for less than condition */
248                         if (float32_lt_nocheck(rFn, rFm))
249                                 flags |= CC_NEGATIVE;
250 
251                         /* test for equal condition */
252                         if (float32_eq_nocheck(rFn, rFm))
253                                 flags |= CC_ZERO;
254 
255                         /* test for greater than or equal condition */
256                         if (float32_lt_nocheck(rFm, rFn))
257                                 flags |= CC_CARRY;
258                 } else {
259                         float64 rFm = getDoubleConstant(Fm);
260                         float64 rFn = fpa11->fpreg[Fn].fDouble;
261 
262                         if (float64_is_nan(rFn))
263                                 goto unordered;
264 
265                         if (n_flag)
266                                 rFm ^= 0x8000000000000000ULL;
267 
268                         /* test for less than condition */
269                         if (float64_lt_nocheck(rFn, rFm))
270                                 flags |= CC_NEGATIVE;
271 
272                         /* test for equal condition */
273                         if (float64_eq_nocheck(rFn, rFm))
274                                 flags |= CC_ZERO;
275 
276                         /* test for greater than or equal condition */
277                         if (float64_lt_nocheck(rFm, rFn))
278                                 flags |= CC_CARRY;
279                 }
280         } else {
281                 /* Both operands are in registers.  */
282                 if (fpa11->fType[Fn] == typeSingle
283                     && fpa11->fType[Fm] == typeSingle) {
284                         float32 rFm = fpa11->fpreg[Fm].fSingle;
285                         float32 rFn = fpa11->fpreg[Fn].fSingle;
286 
287                         if (float32_is_nan(rFn)
288                             || float32_is_nan(rFm))
289                                 goto unordered;
290 
291                         if (n_flag)
292                                 rFm ^= 0x80000000;
293 
294                         /* test for less than condition */
295                         if (float32_lt_nocheck(rFn, rFm))
296                                 flags |= CC_NEGATIVE;
297 
298                         /* test for equal condition */
299                         if (float32_eq_nocheck(rFn, rFm))
300                                 flags |= CC_ZERO;
301 
302                         /* test for greater than or equal condition */
303                         if (float32_lt_nocheck(rFm, rFn))
304                                 flags |= CC_CARRY;
305                 } else {
306                         /* Promote 32-bit operand to 64 bits.  */
307                         float64 rFm, rFn;
308 
309                         rFm = (fpa11->fType[Fm] == typeSingle) ?
310                             float32_to_float64(fpa11->fpreg[Fm].fSingle)
311                             : fpa11->fpreg[Fm].fDouble;
312 
313                         rFn = (fpa11->fType[Fn] == typeSingle) ?
314                             float32_to_float64(fpa11->fpreg[Fn].fSingle)
315                             : fpa11->fpreg[Fn].fDouble;
316 
317                         if (float64_is_nan(rFn)
318                             || float64_is_nan(rFm))
319                                 goto unordered;
320 
321                         if (n_flag)
322                                 rFm ^= 0x8000000000000000ULL;
323 
324                         /* test for less than condition */
325                         if (float64_lt_nocheck(rFn, rFm))
326                                 flags |= CC_NEGATIVE;
327 
328                         /* test for equal condition */
329                         if (float64_eq_nocheck(rFn, rFm))
330                                 flags |= CC_ZERO;
331 
332                         /* test for greater than or equal condition */
333                         if (float64_lt_nocheck(rFm, rFn))
334                                 flags |= CC_CARRY;
335                 }
336         }
337 
338 #endif
339 
340         writeConditionCodes(flags);
341 
342         return 1;
343 
344       unordered:
345         /* ?? The FPA data sheet is pretty vague about this, in particular
346            about whether the non-E comparisons can ever raise exceptions.
347            This implementation is based on a combination of what it says in
348            the data sheet, observation of how the Acorn emulator actually
349            behaves (and how programs expect it to) and guesswork.  */
350         flags |= CC_OVERFLOW;
351         flags &= ~(CC_ZERO | CC_NEGATIVE);
352 
353         if (BIT_AC & readFPSR())
354                 flags |= CC_CARRY;
355 
356         if (e_flag)
357                 float_raise(float_flag_invalid);
358 
359         writeConditionCodes(flags);
360         return 1;
361 }
362 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php