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