Statistics
| Branch: | Revision:

root / linux-user / arm / nwfpe / fpa11_cprt.c @ 70539e18

History | View | Annotate | Download (7.4 kB)

1 00406dff bellard
/*
2 00406dff bellard
    NetWinder Floating Point Emulator
3 00406dff bellard
    (c) Rebel.COM, 1998,1999
4 00406dff bellard
    (c) Philip Blundell, 1999
5 00406dff bellard

6 00406dff bellard
    Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
7 00406dff bellard

8 00406dff bellard
    This program is free software; you can redistribute it and/or modify
9 00406dff bellard
    it under the terms of the GNU General Public License as published by
10 00406dff bellard
    the Free Software Foundation; either version 2 of the License, or
11 00406dff bellard
    (at your option) any later version.
12 00406dff bellard

13 00406dff bellard
    This program is distributed in the hope that it will be useful,
14 00406dff bellard
    but WITHOUT ANY WARRANTY; without even the implied warranty of
15 00406dff bellard
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 00406dff bellard
    GNU General Public License for more details.
17 00406dff bellard

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