Statistics
| Branch: | Revision:

root / linux-user / arm / nwfpe / fpa11_cprt.c @ 79383c9c

History | View | Annotate | Download (7.5 kB)

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, write to the Free Software
20
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
*/
22

    
23
#include "fpa11.h"
24
#include "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 unsigned int __inline__
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(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_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_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_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_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_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_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_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
}