Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003     NetWinder Floating Point Emulator
0004     (c) Rebel.COM, 1998,1999
0005     (c) Philip Blundell, 1999, 2001
0006 
0007     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
0008 
0009 */
0010 
0011 #include "fpa11.h"
0012 #include "fpopcode.h"
0013 #include "fpa11.inl"
0014 #include "fpmodule.h"
0015 #include "fpmodule.inl"
0016 #include "softfloat.h"
0017 
0018 unsigned int PerformFLT(const unsigned int opcode);
0019 unsigned int PerformFIX(const unsigned int opcode);
0020 
0021 static unsigned int PerformComparison(const unsigned int opcode);
0022 
0023 unsigned int EmulateCPRT(const unsigned int opcode)
0024 {
0025 
0026     if (opcode & 0x800000) {
0027         /* This is some variant of a comparison (PerformComparison
0028            will sort out which one).  Since most of the other CPRT
0029            instructions are oddball cases of some sort or other it
0030            makes sense to pull this out into a fast path.  */
0031         return PerformComparison(opcode);
0032     }
0033 
0034     /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
0035     switch ((opcode & 0x700000) >> 20) {
0036     case FLT_CODE >> 20:
0037         return PerformFLT(opcode);
0038         break;
0039     case FIX_CODE >> 20:
0040         return PerformFIX(opcode);
0041         break;
0042 
0043     case WFS_CODE >> 20:
0044         writeFPSR(readRegister(getRd(opcode)));
0045         break;
0046     case RFS_CODE >> 20:
0047         writeRegister(getRd(opcode), readFPSR());
0048         break;
0049 
0050     default:
0051         return 0;
0052     }
0053 
0054     return 1;
0055 }
0056 
0057 unsigned int PerformFLT(const unsigned int opcode)
0058 {
0059     FPA11 *fpa11 = GET_FPA11();
0060     struct roundingData roundData;
0061 
0062     roundData.mode = SetRoundingMode(opcode);
0063     roundData.precision = SetRoundingPrecision(opcode);
0064     roundData.exception = 0;
0065 
0066     switch (opcode & MASK_ROUNDING_PRECISION) {
0067     case ROUND_SINGLE:
0068         {
0069             fpa11->fType[getFn(opcode)] = typeSingle;
0070             fpa11->fpreg[getFn(opcode)].fSingle = int32_to_float32(&roundData, readRegister(getRd(opcode)));
0071         }
0072         break;
0073 
0074     case ROUND_DOUBLE:
0075         {
0076             fpa11->fType[getFn(opcode)] = typeDouble;
0077             fpa11->fpreg[getFn(opcode)].fDouble = int32_to_float64(readRegister(getRd(opcode)));
0078         }
0079         break;
0080 
0081 #ifdef CONFIG_FPE_NWFPE_XP
0082     case ROUND_EXTENDED:
0083         {
0084             fpa11->fType[getFn(opcode)] = typeExtended;
0085             fpa11->fpreg[getFn(opcode)].fExtended = int32_to_floatx80(readRegister(getRd(opcode)));
0086         }
0087         break;
0088 #endif
0089 
0090     default:
0091         return 0;
0092     }
0093 
0094     if (roundData.exception)
0095         float_raise(roundData.exception);
0096 
0097     return 1;
0098 }
0099 
0100 unsigned int PerformFIX(const unsigned int opcode)
0101 {
0102     FPA11 *fpa11 = GET_FPA11();
0103     unsigned int Fn = getFm(opcode);
0104     struct roundingData roundData;
0105 
0106     roundData.mode = SetRoundingMode(opcode);
0107     roundData.precision = SetRoundingPrecision(opcode);
0108     roundData.exception = 0;
0109 
0110     switch (fpa11->fType[Fn]) {
0111     case typeSingle:
0112         {
0113             writeRegister(getRd(opcode), float32_to_int32(&roundData, fpa11->fpreg[Fn].fSingle));
0114         }
0115         break;
0116 
0117     case typeDouble:
0118         {
0119             writeRegister(getRd(opcode), float64_to_int32(&roundData, fpa11->fpreg[Fn].fDouble));
0120         }
0121         break;
0122 
0123 #ifdef CONFIG_FPE_NWFPE_XP
0124     case typeExtended:
0125         {
0126             writeRegister(getRd(opcode), floatx80_to_int32(&roundData, fpa11->fpreg[Fn].fExtended));
0127         }
0128         break;
0129 #endif
0130 
0131     default:
0132         return 0;
0133     }
0134 
0135     if (roundData.exception)
0136         float_raise(roundData.exception);
0137 
0138     return 1;
0139 }
0140 
0141 /* This instruction sets the flags N, Z, C, V in the FPSR. */
0142 static unsigned int PerformComparison(const unsigned int opcode)
0143 {
0144     FPA11 *fpa11 = GET_FPA11();
0145     unsigned int Fn = getFn(opcode), Fm = getFm(opcode);
0146     int e_flag = opcode & 0x400000; /* 1 if CxFE */
0147     int n_flag = opcode & 0x200000; /* 1 if CNxx */
0148     unsigned int flags = 0;
0149 
0150 #ifdef CONFIG_FPE_NWFPE_XP
0151     floatx80 rFn, rFm;
0152 
0153     /* Check for unordered condition and convert all operands to 80-bit
0154        format.
0155        ?? Might be some mileage in avoiding this conversion if possible.
0156        Eg, if both operands are 32-bit, detect this and do a 32-bit
0157        comparison (cheaper than an 80-bit one).  */
0158     switch (fpa11->fType[Fn]) {
0159     case typeSingle:
0160         //printk("single.\n");
0161         if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
0162             goto unordered;
0163         rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
0164         break;
0165 
0166     case typeDouble:
0167         //printk("double.\n");
0168         if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
0169             goto unordered;
0170         rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
0171         break;
0172 
0173     case typeExtended:
0174         //printk("extended.\n");
0175         if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
0176             goto unordered;
0177         rFn = fpa11->fpreg[Fn].fExtended;
0178         break;
0179 
0180     default:
0181         return 0;
0182     }
0183 
0184     if (CONSTANT_FM(opcode)) {
0185         //printk("Fm is a constant: #%d.\n",Fm);
0186         rFm = getExtendedConstant(Fm);
0187         if (floatx80_is_nan(rFm))
0188             goto unordered;
0189     } else {
0190         //printk("Fm = r%d which contains a ",Fm);
0191         switch (fpa11->fType[Fm]) {
0192         case typeSingle:
0193             //printk("single.\n");
0194             if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
0195                 goto unordered;
0196             rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
0197             break;
0198 
0199         case typeDouble:
0200             //printk("double.\n");
0201             if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
0202                 goto unordered;
0203             rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble);
0204             break;
0205 
0206         case typeExtended:
0207             //printk("extended.\n");
0208             if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
0209                 goto unordered;
0210             rFm = fpa11->fpreg[Fm].fExtended;
0211             break;
0212 
0213         default:
0214             return 0;
0215         }
0216     }
0217 
0218     if (n_flag)
0219         rFm.high ^= 0x8000;
0220 
0221     /* test for less than condition */
0222     if (floatx80_lt(rFn, rFm))
0223         flags |= CC_NEGATIVE;
0224 
0225     /* test for equal condition */
0226     if (floatx80_eq(rFn, rFm))
0227         flags |= CC_ZERO;
0228 
0229     /* test for greater than or equal condition */
0230     if (floatx80_lt(rFm, rFn))
0231         flags |= CC_CARRY;
0232 
0233 #else
0234     if (CONSTANT_FM(opcode)) {
0235         /* Fm is a constant.  Do the comparison in whatever precision
0236            Fn happens to be stored in.  */
0237         if (fpa11->fType[Fn] == typeSingle) {
0238             float32 rFm = getSingleConstant(Fm);
0239             float32 rFn = fpa11->fpreg[Fn].fSingle;
0240 
0241             if (float32_is_nan(rFn))
0242                 goto unordered;
0243 
0244             if (n_flag)
0245                 rFm ^= 0x80000000;
0246 
0247             /* test for less than condition */
0248             if (float32_lt_nocheck(rFn, rFm))
0249                 flags |= CC_NEGATIVE;
0250 
0251             /* test for equal condition */
0252             if (float32_eq_nocheck(rFn, rFm))
0253                 flags |= CC_ZERO;
0254 
0255             /* test for greater than or equal condition */
0256             if (float32_lt_nocheck(rFm, rFn))
0257                 flags |= CC_CARRY;
0258         } else {
0259             float64 rFm = getDoubleConstant(Fm);
0260             float64 rFn = fpa11->fpreg[Fn].fDouble;
0261 
0262             if (float64_is_nan(rFn))
0263                 goto unordered;
0264 
0265             if (n_flag)
0266                 rFm ^= 0x8000000000000000ULL;
0267 
0268             /* test for less than condition */
0269             if (float64_lt_nocheck(rFn, rFm))
0270                 flags |= CC_NEGATIVE;
0271 
0272             /* test for equal condition */
0273             if (float64_eq_nocheck(rFn, rFm))
0274                 flags |= CC_ZERO;
0275 
0276             /* test for greater than or equal condition */
0277             if (float64_lt_nocheck(rFm, rFn))
0278                 flags |= CC_CARRY;
0279         }
0280     } else {
0281         /* Both operands are in registers.  */
0282         if (fpa11->fType[Fn] == typeSingle
0283             && fpa11->fType[Fm] == typeSingle) {
0284             float32 rFm = fpa11->fpreg[Fm].fSingle;
0285             float32 rFn = fpa11->fpreg[Fn].fSingle;
0286 
0287             if (float32_is_nan(rFn)
0288                 || float32_is_nan(rFm))
0289                 goto unordered;
0290 
0291             if (n_flag)
0292                 rFm ^= 0x80000000;
0293 
0294             /* test for less than condition */
0295             if (float32_lt_nocheck(rFn, rFm))
0296                 flags |= CC_NEGATIVE;
0297 
0298             /* test for equal condition */
0299             if (float32_eq_nocheck(rFn, rFm))
0300                 flags |= CC_ZERO;
0301 
0302             /* test for greater than or equal condition */
0303             if (float32_lt_nocheck(rFm, rFn))
0304                 flags |= CC_CARRY;
0305         } else {
0306             /* Promote 32-bit operand to 64 bits.  */
0307             float64 rFm, rFn;
0308 
0309             rFm = (fpa11->fType[Fm] == typeSingle) ?
0310                 float32_to_float64(fpa11->fpreg[Fm].fSingle)
0311                 : fpa11->fpreg[Fm].fDouble;
0312 
0313             rFn = (fpa11->fType[Fn] == typeSingle) ?
0314                 float32_to_float64(fpa11->fpreg[Fn].fSingle)
0315                 : fpa11->fpreg[Fn].fDouble;
0316 
0317             if (float64_is_nan(rFn)
0318                 || float64_is_nan(rFm))
0319                 goto unordered;
0320 
0321             if (n_flag)
0322                 rFm ^= 0x8000000000000000ULL;
0323 
0324             /* test for less than condition */
0325             if (float64_lt_nocheck(rFn, rFm))
0326                 flags |= CC_NEGATIVE;
0327 
0328             /* test for equal condition */
0329             if (float64_eq_nocheck(rFn, rFm))
0330                 flags |= CC_ZERO;
0331 
0332             /* test for greater than or equal condition */
0333             if (float64_lt_nocheck(rFm, rFn))
0334                 flags |= CC_CARRY;
0335         }
0336     }
0337 
0338 #endif
0339 
0340     writeConditionCodes(flags);
0341 
0342     return 1;
0343 
0344       unordered:
0345     /* ?? The FPA data sheet is pretty vague about this, in particular
0346        about whether the non-E comparisons can ever raise exceptions.
0347        This implementation is based on a combination of what it says in
0348        the data sheet, observation of how the Acorn emulator actually
0349        behaves (and how programs expect it to) and guesswork.  */
0350     flags |= CC_OVERFLOW;
0351     flags &= ~(CC_ZERO | CC_NEGATIVE);
0352 
0353     if (BIT_AC & readFPSR())
0354         flags |= CC_CARRY;
0355 
0356     if (e_flag)
0357         float_raise(float_flag_invalid);
0358 
0359     writeConditionCodes(flags);
0360     return 1;
0361 }