blob: 007a3d65052e526db08f02df79db5896a73741f1 [file] [log] [blame]
bellard00406df2004-02-16 21:43:58 +00001/*
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
Blue Swirl70539e12010-03-07 15:48:43 +000019 along with this program; if not, see <http://www.gnu.org/licenses/>.
bellard00406df2004-02-16 21:43:58 +000020*/
21
22#include "fpa11.h"
Paolo Bonzini6b4c3052012-10-24 13:12:00 +020023#include "fpu/softfloat.h"
bellard00406df2004-02-16 21:43:58 +000024#include "fpopcode.h"
25//#include "fpmodule.h"
26//#include "fpmodule.inl"
27
28//#include <asm/uaccess.h>
29
30static inline
Paul Brook65a650c2009-05-04 15:19:04 +010031void loadSingle(const unsigned int Fn, target_ulong addr)
bellard00406df2004-02-16 21:43:58 +000032{
33 FPA11 *fpa11 = GET_FPA11();
34 fpa11->fType[Fn] = typeSingle;
bellard2f619692007-11-16 10:46:05 +000035 /* FIXME - handle failure of get_user() */
Peter Maydell005e1a02011-02-10 13:59:35 +000036 get_user_u32(float32_val(fpa11->fpreg[Fn].fSingle), addr);
bellard00406df2004-02-16 21:43:58 +000037}
38
39static inline
Paul Brook65a650c2009-05-04 15:19:04 +010040void loadDouble(const unsigned int Fn, target_ulong addr)
bellard00406df2004-02-16 21:43:58 +000041{
42 FPA11 *fpa11 = GET_FPA11();
43 unsigned int *p;
44 p = (unsigned int*)&fpa11->fpreg[Fn].fDouble;
45 fpa11->fType[Fn] = typeDouble;
Juan Quintelae2542fe2009-07-27 16:13:06 +020046#ifdef HOST_WORDS_BIGENDIAN
bellard2f619692007-11-16 10:46:05 +000047 /* FIXME - handle failure of get_user() */
48 get_user_u32(p[0], addr); /* sign & exponent */
49 get_user_u32(p[1], addr + 4);
bellarda8d34312005-02-07 12:43:57 +000050#else
bellard2f619692007-11-16 10:46:05 +000051 /* FIXME - handle failure of get_user() */
52 get_user_u32(p[0], addr + 4);
53 get_user_u32(p[1], addr); /* sign & exponent */
bellarda8d34312005-02-07 12:43:57 +000054#endif
ths3b46e622007-09-17 08:09:54 +000055}
bellard00406df2004-02-16 21:43:58 +000056
57static inline
Paul Brook65a650c2009-05-04 15:19:04 +010058void loadExtended(const unsigned int Fn, target_ulong addr)
bellard00406df2004-02-16 21:43:58 +000059{
60 FPA11 *fpa11 = GET_FPA11();
61 unsigned int *p;
62 p = (unsigned int*)&fpa11->fpreg[Fn].fExtended;
63 fpa11->fType[Fn] = typeExtended;
bellard2f619692007-11-16 10:46:05 +000064 /* FIXME - handle failure of get_user() */
65 get_user_u32(p[0], addr); /* sign & exponent */
66 get_user_u32(p[1], addr + 8); /* ls bits */
67 get_user_u32(p[2], addr + 4); /* ms bits */
ths3b46e622007-09-17 08:09:54 +000068}
bellard00406df2004-02-16 21:43:58 +000069
70static inline
Paul Brook65a650c2009-05-04 15:19:04 +010071void loadMultiple(const unsigned int Fn, target_ulong addr)
bellard00406df2004-02-16 21:43:58 +000072{
73 FPA11 *fpa11 = GET_FPA11();
74 register unsigned int *p;
75 unsigned long x;
76
77 p = (unsigned int*)&(fpa11->fpreg[Fn]);
bellard2f619692007-11-16 10:46:05 +000078 /* FIXME - handle failure of get_user() */
79 get_user_u32(x, addr);
bellard00406df2004-02-16 21:43:58 +000080 fpa11->fType[Fn] = (x >> 14) & 0x00000003;
ths3b46e622007-09-17 08:09:54 +000081
bellard00406df2004-02-16 21:43:58 +000082 switch (fpa11->fType[Fn])
83 {
84 case typeSingle:
85 case typeDouble:
86 {
bellard2f619692007-11-16 10:46:05 +000087 /* FIXME - handle failure of get_user() */
88 get_user_u32(p[0], addr + 8); /* Single */
89 get_user_u32(p[1], addr + 4); /* double msw */
bellard00406df2004-02-16 21:43:58 +000090 p[2] = 0; /* empty */
91 }
ths5fafdf22007-09-16 21:08:06 +000092 break;
ths3b46e622007-09-17 08:09:54 +000093
bellard00406df2004-02-16 21:43:58 +000094 case typeExtended:
95 {
bellard2f619692007-11-16 10:46:05 +000096 /* FIXME - handle failure of get_user() */
97 get_user_u32(p[1], addr + 8);
98 get_user_u32(p[2], addr + 4); /* msw */
ths3b46e622007-09-17 08:09:54 +000099 p[0] = (x & 0x80003fff);
bellard00406df2004-02-16 21:43:58 +0000100 }
101 break;
102 }
103}
104
105static inline
Paul Brook65a650c2009-05-04 15:19:04 +0100106void storeSingle(const unsigned int Fn, target_ulong addr)
bellard00406df2004-02-16 21:43:58 +0000107{
108 FPA11 *fpa11 = GET_FPA11();
109 float32 val;
110 register unsigned int *p = (unsigned int*)&val;
ths3b46e622007-09-17 08:09:54 +0000111
bellard00406df2004-02-16 21:43:58 +0000112 switch (fpa11->fType[Fn])
113 {
ths5fafdf22007-09-16 21:08:06 +0000114 case typeDouble:
bellard20495212005-03-13 16:55:58 +0000115 val = float64_to_float32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
bellard00406df2004-02-16 21:43:58 +0000116 break;
117
ths5fafdf22007-09-16 21:08:06 +0000118 case typeExtended:
bellard20495212005-03-13 16:55:58 +0000119 val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status);
bellard00406df2004-02-16 21:43:58 +0000120 break;
121
122 default: val = fpa11->fpreg[Fn].fSingle;
123 }
ths3b46e622007-09-17 08:09:54 +0000124
bellard2f619692007-11-16 10:46:05 +0000125 /* FIXME - handle put_user() failures */
126 put_user_u32(p[0], addr);
ths3b46e622007-09-17 08:09:54 +0000127}
bellard00406df2004-02-16 21:43:58 +0000128
129static inline
Paul Brook65a650c2009-05-04 15:19:04 +0100130void storeDouble(const unsigned int Fn, target_ulong addr)
bellard00406df2004-02-16 21:43:58 +0000131{
132 FPA11 *fpa11 = GET_FPA11();
133 float64 val;
134 register unsigned int *p = (unsigned int*)&val;
135
136 switch (fpa11->fType[Fn])
137 {
ths5fafdf22007-09-16 21:08:06 +0000138 case typeSingle:
bellard20495212005-03-13 16:55:58 +0000139 val = float32_to_float64(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
bellard00406df2004-02-16 21:43:58 +0000140 break;
141
142 case typeExtended:
bellard20495212005-03-13 16:55:58 +0000143 val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status);
bellard00406df2004-02-16 21:43:58 +0000144 break;
145
146 default: val = fpa11->fpreg[Fn].fDouble;
147 }
bellard2f619692007-11-16 10:46:05 +0000148 /* FIXME - handle put_user() failures */
Juan Quintelae2542fe2009-07-27 16:13:06 +0200149#ifdef HOST_WORDS_BIGENDIAN
bellard2f619692007-11-16 10:46:05 +0000150 put_user_u32(p[0], addr); /* msw */
151 put_user_u32(p[1], addr + 4); /* lsw */
bellarda8d34312005-02-07 12:43:57 +0000152#else
bellard2f619692007-11-16 10:46:05 +0000153 put_user_u32(p[1], addr); /* msw */
154 put_user_u32(p[0], addr + 4); /* lsw */
bellarda8d34312005-02-07 12:43:57 +0000155#endif
ths3b46e622007-09-17 08:09:54 +0000156}
bellard00406df2004-02-16 21:43:58 +0000157
158static inline
Paul Brook65a650c2009-05-04 15:19:04 +0100159void storeExtended(const unsigned int Fn, target_ulong addr)
bellard00406df2004-02-16 21:43:58 +0000160{
161 FPA11 *fpa11 = GET_FPA11();
162 floatx80 val;
163 register unsigned int *p = (unsigned int*)&val;
ths3b46e622007-09-17 08:09:54 +0000164
bellard00406df2004-02-16 21:43:58 +0000165 switch (fpa11->fType[Fn])
166 {
ths5fafdf22007-09-16 21:08:06 +0000167 case typeSingle:
bellard20495212005-03-13 16:55:58 +0000168 val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
bellard00406df2004-02-16 21:43:58 +0000169 break;
170
ths5fafdf22007-09-16 21:08:06 +0000171 case typeDouble:
bellard20495212005-03-13 16:55:58 +0000172 val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
bellard00406df2004-02-16 21:43:58 +0000173 break;
174
175 default: val = fpa11->fpreg[Fn].fExtended;
176 }
ths3b46e622007-09-17 08:09:54 +0000177
bellard2f619692007-11-16 10:46:05 +0000178 /* FIXME - handle put_user() failures */
179 put_user_u32(p[0], addr); /* sign & exp */
180 put_user_u32(p[1], addr + 8);
181 put_user_u32(p[2], addr + 4); /* msw */
ths3b46e622007-09-17 08:09:54 +0000182}
bellard00406df2004-02-16 21:43:58 +0000183
184static inline
Paul Brook65a650c2009-05-04 15:19:04 +0100185void storeMultiple(const unsigned int Fn, target_ulong addr)
bellard00406df2004-02-16 21:43:58 +0000186{
187 FPA11 *fpa11 = GET_FPA11();
188 register unsigned int nType, *p;
ths3b46e622007-09-17 08:09:54 +0000189
bellard00406df2004-02-16 21:43:58 +0000190 p = (unsigned int*)&(fpa11->fpreg[Fn]);
191 nType = fpa11->fType[Fn];
ths3b46e622007-09-17 08:09:54 +0000192
bellard00406df2004-02-16 21:43:58 +0000193 switch (nType)
194 {
195 case typeSingle:
196 case typeDouble:
197 {
bellard2f619692007-11-16 10:46:05 +0000198 put_user_u32(p[0], addr + 8); /* single */
199 put_user_u32(p[1], addr + 4); /* double msw */
200 put_user_u32(nType << 14, addr);
bellard00406df2004-02-16 21:43:58 +0000201 }
ths5fafdf22007-09-16 21:08:06 +0000202 break;
ths3b46e622007-09-17 08:09:54 +0000203
bellard00406df2004-02-16 21:43:58 +0000204 case typeExtended:
205 {
bellard2f619692007-11-16 10:46:05 +0000206 put_user_u32(p[2], addr + 4); /* msw */
207 put_user_u32(p[1], addr + 8);
208 put_user_u32((p[0] & 0x80003fff) | (nType << 14), addr);
bellard00406df2004-02-16 21:43:58 +0000209 }
210 break;
211 }
212}
213
Paul Brook65a650c2009-05-04 15:19:04 +0100214static unsigned int PerformLDF(const unsigned int opcode)
bellard00406df2004-02-16 21:43:58 +0000215{
Paul Brook65a650c2009-05-04 15:19:04 +0100216 target_ulong pBase, pAddress, pFinal;
217 unsigned int nRc = 1,
bellard00406df2004-02-16 21:43:58 +0000218 write_back = WRITE_BACK(opcode);
219
220 //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
221
Paul Brook65a650c2009-05-04 15:19:04 +0100222 pBase = readRegister(getRn(opcode));
Peter Maydell7cb4db82011-04-20 11:19:15 +0100223 if (ARM_REG_PC == getRn(opcode))
bellard00406df2004-02-16 21:43:58 +0000224 {
Paul Brook65a650c2009-05-04 15:19:04 +0100225 pBase += 8;
bellard00406df2004-02-16 21:43:58 +0000226 write_back = 0;
227 }
228
229 pFinal = pBase;
230 if (BIT_UP_SET(opcode))
Paul Brook65a650c2009-05-04 15:19:04 +0100231 pFinal += getOffset(opcode) * 4;
bellard00406df2004-02-16 21:43:58 +0000232 else
Paul Brook65a650c2009-05-04 15:19:04 +0100233 pFinal -= getOffset(opcode) * 4;
bellard00406df2004-02-16 21:43:58 +0000234
235 if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
236
237 switch (opcode & MASK_TRANSFER_LENGTH)
238 {
239 case TRANSFER_SINGLE : loadSingle(getFd(opcode),pAddress); break;
240 case TRANSFER_DOUBLE : loadDouble(getFd(opcode),pAddress); break;
241 case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break;
242 default: nRc = 0;
243 }
ths3b46e622007-09-17 08:09:54 +0000244
bellard00406df2004-02-16 21:43:58 +0000245 if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
246 return nRc;
247}
248
Paul Brook65a650c2009-05-04 15:19:04 +0100249static unsigned int PerformSTF(const unsigned int opcode)
bellard00406df2004-02-16 21:43:58 +0000250{
Paul Brook65a650c2009-05-04 15:19:04 +0100251 target_ulong pBase, pAddress, pFinal;
252 unsigned int nRc = 1,
bellard00406df2004-02-16 21:43:58 +0000253 write_back = WRITE_BACK(opcode);
ths3b46e622007-09-17 08:09:54 +0000254
bellard00406df2004-02-16 21:43:58 +0000255 //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
256 SetRoundingMode(ROUND_TO_NEAREST);
ths3b46e622007-09-17 08:09:54 +0000257
Paul Brook65a650c2009-05-04 15:19:04 +0100258 pBase = readRegister(getRn(opcode));
Peter Maydell7cb4db82011-04-20 11:19:15 +0100259 if (ARM_REG_PC == getRn(opcode))
bellard00406df2004-02-16 21:43:58 +0000260 {
Paul Brook65a650c2009-05-04 15:19:04 +0100261 pBase += 8;
bellard00406df2004-02-16 21:43:58 +0000262 write_back = 0;
263 }
264
265 pFinal = pBase;
266 if (BIT_UP_SET(opcode))
Paul Brook65a650c2009-05-04 15:19:04 +0100267 pFinal += getOffset(opcode) * 4;
bellard00406df2004-02-16 21:43:58 +0000268 else
Paul Brook65a650c2009-05-04 15:19:04 +0100269 pFinal -= getOffset(opcode) * 4;
bellard00406df2004-02-16 21:43:58 +0000270
271 if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
272
273 switch (opcode & MASK_TRANSFER_LENGTH)
274 {
275 case TRANSFER_SINGLE : storeSingle(getFd(opcode),pAddress); break;
276 case TRANSFER_DOUBLE : storeDouble(getFd(opcode),pAddress); break;
277 case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break;
278 default: nRc = 0;
279 }
ths3b46e622007-09-17 08:09:54 +0000280
bellard00406df2004-02-16 21:43:58 +0000281 if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
282 return nRc;
283}
284
Paul Brook65a650c2009-05-04 15:19:04 +0100285static unsigned int PerformLFM(const unsigned int opcode)
bellard00406df2004-02-16 21:43:58 +0000286{
Paul Brook65a650c2009-05-04 15:19:04 +0100287 unsigned int i, Fd,
bellard00406df2004-02-16 21:43:58 +0000288 write_back = WRITE_BACK(opcode);
Paul Brook65a650c2009-05-04 15:19:04 +0100289 target_ulong pBase, pAddress, pFinal;
bellard00406df2004-02-16 21:43:58 +0000290
Paul Brook65a650c2009-05-04 15:19:04 +0100291 pBase = readRegister(getRn(opcode));
Peter Maydell7cb4db82011-04-20 11:19:15 +0100292 if (ARM_REG_PC == getRn(opcode))
bellard00406df2004-02-16 21:43:58 +0000293 {
Paul Brook65a650c2009-05-04 15:19:04 +0100294 pBase += 8;
bellard00406df2004-02-16 21:43:58 +0000295 write_back = 0;
296 }
297
298 pFinal = pBase;
299 if (BIT_UP_SET(opcode))
Paul Brook65a650c2009-05-04 15:19:04 +0100300 pFinal += getOffset(opcode) * 4;
bellard00406df2004-02-16 21:43:58 +0000301 else
Paul Brook65a650c2009-05-04 15:19:04 +0100302 pFinal -= getOffset(opcode) * 4;
bellard00406df2004-02-16 21:43:58 +0000303
304 if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
305
306 Fd = getFd(opcode);
307 for (i=getRegisterCount(opcode);i>0;i--)
308 {
309 loadMultiple(Fd,pAddress);
Paul Brook65a650c2009-05-04 15:19:04 +0100310 pAddress += 12; Fd++;
bellard00406df2004-02-16 21:43:58 +0000311 if (Fd == 8) Fd = 0;
312 }
313
314 if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
315 return 1;
316}
317
Paul Brook65a650c2009-05-04 15:19:04 +0100318static unsigned int PerformSFM(const unsigned int opcode)
bellard00406df2004-02-16 21:43:58 +0000319{
Paul Brook65a650c2009-05-04 15:19:04 +0100320 unsigned int i, Fd,
bellard00406df2004-02-16 21:43:58 +0000321 write_back = WRITE_BACK(opcode);
Paul Brook65a650c2009-05-04 15:19:04 +0100322 target_ulong pBase, pAddress, pFinal;
ths3b46e622007-09-17 08:09:54 +0000323
Paul Brook65a650c2009-05-04 15:19:04 +0100324 pBase = readRegister(getRn(opcode));
Peter Maydell7cb4db82011-04-20 11:19:15 +0100325 if (ARM_REG_PC == getRn(opcode))
bellard00406df2004-02-16 21:43:58 +0000326 {
Paul Brook65a650c2009-05-04 15:19:04 +0100327 pBase += 8;
bellard00406df2004-02-16 21:43:58 +0000328 write_back = 0;
329 }
ths3b46e622007-09-17 08:09:54 +0000330
bellard00406df2004-02-16 21:43:58 +0000331 pFinal = pBase;
332 if (BIT_UP_SET(opcode))
Paul Brook65a650c2009-05-04 15:19:04 +0100333 pFinal += getOffset(opcode) * 4;
bellard00406df2004-02-16 21:43:58 +0000334 else
Paul Brook65a650c2009-05-04 15:19:04 +0100335 pFinal -= getOffset(opcode) * 4;
bellard00406df2004-02-16 21:43:58 +0000336
337 if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
338
339 Fd = getFd(opcode);
340 for (i=getRegisterCount(opcode);i>0;i--)
341 {
342 storeMultiple(Fd,pAddress);
Paul Brook65a650c2009-05-04 15:19:04 +0100343 pAddress += 12; Fd++;
bellard00406df2004-02-16 21:43:58 +0000344 if (Fd == 8) Fd = 0;
345 }
346
347 if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
348 return 1;
349}
350
351#if 1
352unsigned int EmulateCPDT(const unsigned int opcode)
353{
354 unsigned int nRc = 0;
355
356 //printk("EmulateCPDT(0x%08x)\n",opcode);
ths3b46e622007-09-17 08:09:54 +0000357
bellard00406df2004-02-16 21:43:58 +0000358 if (LDF_OP(opcode))
359 {
360 nRc = PerformLDF(opcode);
361 }
362 else if (LFM_OP(opcode))
363 {
364 nRc = PerformLFM(opcode);
365 }
366 else if (STF_OP(opcode))
367 {
368 nRc = PerformSTF(opcode);
ths5fafdf22007-09-16 21:08:06 +0000369 }
bellard00406df2004-02-16 21:43:58 +0000370 else if (SFM_OP(opcode))
371 {
372 nRc = PerformSFM(opcode);
373 }
374 else
375 {
376 nRc = 0;
377 }
ths3b46e622007-09-17 08:09:54 +0000378
bellard00406df2004-02-16 21:43:58 +0000379 return nRc;
380}
381#endif