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