qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

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 
     30 unsigned int PerformFLT(const unsigned int opcode);
     31 unsigned int PerformFIX(const unsigned int opcode);
     32 
     33 static unsigned int
     34 PerformComparison(const unsigned int opcode);
     35 
     36 unsigned 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 
     72 unsigned 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 
    111 unsigned 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 
    150 static __inline unsigned int
    151 PerformComparisonOperation(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 
    180 static 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 }