Statistics
| Branch: | Revision:

root / linux-user / arm / nwfpe / fpa11_cprt.c @ b53d44e5

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