2 NetWinder Floating Point Emulator
3 (c) Rebel.com, 1998-1999
4 (c) Philip Blundell, 1998, 2001
6 Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
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.
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.
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.
23 #include <linux/config.h>
25 #include "softfloat.h"
28 #include "fpmodule.inl"
30 #include <asm/uaccess.h>
32 static inline void loadSingle(const unsigned int Fn, const unsigned int __user *pMem)
34 FPA11 *fpa11 = GET_FPA11();
35 fpa11->fType[Fn] = typeSingle;
36 get_user(fpa11->fpreg[Fn].fSingle, pMem);
39 static inline void loadDouble(const unsigned int Fn, const unsigned int __user *pMem)
41 FPA11 *fpa11 = GET_FPA11();
43 p = (unsigned int *) &fpa11->fpreg[Fn].fDouble;
44 fpa11->fType[Fn] = typeDouble;
46 get_user(p[0], &pMem[0]); /* sign & exponent */
47 get_user(p[1], &pMem[1]);
49 get_user(p[0], &pMem[1]);
50 get_user(p[1], &pMem[0]); /* sign & exponent */
54 #ifdef CONFIG_FPE_NWFPE_XP
55 static inline void loadExtended(const unsigned int Fn, const unsigned int __user *pMem)
57 FPA11 *fpa11 = GET_FPA11();
59 p = (unsigned int *) &fpa11->fpreg[Fn].fExtended;
60 fpa11->fType[Fn] = typeExtended;
61 get_user(p[0], &pMem[0]); /* sign & exponent */
63 get_user(p[1], &pMem[1]); /* ms bits */
64 get_user(p[2], &pMem[2]); /* ls bits */
66 get_user(p[1], &pMem[2]); /* ls bits */
67 get_user(p[2], &pMem[1]); /* ms bits */
72 static inline void loadMultiple(const unsigned int Fn, const unsigned int __user *pMem)
74 FPA11 *fpa11 = GET_FPA11();
75 register unsigned int *p;
78 p = (unsigned int *) &(fpa11->fpreg[Fn]);
79 get_user(x, &pMem[0]);
80 fpa11->fType[Fn] = (x >> 14) & 0x00000003;
82 switch (fpa11->fType[Fn]) {
86 get_user(p[0], &pMem[2]); /* Single */
87 get_user(p[1], &pMem[1]); /* double msw */
92 #ifdef CONFIG_FPE_NWFPE_XP
95 get_user(p[1], &pMem[2]);
96 get_user(p[2], &pMem[1]); /* msw */
97 p[0] = (x & 0x80003fff);
104 static inline void storeSingle(struct roundingData *roundData, const unsigned int Fn, unsigned int __user *pMem)
106 FPA11 *fpa11 = GET_FPA11();
112 switch (fpa11->fType[Fn]) {
114 val.f = float64_to_float32(roundData, fpa11->fpreg[Fn].fDouble);
117 #ifdef CONFIG_FPE_NWFPE_XP
119 val.f = floatx80_to_float32(roundData, fpa11->fpreg[Fn].fExtended);
124 val.f = fpa11->fpreg[Fn].fSingle;
127 put_user(val.i[0], pMem);
130 static inline void storeDouble(struct roundingData *roundData, const unsigned int Fn, unsigned int __user *pMem)
132 FPA11 *fpa11 = GET_FPA11();
138 switch (fpa11->fType[Fn]) {
140 val.f = float32_to_float64(fpa11->fpreg[Fn].fSingle);
143 #ifdef CONFIG_FPE_NWFPE_XP
145 val.f = floatx80_to_float64(roundData, fpa11->fpreg[Fn].fExtended);
150 val.f = fpa11->fpreg[Fn].fDouble;
154 put_user(val.i[0], &pMem[0]); /* msw */
155 put_user(val.i[1], &pMem[1]); /* lsw */
157 put_user(val.i[1], &pMem[0]); /* msw */
158 put_user(val.i[0], &pMem[1]); /* lsw */
162 #ifdef CONFIG_FPE_NWFPE_XP
163 static inline void storeExtended(const unsigned int Fn, unsigned int __user *pMem)
165 FPA11 *fpa11 = GET_FPA11();
171 switch (fpa11->fType[Fn]) {
173 val.f = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
177 val.f = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
181 val.f = fpa11->fpreg[Fn].fExtended;
184 put_user(val.i[0], &pMem[0]); /* sign & exp */
186 put_user(val.i[1], &pMem[1]); /* msw */
187 put_user(val.i[2], &pMem[2]);
189 put_user(val.i[1], &pMem[2]);
190 put_user(val.i[2], &pMem[1]); /* msw */
195 static inline void storeMultiple(const unsigned int Fn, unsigned int __user *pMem)
197 FPA11 *fpa11 = GET_FPA11();
198 register unsigned int nType, *p;
200 p = (unsigned int *) &(fpa11->fpreg[Fn]);
201 nType = fpa11->fType[Fn];
207 put_user(p[0], &pMem[2]); /* single */
208 put_user(p[1], &pMem[1]); /* double msw */
209 put_user(nType << 14, &pMem[0]);
213 #ifdef CONFIG_FPE_NWFPE_XP
216 put_user(p[2], &pMem[1]); /* msw */
217 put_user(p[1], &pMem[2]);
218 put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]);
225 unsigned int PerformLDF(const unsigned int opcode)
227 unsigned int __user *pBase, *pAddress, *pFinal;
228 unsigned int nRc = 1, write_back = WRITE_BACK(opcode);
230 pBase = (unsigned int __user *) readRegister(getRn(opcode));
231 if (REG_PC == getRn(opcode)) {
237 if (BIT_UP_SET(opcode))
238 pFinal += getOffset(opcode);
240 pFinal -= getOffset(opcode);
242 if (PREINDEXED(opcode))
247 switch (opcode & MASK_TRANSFER_LENGTH) {
248 case TRANSFER_SINGLE:
249 loadSingle(getFd(opcode), pAddress);
251 case TRANSFER_DOUBLE:
252 loadDouble(getFd(opcode), pAddress);
254 #ifdef CONFIG_FPE_NWFPE_XP
255 case TRANSFER_EXTENDED:
256 loadExtended(getFd(opcode), pAddress);
264 writeRegister(getRn(opcode), (unsigned long) pFinal);
268 unsigned int PerformSTF(const unsigned int opcode)
270 unsigned int __user *pBase, *pAddress, *pFinal;
271 unsigned int nRc = 1, write_back = WRITE_BACK(opcode);
272 struct roundingData roundData;
274 roundData.mode = SetRoundingMode(opcode);
275 roundData.precision = SetRoundingPrecision(opcode);
276 roundData.exception = 0;
278 pBase = (unsigned int __user *) readRegister(getRn(opcode));
279 if (REG_PC == getRn(opcode)) {
285 if (BIT_UP_SET(opcode))
286 pFinal += getOffset(opcode);
288 pFinal -= getOffset(opcode);
290 if (PREINDEXED(opcode))
295 switch (opcode & MASK_TRANSFER_LENGTH) {
296 case TRANSFER_SINGLE:
297 storeSingle(&roundData, getFd(opcode), pAddress);
299 case TRANSFER_DOUBLE:
300 storeDouble(&roundData, getFd(opcode), pAddress);
302 #ifdef CONFIG_FPE_NWFPE_XP
303 case TRANSFER_EXTENDED:
304 storeExtended(getFd(opcode), pAddress);
311 if (roundData.exception)
312 float_raise(roundData.exception);
315 writeRegister(getRn(opcode), (unsigned long) pFinal);
319 unsigned int PerformLFM(const unsigned int opcode)
321 unsigned int __user *pBase, *pAddress, *pFinal;
322 unsigned int i, Fd, write_back = WRITE_BACK(opcode);
324 pBase = (unsigned int __user *) readRegister(getRn(opcode));
325 if (REG_PC == getRn(opcode)) {
331 if (BIT_UP_SET(opcode))
332 pFinal += getOffset(opcode);
334 pFinal -= getOffset(opcode);
336 if (PREINDEXED(opcode))
342 for (i = getRegisterCount(opcode); i > 0; i--) {
343 loadMultiple(Fd, pAddress);
351 writeRegister(getRn(opcode), (unsigned long) pFinal);
355 unsigned int PerformSFM(const unsigned int opcode)
357 unsigned int __user *pBase, *pAddress, *pFinal;
358 unsigned int i, Fd, write_back = WRITE_BACK(opcode);
360 pBase = (unsigned int __user *) readRegister(getRn(opcode));
361 if (REG_PC == getRn(opcode)) {
367 if (BIT_UP_SET(opcode))
368 pFinal += getOffset(opcode);
370 pFinal -= getOffset(opcode);
372 if (PREINDEXED(opcode))
378 for (i = getRegisterCount(opcode); i > 0; i--) {
379 storeMultiple(Fd, pAddress);
387 writeRegister(getRn(opcode), (unsigned long) pFinal);
391 unsigned int EmulateCPDT(const unsigned int opcode)
393 unsigned int nRc = 0;
395 if (LDF_OP(opcode)) {
396 nRc = PerformLDF(opcode);
397 } else if (LFM_OP(opcode)) {
398 nRc = PerformLFM(opcode);
399 } else if (STF_OP(opcode)) {
400 nRc = PerformSTF(opcode);
401 } else if (SFM_OP(opcode)) {
402 nRc = PerformSFM(opcode);