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 */
62 get_user(p[1], &pMem[2]); /* ls bits */
63 get_user(p[2], &pMem[1]); /* ms bits */
67 static inline void loadMultiple(const unsigned int Fn, const unsigned int __user *pMem)
69 FPA11 *fpa11 = GET_FPA11();
70 register unsigned int *p;
73 p = (unsigned int *) &(fpa11->fpreg[Fn]);
74 get_user(x, &pMem[0]);
75 fpa11->fType[Fn] = (x >> 14) & 0x00000003;
77 switch (fpa11->fType[Fn]) {
81 get_user(p[0], &pMem[2]); /* Single */
82 get_user(p[1], &pMem[1]); /* double msw */
87 #ifdef CONFIG_FPE_NWFPE_XP
90 get_user(p[1], &pMem[2]);
91 get_user(p[2], &pMem[1]); /* msw */
92 p[0] = (x & 0x80003fff);
99 static inline void storeSingle(struct roundingData *roundData, const unsigned int Fn, unsigned int __user *pMem)
101 FPA11 *fpa11 = GET_FPA11();
107 switch (fpa11->fType[Fn]) {
109 val.f = float64_to_float32(roundData, fpa11->fpreg[Fn].fDouble);
112 #ifdef CONFIG_FPE_NWFPE_XP
114 val.f = floatx80_to_float32(roundData, fpa11->fpreg[Fn].fExtended);
119 val.f = fpa11->fpreg[Fn].fSingle;
122 put_user(val.i[0], pMem);
125 static inline void storeDouble(struct roundingData *roundData, const unsigned int Fn, unsigned int __user *pMem)
127 FPA11 *fpa11 = GET_FPA11();
133 switch (fpa11->fType[Fn]) {
135 val.f = float32_to_float64(fpa11->fpreg[Fn].fSingle);
138 #ifdef CONFIG_FPE_NWFPE_XP
140 val.f = floatx80_to_float64(roundData, fpa11->fpreg[Fn].fExtended);
145 val.f = fpa11->fpreg[Fn].fDouble;
149 put_user(val.i[0], &pMem[0]); /* msw */
150 put_user(val.i[1], &pMem[1]); /* lsw */
152 put_user(val.i[1], &pMem[0]); /* msw */
153 put_user(val.i[0], &pMem[1]); /* lsw */
157 #ifdef CONFIG_FPE_NWFPE_XP
158 static inline void storeExtended(const unsigned int Fn, unsigned int __user *pMem)
160 FPA11 *fpa11 = GET_FPA11();
166 switch (fpa11->fType[Fn]) {
168 val.f = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
172 val.f = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
176 val.f = fpa11->fpreg[Fn].fExtended;
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 */
185 static inline void storeMultiple(const unsigned int Fn, unsigned int __user *pMem)
187 FPA11 *fpa11 = GET_FPA11();
188 register unsigned int nType, *p;
190 p = (unsigned int *) &(fpa11->fpreg[Fn]);
191 nType = fpa11->fType[Fn];
197 put_user(p[0], &pMem[2]); /* single */
198 put_user(p[1], &pMem[1]); /* double msw */
199 put_user(nType << 14, &pMem[0]);
203 #ifdef CONFIG_FPE_NWFPE_XP
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]);
215 unsigned int PerformLDF(const unsigned int opcode)
217 unsigned int __user *pBase, *pAddress, *pFinal;
218 unsigned int nRc = 1, write_back = WRITE_BACK(opcode);
220 pBase = (unsigned int __user *) readRegister(getRn(opcode));
221 if (REG_PC == getRn(opcode)) {
227 if (BIT_UP_SET(opcode))
228 pFinal += getOffset(opcode);
230 pFinal -= getOffset(opcode);
232 if (PREINDEXED(opcode))
237 switch (opcode & MASK_TRANSFER_LENGTH) {
238 case TRANSFER_SINGLE:
239 loadSingle(getFd(opcode), pAddress);
241 case TRANSFER_DOUBLE:
242 loadDouble(getFd(opcode), pAddress);
244 #ifdef CONFIG_FPE_NWFPE_XP
245 case TRANSFER_EXTENDED:
246 loadExtended(getFd(opcode), pAddress);
254 writeRegister(getRn(opcode), (unsigned long) pFinal);
258 unsigned int PerformSTF(const unsigned int opcode)
260 unsigned int __user *pBase, *pAddress, *pFinal;
261 unsigned int nRc = 1, write_back = WRITE_BACK(opcode);
262 struct roundingData roundData;
264 roundData.mode = SetRoundingMode(opcode);
265 roundData.precision = SetRoundingPrecision(opcode);
266 roundData.exception = 0;
268 pBase = (unsigned int __user *) readRegister(getRn(opcode));
269 if (REG_PC == getRn(opcode)) {
275 if (BIT_UP_SET(opcode))
276 pFinal += getOffset(opcode);
278 pFinal -= getOffset(opcode);
280 if (PREINDEXED(opcode))
285 switch (opcode & MASK_TRANSFER_LENGTH) {
286 case TRANSFER_SINGLE:
287 storeSingle(&roundData, getFd(opcode), pAddress);
289 case TRANSFER_DOUBLE:
290 storeDouble(&roundData, getFd(opcode), pAddress);
292 #ifdef CONFIG_FPE_NWFPE_XP
293 case TRANSFER_EXTENDED:
294 storeExtended(getFd(opcode), pAddress);
301 if (roundData.exception)
302 float_raise(roundData.exception);
305 writeRegister(getRn(opcode), (unsigned long) pFinal);
309 unsigned int PerformLFM(const unsigned int opcode)
311 unsigned int __user *pBase, *pAddress, *pFinal;
312 unsigned int i, Fd, write_back = WRITE_BACK(opcode);
314 pBase = (unsigned int __user *) readRegister(getRn(opcode));
315 if (REG_PC == getRn(opcode)) {
321 if (BIT_UP_SET(opcode))
322 pFinal += getOffset(opcode);
324 pFinal -= getOffset(opcode);
326 if (PREINDEXED(opcode))
332 for (i = getRegisterCount(opcode); i > 0; i--) {
333 loadMultiple(Fd, pAddress);
341 writeRegister(getRn(opcode), (unsigned long) pFinal);
345 unsigned int PerformSFM(const unsigned int opcode)
347 unsigned int __user *pBase, *pAddress, *pFinal;
348 unsigned int i, Fd, write_back = WRITE_BACK(opcode);
350 pBase = (unsigned int __user *) readRegister(getRn(opcode));
351 if (REG_PC == getRn(opcode)) {
357 if (BIT_UP_SET(opcode))
358 pFinal += getOffset(opcode);
360 pFinal -= getOffset(opcode);
362 if (PREINDEXED(opcode))
368 for (i = getRegisterCount(opcode); i > 0; i--) {
369 storeMultiple(Fd, pAddress);
377 writeRegister(getRn(opcode), (unsigned long) pFinal);
381 unsigned int EmulateCPDT(const unsigned int opcode)
383 unsigned int nRc = 0;
385 if (LDF_OP(opcode)) {
386 nRc = PerformLDF(opcode);
387 } else if (LFM_OP(opcode)) {
388 nRc = PerformLFM(opcode);
389 } else if (STF_OP(opcode)) {
390 nRc = PerformSTF(opcode);
391 } else if (SFM_OP(opcode)) {
392 nRc = PerformSFM(opcode);