Import 2.3.16
[davej-history.git] / arch / arm / nwfpe / fpa11_cpdt.c
blobe32bf342159ea207c53d2fa03a3380af79cf93fc
1 /*
2 NetWinder Floating Point Emulator
3 (c) Rebel.com, 1998-1999
4 (c) Philip Blundell, 1998
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 "config.h"
24 #include "softfloat.h"
25 #include "fpopcode.h"
26 #include "fpa11.h"
27 #include "fpmodule.h"
28 #include "fpmodule.inl"
30 #include <asm/uaccess.h>
32 extern __inline__
33 void loadSingle(const unsigned int Fn,const unsigned int *pMem)
35 fpa11->fpreg[Fn].fType = typeSingle;
36 get_user(fpa11->fpreg[Fn].fValue.fSingle, pMem);
39 extern __inline__
40 void loadDouble(const unsigned int Fn,const unsigned int *pMem)
42 unsigned int *p;
43 p = (unsigned int*)&fpa11->fpreg[Fn].fValue.fDouble;
44 fpa11->fpreg[Fn].fType = typeDouble;
45 get_user(p[0], &pMem[1]);
46 get_user(p[1], &pMem[0]); /* sign & exponent */
49 extern __inline__
50 void loadExtended(const unsigned int Fn,const unsigned int *pMem)
52 unsigned int *p;
53 p = (unsigned int*)&fpa11->fpreg[Fn].fValue.fExtended;
54 fpa11->fpreg[Fn].fType = 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 */
60 extern __inline__
61 void loadMultiple(const unsigned int Fn,const unsigned int *pMem)
63 register unsigned int *p;
64 unsigned long x;
66 p = (unsigned int*)&(fpa11->fpreg[Fn].fValue);
67 get_user(x, &pMem[0]);
68 fpa11->fpreg[Fn].fType = (x >> 14) & 0x00000003;
70 switch (fpa11->fpreg[Fn].fType)
72 case typeSingle:
73 case typeDouble:
75 get_user(p[0], &pMem[2]); /* Single */
76 get_user(p[1], &pMem[1]); /* double msw */
77 p[2] = 0; /* empty */
79 break;
81 case typeExtended:
83 get_user(p[1], &pMem[2]);
84 get_user(p[2], &pMem[1]); /* msw */
85 p[0] = (x & 0x80003fff);
87 break;
91 extern __inline__
92 void storeSingle(const unsigned int Fn,unsigned int *pMem)
94 float32 val;
95 register unsigned int *p = (unsigned int*)&val;
97 switch (fpa11->fpreg[Fn].fType)
99 case typeDouble:
100 val = float64_to_float32(fpa11->fpreg[Fn].fValue.fDouble);
101 break;
103 case typeExtended:
104 val = floatx80_to_float32(fpa11->fpreg[Fn].fValue.fExtended);
105 break;
107 default: val = fpa11->fpreg[Fn].fValue.fSingle;
110 put_user(p[0], pMem);
113 extern __inline__
114 void storeDouble(const unsigned int Fn,unsigned int *pMem)
116 float64 val;
117 register unsigned int *p = (unsigned int*)&val;
119 switch (fpa11->fpreg[Fn].fType)
121 case typeSingle:
122 val = float32_to_float64(fpa11->fpreg[Fn].fValue.fSingle);
123 break;
125 case typeExtended:
126 val = floatx80_to_float64(fpa11->fpreg[Fn].fValue.fExtended);
127 break;
129 default: val = fpa11->fpreg[Fn].fValue.fDouble;
131 put_user(p[1], &pMem[0]); /* msw */
132 put_user(p[0], &pMem[1]); /* lsw */
135 extern __inline__
136 void storeExtended(const unsigned int Fn,unsigned int *pMem)
138 floatx80 val;
139 register unsigned int *p = (unsigned int*)&val;
141 switch (fpa11->fpreg[Fn].fType)
143 case typeSingle:
144 val = float32_to_floatx80(fpa11->fpreg[Fn].fValue.fSingle);
145 break;
147 case typeDouble:
148 val = float64_to_floatx80(fpa11->fpreg[Fn].fValue.fDouble);
149 break;
151 default: val = fpa11->fpreg[Fn].fValue.fExtended;
154 put_user(p[0], &pMem[0]); /* sign & exp */
155 put_user(p[1], &pMem[2]);
156 put_user(p[2], &pMem[1]); /* msw */
159 extern __inline__
160 void storeMultiple(const unsigned int Fn,unsigned int *pMem)
162 register unsigned int nType, *p;
164 p = (unsigned int*)&(fpa11->fpreg[Fn].fValue);
165 nType = fpa11->fpreg[Fn].fType;
167 switch (nType)
169 case typeSingle:
170 case typeDouble:
172 put_user(p[0], &pMem[2]); /* single */
173 put_user(p[1], &pMem[1]); /* double msw */
174 put_user(nType << 14, &pMem[0]);
176 break;
178 case typeExtended:
180 put_user(p[2], &pMem[1]); /* msw */
181 put_user(p[1], &pMem[2]);
182 put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]);
184 break;
188 unsigned int PerformLDF(const unsigned int opcode)
190 unsigned int *pBase, *pAddress, *pFinal, nRc = 1;
192 //fp_printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
194 pBase = (unsigned int*)readRegister(getRn(opcode));
195 if (REG_PC == getRn(opcode)) pBase += 2;
197 pFinal = pBase;
198 if (BIT_UP_SET(opcode))
199 pFinal += getOffset(opcode);
200 else
201 pFinal -= getOffset(opcode);
203 if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
205 switch (opcode & MASK_TRANSFER_LENGTH)
207 case TRANSFER_SINGLE : loadSingle(getFd(opcode),pAddress); break;
208 case TRANSFER_DOUBLE : loadDouble(getFd(opcode),pAddress); break;
209 case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break;
210 default: nRc = 0;
213 if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal);
214 return nRc;
217 unsigned int PerformSTF(const unsigned int opcode)
219 unsigned int *pBase, *pAddress, *pFinal, nRc = 1;
221 //fp_printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
222 SetRoundingMode(ROUND_TO_NEAREST);
224 pBase = (unsigned int*)readRegister(getRn(opcode));
225 if (REG_PC == getRn(opcode)) pBase += 2;
227 pFinal = pBase;
228 if (BIT_UP_SET(opcode))
229 pFinal += getOffset(opcode);
230 else
231 pFinal -= getOffset(opcode);
233 if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
235 switch (opcode & MASK_TRANSFER_LENGTH)
237 case TRANSFER_SINGLE : storeSingle(getFd(opcode),pAddress); break;
238 case TRANSFER_DOUBLE : storeDouble(getFd(opcode),pAddress); break;
239 case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break;
240 default: nRc = 0;
243 if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal);
244 return nRc;
247 unsigned int PerformLFM(const unsigned int opcode)
249 unsigned int i, Fd, *pBase, *pAddress, *pFinal;
250 pBase = (unsigned int*)readRegister(getRn(opcode));
251 if (REG_PC == getRn(opcode)) pBase += 2;
253 pFinal = pBase;
254 if (BIT_UP_SET(opcode))
255 pFinal += getOffset(opcode);
256 else
257 pFinal -= getOffset(opcode);
259 if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
261 Fd = getFd(opcode);
262 for (i=getRegisterCount(opcode);i>0;i--)
264 loadMultiple(Fd,pAddress);
265 pAddress += 3; Fd++;
266 if (Fd == 8) Fd = 0;
269 if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal);
270 return 1;
273 unsigned int PerformSFM(const unsigned int opcode)
275 unsigned int i, Fd, *pBase, *pAddress, *pFinal;
277 pBase = (unsigned int*)readRegister(getRn(opcode));
278 if (REG_PC == getRn(opcode)) pBase += 2;
280 pFinal = pBase;
281 if (BIT_UP_SET(opcode))
282 pFinal += getOffset(opcode);
283 else
284 pFinal -= getOffset(opcode);
286 if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
288 Fd = getFd(opcode);
289 for (i=getRegisterCount(opcode);i>0;i--)
291 storeMultiple(Fd,pAddress);
292 pAddress += 3; Fd++;
293 if (Fd == 8) Fd = 0;
296 if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal);
297 return 1;
300 #if 1
301 unsigned int EmulateCPDT(const unsigned int opcode)
303 unsigned int nRc = 0;
305 //fp_printk("EmulateCPDT(0x%08x)\n",opcode);
307 if (LDF_OP(opcode))
309 nRc = PerformLDF(opcode);
311 else if (LFM_OP(opcode))
313 nRc = PerformLFM(opcode);
315 else if (STF_OP(opcode))
317 nRc = PerformSTF(opcode);
319 else if (SFM_OP(opcode))
321 nRc = PerformSFM(opcode);
323 else
325 nRc = 0;
328 return nRc;
330 #endif