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
);