OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [arm/] [nwfpe/] [fpa11_cprt.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
    NetWinder Floating Point Emulator
3
    (c) Rebel.COM, 1998,1999
4
    (c) Philip Blundell, 1999, 2001
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 "fpopcode.h"
25
#include "fpa11.inl"
26
#include "fpmodule.h"
27
#include "fpmodule.inl"
28
 
29
#ifdef CONFIG_FPE_NWFPE_XP
30
extern flag floatx80_is_nan(floatx80);
31
#endif
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 PerformComparison(const unsigned int opcode);
41
 
42
unsigned int EmulateCPRT(const unsigned int opcode)
43
{
44
 
45
        if (opcode & 0x800000) {
46
                /* This is some variant of a comparison (PerformComparison
47
                   will sort out which one).  Since most of the other CPRT
48
                   instructions are oddball cases of some sort or other it
49
                   makes 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
        case FLT_CODE >> 20:
56
                return PerformFLT(opcode);
57
                break;
58
        case FIX_CODE >> 20:
59
                return PerformFIX(opcode);
60
                break;
61
 
62
        case WFS_CODE >> 20:
63
                writeFPSR(readRegister(getRd(opcode)));
64
                break;
65
        case RFS_CODE >> 20:
66
                writeRegister(getRd(opcode), readFPSR());
67
                break;
68
 
69
        default:
70
                return 0;
71
        }
72
 
73
        return 1;
74
}
75
 
76
unsigned int PerformFLT(const unsigned int opcode)
77
{
78
        FPA11 *fpa11 = GET_FPA11();
79
        SetRoundingMode(opcode);
80
        SetRoundingPrecision(opcode);
81
 
82
        switch (opcode & MASK_ROUNDING_PRECISION) {
83
        case ROUND_SINGLE:
84
                {
85
                        fpa11->fType[getFn(opcode)] = typeSingle;
86
                        fpa11->fpreg[getFn(opcode)].fSingle = int32_to_float32(readRegister(getRd(opcode)));
87
                }
88
                break;
89
 
90
        case ROUND_DOUBLE:
91
                {
92
                        fpa11->fType[getFn(opcode)] = typeDouble;
93
                        fpa11->fpreg[getFn(opcode)].fDouble = int32_to_float64(readRegister(getRd(opcode)));
94
                }
95
                break;
96
 
97
#ifdef CONFIG_FPE_NWFPE_XP
98
        case ROUND_EXTENDED:
99
                {
100
                        fpa11->fType[getFn(opcode)] = typeExtended;
101
                        fpa11->fpreg[getFn(opcode)].fExtended = int32_to_floatx80(readRegister(getRd(opcode)));
102
                }
103
                break;
104
#endif
105
 
106
        default:
107
                return 0;
108
        }
109
 
110
        return 1;
111
}
112
 
113
unsigned int PerformFIX(const unsigned int opcode)
114
{
115
        FPA11 *fpa11 = GET_FPA11();
116
        unsigned int Fn = getFm(opcode);
117
 
118
        SetRoundingMode(opcode);
119
 
120
        switch (fpa11->fType[Fn]) {
121
        case typeSingle:
122
                {
123
                        writeRegister(getRd(opcode), float32_to_int32(fpa11->fpreg[Fn].fSingle));
124
                }
125
                break;
126
 
127
        case typeDouble:
128
                {
129
                        writeRegister(getRd(opcode), float64_to_int32(fpa11->fpreg[Fn].fDouble));
130
                }
131
                break;
132
 
133
#ifdef CONFIG_FPE_NWFPE_XP
134
        case typeExtended:
135
                {
136
                        writeRegister(getRd(opcode), floatx80_to_int32(fpa11->fpreg[Fn].fExtended));
137
                }
138
                break;
139
#endif
140
 
141
        default:
142
                return 0;
143
        }
144
 
145
        return 1;
146
}
147
 
148
/* This instruction sets the flags N, Z, C, V in the FPSR. */
149
static unsigned int PerformComparison(const unsigned int opcode)
150
{
151
        FPA11 *fpa11 = GET_FPA11();
152
        unsigned int Fn = getFn(opcode), Fm = getFm(opcode);
153
        int e_flag = opcode & 0x400000; /* 1 if CxFE */
154
        int n_flag = opcode & 0x200000; /* 1 if CNxx */
155
        unsigned int flags = 0;
156
 
157
#ifdef CONFIG_FPE_NWFPE_XP
158
        floatx80 rFn, rFm;
159
 
160
        /* Check for unordered condition and convert all operands to 80-bit
161
           format.
162
           ?? Might be some mileage in avoiding this conversion if possible.
163
           Eg, if both operands are 32-bit, detect this and do a 32-bit
164
           comparison (cheaper than an 80-bit one).  */
165
        switch (fpa11->fType[Fn]) {
166
        case typeSingle:
167
                //printk("single.\n");
168
                if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
169
                        goto unordered;
170
                rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
171
                break;
172
 
173
        case typeDouble:
174
                //printk("double.\n");
175
                if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
176
                        goto unordered;
177
                rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
178
                break;
179
 
180
        case typeExtended:
181
                //printk("extended.\n");
182
                if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
183
                        goto unordered;
184
                rFn = fpa11->fpreg[Fn].fExtended;
185
                break;
186
 
187
        default:
188
                return 0;
189
        }
190
 
191
        if (CONSTANT_FM(opcode)) {
192
                //printk("Fm is a constant: #%d.\n",Fm);
193
                rFm = getExtendedConstant(Fm);
194
                if (floatx80_is_nan(rFm))
195
                        goto unordered;
196
        } else {
197
                //printk("Fm = r%d which contains a ",Fm);
198
                switch (fpa11->fType[Fm]) {
199
                case typeSingle:
200
                        //printk("single.\n");
201
                        if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
202
                                goto unordered;
203
                        rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
204
                        break;
205
 
206
                case typeDouble:
207
                        //printk("double.\n");
208
                        if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
209
                                goto unordered;
210
                        rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble);
211
                        break;
212
 
213
                case typeExtended:
214
                        //printk("extended.\n");
215
                        if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
216
                                goto unordered;
217
                        rFm = fpa11->fpreg[Fm].fExtended;
218
                        break;
219
 
220
                default:
221
                        return 0;
222
                }
223
        }
224
 
225
        if (n_flag)
226
                rFm.high ^= 0x8000;
227
 
228
        /* test for less than condition */
229
        if (floatx80_lt(rFn, rFm))
230
                flags |= CC_NEGATIVE;
231
 
232
        /* test for equal condition */
233
        if (floatx80_eq(rFn, rFm))
234
                flags |= CC_ZERO;
235
 
236
        /* test for greater than or equal condition */
237
        if (floatx80_lt(rFm, rFn))
238
                flags |= CC_CARRY;
239
 
240
#else
241
        if (CONSTANT_FM(opcode)) {
242
                /* Fm is a constant.  Do the comparison in whatever precision
243
                   Fn happens to be stored in.  */
244
                if (fpa11->fType[Fn] == typeSingle) {
245
                        float32 rFm = getSingleConstant(Fm);
246
                        float32 rFn = fpa11->fpreg[Fn].fSingle;
247
 
248
                        if (float32_is_nan(rFn))
249
                                goto unordered;
250
 
251
                        if (n_flag)
252
                                rFm ^= 0x80000000;
253
 
254
                        /* test for less than condition */
255
                        if (float32_lt_nocheck(rFn, rFm))
256
                                flags |= CC_NEGATIVE;
257
 
258
                        /* test for equal condition */
259
                        if (float32_eq_nocheck(rFn, rFm))
260
                                flags |= CC_ZERO;
261
 
262
                        /* test for greater than or equal condition */
263
                        if (float32_lt_nocheck(rFm, rFn))
264
                                flags |= CC_CARRY;
265
                } else {
266
                        float64 rFm = getDoubleConstant(Fm);
267
                        float64 rFn = fpa11->fpreg[Fn].fDouble;
268
 
269
                        if (float64_is_nan(rFn))
270
                                goto unordered;
271
 
272
                        if (n_flag)
273
                                rFm ^= 0x8000000000000000ULL;
274
 
275
                        /* test for less than condition */
276
                        if (float64_lt_nocheck(rFn, rFm))
277
                                flags |= CC_NEGATIVE;
278
 
279
                        /* test for equal condition */
280
                        if (float64_eq_nocheck(rFn, rFm))
281
                                flags |= CC_ZERO;
282
 
283
                        /* test for greater than or equal condition */
284
                        if (float64_lt_nocheck(rFm, rFn))
285
                                flags |= CC_CARRY;
286
                }
287
        } else {
288
                /* Both operands are in registers.  */
289
                if (fpa11->fType[Fn] == typeSingle
290
                    && fpa11->fType[Fm] == typeSingle) {
291
                        float32 rFm = fpa11->fpreg[Fm].fSingle;
292
                        float32 rFn = fpa11->fpreg[Fn].fSingle;
293
 
294
                        if (float32_is_nan(rFn)
295
                            || float32_is_nan(rFm))
296
                                goto unordered;
297
 
298
                        if (n_flag)
299
                                rFm ^= 0x80000000;
300
 
301
                        /* test for less than condition */
302
                        if (float32_lt_nocheck(rFn, rFm))
303
                                flags |= CC_NEGATIVE;
304
 
305
                        /* test for equal condition */
306
                        if (float32_eq_nocheck(rFn, rFm))
307
                                flags |= CC_ZERO;
308
 
309
                        /* test for greater than or equal condition */
310
                        if (float32_lt_nocheck(rFm, rFn))
311
                                flags |= CC_CARRY;
312
                } else {
313
                        /* Promote 32-bit operand to 64 bits.  */
314
                        float64 rFm, rFn;
315
 
316
                        rFm = (fpa11->fType[Fm] == typeSingle) ?
317
                            float32_to_float64(fpa11->fpreg[Fm].fSingle)
318
                            : fpa11->fpreg[Fm].fDouble;
319
 
320
                        rFn = (fpa11->fType[Fn] == typeSingle) ?
321
                            float32_to_float64(fpa11->fpreg[Fn].fSingle)
322
                            : fpa11->fpreg[Fn].fDouble;
323
 
324
                        if (float64_is_nan(rFn)
325
                            || float64_is_nan(rFm))
326
                                goto unordered;
327
 
328
                        if (n_flag)
329
                                rFm ^= 0x8000000000000000ULL;
330
 
331
                        /* test for less than condition */
332
                        if (float64_lt_nocheck(rFn, rFm))
333
                                flags |= CC_NEGATIVE;
334
 
335
                        /* test for equal condition */
336
                        if (float64_eq_nocheck(rFn, rFm))
337
                                flags |= CC_ZERO;
338
 
339
                        /* test for greater than or equal condition */
340
                        if (float64_lt_nocheck(rFm, rFn))
341
                                flags |= CC_CARRY;
342
                }
343
        }
344
 
345
#endif
346
 
347
        writeConditionCodes(flags);
348
 
349
        return 1;
350
 
351
      unordered:
352
        /* ?? The FPA data sheet is pretty vague about this, in particular
353
           about whether the non-E comparisons can ever raise exceptions.
354
           This implementation is based on a combination of what it says in
355
           the data sheet, observation of how the Acorn emulator actually
356
           behaves (and how programs expect it to) and guesswork.  */
357
        flags |= CC_OVERFLOW;
358
        flags &= ~(CC_ZERO | CC_NEGATIVE);
359
 
360
        if (BIT_AC & readFPSR())
361
                flags |= CC_CARRY;
362
 
363
        if (e_flag)
364
                float_raise(float_flag_invalid);
365
 
366
        writeConditionCodes(flags);
367
        return 1;
368
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.