Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
fpa11_cpdt.c
Go to the documentation of this file.
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 <[email protected]>
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 }