Merge master.kernel.org:/home/rmk/linux-2.6-serial
[linux-2.6] / 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(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(fpa11->fpreg[Fn].fDouble);
110                 break;
111
112 #ifdef CONFIG_FPE_NWFPE_XP
113         case typeExtended:
114                 val.f = floatx80_to_float32(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(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(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
263         SetRoundingMode(ROUND_TO_NEAREST);
264
265         pBase = (unsigned int __user *) readRegister(getRn(opcode));
266         if (REG_PC == getRn(opcode)) {
267                 pBase += 2;
268                 write_back = 0;
269         }
270
271         pFinal = pBase;
272         if (BIT_UP_SET(opcode))
273                 pFinal += getOffset(opcode);
274         else
275                 pFinal -= getOffset(opcode);
276
277         if (PREINDEXED(opcode))
278                 pAddress = pFinal;
279         else
280                 pAddress = pBase;
281
282         switch (opcode & MASK_TRANSFER_LENGTH) {
283         case TRANSFER_SINGLE:
284                 storeSingle(getFd(opcode), pAddress);
285                 break;
286         case TRANSFER_DOUBLE:
287                 storeDouble(getFd(opcode), pAddress);
288                 break;
289 #ifdef CONFIG_FPE_NWFPE_XP
290         case TRANSFER_EXTENDED:
291                 storeExtended(getFd(opcode), pAddress);
292                 break;
293 #endif
294         default:
295                 nRc = 0;
296         }
297
298         if (write_back)
299                 writeRegister(getRn(opcode), (unsigned long) pFinal);
300         return nRc;
301 }
302
303 unsigned int PerformLFM(const unsigned int opcode)
304 {
305         unsigned int __user *pBase, *pAddress, *pFinal;
306         unsigned int i, Fd, write_back = WRITE_BACK(opcode);
307
308         pBase = (unsigned int __user *) readRegister(getRn(opcode));
309         if (REG_PC == getRn(opcode)) {
310                 pBase += 2;
311                 write_back = 0;
312         }
313
314         pFinal = pBase;
315         if (BIT_UP_SET(opcode))
316                 pFinal += getOffset(opcode);
317         else
318                 pFinal -= getOffset(opcode);
319
320         if (PREINDEXED(opcode))
321                 pAddress = pFinal;
322         else
323                 pAddress = pBase;
324
325         Fd = getFd(opcode);
326         for (i = getRegisterCount(opcode); i > 0; i--) {
327                 loadMultiple(Fd, pAddress);
328                 pAddress += 3;
329                 Fd++;
330                 if (Fd == 8)
331                         Fd = 0;
332         }
333
334         if (write_back)
335                 writeRegister(getRn(opcode), (unsigned long) pFinal);
336         return 1;
337 }
338
339 unsigned int PerformSFM(const unsigned int opcode)
340 {
341         unsigned int __user *pBase, *pAddress, *pFinal;
342         unsigned int i, Fd, write_back = WRITE_BACK(opcode);
343
344         pBase = (unsigned int __user *) readRegister(getRn(opcode));
345         if (REG_PC == getRn(opcode)) {
346                 pBase += 2;
347                 write_back = 0;
348         }
349
350         pFinal = pBase;
351         if (BIT_UP_SET(opcode))
352                 pFinal += getOffset(opcode);
353         else
354                 pFinal -= getOffset(opcode);
355
356         if (PREINDEXED(opcode))
357                 pAddress = pFinal;
358         else
359                 pAddress = pBase;
360
361         Fd = getFd(opcode);
362         for (i = getRegisterCount(opcode); i > 0; i--) {
363                 storeMultiple(Fd, pAddress);
364                 pAddress += 3;
365                 Fd++;
366                 if (Fd == 8)
367                         Fd = 0;
368         }
369
370         if (write_back)
371                 writeRegister(getRn(opcode), (unsigned long) pFinal);
372         return 1;
373 }
374
375 unsigned int EmulateCPDT(const unsigned int opcode)
376 {
377         unsigned int nRc = 0;
378
379         if (LDF_OP(opcode)) {
380                 nRc = PerformLDF(opcode);
381         } else if (LFM_OP(opcode)) {
382                 nRc = PerformLFM(opcode);
383         } else if (STF_OP(opcode)) {
384                 nRc = PerformSTF(opcode);
385         } else if (SFM_OP(opcode)) {
386                 nRc = PerformSFM(opcode);
387         } else {
388                 nRc = 0;
389         }
390
391         return nRc;
392 }