13ebdd119Saurel32 /*
23ebdd119Saurel32 NetWinder Floating Point Emulator
33ebdd119Saurel32 (c) Rebel.com, 1998-1999
43ebdd119Saurel32 (c) Philip Blundell, 1998
53ebdd119Saurel32
63ebdd119Saurel32 Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
73ebdd119Saurel32
83ebdd119Saurel32 This program is free software; you can redistribute it and/or modify
93ebdd119Saurel32 it under the terms of the GNU General Public License as published by
103ebdd119Saurel32 the Free Software Foundation; either version 2 of the License, or
113ebdd119Saurel32 (at your option) any later version.
123ebdd119Saurel32
133ebdd119Saurel32 This program is distributed in the hope that it will be useful,
143ebdd119Saurel32 but WITHOUT ANY WARRANTY; without even the implied warranty of
153ebdd119Saurel32 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
163ebdd119Saurel32 GNU General Public License for more details.
173ebdd119Saurel32
183ebdd119Saurel32 You should have received a copy of the GNU General Public License
1970539e18SBlue Swirl along with this program; if not, see <http://www.gnu.org/licenses/>.
203ebdd119Saurel32 */
213ebdd119Saurel32
22d39594e9SPeter Maydell #include "qemu/osdep.h"
233ebdd119Saurel32 #include "fpa11.h"
246b4c305cSPaolo Bonzini #include "fpu/softfloat.h"
253ebdd119Saurel32 #include "fpopcode.h"
263ebdd119Saurel32 //#include "fpmodule.h"
273ebdd119Saurel32 //#include "fpmodule.inl"
283ebdd119Saurel32
293ebdd119Saurel32 //#include <asm/uaccess.h>
303ebdd119Saurel32
313ebdd119Saurel32 static inline
loadSingle(const unsigned int Fn,target_ulong addr)3265a650c2SPaul Brook void loadSingle(const unsigned int Fn, target_ulong addr)
333ebdd119Saurel32 {
343ebdd119Saurel32 FPA11 *fpa11 = GET_FPA11();
353ebdd119Saurel32 fpa11->fType[Fn] = typeSingle;
363ebdd119Saurel32 /* FIXME - handle failure of get_user() */
37005e1a0aSPeter Maydell get_user_u32(float32_val(fpa11->fpreg[Fn].fSingle), addr);
383ebdd119Saurel32 }
393ebdd119Saurel32
403ebdd119Saurel32 static inline
loadDouble(const unsigned int Fn,target_ulong addr)4165a650c2SPaul Brook void loadDouble(const unsigned int Fn, target_ulong addr)
423ebdd119Saurel32 {
433ebdd119Saurel32 FPA11 *fpa11 = GET_FPA11();
443ebdd119Saurel32 unsigned int *p;
453ebdd119Saurel32 p = (unsigned int*)&fpa11->fpreg[Fn].fDouble;
463ebdd119Saurel32 fpa11->fType[Fn] = typeDouble;
47*e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
483ebdd119Saurel32 /* FIXME - handle failure of get_user() */
493ebdd119Saurel32 get_user_u32(p[0], addr); /* sign & exponent */
503ebdd119Saurel32 get_user_u32(p[1], addr + 4);
513ebdd119Saurel32 #else
523ebdd119Saurel32 /* FIXME - handle failure of get_user() */
533ebdd119Saurel32 get_user_u32(p[0], addr + 4);
543ebdd119Saurel32 get_user_u32(p[1], addr); /* sign & exponent */
553ebdd119Saurel32 #endif
563ebdd119Saurel32 }
573ebdd119Saurel32
583ebdd119Saurel32 static inline
loadExtended(const unsigned int Fn,target_ulong addr)5965a650c2SPaul Brook void loadExtended(const unsigned int Fn, target_ulong addr)
603ebdd119Saurel32 {
613ebdd119Saurel32 FPA11 *fpa11 = GET_FPA11();
623ebdd119Saurel32 unsigned int *p;
633ebdd119Saurel32 p = (unsigned int*)&fpa11->fpreg[Fn].fExtended;
643ebdd119Saurel32 fpa11->fType[Fn] = typeExtended;
653ebdd119Saurel32 /* FIXME - handle failure of get_user() */
663ebdd119Saurel32 get_user_u32(p[0], addr); /* sign & exponent */
673ebdd119Saurel32 get_user_u32(p[1], addr + 8); /* ls bits */
683ebdd119Saurel32 get_user_u32(p[2], addr + 4); /* ms bits */
693ebdd119Saurel32 }
703ebdd119Saurel32
713ebdd119Saurel32 static inline
loadMultiple(const unsigned int Fn,target_ulong addr)7265a650c2SPaul Brook void loadMultiple(const unsigned int Fn, target_ulong addr)
733ebdd119Saurel32 {
743ebdd119Saurel32 FPA11 *fpa11 = GET_FPA11();
753ebdd119Saurel32 register unsigned int *p;
763ebdd119Saurel32 unsigned long x;
773ebdd119Saurel32
783ebdd119Saurel32 p = (unsigned int*)&(fpa11->fpreg[Fn]);
793ebdd119Saurel32 /* FIXME - handle failure of get_user() */
803ebdd119Saurel32 get_user_u32(x, addr);
813ebdd119Saurel32 fpa11->fType[Fn] = (x >> 14) & 0x00000003;
823ebdd119Saurel32
833ebdd119Saurel32 switch (fpa11->fType[Fn])
843ebdd119Saurel32 {
853ebdd119Saurel32 case typeSingle:
863ebdd119Saurel32 case typeDouble:
873ebdd119Saurel32 {
883ebdd119Saurel32 /* FIXME - handle failure of get_user() */
893ebdd119Saurel32 get_user_u32(p[0], addr + 8); /* Single */
903ebdd119Saurel32 get_user_u32(p[1], addr + 4); /* double msw */
913ebdd119Saurel32 p[2] = 0; /* empty */
923ebdd119Saurel32 }
933ebdd119Saurel32 break;
943ebdd119Saurel32
953ebdd119Saurel32 case typeExtended:
963ebdd119Saurel32 {
973ebdd119Saurel32 /* FIXME - handle failure of get_user() */
983ebdd119Saurel32 get_user_u32(p[1], addr + 8);
993ebdd119Saurel32 get_user_u32(p[2], addr + 4); /* msw */
1003ebdd119Saurel32 p[0] = (x & 0x80003fff);
1013ebdd119Saurel32 }
1023ebdd119Saurel32 break;
1033ebdd119Saurel32 }
1043ebdd119Saurel32 }
1053ebdd119Saurel32
1063ebdd119Saurel32 static inline
storeSingle(const unsigned int Fn,target_ulong addr)10765a650c2SPaul Brook void storeSingle(const unsigned int Fn, target_ulong addr)
1083ebdd119Saurel32 {
1093ebdd119Saurel32 FPA11 *fpa11 = GET_FPA11();
1103ebdd119Saurel32 float32 val;
1113ebdd119Saurel32 register unsigned int *p = (unsigned int*)&val;
1123ebdd119Saurel32
1133ebdd119Saurel32 switch (fpa11->fType[Fn])
1143ebdd119Saurel32 {
1153ebdd119Saurel32 case typeDouble:
1163ebdd119Saurel32 val = float64_to_float32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
1173ebdd119Saurel32 break;
1183ebdd119Saurel32
1193ebdd119Saurel32 case typeExtended:
1203ebdd119Saurel32 val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status);
1213ebdd119Saurel32 break;
1223ebdd119Saurel32
1233ebdd119Saurel32 default: val = fpa11->fpreg[Fn].fSingle;
1243ebdd119Saurel32 }
1253ebdd119Saurel32
1263ebdd119Saurel32 /* FIXME - handle put_user() failures */
1273ebdd119Saurel32 put_user_u32(p[0], addr);
1283ebdd119Saurel32 }
1293ebdd119Saurel32
1303ebdd119Saurel32 static inline
storeDouble(const unsigned int Fn,target_ulong addr)13165a650c2SPaul Brook void storeDouble(const unsigned int Fn, target_ulong addr)
1323ebdd119Saurel32 {
1333ebdd119Saurel32 FPA11 *fpa11 = GET_FPA11();
1343ebdd119Saurel32 float64 val;
1353ebdd119Saurel32 register unsigned int *p = (unsigned int*)&val;
1363ebdd119Saurel32
1373ebdd119Saurel32 switch (fpa11->fType[Fn])
1383ebdd119Saurel32 {
1393ebdd119Saurel32 case typeSingle:
1403ebdd119Saurel32 val = float32_to_float64(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
1413ebdd119Saurel32 break;
1423ebdd119Saurel32
1433ebdd119Saurel32 case typeExtended:
1443ebdd119Saurel32 val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status);
1453ebdd119Saurel32 break;
1463ebdd119Saurel32
1473ebdd119Saurel32 default: val = fpa11->fpreg[Fn].fDouble;
1483ebdd119Saurel32 }
1493ebdd119Saurel32 /* FIXME - handle put_user() failures */
150*e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
1513ebdd119Saurel32 put_user_u32(p[0], addr); /* msw */
1523ebdd119Saurel32 put_user_u32(p[1], addr + 4); /* lsw */
1533ebdd119Saurel32 #else
1543ebdd119Saurel32 put_user_u32(p[1], addr); /* msw */
1553ebdd119Saurel32 put_user_u32(p[0], addr + 4); /* lsw */
1563ebdd119Saurel32 #endif
1573ebdd119Saurel32 }
1583ebdd119Saurel32
1593ebdd119Saurel32 static inline
storeExtended(const unsigned int Fn,target_ulong addr)16065a650c2SPaul Brook void storeExtended(const unsigned int Fn, target_ulong addr)
1613ebdd119Saurel32 {
1623ebdd119Saurel32 FPA11 *fpa11 = GET_FPA11();
1633ebdd119Saurel32 floatx80 val;
1643ebdd119Saurel32 register unsigned int *p = (unsigned int*)&val;
1653ebdd119Saurel32
1663ebdd119Saurel32 switch (fpa11->fType[Fn])
1673ebdd119Saurel32 {
1683ebdd119Saurel32 case typeSingle:
1693ebdd119Saurel32 val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
1703ebdd119Saurel32 break;
1713ebdd119Saurel32
1723ebdd119Saurel32 case typeDouble:
1733ebdd119Saurel32 val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
1743ebdd119Saurel32 break;
1753ebdd119Saurel32
1763ebdd119Saurel32 default: val = fpa11->fpreg[Fn].fExtended;
1773ebdd119Saurel32 }
1783ebdd119Saurel32
1793ebdd119Saurel32 /* FIXME - handle put_user() failures */
1803ebdd119Saurel32 put_user_u32(p[0], addr); /* sign & exp */
1813ebdd119Saurel32 put_user_u32(p[1], addr + 8);
1823ebdd119Saurel32 put_user_u32(p[2], addr + 4); /* msw */
1833ebdd119Saurel32 }
1843ebdd119Saurel32
1853ebdd119Saurel32 static inline
storeMultiple(const unsigned int Fn,target_ulong addr)18665a650c2SPaul Brook void storeMultiple(const unsigned int Fn, target_ulong addr)
1873ebdd119Saurel32 {
1883ebdd119Saurel32 FPA11 *fpa11 = GET_FPA11();
1893ebdd119Saurel32 register unsigned int nType, *p;
1903ebdd119Saurel32
1913ebdd119Saurel32 p = (unsigned int*)&(fpa11->fpreg[Fn]);
1923ebdd119Saurel32 nType = fpa11->fType[Fn];
1933ebdd119Saurel32
1943ebdd119Saurel32 switch (nType)
1953ebdd119Saurel32 {
1963ebdd119Saurel32 case typeSingle:
1973ebdd119Saurel32 case typeDouble:
1983ebdd119Saurel32 {
1993ebdd119Saurel32 put_user_u32(p[0], addr + 8); /* single */
2003ebdd119Saurel32 put_user_u32(p[1], addr + 4); /* double msw */
2013ebdd119Saurel32 put_user_u32(nType << 14, addr);
2023ebdd119Saurel32 }
2033ebdd119Saurel32 break;
2043ebdd119Saurel32
2053ebdd119Saurel32 case typeExtended:
2063ebdd119Saurel32 {
2073ebdd119Saurel32 put_user_u32(p[2], addr + 4); /* msw */
2083ebdd119Saurel32 put_user_u32(p[1], addr + 8);
2093ebdd119Saurel32 put_user_u32((p[0] & 0x80003fff) | (nType << 14), addr);
2103ebdd119Saurel32 }
2113ebdd119Saurel32 break;
2123ebdd119Saurel32 }
2133ebdd119Saurel32 }
2143ebdd119Saurel32
PerformLDF(const unsigned int opcode)21565a650c2SPaul Brook static unsigned int PerformLDF(const unsigned int opcode)
2163ebdd119Saurel32 {
21765a650c2SPaul Brook target_ulong pBase, pAddress, pFinal;
21865a650c2SPaul Brook unsigned int nRc = 1,
2193ebdd119Saurel32 write_back = WRITE_BACK(opcode);
2203ebdd119Saurel32
2213ebdd119Saurel32 //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
2223ebdd119Saurel32
22365a650c2SPaul Brook pBase = readRegister(getRn(opcode));
2247cb4db8fSPeter Maydell if (ARM_REG_PC == getRn(opcode))
2253ebdd119Saurel32 {
22665a650c2SPaul Brook pBase += 8;
2273ebdd119Saurel32 write_back = 0;
2283ebdd119Saurel32 }
2293ebdd119Saurel32
2303ebdd119Saurel32 pFinal = pBase;
2313ebdd119Saurel32 if (BIT_UP_SET(opcode))
23265a650c2SPaul Brook pFinal += getOffset(opcode) * 4;
2333ebdd119Saurel32 else
23465a650c2SPaul Brook pFinal -= getOffset(opcode) * 4;
2353ebdd119Saurel32
2363ebdd119Saurel32 if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
2373ebdd119Saurel32
2383ebdd119Saurel32 switch (opcode & MASK_TRANSFER_LENGTH)
2393ebdd119Saurel32 {
2403ebdd119Saurel32 case TRANSFER_SINGLE : loadSingle(getFd(opcode),pAddress); break;
2413ebdd119Saurel32 case TRANSFER_DOUBLE : loadDouble(getFd(opcode),pAddress); break;
2423ebdd119Saurel32 case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break;
2433ebdd119Saurel32 default: nRc = 0;
2443ebdd119Saurel32 }
2453ebdd119Saurel32
2463ebdd119Saurel32 if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
2473ebdd119Saurel32 return nRc;
2483ebdd119Saurel32 }
2493ebdd119Saurel32
PerformSTF(const unsigned int opcode)25065a650c2SPaul Brook static unsigned int PerformSTF(const unsigned int opcode)
2513ebdd119Saurel32 {
25265a650c2SPaul Brook target_ulong pBase, pAddress, pFinal;
25365a650c2SPaul Brook unsigned int nRc = 1,
2543ebdd119Saurel32 write_back = WRITE_BACK(opcode);
2553ebdd119Saurel32
2563ebdd119Saurel32 //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
2573ebdd119Saurel32 SetRoundingMode(ROUND_TO_NEAREST);
2583ebdd119Saurel32
25965a650c2SPaul Brook pBase = readRegister(getRn(opcode));
2607cb4db8fSPeter Maydell if (ARM_REG_PC == getRn(opcode))
2613ebdd119Saurel32 {
26265a650c2SPaul Brook pBase += 8;
2633ebdd119Saurel32 write_back = 0;
2643ebdd119Saurel32 }
2653ebdd119Saurel32
2663ebdd119Saurel32 pFinal = pBase;
2673ebdd119Saurel32 if (BIT_UP_SET(opcode))
26865a650c2SPaul Brook pFinal += getOffset(opcode) * 4;
2693ebdd119Saurel32 else
27065a650c2SPaul Brook pFinal -= getOffset(opcode) * 4;
2713ebdd119Saurel32
2723ebdd119Saurel32 if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
2733ebdd119Saurel32
2743ebdd119Saurel32 switch (opcode & MASK_TRANSFER_LENGTH)
2753ebdd119Saurel32 {
2763ebdd119Saurel32 case TRANSFER_SINGLE : storeSingle(getFd(opcode),pAddress); break;
2773ebdd119Saurel32 case TRANSFER_DOUBLE : storeDouble(getFd(opcode),pAddress); break;
2783ebdd119Saurel32 case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break;
2793ebdd119Saurel32 default: nRc = 0;
2803ebdd119Saurel32 }
2813ebdd119Saurel32
2823ebdd119Saurel32 if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
2833ebdd119Saurel32 return nRc;
2843ebdd119Saurel32 }
2853ebdd119Saurel32
PerformLFM(const unsigned int opcode)28665a650c2SPaul Brook static unsigned int PerformLFM(const unsigned int opcode)
2873ebdd119Saurel32 {
28865a650c2SPaul Brook unsigned int i, Fd,
2893ebdd119Saurel32 write_back = WRITE_BACK(opcode);
29065a650c2SPaul Brook target_ulong pBase, pAddress, pFinal;
2913ebdd119Saurel32
29265a650c2SPaul Brook pBase = readRegister(getRn(opcode));
2937cb4db8fSPeter Maydell if (ARM_REG_PC == getRn(opcode))
2943ebdd119Saurel32 {
29565a650c2SPaul Brook pBase += 8;
2963ebdd119Saurel32 write_back = 0;
2973ebdd119Saurel32 }
2983ebdd119Saurel32
2993ebdd119Saurel32 pFinal = pBase;
3003ebdd119Saurel32 if (BIT_UP_SET(opcode))
30165a650c2SPaul Brook pFinal += getOffset(opcode) * 4;
3023ebdd119Saurel32 else
30365a650c2SPaul Brook pFinal -= getOffset(opcode) * 4;
3043ebdd119Saurel32
3053ebdd119Saurel32 if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
3063ebdd119Saurel32
3073ebdd119Saurel32 Fd = getFd(opcode);
3083ebdd119Saurel32 for (i=getRegisterCount(opcode);i>0;i--)
3093ebdd119Saurel32 {
3103ebdd119Saurel32 loadMultiple(Fd,pAddress);
31165a650c2SPaul Brook pAddress += 12; Fd++;
3123ebdd119Saurel32 if (Fd == 8) Fd = 0;
3133ebdd119Saurel32 }
3143ebdd119Saurel32
3153ebdd119Saurel32 if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
3163ebdd119Saurel32 return 1;
3173ebdd119Saurel32 }
3183ebdd119Saurel32
PerformSFM(const unsigned int opcode)31965a650c2SPaul Brook static unsigned int PerformSFM(const unsigned int opcode)
3203ebdd119Saurel32 {
32165a650c2SPaul Brook unsigned int i, Fd,
3223ebdd119Saurel32 write_back = WRITE_BACK(opcode);
32365a650c2SPaul Brook target_ulong pBase, pAddress, pFinal;
3243ebdd119Saurel32
32565a650c2SPaul Brook pBase = readRegister(getRn(opcode));
3267cb4db8fSPeter Maydell if (ARM_REG_PC == getRn(opcode))
3273ebdd119Saurel32 {
32865a650c2SPaul Brook pBase += 8;
3293ebdd119Saurel32 write_back = 0;
3303ebdd119Saurel32 }
3313ebdd119Saurel32
3323ebdd119Saurel32 pFinal = pBase;
3333ebdd119Saurel32 if (BIT_UP_SET(opcode))
33465a650c2SPaul Brook pFinal += getOffset(opcode) * 4;
3353ebdd119Saurel32 else
33665a650c2SPaul Brook pFinal -= getOffset(opcode) * 4;
3373ebdd119Saurel32
3383ebdd119Saurel32 if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
3393ebdd119Saurel32
3403ebdd119Saurel32 Fd = getFd(opcode);
3413ebdd119Saurel32 for (i=getRegisterCount(opcode);i>0;i--)
3423ebdd119Saurel32 {
3433ebdd119Saurel32 storeMultiple(Fd,pAddress);
34465a650c2SPaul Brook pAddress += 12; Fd++;
3453ebdd119Saurel32 if (Fd == 8) Fd = 0;
3463ebdd119Saurel32 }
3473ebdd119Saurel32
3483ebdd119Saurel32 if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
3493ebdd119Saurel32 return 1;
3503ebdd119Saurel32 }
3513ebdd119Saurel32
3523ebdd119Saurel32 #if 1
EmulateCPDT(const unsigned int opcode)3533ebdd119Saurel32 unsigned int EmulateCPDT(const unsigned int opcode)
3543ebdd119Saurel32 {
3553ebdd119Saurel32 unsigned int nRc = 0;
3563ebdd119Saurel32
3573ebdd119Saurel32 //printk("EmulateCPDT(0x%08x)\n",opcode);
3583ebdd119Saurel32
3593ebdd119Saurel32 if (LDF_OP(opcode))
3603ebdd119Saurel32 {
3613ebdd119Saurel32 nRc = PerformLDF(opcode);
3623ebdd119Saurel32 }
3633ebdd119Saurel32 else if (LFM_OP(opcode))
3643ebdd119Saurel32 {
3653ebdd119Saurel32 nRc = PerformLFM(opcode);
3663ebdd119Saurel32 }
3673ebdd119Saurel32 else if (STF_OP(opcode))
3683ebdd119Saurel32 {
3693ebdd119Saurel32 nRc = PerformSTF(opcode);
3703ebdd119Saurel32 }
3713ebdd119Saurel32 else if (SFM_OP(opcode))
3723ebdd119Saurel32 {
3733ebdd119Saurel32 nRc = PerformSFM(opcode);
3743ebdd119Saurel32 }
3753ebdd119Saurel32 else
3763ebdd119Saurel32 {
3773ebdd119Saurel32 nRc = 0;
3783ebdd119Saurel32 }
3793ebdd119Saurel32
3803ebdd119Saurel32 return nRc;
3813ebdd119Saurel32 }
3823ebdd119Saurel32 #endif
383