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 *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 *pMem)
41 FPA11 *fpa11 = GET_FPA11();
43 p = (unsigned int *) &fpa11->fpreg[Fn].fDouble;
44 fpa11->fType[Fn] = typeDouble;
45 get_user(p[0], &pMem[1]);
46 get_user(p[1], &pMem[0]); /* sign & exponent */
49 #ifdef CONFIG_FPE_NWFPE_XP
50 static inline void loadExtended(const unsigned int Fn, const unsigned int *pMem)
52 FPA11 *fpa11 = GET_FPA11();
54 p = (unsigned int *) &fpa11->fpreg[Fn].fExtended;
55 fpa11->fType[Fn] = typeExtended;
56 get_user(p[0], &pMem[0]); /* sign & exponent */
57 get_user(p[1], &pMem[2]); /* ls bits */
58 get_user(p[2], &pMem[1]); /* ms bits */
62 static inline void loadMultiple(const unsigned int Fn, const unsigned int *pMem)
64 FPA11 *fpa11 = GET_FPA11();
65 register unsigned int *p;
68 p = (unsigned int *) &(fpa11->fpreg[Fn]);
69 get_user(x, &pMem[0]);
70 fpa11->fType[Fn] = (x >> 14) & 0x00000003;
72 switch (fpa11->fType[Fn]) {
76 get_user(p[0], &pMem[2]); /* Single */
77 get_user(p[1], &pMem[1]); /* double msw */
82 #ifdef CONFIG_FPE_NWFPE_XP
85 get_user(p[1], &pMem[2]);
86 get_user(p[2], &pMem[1]); /* msw */
87 p[0] = (x & 0x80003fff);
94 static inline void storeSingle(const unsigned int Fn, unsigned int *pMem)
96 FPA11 *fpa11 = GET_FPA11();
102 switch (fpa11->fType[Fn]) {
104 val.f = float64_to_float32(fpa11->fpreg[Fn].fDouble);
107 #ifdef CONFIG_FPE_NWFPE_XP
109 val.f = floatx80_to_float32(fpa11->fpreg[Fn].fExtended);
114 val.f = fpa11->fpreg[Fn].fSingle;
117 put_user(val.i[0], pMem);
120 static inline void storeDouble(const unsigned int Fn, unsigned int *pMem)
122 FPA11 *fpa11 = GET_FPA11();
128 switch (fpa11->fType[Fn]) {
130 val.f = float32_to_float64(fpa11->fpreg[Fn].fSingle);
133 #ifdef CONFIG_FPE_NWFPE_XP
135 val.f = floatx80_to_float64(fpa11->fpreg[Fn].fExtended);
140 val.f = fpa11->fpreg[Fn].fDouble;
143 put_user(val.i[1], &pMem[0]); /* msw */
144 put_user(val.i[0], &pMem[1]); /* lsw */
147 #ifdef CONFIG_FPE_NWFPE_XP
148 static inline void storeExtended(const unsigned int Fn, unsigned int *pMem)
150 FPA11 *fpa11 = GET_FPA11();
156 switch (fpa11->fType[Fn]) {
158 val.f = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
162 val.f = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
166 val.f = fpa11->fpreg[Fn].fExtended;
169 put_user(val.i[0], &pMem[0]); /* sign & exp */
170 put_user(val.i[1], &pMem[2]);
171 put_user(val.i[2], &pMem[1]); /* msw */
175 static inline void storeMultiple(const unsigned int Fn, unsigned int *pMem)
177 FPA11 *fpa11 = GET_FPA11();
178 register unsigned int nType, *p;
180 p = (unsigned int *) &(fpa11->fpreg[Fn]);
181 nType = fpa11->fType[Fn];
187 put_user(p[0], &pMem[2]); /* single */
188 put_user(p[1], &pMem[1]); /* double msw */
189 put_user(nType << 14, &pMem[0]);
193 #ifdef CONFIG_FPE_NWFPE_XP
196 put_user(p[2], &pMem[1]); /* msw */
197 put_user(p[1], &pMem[2]);
198 put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]);
205 unsigned int PerformLDF(const unsigned int opcode)
207 unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
208 write_back = WRITE_BACK(opcode);
210 pBase = (unsigned int *) readRegister(getRn(opcode));
211 if (REG_PC == getRn(opcode)) {
217 if (BIT_UP_SET(opcode))
218 pFinal += getOffset(opcode);
220 pFinal -= getOffset(opcode);
222 if (PREINDEXED(opcode))
227 switch (opcode & MASK_TRANSFER_LENGTH) {
228 case TRANSFER_SINGLE:
229 loadSingle(getFd(opcode), pAddress);
231 case TRANSFER_DOUBLE:
232 loadDouble(getFd(opcode), pAddress);
234 #ifdef CONFIG_FPE_NWFPE_XP
235 case TRANSFER_EXTENDED:
236 loadExtended(getFd(opcode), pAddress);
244 writeRegister(getRn(opcode), (unsigned int) pFinal);
248 unsigned int PerformSTF(const unsigned int opcode)
250 unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
251 write_back = WRITE_BACK(opcode);
253 SetRoundingMode(ROUND_TO_NEAREST);
255 pBase = (unsigned int *) readRegister(getRn(opcode));
256 if (REG_PC == getRn(opcode)) {
262 if (BIT_UP_SET(opcode))
263 pFinal += getOffset(opcode);
265 pFinal -= getOffset(opcode);
267 if (PREINDEXED(opcode))
272 switch (opcode & MASK_TRANSFER_LENGTH) {
273 case TRANSFER_SINGLE:
274 storeSingle(getFd(opcode), pAddress);
276 case TRANSFER_DOUBLE:
277 storeDouble(getFd(opcode), pAddress);
279 #ifdef CONFIG_FPE_NWFPE_XP
280 case TRANSFER_EXTENDED:
281 storeExtended(getFd(opcode), pAddress);
289 writeRegister(getRn(opcode), (unsigned int) pFinal);
293 unsigned int PerformLFM(const unsigned int opcode)
295 unsigned int i, Fd, *pBase, *pAddress, *pFinal,
296 write_back = WRITE_BACK(opcode);
298 pBase = (unsigned int *) readRegister(getRn(opcode));
299 if (REG_PC == getRn(opcode)) {
305 if (BIT_UP_SET(opcode))
306 pFinal += getOffset(opcode);
308 pFinal -= getOffset(opcode);
310 if (PREINDEXED(opcode))
316 for (i = getRegisterCount(opcode); i > 0; i--) {
317 loadMultiple(Fd, pAddress);
325 writeRegister(getRn(opcode), (unsigned int) pFinal);
329 unsigned int PerformSFM(const unsigned int opcode)
331 unsigned int i, Fd, *pBase, *pAddress, *pFinal,
332 write_back = WRITE_BACK(opcode);
334 pBase = (unsigned int *) readRegister(getRn(opcode));
335 if (REG_PC == getRn(opcode)) {
341 if (BIT_UP_SET(opcode))
342 pFinal += getOffset(opcode);
344 pFinal -= getOffset(opcode);
346 if (PREINDEXED(opcode))
352 for (i = getRegisterCount(opcode); i > 0; i--) {
353 storeMultiple(Fd, pAddress);
361 writeRegister(getRn(opcode), (unsigned int) pFinal);
365 unsigned int EmulateCPDT(const unsigned int opcode)
367 unsigned int nRc = 0;
369 if (LDF_OP(opcode)) {
370 nRc = PerformLDF(opcode);
371 } else if (LFM_OP(opcode)) {
372 nRc = PerformLFM(opcode);
373 } else if (STF_OP(opcode)) {
374 nRc = PerformSTF(opcode);
375 } else if (SFM_OP(opcode)) {
376 nRc = PerformSFM(opcode);