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(const unsigned int Fn, unsigned int __user *pMem)
101 FPA11 *fpa11 = GET_FPA11();
107 switch (fpa11->fType[Fn]) {
109 val.f = float64_to_float32(fpa11->fpreg[Fn].fDouble);
112 #ifdef CONFIG_FPE_NWFPE_XP
114 val.f = floatx80_to_float32(fpa11->fpreg[Fn].fExtended);
119 val.f = fpa11->fpreg[Fn].fSingle;
122 put_user(val.i[0], pMem);
125 static inline void storeDouble(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(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);
263 SetRoundingMode(ROUND_TO_NEAREST);
265 pBase = (unsigned int __user *) readRegister(getRn(opcode));
266 if (REG_PC == getRn(opcode)) {
272 if (BIT_UP_SET(opcode))
273 pFinal += getOffset(opcode);
275 pFinal -= getOffset(opcode);
277 if (PREINDEXED(opcode))
282 switch (opcode & MASK_TRANSFER_LENGTH) {
283 case TRANSFER_SINGLE:
284 storeSingle(getFd(opcode), pAddress);
286 case TRANSFER_DOUBLE:
287 storeDouble(getFd(opcode), pAddress);
289 #ifdef CONFIG_FPE_NWFPE_XP
290 case TRANSFER_EXTENDED:
291 storeExtended(getFd(opcode), pAddress);
299 writeRegister(getRn(opcode), (unsigned long) pFinal);
303 unsigned int PerformLFM(const unsigned int opcode)
305 unsigned int __user *pBase, *pAddress, *pFinal;
306 unsigned int i, Fd, write_back = WRITE_BACK(opcode);
308 pBase = (unsigned int __user *) readRegister(getRn(opcode));
309 if (REG_PC == getRn(opcode)) {
315 if (BIT_UP_SET(opcode))
316 pFinal += getOffset(opcode);
318 pFinal -= getOffset(opcode);
320 if (PREINDEXED(opcode))
326 for (i = getRegisterCount(opcode); i > 0; i--) {
327 loadMultiple(Fd, pAddress);
335 writeRegister(getRn(opcode), (unsigned long) pFinal);
339 unsigned int PerformSFM(const unsigned int opcode)
341 unsigned int __user *pBase, *pAddress, *pFinal;
342 unsigned int i, Fd, write_back = WRITE_BACK(opcode);
344 pBase = (unsigned int __user *) readRegister(getRn(opcode));
345 if (REG_PC == getRn(opcode)) {
351 if (BIT_UP_SET(opcode))
352 pFinal += getOffset(opcode);
354 pFinal -= getOffset(opcode);
356 if (PREINDEXED(opcode))
362 for (i = getRegisterCount(opcode); i > 0; i--) {
363 storeMultiple(Fd, pAddress);
371 writeRegister(getRn(opcode), (unsigned long) pFinal);
375 unsigned int EmulateCPDT(const unsigned int opcode)
377 unsigned int nRc = 0;
379 if (LDF_OP(opcode)) {
380 nRc = PerformLDF(opcode);
381 } else if (LFM_OP(opcode)) {
382 nRc = PerformLFM(opcode);
383 } else if (STF_OP(opcode)) {
384 nRc = PerformSTF(opcode);
385 } else if (SFM_OP(opcode)) {
386 nRc = PerformSFM(opcode);