1 // SPDX-License-Identifier: GPL-2.0-or-later
3 NetWinder Floating Point Emulator
4 (c) Rebel.com, 1998-1999
5 (c) Philip Blundell, 1998, 2001
7 Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
12 #include "softfloat.h"
15 #include "fpmodule.inl"
17 #include <linux/uaccess.h>
19 static inline void loadSingle(const unsigned int Fn
, const unsigned int __user
*pMem
)
21 FPA11
*fpa11
= GET_FPA11();
22 fpa11
->fType
[Fn
] = typeSingle
;
23 get_user(fpa11
->fpreg
[Fn
].fSingle
, pMem
);
26 static inline void loadDouble(const unsigned int Fn
, const unsigned int __user
*pMem
)
28 FPA11
*fpa11
= GET_FPA11();
30 p
= (unsigned int *) &fpa11
->fpreg
[Fn
].fDouble
;
31 fpa11
->fType
[Fn
] = typeDouble
;
33 get_user(p
[0], &pMem
[0]); /* sign & exponent */
34 get_user(p
[1], &pMem
[1]);
36 get_user(p
[0], &pMem
[1]);
37 get_user(p
[1], &pMem
[0]); /* sign & exponent */
41 #ifdef CONFIG_FPE_NWFPE_XP
42 static inline void loadExtended(const unsigned int Fn
, const unsigned int __user
*pMem
)
44 FPA11
*fpa11
= GET_FPA11();
46 p
= (unsigned int *) &fpa11
->fpreg
[Fn
].fExtended
;
47 fpa11
->fType
[Fn
] = typeExtended
;
48 get_user(p
[0], &pMem
[0]); /* sign & exponent */
50 get_user(p
[1], &pMem
[1]); /* ms bits */
51 get_user(p
[2], &pMem
[2]); /* ls bits */
53 get_user(p
[1], &pMem
[2]); /* ls bits */
54 get_user(p
[2], &pMem
[1]); /* ms bits */
59 static inline void loadMultiple(const unsigned int Fn
, const unsigned int __user
*pMem
)
61 FPA11
*fpa11
= GET_FPA11();
62 register unsigned int *p
;
65 p
= (unsigned int *) &(fpa11
->fpreg
[Fn
]);
66 get_user(x
, &pMem
[0]);
67 fpa11
->fType
[Fn
] = (x
>> 14) & 0x00000003;
69 switch (fpa11
->fType
[Fn
]) {
73 get_user(p
[0], &pMem
[2]); /* Single */
74 get_user(p
[1], &pMem
[1]); /* double msw */
79 #ifdef CONFIG_FPE_NWFPE_XP
82 get_user(p
[1], &pMem
[2]);
83 get_user(p
[2], &pMem
[1]); /* msw */
84 p
[0] = (x
& 0x80003fff);
91 static inline void storeSingle(struct roundingData
*roundData
, const unsigned int Fn
, unsigned int __user
*pMem
)
93 FPA11
*fpa11
= GET_FPA11();
99 switch (fpa11
->fType
[Fn
]) {
101 val
.f
= float64_to_float32(roundData
, fpa11
->fpreg
[Fn
].fDouble
);
104 #ifdef CONFIG_FPE_NWFPE_XP
106 val
.f
= floatx80_to_float32(roundData
, fpa11
->fpreg
[Fn
].fExtended
);
111 val
.f
= fpa11
->fpreg
[Fn
].fSingle
;
114 put_user(val
.i
[0], pMem
);
117 static inline void storeDouble(struct roundingData
*roundData
, const unsigned int Fn
, unsigned int __user
*pMem
)
119 FPA11
*fpa11
= GET_FPA11();
125 switch (fpa11
->fType
[Fn
]) {
127 val
.f
= float32_to_float64(fpa11
->fpreg
[Fn
].fSingle
);
130 #ifdef CONFIG_FPE_NWFPE_XP
132 val
.f
= floatx80_to_float64(roundData
, fpa11
->fpreg
[Fn
].fExtended
);
137 val
.f
= fpa11
->fpreg
[Fn
].fDouble
;
141 put_user(val
.i
[0], &pMem
[0]); /* msw */
142 put_user(val
.i
[1], &pMem
[1]); /* lsw */
144 put_user(val
.i
[1], &pMem
[0]); /* msw */
145 put_user(val
.i
[0], &pMem
[1]); /* lsw */
149 #ifdef CONFIG_FPE_NWFPE_XP
150 static inline void storeExtended(const unsigned int Fn
, unsigned int __user
*pMem
)
152 FPA11
*fpa11
= GET_FPA11();
158 switch (fpa11
->fType
[Fn
]) {
160 val
.f
= float32_to_floatx80(fpa11
->fpreg
[Fn
].fSingle
);
164 val
.f
= float64_to_floatx80(fpa11
->fpreg
[Fn
].fDouble
);
168 val
.f
= fpa11
->fpreg
[Fn
].fExtended
;
171 put_user(val
.i
[0], &pMem
[0]); /* sign & exp */
173 put_user(val
.i
[1], &pMem
[1]); /* msw */
174 put_user(val
.i
[2], &pMem
[2]);
176 put_user(val
.i
[1], &pMem
[2]);
177 put_user(val
.i
[2], &pMem
[1]); /* msw */
182 static inline void storeMultiple(const unsigned int Fn
, unsigned int __user
*pMem
)
184 FPA11
*fpa11
= GET_FPA11();
185 register unsigned int nType
, *p
;
187 p
= (unsigned int *) &(fpa11
->fpreg
[Fn
]);
188 nType
= fpa11
->fType
[Fn
];
194 put_user(p
[0], &pMem
[2]); /* single */
195 put_user(p
[1], &pMem
[1]); /* double msw */
196 put_user(nType
<< 14, &pMem
[0]);
200 #ifdef CONFIG_FPE_NWFPE_XP
203 put_user(p
[2], &pMem
[1]); /* msw */
204 put_user(p
[1], &pMem
[2]);
205 put_user((p
[0] & 0x80003fff) | (nType
<< 14), &pMem
[0]);
212 unsigned int PerformLDF(const unsigned int opcode
)
214 unsigned int __user
*pBase
, *pAddress
, *pFinal
;
215 unsigned int nRc
= 1, write_back
= WRITE_BACK(opcode
);
217 pBase
= (unsigned int __user
*) readRegister(getRn(opcode
));
218 if (REG_PC
== getRn(opcode
)) {
224 if (BIT_UP_SET(opcode
))
225 pFinal
+= getOffset(opcode
);
227 pFinal
-= getOffset(opcode
);
229 if (PREINDEXED(opcode
))
234 switch (opcode
& MASK_TRANSFER_LENGTH
) {
235 case TRANSFER_SINGLE
:
236 loadSingle(getFd(opcode
), pAddress
);
238 case TRANSFER_DOUBLE
:
239 loadDouble(getFd(opcode
), pAddress
);
241 #ifdef CONFIG_FPE_NWFPE_XP
242 case TRANSFER_EXTENDED
:
243 loadExtended(getFd(opcode
), pAddress
);
251 writeRegister(getRn(opcode
), (unsigned long) pFinal
);
255 unsigned int PerformSTF(const unsigned int opcode
)
257 unsigned int __user
*pBase
, *pAddress
, *pFinal
;
258 unsigned int nRc
= 1, write_back
= WRITE_BACK(opcode
);
259 struct roundingData roundData
;
261 roundData
.mode
= SetRoundingMode(opcode
);
262 roundData
.precision
= SetRoundingPrecision(opcode
);
263 roundData
.exception
= 0;
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(&roundData
, getFd(opcode
), pAddress
);
286 case TRANSFER_DOUBLE
:
287 storeDouble(&roundData
, getFd(opcode
), pAddress
);
289 #ifdef CONFIG_FPE_NWFPE_XP
290 case TRANSFER_EXTENDED
:
291 storeExtended(getFd(opcode
), pAddress
);
298 if (roundData
.exception
)
299 float_raise(roundData
.exception
);
302 writeRegister(getRn(opcode
), (unsigned long) pFinal
);
306 unsigned int PerformLFM(const unsigned int opcode
)
308 unsigned int __user
*pBase
, *pAddress
, *pFinal
;
309 unsigned int i
, Fd
, write_back
= WRITE_BACK(opcode
);
311 pBase
= (unsigned int __user
*) readRegister(getRn(opcode
));
312 if (REG_PC
== getRn(opcode
)) {
318 if (BIT_UP_SET(opcode
))
319 pFinal
+= getOffset(opcode
);
321 pFinal
-= getOffset(opcode
);
323 if (PREINDEXED(opcode
))
329 for (i
= getRegisterCount(opcode
); i
> 0; i
--) {
330 loadMultiple(Fd
, pAddress
);
338 writeRegister(getRn(opcode
), (unsigned long) pFinal
);
342 unsigned int PerformSFM(const unsigned int opcode
)
344 unsigned int __user
*pBase
, *pAddress
, *pFinal
;
345 unsigned int i
, Fd
, write_back
= WRITE_BACK(opcode
);
347 pBase
= (unsigned int __user
*) readRegister(getRn(opcode
));
348 if (REG_PC
== getRn(opcode
)) {
354 if (BIT_UP_SET(opcode
))
355 pFinal
+= getOffset(opcode
);
357 pFinal
-= getOffset(opcode
);
359 if (PREINDEXED(opcode
))
365 for (i
= getRegisterCount(opcode
); i
> 0; i
--) {
366 storeMultiple(Fd
, pAddress
);
374 writeRegister(getRn(opcode
), (unsigned long) pFinal
);
378 unsigned int EmulateCPDT(const unsigned int opcode
)
380 unsigned int nRc
= 0;
382 if (LDF_OP(opcode
)) {
383 nRc
= PerformLDF(opcode
);
384 } else if (LFM_OP(opcode
)) {
385 nRc
= PerformLFM(opcode
);
386 } else if (STF_OP(opcode
)) {
387 nRc
= PerformSTF(opcode
);
388 } else if (SFM_OP(opcode
)) {
389 nRc
= PerformSFM(opcode
);