root/arch/arm/nwfpe/fpa11_cprt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. EmulateCPRT
  2. PerformFLT
  3. PerformFIX
  4. PerformComparison

   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 }

/* [<][>][^][v][top][bottom][index][help] */