Statistics
| Branch: | Revision:

root / target-arm / nwfpe / fpa11_cprt.c @ 5fafdf24

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