Statistics
| Branch: | Revision:

root / target-arm / nwfpe / fpa11_cprt.c @ 97eb5b14

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 "milieu.h"
25
#include "softfloat.h"
26
#include "fpopcode.h"
27
#include "fpa11.inl"
28
//#include "fpmodule.h"
29
//#include "fpmodule.inl"
30

    
31
extern flag floatx80_is_nan(floatx80);
32
extern flag float64_is_nan( float64);
33
extern flag float32_is_nan( float32);
34

    
35
void SetRoundingMode(const unsigned int opcode);
36

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
174
   /* test for greater than or equal condition */
175
   if (floatx80_lt(Fm,Fn))
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);
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);
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);
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);
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);
287

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