File: /usr/src/linux/arch/arm/nwfpe/fpa11_cpdt.c
1 /*
2 NetWinder Floating Point Emulator
3 (c) Rebel.com, 1998-1999
4 (c) Philip Blundell, 1998
5
6 Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
7
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.
12
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.
17
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.
21 */
22
23 #include "softfloat.h"
24 #include "fpopcode.h"
25 #include "fpa11.h"
26 #include "fpmodule.h"
27 #include "fpmodule.inl"
28
29 #include <asm/uaccess.h>
30
31 static inline
32 void loadSingle(const unsigned int Fn,const unsigned int *pMem)
33 {
34 FPA11 *fpa11 = GET_FPA11();
35 fpa11->fType[Fn] = typeSingle;
36 get_user(fpa11->fpreg[Fn].fSingle, pMem);
37 }
38
39 static inline
40 void loadDouble(const unsigned int Fn,const unsigned int *pMem)
41 {
42 FPA11 *fpa11 = GET_FPA11();
43 unsigned int *p;
44 p = (unsigned int*)&fpa11->fpreg[Fn].fDouble;
45 fpa11->fType[Fn] = typeDouble;
46 get_user(p[0], &pMem[1]);
47 get_user(p[1], &pMem[0]); /* sign & exponent */
48 }
49
50 static inline
51 void loadExtended(const unsigned int Fn,const unsigned int *pMem)
52 {
53 FPA11 *fpa11 = GET_FPA11();
54 unsigned int *p;
55 p = (unsigned int*)&fpa11->fpreg[Fn].fExtended;
56 fpa11->fType[Fn] = typeExtended;
57 get_user(p[0], &pMem[0]); /* sign & exponent */
58 get_user(p[1], &pMem[2]); /* ls bits */
59 get_user(p[2], &pMem[1]); /* ms bits */
60 }
61
62 static inline
63 void loadMultiple(const unsigned int Fn,const unsigned int *pMem)
64 {
65 FPA11 *fpa11 = GET_FPA11();
66 register unsigned int *p;
67 unsigned long x;
68
69 p = (unsigned int*)&(fpa11->fpreg[Fn]);
70 get_user(x, &pMem[0]);
71 fpa11->fType[Fn] = (x >> 14) & 0x00000003;
72
73 switch (fpa11->fType[Fn])
74 {
75 case typeSingle:
76 case typeDouble:
77 {
78 get_user(p[0], &pMem[2]); /* Single */
79 get_user(p[1], &pMem[1]); /* double msw */
80 p[2] = 0; /* empty */
81 }
82 break;
83
84 case typeExtended:
85 {
86 get_user(p[1], &pMem[2]);
87 get_user(p[2], &pMem[1]); /* msw */
88 p[0] = (x & 0x80003fff);
89 }
90 break;
91 }
92 }
93
94 static inline
95 void storeSingle(const unsigned int Fn,unsigned int *pMem)
96 {
97 FPA11 *fpa11 = GET_FPA11();
98 float32 val;
99 register unsigned int *p = (unsigned int*)&val;
100
101 switch (fpa11->fType[Fn])
102 {
103 case typeDouble:
104 val = float64_to_float32(fpa11->fpreg[Fn].fDouble);
105 break;
106
107 case typeExtended:
108 val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended);
109 break;
110
111 default: val = fpa11->fpreg[Fn].fSingle;
112 }
113
114 put_user(p[0], pMem);
115 }
116
117 static inline
118 void storeDouble(const unsigned int Fn,unsigned int *pMem)
119 {
120 FPA11 *fpa11 = GET_FPA11();
121 float64 val;
122 register unsigned int *p = (unsigned int*)&val;
123
124 switch (fpa11->fType[Fn])
125 {
126 case typeSingle:
127 val = float32_to_float64(fpa11->fpreg[Fn].fSingle);
128 break;
129
130 case typeExtended:
131 val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended);
132 break;
133
134 default: val = fpa11->fpreg[Fn].fDouble;
135 }
136 put_user(p[1], &pMem[0]); /* msw */
137 put_user(p[0], &pMem[1]); /* lsw */
138 }
139
140 static inline
141 void storeExtended(const unsigned int Fn,unsigned int *pMem)
142 {
143 FPA11 *fpa11 = GET_FPA11();
144 floatx80 val;
145 register unsigned int *p = (unsigned int*)&val;
146
147 switch (fpa11->fType[Fn])
148 {
149 case typeSingle:
150 val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
151 break;
152
153 case typeDouble:
154 val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
155 break;
156
157 default: val = fpa11->fpreg[Fn].fExtended;
158 }
159
160 put_user(p[0], &pMem[0]); /* sign & exp */
161 put_user(p[1], &pMem[2]);
162 put_user(p[2], &pMem[1]); /* msw */
163 }
164
165 static inline
166 void storeMultiple(const unsigned int Fn,unsigned int *pMem)
167 {
168 FPA11 *fpa11 = GET_FPA11();
169 register unsigned int nType, *p;
170
171 p = (unsigned int*)&(fpa11->fpreg[Fn]);
172 nType = fpa11->fType[Fn];
173
174 switch (nType)
175 {
176 case typeSingle:
177 case typeDouble:
178 {
179 put_user(p[0], &pMem[2]); /* single */
180 put_user(p[1], &pMem[1]); /* double msw */
181 put_user(nType << 14, &pMem[0]);
182 }
183 break;
184
185 case typeExtended:
186 {
187 put_user(p[2], &pMem[1]); /* msw */
188 put_user(p[1], &pMem[2]);
189 put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]);
190 }
191 break;
192 }
193 }
194
195 unsigned int PerformLDF(const unsigned int opcode)
196 {
197 unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
198 write_back = WRITE_BACK(opcode);
199
200 //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
201
202 pBase = (unsigned int*)readRegister(getRn(opcode));
203 if (REG_PC == getRn(opcode))
204 {
205 pBase += 2;
206 write_back = 0;
207 }
208
209 pFinal = pBase;
210 if (BIT_UP_SET(opcode))
211 pFinal += getOffset(opcode);
212 else
213 pFinal -= getOffset(opcode);
214
215 if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
216
217 switch (opcode & MASK_TRANSFER_LENGTH)
218 {
219 case TRANSFER_SINGLE : loadSingle(getFd(opcode),pAddress); break;
220 case TRANSFER_DOUBLE : loadDouble(getFd(opcode),pAddress); break;
221 case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break;
222 default: nRc = 0;
223 }
224
225 if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
226 return nRc;
227 }
228
229 unsigned int PerformSTF(const unsigned int opcode)
230 {
231 unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
232 write_back = WRITE_BACK(opcode);
233
234 //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
235 SetRoundingMode(ROUND_TO_NEAREST);
236
237 pBase = (unsigned int*)readRegister(getRn(opcode));
238 if (REG_PC == getRn(opcode))
239 {
240 pBase += 2;
241 write_back = 0;
242 }
243
244 pFinal = pBase;
245 if (BIT_UP_SET(opcode))
246 pFinal += getOffset(opcode);
247 else
248 pFinal -= getOffset(opcode);
249
250 if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
251
252 switch (opcode & MASK_TRANSFER_LENGTH)
253 {
254 case TRANSFER_SINGLE : storeSingle(getFd(opcode),pAddress); break;
255 case TRANSFER_DOUBLE : storeDouble(getFd(opcode),pAddress); break;
256 case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break;
257 default: nRc = 0;
258 }
259
260 if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
261 return nRc;
262 }
263
264 unsigned int PerformLFM(const unsigned int opcode)
265 {
266 unsigned int i, Fd, *pBase, *pAddress, *pFinal,
267 write_back = WRITE_BACK(opcode);
268
269 pBase = (unsigned int*)readRegister(getRn(opcode));
270 if (REG_PC == getRn(opcode))
271 {
272 pBase += 2;
273 write_back = 0;
274 }
275
276 pFinal = pBase;
277 if (BIT_UP_SET(opcode))
278 pFinal += getOffset(opcode);
279 else
280 pFinal -= getOffset(opcode);
281
282 if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
283
284 Fd = getFd(opcode);
285 for (i=getRegisterCount(opcode);i>0;i--)
286 {
287 loadMultiple(Fd,pAddress);
288 pAddress += 3; Fd++;
289 if (Fd == 8) Fd = 0;
290 }
291
292 if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
293 return 1;
294 }
295
296 unsigned int PerformSFM(const unsigned int opcode)
297 {
298 unsigned int i, Fd, *pBase, *pAddress, *pFinal,
299 write_back = WRITE_BACK(opcode);
300
301 pBase = (unsigned int*)readRegister(getRn(opcode));
302 if (REG_PC == getRn(opcode))
303 {
304 pBase += 2;
305 write_back = 0;
306 }
307
308 pFinal = pBase;
309 if (BIT_UP_SET(opcode))
310 pFinal += getOffset(opcode);
311 else
312 pFinal -= getOffset(opcode);
313
314 if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
315
316 Fd = getFd(opcode);
317 for (i=getRegisterCount(opcode);i>0;i--)
318 {
319 storeMultiple(Fd,pAddress);
320 pAddress += 3; Fd++;
321 if (Fd == 8) Fd = 0;
322 }
323
324 if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
325 return 1;
326 }
327
328 #if 1
329 unsigned int EmulateCPDT(const unsigned int opcode)
330 {
331 unsigned int nRc = 0;
332
333 //printk("EmulateCPDT(0x%08x)\n",opcode);
334
335 if (LDF_OP(opcode))
336 {
337 nRc = PerformLDF(opcode);
338 }
339 else if (LFM_OP(opcode))
340 {
341 nRc = PerformLFM(opcode);
342 }
343 else if (STF_OP(opcode))
344 {
345 nRc = PerformSTF(opcode);
346 }
347 else if (SFM_OP(opcode))
348 {
349 nRc = PerformSFM(opcode);
350 }
351 else
352 {
353 nRc = 0;
354 }
355
356 return nRc;
357 }
358 #endif
359