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.
24 #include "softfloat.h"
27 #include "fpmodule.inl"
29 #include <linux/uaccess.h>
31 static inline void loadSingle(const unsigned int Fn
, const unsigned int __user
*pMem
)
33 FPA11
*fpa11
= GET_FPA11();
34 fpa11
->fType
[Fn
] = typeSingle
;
35 get_user(fpa11
->fpreg
[Fn
].fSingle
, pMem
);
38 static inline void loadDouble(const unsigned int Fn
, const unsigned int __user
*pMem
)
40 FPA11
*fpa11
= GET_FPA11();
42 p
= (unsigned int *) &fpa11
->fpreg
[Fn
].fDouble
;
43 fpa11
->fType
[Fn
] = typeDouble
;
45 get_user(p
[0], &pMem
[0]); /* sign & exponent */
46 get_user(p
[1], &pMem
[1]);
48 get_user(p
[0], &pMem
[1]);
49 get_user(p
[1], &pMem
[0]); /* sign & exponent */
53 #ifdef CONFIG_FPE_NWFPE_XP
54 static inline void loadExtended(const unsigned int Fn
, const unsigned int __user
*pMem
)
56 FPA11
*fpa11
= GET_FPA11();
58 p
= (unsigned int *) &fpa11
->fpreg
[Fn
].fExtended
;
59 fpa11
->fType
[Fn
] = typeExtended
;
60 get_user(p
[0], &pMem
[0]); /* sign & exponent */
62 get_user(p
[1], &pMem
[1]); /* ms bits */
63 get_user(p
[2], &pMem
[2]); /* ls bits */
65 get_user(p
[1], &pMem
[2]); /* ls bits */
66 get_user(p
[2], &pMem
[1]); /* ms bits */
71 static inline void loadMultiple(const unsigned int Fn
, const unsigned int __user
*pMem
)
73 FPA11
*fpa11
= GET_FPA11();
74 register unsigned int *p
;
77 p
= (unsigned int *) &(fpa11
->fpreg
[Fn
]);
78 get_user(x
, &pMem
[0]);
79 fpa11
->fType
[Fn
] = (x
>> 14) & 0x00000003;
81 switch (fpa11
->fType
[Fn
]) {
85 get_user(p
[0], &pMem
[2]); /* Single */
86 get_user(p
[1], &pMem
[1]); /* double msw */
91 #ifdef CONFIG_FPE_NWFPE_XP
94 get_user(p
[1], &pMem
[2]);
95 get_user(p
[2], &pMem
[1]); /* msw */
96 p
[0] = (x
& 0x80003fff);
103 static inline void storeSingle(struct roundingData
*roundData
, const unsigned int Fn
, unsigned int __user
*pMem
)
105 FPA11
*fpa11
= GET_FPA11();
111 switch (fpa11
->fType
[Fn
]) {
113 val
.f
= float64_to_float32(roundData
, fpa11
->fpreg
[Fn
].fDouble
);
116 #ifdef CONFIG_FPE_NWFPE_XP
118 val
.f
= floatx80_to_float32(roundData
, fpa11
->fpreg
[Fn
].fExtended
);
123 val
.f
= fpa11
->fpreg
[Fn
].fSingle
;
126 put_user(val
.i
[0], pMem
);
129 static inline void storeDouble(struct roundingData
*roundData
, const unsigned int Fn
, unsigned int __user
*pMem
)
131 FPA11
*fpa11
= GET_FPA11();
137 switch (fpa11
->fType
[Fn
]) {
139 val
.f
= float32_to_float64(fpa11
->fpreg
[Fn
].fSingle
);
142 #ifdef CONFIG_FPE_NWFPE_XP
144 val
.f
= floatx80_to_float64(roundData
, fpa11
->fpreg
[Fn
].fExtended
);
149 val
.f
= fpa11
->fpreg
[Fn
].fDouble
;
153 put_user(val
.i
[0], &pMem
[0]); /* msw */
154 put_user(val
.i
[1], &pMem
[1]); /* lsw */
156 put_user(val
.i
[1], &pMem
[0]); /* msw */
157 put_user(val
.i
[0], &pMem
[1]); /* lsw */
161 #ifdef CONFIG_FPE_NWFPE_XP
162 static inline void storeExtended(const unsigned int Fn
, unsigned int __user
*pMem
)
164 FPA11
*fpa11
= GET_FPA11();
170 switch (fpa11
->fType
[Fn
]) {
172 val
.f
= float32_to_floatx80(fpa11
->fpreg
[Fn
].fSingle
);
176 val
.f
= float64_to_floatx80(fpa11
->fpreg
[Fn
].fDouble
);
180 val
.f
= fpa11
->fpreg
[Fn
].fExtended
;
183 put_user(val
.i
[0], &pMem
[0]); /* sign & exp */
185 put_user(val
.i
[1], &pMem
[1]); /* msw */
186 put_user(val
.i
[2], &pMem
[2]);
188 put_user(val
.i
[1], &pMem
[2]);
189 put_user(val
.i
[2], &pMem
[1]); /* msw */
194 static inline void storeMultiple(const unsigned int Fn
, unsigned int __user
*pMem
)
196 FPA11
*fpa11
= GET_FPA11();
197 register unsigned int nType
, *p
;
199 p
= (unsigned int *) &(fpa11
->fpreg
[Fn
]);
200 nType
= fpa11
->fType
[Fn
];
206 put_user(p
[0], &pMem
[2]); /* single */
207 put_user(p
[1], &pMem
[1]); /* double msw */
208 put_user(nType
<< 14, &pMem
[0]);
212 #ifdef CONFIG_FPE_NWFPE_XP
215 put_user(p
[2], &pMem
[1]); /* msw */
216 put_user(p
[1], &pMem
[2]);
217 put_user((p
[0] & 0x80003fff) | (nType
<< 14), &pMem
[0]);
224 unsigned int PerformLDF(const unsigned int opcode
)
226 unsigned int __user
*pBase
, *pAddress
, *pFinal
;
227 unsigned int nRc
= 1, write_back
= WRITE_BACK(opcode
);
229 pBase
= (unsigned int __user
*) readRegister(getRn(opcode
));
230 if (REG_PC
== getRn(opcode
)) {
236 if (BIT_UP_SET(opcode
))
237 pFinal
+= getOffset(opcode
);
239 pFinal
-= getOffset(opcode
);
241 if (PREINDEXED(opcode
))
246 switch (opcode
& MASK_TRANSFER_LENGTH
) {
247 case TRANSFER_SINGLE
:
248 loadSingle(getFd(opcode
), pAddress
);
250 case TRANSFER_DOUBLE
:
251 loadDouble(getFd(opcode
), pAddress
);
253 #ifdef CONFIG_FPE_NWFPE_XP
254 case TRANSFER_EXTENDED
:
255 loadExtended(getFd(opcode
), pAddress
);
263 writeRegister(getRn(opcode
), (unsigned long) pFinal
);
267 unsigned int PerformSTF(const unsigned int opcode
)
269 unsigned int __user
*pBase
, *pAddress
, *pFinal
;
270 unsigned int nRc
= 1, write_back
= WRITE_BACK(opcode
);
271 struct roundingData roundData
;
273 roundData
.mode
= SetRoundingMode(opcode
);
274 roundData
.precision
= SetRoundingPrecision(opcode
);
275 roundData
.exception
= 0;
277 pBase
= (unsigned int __user
*) readRegister(getRn(opcode
));
278 if (REG_PC
== getRn(opcode
)) {
284 if (BIT_UP_SET(opcode
))
285 pFinal
+= getOffset(opcode
);
287 pFinal
-= getOffset(opcode
);
289 if (PREINDEXED(opcode
))
294 switch (opcode
& MASK_TRANSFER_LENGTH
) {
295 case TRANSFER_SINGLE
:
296 storeSingle(&roundData
, getFd(opcode
), pAddress
);
298 case TRANSFER_DOUBLE
:
299 storeDouble(&roundData
, getFd(opcode
), pAddress
);
301 #ifdef CONFIG_FPE_NWFPE_XP
302 case TRANSFER_EXTENDED
:
303 storeExtended(getFd(opcode
), pAddress
);
310 if (roundData
.exception
)
311 float_raise(roundData
.exception
);
314 writeRegister(getRn(opcode
), (unsigned long) pFinal
);
318 unsigned int PerformLFM(const unsigned int opcode
)
320 unsigned int __user
*pBase
, *pAddress
, *pFinal
;
321 unsigned int i
, Fd
, write_back
= WRITE_BACK(opcode
);
323 pBase
= (unsigned int __user
*) readRegister(getRn(opcode
));
324 if (REG_PC
== getRn(opcode
)) {
330 if (BIT_UP_SET(opcode
))
331 pFinal
+= getOffset(opcode
);
333 pFinal
-= getOffset(opcode
);
335 if (PREINDEXED(opcode
))
341 for (i
= getRegisterCount(opcode
); i
> 0; i
--) {
342 loadMultiple(Fd
, pAddress
);
350 writeRegister(getRn(opcode
), (unsigned long) pFinal
);
354 unsigned int PerformSFM(const unsigned int opcode
)
356 unsigned int __user
*pBase
, *pAddress
, *pFinal
;
357 unsigned int i
, Fd
, write_back
= WRITE_BACK(opcode
);
359 pBase
= (unsigned int __user
*) readRegister(getRn(opcode
));
360 if (REG_PC
== getRn(opcode
)) {
366 if (BIT_UP_SET(opcode
))
367 pFinal
+= getOffset(opcode
);
369 pFinal
-= getOffset(opcode
);
371 if (PREINDEXED(opcode
))
377 for (i
= getRegisterCount(opcode
); i
> 0; i
--) {
378 storeMultiple(Fd
, pAddress
);
386 writeRegister(getRn(opcode
), (unsigned long) pFinal
);
390 unsigned int EmulateCPDT(const unsigned int opcode
)
392 unsigned int nRc
= 0;
394 if (LDF_OP(opcode
)) {
395 nRc
= PerformLDF(opcode
);
396 } else if (LFM_OP(opcode
)) {
397 nRc
= PerformLFM(opcode
);
398 } else if (STF_OP(opcode
)) {
399 nRc
= PerformSTF(opcode
);
400 } else if (SFM_OP(opcode
)) {
401 nRc
= PerformSFM(opcode
);