]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/arm/nwfpe/fpa11_cpdt.c
Merge head 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband
[linux-2.6-omap-h63xx.git] / arch / arm / nwfpe / fpa11_cpdt.c
1 /*
2     NetWinder Floating Point Emulator
3     (c) Rebel.com, 1998-1999
4     (c) Philip Blundell, 1998, 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 <linux/config.h>
24 #include "fpa11.h"
25 #include "softfloat.h"
26 #include "fpopcode.h"
27 #include "fpmodule.h"
28 #include "fpmodule.inl"
29
30 #include <asm/uaccess.h>
31
32 static inline void loadSingle(const unsigned int Fn, const unsigned int __user *pMem)
33 {
34         FPA11 *fpa11 = GET_FPA11();
35         fpa11->fType[Fn] = typeSingle;
36         get_user(fpa11->fpreg[Fn].fSingle, pMem);
37 }
38
39 static inline void loadDouble(const unsigned int Fn, const unsigned int __user *pMem)
40 {
41         FPA11 *fpa11 = GET_FPA11();
42         unsigned int *p;
43         p = (unsigned int *) &fpa11->fpreg[Fn].fDouble;
44         fpa11->fType[Fn] = typeDouble;
45 #ifdef __ARMEB__
46         get_user(p[0], &pMem[0]);       /* sign & exponent */
47         get_user(p[1], &pMem[1]);
48 #else
49         get_user(p[0], &pMem[1]);
50         get_user(p[1], &pMem[0]);       /* sign & exponent */
51 #endif
52 }
53
54 #ifdef CONFIG_FPE_NWFPE_XP
55 static inline void loadExtended(const unsigned int Fn, const unsigned int __user *pMem)
56 {
57         FPA11 *fpa11 = GET_FPA11();
58         unsigned int *p;
59         p = (unsigned int *) &fpa11->fpreg[Fn].fExtended;
60         fpa11->fType[Fn] = typeExtended;
61         get_user(p[0], &pMem[0]);       /* sign & exponent */
62         get_user(p[1], &pMem[2]);       /* ls bits */
63         get_user(p[2], &pMem[1]);       /* ms bits */
64 }
65 #endif
66
67 static inline void loadMultiple(const unsigned int Fn, const unsigned int __user *pMem)
68 {
69         FPA11 *fpa11 = GET_FPA11();
70         register unsigned int *p;
71         unsigned long x;
72
73         p = (unsigned int *) &(fpa11->fpreg[Fn]);
74         get_user(x, &pMem[0]);
75         fpa11->fType[Fn] = (x >> 14) & 0x00000003;
76
77         switch (fpa11->fType[Fn]) {
78         case typeSingle:
79         case typeDouble:
80                 {
81                         get_user(p[0], &pMem[2]);       /* Single */
82                         get_user(p[1], &pMem[1]);       /* double msw */
83                         p[2] = 0;                       /* empty */
84                 }
85                 break;
86
87 #ifdef CONFIG_FPE_NWFPE_XP
88         case typeExtended:
89                 {
90                         get_user(p[1], &pMem[2]);
91                         get_user(p[2], &pMem[1]);       /* msw */
92                         p[0] = (x & 0x80003fff);
93                 }
94                 break;
95 #endif
96         }
97 }
98
99 static inline void storeSingle(struct roundingData *roundData, const unsigned int Fn, unsigned int __user *pMem)
100 {
101         FPA11 *fpa11 = GET_FPA11();
102         union {
103                 float32 f;
104                 unsigned int i[1];
105         } val;
106
107         switch (fpa11->fType[Fn]) {
108         case typeDouble:
109                 val.f = float64_to_float32(roundData, fpa11->fpreg[Fn].fDouble);
110                 break;
111
112 #ifdef CONFIG_FPE_NWFPE_XP
113         case typeExtended:
114                 val.f = floatx80_to_float32(roundData, fpa11->fpreg[Fn].fExtended);
115                 break;
116 #endif
117
118         default:
119                 val.f = fpa11->fpreg[Fn].fSingle;
120         }
121
122         put_user(val.i[0], pMem);
123 }
124
125 static inline void storeDouble(struct roundingData *roundData, const unsigned int Fn, unsigned int __user *pMem)
126 {
127         FPA11 *fpa11 = GET_FPA11();
128         union {
129                 float64 f;
130                 unsigned int i[2];
131         } val;
132
133         switch (fpa11->fType[Fn]) {
134         case typeSingle:
135                 val.f = float32_to_float64(fpa11->fpreg[Fn].fSingle);
136                 break;
137
138 #ifdef CONFIG_FPE_NWFPE_XP
139         case typeExtended:
140                 val.f = floatx80_to_float64(roundData, fpa11->fpreg[Fn].fExtended);
141                 break;
142 #endif
143
144         default:
145                 val.f = fpa11->fpreg[Fn].fDouble;
146         }
147
148 #ifdef __ARMEB__
149         put_user(val.i[0], &pMem[0]);   /* msw */
150         put_user(val.i[1], &pMem[1]);   /* lsw */
151 #else
152         put_user(val.i[1], &pMem[0]);   /* msw */
153         put_user(val.i[0], &pMem[1]);   /* lsw */
154 #endif
155 }
156
157 #ifdef CONFIG_FPE_NWFPE_XP
158 static inline void storeExtended(const unsigned int Fn, unsigned int __user *pMem)
159 {
160         FPA11 *fpa11 = GET_FPA11();
161         union {
162                 floatx80 f;
163                 unsigned int i[3];
164         } val;
165
166         switch (fpa11->fType[Fn]) {
167         case typeSingle:
168                 val.f = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
169                 break;
170
171         case typeDouble:
172                 val.f = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
173                 break;
174
175         default:
176                 val.f = fpa11->fpreg[Fn].fExtended;
177         }
178
179         put_user(val.i[0], &pMem[0]);   /* sign & exp */
180         put_user(val.i[1], &pMem[2]);
181         put_user(val.i[2], &pMem[1]);   /* msw */
182 }
183 #endif
184
185 static inline void storeMultiple(const unsigned int Fn, unsigned int __user *pMem)
186 {
187         FPA11 *fpa11 = GET_FPA11();
188         register unsigned int nType, *p;
189
190         p = (unsigned int *) &(fpa11->fpreg[Fn]);
191         nType = fpa11->fType[Fn];
192
193         switch (nType) {
194         case typeSingle:
195         case typeDouble:
196                 {
197                         put_user(p[0], &pMem[2]);       /* single */
198                         put_user(p[1], &pMem[1]);       /* double msw */
199                         put_user(nType << 14, &pMem[0]);
200                 }
201                 break;
202
203 #ifdef CONFIG_FPE_NWFPE_XP
204         case typeExtended:
205                 {
206                         put_user(p[2], &pMem[1]);       /* msw */
207                         put_user(p[1], &pMem[2]);
208                         put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]);
209                 }
210                 break;
211 #endif
212         }
213 }
214
215 unsigned int PerformLDF(const unsigned int opcode)
216 {
217         unsigned int __user *pBase, *pAddress, *pFinal;
218         unsigned int nRc = 1, write_back = WRITE_BACK(opcode);
219
220         pBase = (unsigned int __user *) readRegister(getRn(opcode));
221         if (REG_PC == getRn(opcode)) {
222                 pBase += 2;
223                 write_back = 0;
224         }
225
226         pFinal = pBase;
227         if (BIT_UP_SET(opcode))
228                 pFinal += getOffset(opcode);
229         else
230                 pFinal -= getOffset(opcode);
231
232         if (PREINDEXED(opcode))
233                 pAddress = pFinal;
234         else
235                 pAddress = pBase;
236
237         switch (opcode & MASK_TRANSFER_LENGTH) {
238         case TRANSFER_SINGLE:
239                 loadSingle(getFd(opcode), pAddress);
240                 break;
241         case TRANSFER_DOUBLE:
242                 loadDouble(getFd(opcode), pAddress);
243                 break;
244 #ifdef CONFIG_FPE_NWFPE_XP
245         case TRANSFER_EXTENDED:
246                 loadExtended(getFd(opcode), pAddress);
247                 break;
248 #endif
249         default:
250                 nRc = 0;
251         }
252
253         if (write_back)
254                 writeRegister(getRn(opcode), (unsigned long) pFinal);
255         return nRc;
256 }
257
258 unsigned int PerformSTF(const unsigned int opcode)
259 {
260         unsigned int __user *pBase, *pAddress, *pFinal;
261         unsigned int nRc = 1, write_back = WRITE_BACK(opcode);
262         struct roundingData roundData;
263
264         roundData.mode = SetRoundingMode(opcode);
265         roundData.precision = SetRoundingPrecision(opcode);
266         roundData.exception = 0;
267
268         pBase = (unsigned int __user *) readRegister(getRn(opcode));
269         if (REG_PC == getRn(opcode)) {
270                 pBase += 2;
271                 write_back = 0;
272         }
273
274         pFinal = pBase;
275         if (BIT_UP_SET(opcode))
276                 pFinal += getOffset(opcode);
277         else
278                 pFinal -= getOffset(opcode);
279
280         if (PREINDEXED(opcode))
281                 pAddress = pFinal;
282         else
283                 pAddress = pBase;
284
285         switch (opcode & MASK_TRANSFER_LENGTH) {
286         case TRANSFER_SINGLE:
287                 storeSingle(&roundData, getFd(opcode), pAddress);
288                 break;
289         case TRANSFER_DOUBLE:
290                 storeDouble(&roundData, getFd(opcode), pAddress);
291                 break;
292 #ifdef CONFIG_FPE_NWFPE_XP
293         case TRANSFER_EXTENDED:
294                 storeExtended(getFd(opcode), pAddress);
295                 break;
296 #endif
297         default:
298                 nRc = 0;
299         }
300
301         if (roundData.exception)
302                 float_raise(roundData.exception);
303
304         if (write_back)
305                 writeRegister(getRn(opcode), (unsigned long) pFinal);
306         return nRc;
307 }
308
309 unsigned int PerformLFM(const unsigned int opcode)
310 {
311         unsigned int __user *pBase, *pAddress, *pFinal;
312         unsigned int i, Fd, write_back = WRITE_BACK(opcode);
313
314         pBase = (unsigned int __user *) readRegister(getRn(opcode));
315         if (REG_PC == getRn(opcode)) {
316                 pBase += 2;
317                 write_back = 0;
318         }
319
320         pFinal = pBase;
321         if (BIT_UP_SET(opcode))
322                 pFinal += getOffset(opcode);
323         else
324                 pFinal -= getOffset(opcode);
325
326         if (PREINDEXED(opcode))
327                 pAddress = pFinal;
328         else
329                 pAddress = pBase;
330
331         Fd = getFd(opcode);
332         for (i = getRegisterCount(opcode); i > 0; i--) {
333                 loadMultiple(Fd, pAddress);
334                 pAddress += 3;
335                 Fd++;
336                 if (Fd == 8)
337                         Fd = 0;
338         }
339
340         if (write_back)
341                 writeRegister(getRn(opcode), (unsigned long) pFinal);
342         return 1;
343 }
344
345 unsigned int PerformSFM(const unsigned int opcode)
346 {
347         unsigned int __user *pBase, *pAddress, *pFinal;
348         unsigned int i, Fd, write_back = WRITE_BACK(opcode);
349
350         pBase = (unsigned int __user *) readRegister(getRn(opcode));
351         if (REG_PC == getRn(opcode)) {
352                 pBase += 2;
353                 write_back = 0;
354         }
355
356         pFinal = pBase;
357         if (BIT_UP_SET(opcode))
358                 pFinal += getOffset(opcode);
359         else
360                 pFinal -= getOffset(opcode);
361
362         if (PREINDEXED(opcode))
363                 pAddress = pFinal;
364         else
365                 pAddress = pBase;
366
367         Fd = getFd(opcode);
368         for (i = getRegisterCount(opcode); i > 0; i--) {
369                 storeMultiple(Fd, pAddress);
370                 pAddress += 3;
371                 Fd++;
372                 if (Fd == 8)
373                         Fd = 0;
374         }
375
376         if (write_back)
377                 writeRegister(getRn(opcode), (unsigned long) pFinal);
378         return 1;
379 }
380
381 unsigned int EmulateCPDT(const unsigned int opcode)
382 {
383         unsigned int nRc = 0;
384
385         if (LDF_OP(opcode)) {
386                 nRc = PerformLDF(opcode);
387         } else if (LFM_OP(opcode)) {
388                 nRc = PerformLFM(opcode);
389         } else if (STF_OP(opcode)) {
390                 nRc = PerformSTF(opcode);
391         } else if (SFM_OP(opcode)) {
392                 nRc = PerformSFM(opcode);
393         } else {
394                 nRc = 0;
395         }
396
397         return nRc;
398 }