cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

fpa11_cprt.c (7676B)


      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}