Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (7.7 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
extern flag floatx80_is_nan(floatx80);
31
extern flag float64_is_nan( float64);
32
extern flag float32_is_nan( float32);
33

    
34
void SetRoundingMode(const unsigned int opcode);
35

    
36
unsigned int PerformFLT(const unsigned int opcode);
37
unsigned int PerformFIX(const unsigned int opcode);
38

    
39
static unsigned int
40
PerformComparison(const unsigned int opcode);
41

    
42
unsigned int EmulateCPRT(const unsigned int opcode)
43
{
44
  unsigned int nRc = 1;
45

    
46
  //printk("EmulateCPRT(0x%08x)\n",opcode);
47

    
48
  if (opcode & 0x800000)
49
  {
50
     /* This is some variant of a comparison (PerformComparison will
51
        sort out which one).  Since most of the other CPRT
52
        instructions are oddball cases of some sort or other it makes
53
        sense to pull this out into a fast path.  */
54
     return PerformComparison(opcode);
55
  }
56

    
57
  /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
58
  switch ((opcode & 0x700000) >> 20)
59
  {
60
    case  FLT_CODE >> 20: nRc = PerformFLT(opcode); break;
61
    case  FIX_CODE >> 20: nRc = PerformFIX(opcode); break;
62
    
63
    case  WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break;
64
    case  RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break;
65

    
66
#if 0    /* We currently have no use for the FPCR, so there's no point
67
            in emulating it. */
68
    case  WFC_CODE >> 20: writeFPCR(readRegister(getRd(opcode)));
69
    case  RFC_CODE >> 20: writeRegister(getRd(opcode),readFPCR()); break;
70
#endif
71

    
72
    default: nRc = 0;
73
  }
74
  
75
  return nRc;
76
}
77

    
78
unsigned int PerformFLT(const unsigned int opcode)
79
{
80
   FPA11 *fpa11 = GET_FPA11();
81
   
82
   unsigned int nRc = 1;
83
   SetRoundingMode(opcode);
84

    
85
   switch (opcode & MASK_ROUNDING_PRECISION)
86
   {
87
      case ROUND_SINGLE:
88
      {
89
        fpa11->fType[getFn(opcode)] = typeSingle;
90
        fpa11->fpreg[getFn(opcode)].fSingle =
91
           int32_to_float32(readRegister(getRd(opcode)), &fpa11->fp_status);
92
      }
93
      break;
94

    
95
      case ROUND_DOUBLE:
96
      {
97
        fpa11->fType[getFn(opcode)] = typeDouble;
98
        fpa11->fpreg[getFn(opcode)].fDouble =
99
            int32_to_float64(readRegister(getRd(opcode)), &fpa11->fp_status);
100
      }
101
      break;
102
        
103
      case ROUND_EXTENDED:
104
      {
105
        fpa11->fType[getFn(opcode)] = typeExtended;
106
        fpa11->fpreg[getFn(opcode)].fExtended =
107
           int32_to_floatx80(readRegister(getRd(opcode)), &fpa11->fp_status);
108
      }
109
      break;
110
      
111
      default: nRc = 0;
112
  }
113
  
114
  return nRc;
115
}
116

    
117
unsigned int PerformFIX(const unsigned int opcode)
118
{
119
   FPA11 *fpa11 = GET_FPA11();
120
   unsigned int nRc = 1;
121
   unsigned int Fn = getFm(opcode);
122
   
123
   SetRoundingMode(opcode);
124

    
125
   switch (fpa11->fType[Fn])
126
   {
127
      case typeSingle:
128
      {
129
         writeRegister(getRd(opcode),
130
                       float32_to_int32(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status));
131
      }
132
      break;
133

    
134
      case typeDouble:
135
      {
136
         //printf("F%d is 0x%" PRIx64 "\n",Fn,fpa11->fpreg[Fn].fDouble);
137
         writeRegister(getRd(opcode),
138
                       float64_to_int32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status));
139
      }
140
      break;
141
                             
142
      case typeExtended:
143
      {
144
         writeRegister(getRd(opcode),
145
                       floatx80_to_int32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status));
146
      }
147
      break;
148
      
149
      default: nRc = 0;
150
  }
151
  
152
  return nRc;
153
}
154

    
155
   
156
static unsigned int __inline__
157
PerformComparisonOperation(floatx80 Fn, floatx80 Fm)
158
{
159
   FPA11 *fpa11 = GET_FPA11();
160
   unsigned int flags = 0;
161

    
162
   /* test for less than condition */
163
   if (floatx80_lt(Fn,Fm, &fpa11->fp_status))
164
   {
165
      flags |= CC_NEGATIVE;
166
   }
167
  
168
   /* test for equal condition */
169
   if (floatx80_eq(Fn,Fm, &fpa11->fp_status))
170
   {
171
      flags |= CC_ZERO;
172
   }
173

    
174
   /* test for greater than or equal condition */
175
   if (floatx80_lt(Fm,Fn, &fpa11->fp_status))
176
   {
177
      flags |= CC_CARRY;
178
   }
179
   
180
   writeConditionCodes(flags);
181
   return 1;
182
}
183

    
184
/* This instruction sets the flags N, Z, C, V in the FPSR. */
185
   
186
static unsigned int PerformComparison(const unsigned int opcode)
187
{
188
   FPA11 *fpa11 = GET_FPA11();
189
   unsigned int Fn, Fm;
190
   floatx80 rFn, rFm;
191
   int e_flag = opcode & 0x400000;        /* 1 if CxFE */
192
   int n_flag = opcode & 0x200000;        /* 1 if CNxx */
193
   unsigned int flags = 0;
194

    
195
   //printk("PerformComparison(0x%08x)\n",opcode);
196

    
197
   Fn = getFn(opcode);
198
   Fm = getFm(opcode);
199

    
200
   /* Check for unordered condition and convert all operands to 80-bit
201
      format.
202
      ?? Might be some mileage in avoiding this conversion if possible.
203
      Eg, if both operands are 32-bit, detect this and do a 32-bit
204
      comparison (cheaper than an 80-bit one).  */
205
   switch (fpa11->fType[Fn])
206
   {
207
      case typeSingle: 
208
        //printk("single.\n");
209
        if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
210
           goto unordered;
211
        rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
212
      break;
213

    
214
      case typeDouble: 
215
        //printk("double.\n");
216
        if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
217
           goto unordered;
218
        rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
219
      break;
220
      
221
      case typeExtended: 
222
        //printk("extended.\n");
223
        if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
224
           goto unordered;
225
        rFn = fpa11->fpreg[Fn].fExtended;
226
      break;
227
      
228
      default: return 0;
229
   }
230

    
231
   if (CONSTANT_FM(opcode))
232
   {
233
     //printk("Fm is a constant: #%d.\n",Fm);
234
     rFm = getExtendedConstant(Fm);
235
     if (floatx80_is_nan(rFm))
236
        goto unordered;
237
   }
238
   else
239
   {
240
     //printk("Fm = r%d which contains a ",Fm);
241
      switch (fpa11->fType[Fm])
242
      {
243
         case typeSingle: 
244
           //printk("single.\n");
245
           if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
246
              goto unordered;
247
           rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status);
248
         break;
249

    
250
         case typeDouble: 
251
           //printk("double.\n");
252
           if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
253
              goto unordered;
254
           rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status);
255
         break;
256
      
257
         case typeExtended: 
258
           //printk("extended.\n");
259
           if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
260
              goto unordered;
261
           rFm = fpa11->fpreg[Fm].fExtended;
262
         break;
263
      
264
         default: return 0;
265
      }
266
   }
267

    
268
   if (n_flag)
269
   {
270
      rFm.high ^= 0x8000;
271
   }
272

    
273
   return PerformComparisonOperation(rFn,rFm);
274

    
275
 unordered:
276
   /* ?? The FPA data sheet is pretty vague about this, in particular
277
      about whether the non-E comparisons can ever raise exceptions.
278
      This implementation is based on a combination of what it says in
279
      the data sheet, observation of how the Acorn emulator actually
280
      behaves (and how programs expect it to) and guesswork.  */
281
   flags |= CC_OVERFLOW;
282
   flags &= ~(CC_ZERO | CC_NEGATIVE);
283

    
284
   if (BIT_AC & readFPSR()) flags |= CC_CARRY;
285

    
286
   if (e_flag) float_raise(float_flag_invalid, &fpa11->fp_status);
287

    
288
   writeConditionCodes(flags);
289
   return 1;
290
}