Statistics
| Branch: | Revision:

root / target-arm / nwfpe / fpa11_cprt.c @ 3b46e624

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
void SetRoundingMode(const unsigned int opcode);
31

    
32
unsigned int PerformFLT(const unsigned int opcode);
33
unsigned int PerformFIX(const unsigned int opcode);
34

    
35
static unsigned int
36
PerformComparison(const unsigned int opcode);
37

    
38
unsigned int EmulateCPRT(const unsigned int opcode)
39
{
40
  unsigned int nRc = 1;
41

    
42
  //printk("EmulateCPRT(0x%08x)\n",opcode);
43

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

    
53
  /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
54
  switch ((opcode & 0x700000) >> 20)
55
  {
56
    case  FLT_CODE >> 20: nRc = PerformFLT(opcode); break;
57
    case  FIX_CODE >> 20: nRc = PerformFIX(opcode); break;
58

    
59
    case  WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break;
60
    case  RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break;
61

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

    
68
    default: nRc = 0;
69
  }
70

    
71
  return nRc;
72
}
73

    
74
unsigned int PerformFLT(const unsigned int opcode)
75
{
76
   FPA11 *fpa11 = GET_FPA11();
77

    
78
   unsigned int nRc = 1;
79
   SetRoundingMode(opcode);
80

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

    
91
      case ROUND_DOUBLE:
92
      {
93
        fpa11->fType[getFn(opcode)] = typeDouble;
94
        fpa11->fpreg[getFn(opcode)].fDouble =
95
            int32_to_float64(readRegister(getRd(opcode)), &fpa11->fp_status);
96
      }
97
      break;
98

    
99
      case ROUND_EXTENDED:
100
      {
101
        fpa11->fType[getFn(opcode)] = typeExtended;
102
        fpa11->fpreg[getFn(opcode)].fExtended =
103
           int32_to_floatx80(readRegister(getRd(opcode)), &fpa11->fp_status);
104
      }
105
      break;
106

    
107
      default: nRc = 0;
108
  }
109

    
110
  return nRc;
111
}
112

    
113
unsigned int PerformFIX(const unsigned int opcode)
114
{
115
   FPA11 *fpa11 = GET_FPA11();
116
   unsigned int nRc = 1;
117
   unsigned int Fn = getFm(opcode);
118

    
119
   SetRoundingMode(opcode);
120

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

    
130
      case typeDouble:
131
      {
132
         //printf("F%d is 0x%" PRIx64 "\n",Fn,fpa11->fpreg[Fn].fDouble);
133
         writeRegister(getRd(opcode),
134
                       float64_to_int32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status));
135
      }
136
      break;
137

    
138
      case typeExtended:
139
      {
140
         writeRegister(getRd(opcode),
141
                       floatx80_to_int32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status));
142
      }
143
      break;
144

    
145
      default: nRc = 0;
146
  }
147

    
148
  return nRc;
149
}
150

    
151

    
152
static unsigned int __inline__
153
PerformComparisonOperation(floatx80 Fn, floatx80 Fm)
154
{
155
   FPA11 *fpa11 = GET_FPA11();
156
   unsigned int flags = 0;
157

    
158
   /* test for less than condition */
159
   if (floatx80_lt(Fn,Fm, &fpa11->fp_status))
160
   {
161
      flags |= CC_NEGATIVE;
162
   }
163

    
164
   /* test for equal condition */
165
   if (floatx80_eq(Fn,Fm, &fpa11->fp_status))
166
   {
167
      flags |= CC_ZERO;
168
   }
169

    
170
   /* test for greater than or equal condition */
171
   if (floatx80_lt(Fm,Fn, &fpa11->fp_status))
172
   {
173
      flags |= CC_CARRY;
174
   }
175

    
176
   writeConditionCodes(flags);
177
   return 1;
178
}
179

    
180
/* This instruction sets the flags N, Z, C, V in the FPSR. */
181

    
182
static unsigned int PerformComparison(const unsigned int opcode)
183
{
184
   FPA11 *fpa11 = GET_FPA11();
185
   unsigned int Fn, Fm;
186
   floatx80 rFn, rFm;
187
   int e_flag = opcode & 0x400000;        /* 1 if CxFE */
188
   int n_flag = opcode & 0x200000;        /* 1 if CNxx */
189
   unsigned int flags = 0;
190

    
191
   //printk("PerformComparison(0x%08x)\n",opcode);
192

    
193
   Fn = getFn(opcode);
194
   Fm = getFm(opcode);
195

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

    
210
      case typeDouble:
211
        //printk("double.\n");
212
        if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
213
           goto unordered;
214
        rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
215
      break;
216

    
217
      case typeExtended:
218
        //printk("extended.\n");
219
        if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
220
           goto unordered;
221
        rFn = fpa11->fpreg[Fn].fExtended;
222
      break;
223

    
224
      default: return 0;
225
   }
226

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

    
246
         case typeDouble:
247
           //printk("double.\n");
248
           if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
249
              goto unordered;
250
           rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status);
251
         break;
252

    
253
         case typeExtended:
254
           //printk("extended.\n");
255
           if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
256
              goto unordered;
257
           rFm = fpa11->fpreg[Fm].fExtended;
258
         break;
259

    
260
         default: return 0;
261
      }
262
   }
263

    
264
   if (n_flag)
265
   {
266
      rFm.high ^= 0x8000;
267
   }
268

    
269
   return PerformComparisonOperation(rFn,rFm);
270

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

    
280
   if (BIT_AC & readFPSR()) flags |= CC_CARRY;
281

    
282
   if (e_flag) float_raise(float_flag_invalid, &fpa11->fp_status);
283

    
284
   writeConditionCodes(flags);
285
   return 1;
286
}