blob: e12db7c51a768c1901e3bb86b05801bbab5735c4 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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 "fpa11.h"
24#include "softfloat.h"
25#include "fpopcode.h"
26#include "fpmodule.h"
27#include "fpmodule.inl"
28
29#include <asm/uaccess.h>
30
31static inline
32void 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
39static inline
40void 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
50static inline
51void 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
62static inline
63void 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
94static inline
95void storeSingle(const unsigned int Fn,unsigned int *pMem)
96{
97 FPA11 *fpa11 = GET_FPA11();
98 union
99 {
100 float32 f;
101 unsigned int i[1];
102 } val;
103
104 switch (fpa11->fType[Fn])
105 {
106 case typeDouble:
107 val.f = float64_to_float32(fpa11->fpreg[Fn].fDouble);
108 break;
109
110 case typeExtended:
111 val.f = floatx80_to_float32(fpa11->fpreg[Fn].fExtended);
112 break;
113
114 default: val.f = fpa11->fpreg[Fn].fSingle;
115 }
116
117 put_user(val.i[0], pMem);
118}
119
120static inline
121void storeDouble(const unsigned int Fn,unsigned int *pMem)
122{
123 FPA11 *fpa11 = GET_FPA11();
124 union
125 {
126 float64 f;
127 unsigned int i[2];
128 } val;
129
130 switch (fpa11->fType[Fn])
131 {
132 case typeSingle:
133 val.f = float32_to_float64(fpa11->fpreg[Fn].fSingle);
134 break;
135
136 case typeExtended:
137 val.f = floatx80_to_float64(fpa11->fpreg[Fn].fExtended);
138 break;
139
140 default: val.f = fpa11->fpreg[Fn].fDouble;
141 }
142
143 put_user(val.i[1], &pMem[0]); /* msw */
144 put_user(val.i[0], &pMem[1]); /* lsw */
145}
146
147static inline
148void storeExtended(const unsigned int Fn,unsigned int *pMem)
149{
150 FPA11 *fpa11 = GET_FPA11();
151 union
152 {
153 floatx80 f;
154 unsigned int i[3];
155 } val;
156
157 switch (fpa11->fType[Fn])
158 {
159 case typeSingle:
160 val.f = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
161 break;
162
163 case typeDouble:
164 val.f = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
165 break;
166
167 default: val.f = fpa11->fpreg[Fn].fExtended;
168 }
169
170 put_user(val.i[0], &pMem[0]); /* sign & exp */
171 put_user(val.i[1], &pMem[2]);
172 put_user(val.i[2], &pMem[1]); /* msw */
173}
174
175static inline
176void storeMultiple(const unsigned int Fn,unsigned int *pMem)
177{
178 FPA11 *fpa11 = GET_FPA11();
179 register unsigned int nType, *p;
180
181 p = (unsigned int*)&(fpa11->fpreg[Fn]);
182 nType = fpa11->fType[Fn];
183
184 switch (nType)
185 {
186 case typeSingle:
187 case typeDouble:
188 {
189 put_user(p[0], &pMem[2]); /* single */
190 put_user(p[1], &pMem[1]); /* double msw */
191 put_user(nType << 14, &pMem[0]);
192 }
193 break;
194
195 case typeExtended:
196 {
197 put_user(p[2], &pMem[1]); /* msw */
198 put_user(p[1], &pMem[2]);
199 put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]);
200 }
201 break;
202 }
203}
204
205unsigned int PerformLDF(const unsigned int opcode)
206{
207 unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
208 write_back = WRITE_BACK(opcode);
209
210 //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
211
212 pBase = (unsigned int*)readRegister(getRn(opcode));
213 if (REG_PC == getRn(opcode))
214 {
215 pBase += 2;
216 write_back = 0;
217 }
218
219 pFinal = pBase;
220 if (BIT_UP_SET(opcode))
221 pFinal += getOffset(opcode);
222 else
223 pFinal -= getOffset(opcode);
224
225 if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
226
227 switch (opcode & MASK_TRANSFER_LENGTH)
228 {
229 case TRANSFER_SINGLE : loadSingle(getFd(opcode),pAddress); break;
230 case TRANSFER_DOUBLE : loadDouble(getFd(opcode),pAddress); break;
231 case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break;
232 default: nRc = 0;
233 }
234
235 if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
236 return nRc;
237}
238
239unsigned int PerformSTF(const unsigned int opcode)
240{
241 unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
242 write_back = WRITE_BACK(opcode);
243
244 //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
245 SetRoundingMode(ROUND_TO_NEAREST);
246
247 pBase = (unsigned int*)readRegister(getRn(opcode));
248 if (REG_PC == getRn(opcode))
249 {
250 pBase += 2;
251 write_back = 0;
252 }
253
254 pFinal = pBase;
255 if (BIT_UP_SET(opcode))
256 pFinal += getOffset(opcode);
257 else
258 pFinal -= getOffset(opcode);
259
260 if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
261
262 switch (opcode & MASK_TRANSFER_LENGTH)
263 {
264 case TRANSFER_SINGLE : storeSingle(getFd(opcode),pAddress); break;
265 case TRANSFER_DOUBLE : storeDouble(getFd(opcode),pAddress); break;
266 case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break;
267 default: nRc = 0;
268 }
269
270 if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
271 return nRc;
272}
273
274unsigned int PerformLFM(const unsigned int opcode)
275{
276 unsigned int i, Fd, *pBase, *pAddress, *pFinal,
277 write_back = WRITE_BACK(opcode);
278
279 pBase = (unsigned int*)readRegister(getRn(opcode));
280 if (REG_PC == getRn(opcode))
281 {
282 pBase += 2;
283 write_back = 0;
284 }
285
286 pFinal = pBase;
287 if (BIT_UP_SET(opcode))
288 pFinal += getOffset(opcode);
289 else
290 pFinal -= getOffset(opcode);
291
292 if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
293
294 Fd = getFd(opcode);
295 for (i=getRegisterCount(opcode);i>0;i--)
296 {
297 loadMultiple(Fd,pAddress);
298 pAddress += 3; Fd++;
299 if (Fd == 8) Fd = 0;
300 }
301
302 if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
303 return 1;
304}
305
306unsigned int PerformSFM(const unsigned int opcode)
307{
308 unsigned int i, Fd, *pBase, *pAddress, *pFinal,
309 write_back = WRITE_BACK(opcode);
310
311 pBase = (unsigned int*)readRegister(getRn(opcode));
312 if (REG_PC == getRn(opcode))
313 {
314 pBase += 2;
315 write_back = 0;
316 }
317
318 pFinal = pBase;
319 if (BIT_UP_SET(opcode))
320 pFinal += getOffset(opcode);
321 else
322 pFinal -= getOffset(opcode);
323
324 if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
325
326 Fd = getFd(opcode);
327 for (i=getRegisterCount(opcode);i>0;i--)
328 {
329 storeMultiple(Fd,pAddress);
330 pAddress += 3; Fd++;
331 if (Fd == 8) Fd = 0;
332 }
333
334 if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
335 return 1;
336}
337
338#if 1
339unsigned int EmulateCPDT(const unsigned int opcode)
340{
341 unsigned int nRc = 0;
342
343 //printk("EmulateCPDT(0x%08x)\n",opcode);
344
345 if (LDF_OP(opcode))
346 {
347 nRc = PerformLDF(opcode);
348 }
349 else if (LFM_OP(opcode))
350 {
351 nRc = PerformLFM(opcode);
352 }
353 else if (STF_OP(opcode))
354 {
355 nRc = PerformSTF(opcode);
356 }
357 else if (SFM_OP(opcode))
358 {
359 nRc = PerformSFM(opcode);
360 }
361 else
362 {
363 nRc = 0;
364 }
365
366 return nRc;
367}
368#endif