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