qemu/linux-user/arm/nwfpe/fpa11_cprt.c
<<
>>
Prefs
   1/*
   2    NetWinder Floating Point Emulator
   3    (c) Rebel.COM, 1998,1999
   4    (c) Philip Blundell, 1999
   5
   6    Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
   7
   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.
  12
  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.
  17
  18    You should have received a copy of the GNU General Public License
  19    along with this program; if not, see <http://www.gnu.org/licenses/>.
  20*/
  21
  22#include "fpa11.h"
  23#include "softfloat.h"
  24#include "fpopcode.h"
  25#include "fpa11.inl"
  26//#include "fpmodule.h"
  27//#include "fpmodule.inl"
  28
  29unsigned int PerformFLT(const unsigned int opcode);
  30unsigned int PerformFIX(const unsigned int opcode);
  31
  32static unsigned int
  33PerformComparison(const unsigned int opcode);
  34
  35unsigned int EmulateCPRT(const unsigned int opcode)
  36{
  37  unsigned int nRc = 1;
  38
  39  //printk("EmulateCPRT(0x%08x)\n",opcode);
  40
  41  if (opcode & 0x800000)
  42  {
  43     /* This is some variant of a comparison (PerformComparison will
  44        sort out which one).  Since most of the other CPRT
  45        instructions are oddball cases of some sort or other it makes
  46        sense to pull this out into a fast path.  */
  47     return PerformComparison(opcode);
  48  }
  49
  50  /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
  51  switch ((opcode & 0x700000) >> 20)
  52  {
  53    case  FLT_CODE >> 20: nRc = PerformFLT(opcode); break;
  54    case  FIX_CODE >> 20: nRc = PerformFIX(opcode); break;
  55
  56    case  WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break;
  57    case  RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break;
  58
  59#if 0    /* We currently have no use for the FPCR, so there's no point
  60            in emulating it. */
  61    case  WFC_CODE >> 20: writeFPCR(readRegister(getRd(opcode)));
  62    case  RFC_CODE >> 20: writeRegister(getRd(opcode),readFPCR()); break;
  63#endif
  64
  65    default: nRc = 0;
  66  }
  67
  68  return nRc;
  69}
  70
  71unsigned int PerformFLT(const unsigned int opcode)
  72{
  73   FPA11 *fpa11 = GET_FPA11();
  74
  75   unsigned int nRc = 1;
  76   SetRoundingMode(opcode);
  77
  78   switch (opcode & MASK_ROUNDING_PRECISION)
  79   {
  80      case ROUND_SINGLE:
  81      {
  82        fpa11->fType[getFn(opcode)] = typeSingle;
  83        fpa11->fpreg[getFn(opcode)].fSingle =
  84           int32_to_float32(readRegister(getRd(opcode)), &fpa11->fp_status);
  85      }
  86      break;
  87
  88      case ROUND_DOUBLE:
  89      {
  90        fpa11->fType[getFn(opcode)] = typeDouble;
  91        fpa11->fpreg[getFn(opcode)].fDouble =
  92            int32_to_float64(readRegister(getRd(opcode)), &fpa11->fp_status);
  93      }
  94      break;
  95
  96      case ROUND_EXTENDED:
  97      {
  98        fpa11->fType[getFn(opcode)] = typeExtended;
  99        fpa11->fpreg[getFn(opcode)].fExtended =
 100           int32_to_floatx80(readRegister(getRd(opcode)), &fpa11->fp_status);
 101      }
 102      break;
 103
 104      default: nRc = 0;
 105  }
 106
 107  return nRc;
 108}
 109
 110unsigned int PerformFIX(const unsigned int opcode)
 111{
 112   FPA11 *fpa11 = GET_FPA11();
 113   unsigned int nRc = 1;
 114   unsigned int Fn = getFm(opcode);
 115
 116   SetRoundingMode(opcode);
 117
 118   switch (fpa11->fType[Fn])
 119   {
 120      case typeSingle:
 121      {
 122         writeRegister(getRd(opcode),
 123                       float32_to_int32(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status));
 124      }
 125      break;
 126
 127      case typeDouble:
 128      {
 129         //printf("F%d is 0x%" PRIx64 "\n",Fn,fpa11->fpreg[Fn].fDouble);
 130         writeRegister(getRd(opcode),
 131                       float64_to_int32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status));
 132      }
 133      break;
 134
 135      case typeExtended:
 136      {
 137         writeRegister(getRd(opcode),
 138                       floatx80_to_int32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status));
 139      }
 140      break;
 141
 142      default: nRc = 0;
 143  }
 144
 145  return nRc;
 146}
 147
 148
 149static __inline unsigned int
 150PerformComparisonOperation(floatx80 Fn, floatx80 Fm)
 151{
 152   FPA11 *fpa11 = GET_FPA11();
 153   unsigned int flags = 0;
 154
 155   /* test for less than condition */
 156   if (floatx80_lt(Fn,Fm, &fpa11->fp_status))
 157   {
 158      flags |= CC_NEGATIVE;
 159   }
 160
 161   /* test for equal condition */
 162   if (floatx80_eq_quiet(Fn,Fm, &fpa11->fp_status))
 163   {
 164      flags |= CC_ZERO;
 165   }
 166
 167   /* test for greater than or equal condition */
 168   if (floatx80_lt(Fm,Fn, &fpa11->fp_status))
 169   {
 170      flags |= CC_CARRY;
 171   }
 172
 173   writeConditionCodes(flags);
 174   return 1;
 175}
 176
 177/* This instruction sets the flags N, Z, C, V in the FPSR. */
 178
 179static unsigned int PerformComparison(const unsigned int opcode)
 180{
 181   FPA11 *fpa11 = GET_FPA11();
 182   unsigned int Fn, Fm;
 183   floatx80 rFn, rFm;
 184   int e_flag = opcode & 0x400000;      /* 1 if CxFE */
 185   int n_flag = opcode & 0x200000;      /* 1 if CNxx */
 186   unsigned int flags = 0;
 187
 188   //printk("PerformComparison(0x%08x)\n",opcode);
 189
 190   Fn = getFn(opcode);
 191   Fm = getFm(opcode);
 192
 193   /* Check for unordered condition and convert all operands to 80-bit
 194      format.
 195      ?? Might be some mileage in avoiding this conversion if possible.
 196      Eg, if both operands are 32-bit, detect this and do a 32-bit
 197      comparison (cheaper than an 80-bit one).  */
 198   switch (fpa11->fType[Fn])
 199   {
 200      case typeSingle:
 201        //printk("single.\n");
 202        if (float32_is_any_nan(fpa11->fpreg[Fn].fSingle))
 203           goto unordered;
 204        rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
 205      break;
 206
 207      case typeDouble:
 208        //printk("double.\n");
 209        if (float64_is_any_nan(fpa11->fpreg[Fn].fDouble))
 210           goto unordered;
 211        rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
 212      break;
 213
 214      case typeExtended:
 215        //printk("extended.\n");
 216        if (floatx80_is_any_nan(fpa11->fpreg[Fn].fExtended))
 217           goto unordered;
 218        rFn = fpa11->fpreg[Fn].fExtended;
 219      break;
 220
 221      default: return 0;
 222   }
 223
 224   if (CONSTANT_FM(opcode))
 225   {
 226     //printk("Fm is a constant: #%d.\n",Fm);
 227     rFm = getExtendedConstant(Fm);
 228     if (floatx80_is_any_nan(rFm))
 229        goto unordered;
 230   }
 231   else
 232   {
 233     //printk("Fm = r%d which contains a ",Fm);
 234      switch (fpa11->fType[Fm])
 235      {
 236         case typeSingle:
 237           //printk("single.\n");
 238           if (float32_is_any_nan(fpa11->fpreg[Fm].fSingle))
 239              goto unordered;
 240           rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status);
 241         break;
 242
 243         case typeDouble:
 244           //printk("double.\n");
 245           if (float64_is_any_nan(fpa11->fpreg[Fm].fDouble))
 246              goto unordered;
 247           rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status);
 248         break;
 249
 250         case typeExtended:
 251           //printk("extended.\n");
 252           if (floatx80_is_any_nan(fpa11->fpreg[Fm].fExtended))
 253              goto unordered;
 254           rFm = fpa11->fpreg[Fm].fExtended;
 255         break;
 256
 257         default: return 0;
 258      }
 259   }
 260
 261   if (n_flag)
 262   {
 263      rFm.high ^= 0x8000;
 264   }
 265
 266   return PerformComparisonOperation(rFn,rFm);
 267
 268 unordered:
 269   /* ?? The FPA data sheet is pretty vague about this, in particular
 270      about whether the non-E comparisons can ever raise exceptions.
 271      This implementation is based on a combination of what it says in
 272      the data sheet, observation of how the Acorn emulator actually
 273      behaves (and how programs expect it to) and guesswork.  */
 274   flags |= CC_OVERFLOW;
 275   flags &= ~(CC_ZERO | CC_NEGATIVE);
 276
 277   if (BIT_AC & readFPSR()) flags |= CC_CARRY;
 278
 279   if (e_flag) float_raise(float_flag_invalid, &fpa11->fp_status);
 280
 281   writeConditionCodes(flags);
 282   return 1;
 283}
 284