Statistics
| Branch: | Revision:

root / target-arm / nwfpe / fpa11_cprt.c @ 26a76461

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