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 <asm/uaccess.h>
31 static inline void loadSingle(const unsigned int Fn, const unsigned int *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 *pMem)
40 FPA11 *fpa11 = GET_FPA11();
42 p = (unsigned int *) &fpa11->fpreg[Fn].fDouble;
43 fpa11->fType[Fn] = typeDouble;
44 get_user(p[0], &pMem[1]);
45 get_user(p[1], &pMem[0]); /* sign & exponent */
48 #ifdef CONFIG_FPE_NWFPE_XP
49 static inline void loadExtended(const unsigned int Fn, const unsigned int *pMem)
51 FPA11 *fpa11 = GET_FPA11();
53 p = (unsigned int *) &fpa11->fpreg[Fn].fExtended;
54 fpa11->fType[Fn] = typeExtended;
55 get_user(p[0], &pMem[0]); /* sign & exponent */
56 get_user(p[1], &pMem[2]); /* ls bits */
57 get_user(p[2], &pMem[1]); /* ms bits */
61 static inline void loadMultiple(const unsigned int Fn, const unsigned int *pMem)
63 FPA11 *fpa11 = GET_FPA11();
64 register unsigned int *p;
67 p = (unsigned int *) &(fpa11->fpreg[Fn]);
68 get_user(x, &pMem[0]);
69 fpa11->fType[Fn] = (x >> 14) & 0x00000003;
71 switch (fpa11->fType[Fn]) {
75 get_user(p[0], &pMem[2]); /* Single */
76 get_user(p[1], &pMem[1]); /* double msw */
81 #ifdef CONFIG_FPE_NWFPE_XP
84 get_user(p[1], &pMem[2]);
85 get_user(p[2], &pMem[1]); /* msw */
86 p[0] = (x & 0x80003fff);
93 static inline void storeSingle(const unsigned int Fn, unsigned int *pMem)
95 FPA11 *fpa11 = GET_FPA11();
97 register unsigned int *p = (unsigned int *) &val;
99 switch (fpa11->fType[Fn]) {
101 val = float64_to_float32(fpa11->fpreg[Fn].fDouble);
104 #ifdef CONFIG_FPE_NWFPE_XP
106 val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended);
111 val = fpa11->fpreg[Fn].fSingle;
114 put_user(p[0], pMem);
117 static inline void storeDouble(const unsigned int Fn, unsigned int *pMem)
119 FPA11 *fpa11 = GET_FPA11();
121 register unsigned int *p = (unsigned int *) &val;
123 switch (fpa11->fType[Fn]) {
125 val = float32_to_float64(fpa11->fpreg[Fn].fSingle);
128 #ifdef CONFIG_FPE_NWFPE_XP
130 val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended);
135 val = fpa11->fpreg[Fn].fDouble;
137 put_user(p[1], &pMem[0]); /* msw */
138 put_user(p[0], &pMem[1]); /* lsw */
141 #ifdef CONFIG_FPE_NWFPE_XP
142 static inline void storeExtended(const unsigned int Fn, unsigned int *pMem)
144 FPA11 *fpa11 = GET_FPA11();
146 register unsigned int *p = (unsigned int *) &val;
148 switch (fpa11->fType[Fn]) {
150 val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
154 val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
158 val = fpa11->fpreg[Fn].fExtended;
161 put_user(p[0], &pMem[0]); /* sign & exp */
162 put_user(p[1], &pMem[2]);
163 put_user(p[2], &pMem[1]); /* msw */
167 static inline void storeMultiple(const unsigned int Fn, unsigned int *pMem)
169 FPA11 *fpa11 = GET_FPA11();
170 register unsigned int nType, *p;
172 p = (unsigned int *) &(fpa11->fpreg[Fn]);
173 nType = fpa11->fType[Fn];
179 put_user(p[0], &pMem[2]); /* single */
180 put_user(p[1], &pMem[1]); /* double msw */
181 put_user(nType << 14, &pMem[0]);
185 #ifdef CONFIG_FPE_NWFPE_XP
188 put_user(p[2], &pMem[1]); /* msw */
189 put_user(p[1], &pMem[2]);
190 put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]);
197 unsigned int PerformLDF(const unsigned int opcode)
199 unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
200 write_back = WRITE_BACK(opcode);
202 pBase = (unsigned int *) readRegister(getRn(opcode));
203 if (REG_PC == getRn(opcode)) {
209 if (BIT_UP_SET(opcode))
210 pFinal += getOffset(opcode);
212 pFinal -= getOffset(opcode);
214 if (PREINDEXED(opcode))
219 switch (opcode & MASK_TRANSFER_LENGTH) {
220 case TRANSFER_SINGLE:
221 loadSingle(getFd(opcode), pAddress);
223 case TRANSFER_DOUBLE:
224 loadDouble(getFd(opcode), pAddress);
226 #ifdef CONFIG_FPE_NWFPE_XP
227 case TRANSFER_EXTENDED:
228 loadExtended(getFd(opcode), pAddress);
236 writeRegister(getRn(opcode), (unsigned int) pFinal);
240 unsigned int PerformSTF(const unsigned int opcode)
242 unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
243 write_back = WRITE_BACK(opcode);
245 SetRoundingMode(ROUND_TO_NEAREST);
247 pBase = (unsigned int *) readRegister(getRn(opcode));
248 if (REG_PC == getRn(opcode)) {
254 if (BIT_UP_SET(opcode))
255 pFinal += getOffset(opcode);
257 pFinal -= getOffset(opcode);
259 if (PREINDEXED(opcode))
264 switch (opcode & MASK_TRANSFER_LENGTH) {
265 case TRANSFER_SINGLE:
266 storeSingle(getFd(opcode), pAddress);
268 case TRANSFER_DOUBLE:
269 storeDouble(getFd(opcode), pAddress);
271 #ifdef CONFIG_FPE_NWFPE_XP
272 case TRANSFER_EXTENDED:
273 storeExtended(getFd(opcode), pAddress);
281 writeRegister(getRn(opcode), (unsigned int) pFinal);
285 unsigned int PerformLFM(const unsigned int opcode)
287 unsigned int i, Fd, *pBase, *pAddress, *pFinal,
288 write_back = WRITE_BACK(opcode);
290 pBase = (unsigned int *) readRegister(getRn(opcode));
291 if (REG_PC == getRn(opcode)) {
297 if (BIT_UP_SET(opcode))
298 pFinal += getOffset(opcode);
300 pFinal -= getOffset(opcode);
302 if (PREINDEXED(opcode))
308 for (i = getRegisterCount(opcode); i > 0; i--) {
309 loadMultiple(Fd, pAddress);
317 writeRegister(getRn(opcode), (unsigned int) pFinal);
321 unsigned int PerformSFM(const unsigned int opcode)
323 unsigned int i, Fd, *pBase, *pAddress, *pFinal,
324 write_back = WRITE_BACK(opcode);
326 pBase = (unsigned int *) readRegister(getRn(opcode));
327 if (REG_PC == getRn(opcode)) {
333 if (BIT_UP_SET(opcode))
334 pFinal += getOffset(opcode);
336 pFinal -= getOffset(opcode);
338 if (PREINDEXED(opcode))
344 for (i = getRegisterCount(opcode); i > 0; i--) {
345 storeMultiple(Fd, pAddress);
353 writeRegister(getRn(opcode), (unsigned int) pFinal);
357 unsigned int EmulateCPDT(const unsigned int opcode)
359 unsigned int nRc = 0;
361 if (LDF_OP(opcode)) {
362 nRc = PerformLDF(opcode);
363 } else if (LFM_OP(opcode)) {
364 nRc = PerformLFM(opcode);
365 } else if (STF_OP(opcode)) {
366 nRc = PerformSTF(opcode);
367 } else if (SFM_OP(opcode)) {
368 nRc = PerformSFM(opcode);