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