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