100406dffSbellard /*
200406dffSbellard NetWinder Floating Point Emulator
300406dffSbellard (c) Rebel.com, 1998-1999
400406dffSbellard (c) Philip Blundell, 1998
500406dffSbellard
600406dffSbellard Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
700406dffSbellard
800406dffSbellard This program is free software; you can redistribute it and/or modify
900406dffSbellard it under the terms of the GNU General Public License as published by
1000406dffSbellard the Free Software Foundation; either version 2 of the License, or
1100406dffSbellard (at your option) any later version.
1200406dffSbellard
1300406dffSbellard This program is distributed in the hope that it will be useful,
1400406dffSbellard but WITHOUT ANY WARRANTY; without even the implied warranty of
1500406dffSbellard MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1600406dffSbellard GNU General Public License for more details.
1700406dffSbellard
1800406dffSbellard 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/>.
2000406dffSbellard */
2100406dffSbellard
22d39594e9SPeter Maydell #include "qemu/osdep.h"
2300406dffSbellard #include "fpa11.h"
246b4c305cSPaolo Bonzini #include "fpu/softfloat.h"
2500406dffSbellard #include "fpopcode.h"
2600406dffSbellard //#include "fpmodule.h"
2700406dffSbellard //#include "fpmodule.inl"
2800406dffSbellard
2900406dffSbellard //#include <asm/uaccess.h>
3000406dffSbellard
3100406dffSbellard static inline
loadSingle(const unsigned int Fn,target_ulong addr)3265a650c2SPaul Brook void loadSingle(const unsigned int Fn, target_ulong addr)
3300406dffSbellard {
3400406dffSbellard FPA11 *fpa11 = GET_FPA11();
3500406dffSbellard fpa11->fType[Fn] = typeSingle;
362f619698Sbellard /* FIXME - handle failure of get_user() */
37005e1a0aSPeter Maydell get_user_u32(float32_val(fpa11->fpreg[Fn].fSingle), addr);
3800406dffSbellard }
3900406dffSbellard
4000406dffSbellard static inline
loadDouble(const unsigned int Fn,target_ulong addr)4165a650c2SPaul Brook void loadDouble(const unsigned int Fn, target_ulong addr)
4200406dffSbellard {
4300406dffSbellard FPA11 *fpa11 = GET_FPA11();
4400406dffSbellard unsigned int *p;
4500406dffSbellard p = (unsigned int*)&fpa11->fpreg[Fn].fDouble;
4600406dffSbellard fpa11->fType[Fn] = typeDouble;
47*e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
482f619698Sbellard /* FIXME - handle failure of get_user() */
492f619698Sbellard get_user_u32(p[0], addr); /* sign & exponent */
502f619698Sbellard get_user_u32(p[1], addr + 4);
51a8d3431aSbellard #else
522f619698Sbellard /* FIXME - handle failure of get_user() */
532f619698Sbellard get_user_u32(p[0], addr + 4);
542f619698Sbellard get_user_u32(p[1], addr); /* sign & exponent */
55a8d3431aSbellard #endif
5600406dffSbellard }
5700406dffSbellard
5800406dffSbellard static inline
loadExtended(const unsigned int Fn,target_ulong addr)5965a650c2SPaul Brook void loadExtended(const unsigned int Fn, target_ulong addr)
6000406dffSbellard {
6100406dffSbellard FPA11 *fpa11 = GET_FPA11();
6200406dffSbellard unsigned int *p;
6300406dffSbellard p = (unsigned int*)&fpa11->fpreg[Fn].fExtended;
6400406dffSbellard fpa11->fType[Fn] = typeExtended;
652f619698Sbellard /* FIXME - handle failure of get_user() */
662f619698Sbellard get_user_u32(p[0], addr); /* sign & exponent */
672f619698Sbellard get_user_u32(p[1], addr + 8); /* ls bits */
682f619698Sbellard get_user_u32(p[2], addr + 4); /* ms bits */
6900406dffSbellard }
7000406dffSbellard
7100406dffSbellard static inline
loadMultiple(const unsigned int Fn,target_ulong addr)7265a650c2SPaul Brook void loadMultiple(const unsigned int Fn, target_ulong addr)
7300406dffSbellard {
7400406dffSbellard FPA11 *fpa11 = GET_FPA11();
7500406dffSbellard register unsigned int *p;
7600406dffSbellard unsigned long x;
7700406dffSbellard
7800406dffSbellard p = (unsigned int*)&(fpa11->fpreg[Fn]);
792f619698Sbellard /* FIXME - handle failure of get_user() */
802f619698Sbellard get_user_u32(x, addr);
8100406dffSbellard fpa11->fType[Fn] = (x >> 14) & 0x00000003;
8200406dffSbellard
8300406dffSbellard switch (fpa11->fType[Fn])
8400406dffSbellard {
8500406dffSbellard case typeSingle:
8600406dffSbellard case typeDouble:
8700406dffSbellard {
882f619698Sbellard /* FIXME - handle failure of get_user() */
892f619698Sbellard get_user_u32(p[0], addr + 8); /* Single */
902f619698Sbellard get_user_u32(p[1], addr + 4); /* double msw */
9100406dffSbellard p[2] = 0; /* empty */
9200406dffSbellard }
9300406dffSbellard break;
9400406dffSbellard
9500406dffSbellard case typeExtended:
9600406dffSbellard {
972f619698Sbellard /* FIXME - handle failure of get_user() */
982f619698Sbellard get_user_u32(p[1], addr + 8);
992f619698Sbellard get_user_u32(p[2], addr + 4); /* msw */
10000406dffSbellard p[0] = (x & 0x80003fff);
10100406dffSbellard }
10200406dffSbellard break;
10300406dffSbellard }
10400406dffSbellard }
10500406dffSbellard
10600406dffSbellard static inline
storeSingle(const unsigned int Fn,target_ulong addr)10765a650c2SPaul Brook void storeSingle(const unsigned int Fn, target_ulong addr)
10800406dffSbellard {
10900406dffSbellard FPA11 *fpa11 = GET_FPA11();
11000406dffSbellard float32 val;
11100406dffSbellard register unsigned int *p = (unsigned int*)&val;
11200406dffSbellard
11300406dffSbellard switch (fpa11->fType[Fn])
11400406dffSbellard {
11500406dffSbellard case typeDouble:
11620495218Sbellard val = float64_to_float32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
11700406dffSbellard break;
11800406dffSbellard
11900406dffSbellard case typeExtended:
12020495218Sbellard val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status);
12100406dffSbellard break;
12200406dffSbellard
12300406dffSbellard default: val = fpa11->fpreg[Fn].fSingle;
12400406dffSbellard }
12500406dffSbellard
1262f619698Sbellard /* FIXME - handle put_user() failures */
1272f619698Sbellard put_user_u32(p[0], addr);
12800406dffSbellard }
12900406dffSbellard
13000406dffSbellard static inline
storeDouble(const unsigned int Fn,target_ulong addr)13165a650c2SPaul Brook void storeDouble(const unsigned int Fn, target_ulong addr)
13200406dffSbellard {
13300406dffSbellard FPA11 *fpa11 = GET_FPA11();
13400406dffSbellard float64 val;
13500406dffSbellard register unsigned int *p = (unsigned int*)&val;
13600406dffSbellard
13700406dffSbellard switch (fpa11->fType[Fn])
13800406dffSbellard {
13900406dffSbellard case typeSingle:
14020495218Sbellard val = float32_to_float64(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
14100406dffSbellard break;
14200406dffSbellard
14300406dffSbellard case typeExtended:
14420495218Sbellard val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status);
14500406dffSbellard break;
14600406dffSbellard
14700406dffSbellard default: val = fpa11->fpreg[Fn].fDouble;
14800406dffSbellard }
1492f619698Sbellard /* FIXME - handle put_user() failures */
150*e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
1512f619698Sbellard put_user_u32(p[0], addr); /* msw */
1522f619698Sbellard put_user_u32(p[1], addr + 4); /* lsw */
153a8d3431aSbellard #else
1542f619698Sbellard put_user_u32(p[1], addr); /* msw */
1552f619698Sbellard put_user_u32(p[0], addr + 4); /* lsw */
156a8d3431aSbellard #endif
15700406dffSbellard }
15800406dffSbellard
15900406dffSbellard static inline
storeExtended(const unsigned int Fn,target_ulong addr)16065a650c2SPaul Brook void storeExtended(const unsigned int Fn, target_ulong addr)
16100406dffSbellard {
16200406dffSbellard FPA11 *fpa11 = GET_FPA11();
16300406dffSbellard floatx80 val;
16400406dffSbellard register unsigned int *p = (unsigned int*)&val;
16500406dffSbellard
16600406dffSbellard switch (fpa11->fType[Fn])
16700406dffSbellard {
16800406dffSbellard case typeSingle:
16920495218Sbellard val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
17000406dffSbellard break;
17100406dffSbellard
17200406dffSbellard case typeDouble:
17320495218Sbellard val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
17400406dffSbellard break;
17500406dffSbellard
17600406dffSbellard default: val = fpa11->fpreg[Fn].fExtended;
17700406dffSbellard }
17800406dffSbellard
1792f619698Sbellard /* FIXME - handle put_user() failures */
1802f619698Sbellard put_user_u32(p[0], addr); /* sign & exp */
1812f619698Sbellard put_user_u32(p[1], addr + 8);
1822f619698Sbellard put_user_u32(p[2], addr + 4); /* msw */
18300406dffSbellard }
18400406dffSbellard
18500406dffSbellard static inline
storeMultiple(const unsigned int Fn,target_ulong addr)18665a650c2SPaul Brook void storeMultiple(const unsigned int Fn, target_ulong addr)
18700406dffSbellard {
18800406dffSbellard FPA11 *fpa11 = GET_FPA11();
18900406dffSbellard register unsigned int nType, *p;
19000406dffSbellard
19100406dffSbellard p = (unsigned int*)&(fpa11->fpreg[Fn]);
19200406dffSbellard nType = fpa11->fType[Fn];
19300406dffSbellard
19400406dffSbellard switch (nType)
19500406dffSbellard {
19600406dffSbellard case typeSingle:
19700406dffSbellard case typeDouble:
19800406dffSbellard {
1992f619698Sbellard put_user_u32(p[0], addr + 8); /* single */
2002f619698Sbellard put_user_u32(p[1], addr + 4); /* double msw */
2012f619698Sbellard put_user_u32(nType << 14, addr);
20200406dffSbellard }
20300406dffSbellard break;
20400406dffSbellard
20500406dffSbellard case typeExtended:
20600406dffSbellard {
2072f619698Sbellard put_user_u32(p[2], addr + 4); /* msw */
2082f619698Sbellard put_user_u32(p[1], addr + 8);
2092f619698Sbellard put_user_u32((p[0] & 0x80003fff) | (nType << 14), addr);
21000406dffSbellard }
21100406dffSbellard break;
21200406dffSbellard }
21300406dffSbellard }
21400406dffSbellard
PerformLDF(const unsigned int opcode)21565a650c2SPaul Brook static unsigned int PerformLDF(const unsigned int opcode)
21600406dffSbellard {
21765a650c2SPaul Brook target_ulong pBase, pAddress, pFinal;
21865a650c2SPaul Brook unsigned int nRc = 1,
21900406dffSbellard write_back = WRITE_BACK(opcode);
22000406dffSbellard
22100406dffSbellard //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
22200406dffSbellard
22365a650c2SPaul Brook pBase = readRegister(getRn(opcode));
2247cb4db8fSPeter Maydell if (ARM_REG_PC == getRn(opcode))
22500406dffSbellard {
22665a650c2SPaul Brook pBase += 8;
22700406dffSbellard write_back = 0;
22800406dffSbellard }
22900406dffSbellard
23000406dffSbellard pFinal = pBase;
23100406dffSbellard if (BIT_UP_SET(opcode))
23265a650c2SPaul Brook pFinal += getOffset(opcode) * 4;
23300406dffSbellard else
23465a650c2SPaul Brook pFinal -= getOffset(opcode) * 4;
23500406dffSbellard
23600406dffSbellard if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
23700406dffSbellard
23800406dffSbellard switch (opcode & MASK_TRANSFER_LENGTH)
23900406dffSbellard {
24000406dffSbellard case TRANSFER_SINGLE : loadSingle(getFd(opcode),pAddress); break;
24100406dffSbellard case TRANSFER_DOUBLE : loadDouble(getFd(opcode),pAddress); break;
24200406dffSbellard case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break;
24300406dffSbellard default: nRc = 0;
24400406dffSbellard }
24500406dffSbellard
24600406dffSbellard if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
24700406dffSbellard return nRc;
24800406dffSbellard }
24900406dffSbellard
PerformSTF(const unsigned int opcode)25065a650c2SPaul Brook static unsigned int PerformSTF(const unsigned int opcode)
25100406dffSbellard {
25265a650c2SPaul Brook target_ulong pBase, pAddress, pFinal;
25365a650c2SPaul Brook unsigned int nRc = 1,
25400406dffSbellard write_back = WRITE_BACK(opcode);
25500406dffSbellard
25600406dffSbellard //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
25700406dffSbellard SetRoundingMode(ROUND_TO_NEAREST);
25800406dffSbellard
25965a650c2SPaul Brook pBase = readRegister(getRn(opcode));
2607cb4db8fSPeter Maydell if (ARM_REG_PC == getRn(opcode))
26100406dffSbellard {
26265a650c2SPaul Brook pBase += 8;
26300406dffSbellard write_back = 0;
26400406dffSbellard }
26500406dffSbellard
26600406dffSbellard pFinal = pBase;
26700406dffSbellard if (BIT_UP_SET(opcode))
26865a650c2SPaul Brook pFinal += getOffset(opcode) * 4;
26900406dffSbellard else
27065a650c2SPaul Brook pFinal -= getOffset(opcode) * 4;
27100406dffSbellard
27200406dffSbellard if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
27300406dffSbellard
27400406dffSbellard switch (opcode & MASK_TRANSFER_LENGTH)
27500406dffSbellard {
27600406dffSbellard case TRANSFER_SINGLE : storeSingle(getFd(opcode),pAddress); break;
27700406dffSbellard case TRANSFER_DOUBLE : storeDouble(getFd(opcode),pAddress); break;
27800406dffSbellard case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break;
27900406dffSbellard default: nRc = 0;
28000406dffSbellard }
28100406dffSbellard
28200406dffSbellard if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
28300406dffSbellard return nRc;
28400406dffSbellard }
28500406dffSbellard
PerformLFM(const unsigned int opcode)28665a650c2SPaul Brook static unsigned int PerformLFM(const unsigned int opcode)
28700406dffSbellard {
28865a650c2SPaul Brook unsigned int i, Fd,
28900406dffSbellard write_back = WRITE_BACK(opcode);
29065a650c2SPaul Brook target_ulong pBase, pAddress, pFinal;
29100406dffSbellard
29265a650c2SPaul Brook pBase = readRegister(getRn(opcode));
2937cb4db8fSPeter Maydell if (ARM_REG_PC == getRn(opcode))
29400406dffSbellard {
29565a650c2SPaul Brook pBase += 8;
29600406dffSbellard write_back = 0;
29700406dffSbellard }
29800406dffSbellard
29900406dffSbellard pFinal = pBase;
30000406dffSbellard if (BIT_UP_SET(opcode))
30165a650c2SPaul Brook pFinal += getOffset(opcode) * 4;
30200406dffSbellard else
30365a650c2SPaul Brook pFinal -= getOffset(opcode) * 4;
30400406dffSbellard
30500406dffSbellard if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
30600406dffSbellard
30700406dffSbellard Fd = getFd(opcode);
30800406dffSbellard for (i=getRegisterCount(opcode);i>0;i--)
30900406dffSbellard {
31000406dffSbellard loadMultiple(Fd,pAddress);
31165a650c2SPaul Brook pAddress += 12; Fd++;
31200406dffSbellard if (Fd == 8) Fd = 0;
31300406dffSbellard }
31400406dffSbellard
31500406dffSbellard if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
31600406dffSbellard return 1;
31700406dffSbellard }
31800406dffSbellard
PerformSFM(const unsigned int opcode)31965a650c2SPaul Brook static unsigned int PerformSFM(const unsigned int opcode)
32000406dffSbellard {
32165a650c2SPaul Brook unsigned int i, Fd,
32200406dffSbellard write_back = WRITE_BACK(opcode);
32365a650c2SPaul Brook target_ulong pBase, pAddress, pFinal;
32400406dffSbellard
32565a650c2SPaul Brook pBase = readRegister(getRn(opcode));
3267cb4db8fSPeter Maydell if (ARM_REG_PC == getRn(opcode))
32700406dffSbellard {
32865a650c2SPaul Brook pBase += 8;
32900406dffSbellard write_back = 0;
33000406dffSbellard }
33100406dffSbellard
33200406dffSbellard pFinal = pBase;
33300406dffSbellard if (BIT_UP_SET(opcode))
33465a650c2SPaul Brook pFinal += getOffset(opcode) * 4;
33500406dffSbellard else
33665a650c2SPaul Brook pFinal -= getOffset(opcode) * 4;
33700406dffSbellard
33800406dffSbellard if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
33900406dffSbellard
34000406dffSbellard Fd = getFd(opcode);
34100406dffSbellard for (i=getRegisterCount(opcode);i>0;i--)
34200406dffSbellard {
34300406dffSbellard storeMultiple(Fd,pAddress);
34465a650c2SPaul Brook pAddress += 12; Fd++;
34500406dffSbellard if (Fd == 8) Fd = 0;
34600406dffSbellard }
34700406dffSbellard
34800406dffSbellard if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
34900406dffSbellard return 1;
35000406dffSbellard }
35100406dffSbellard
35200406dffSbellard #if 1
EmulateCPDT(const unsigned int opcode)35300406dffSbellard unsigned int EmulateCPDT(const unsigned int opcode)
35400406dffSbellard {
35500406dffSbellard unsigned int nRc = 0;
35600406dffSbellard
35700406dffSbellard //printk("EmulateCPDT(0x%08x)\n",opcode);
35800406dffSbellard
35900406dffSbellard if (LDF_OP(opcode))
36000406dffSbellard {
36100406dffSbellard nRc = PerformLDF(opcode);
36200406dffSbellard }
36300406dffSbellard else if (LFM_OP(opcode))
36400406dffSbellard {
36500406dffSbellard nRc = PerformLFM(opcode);
36600406dffSbellard }
36700406dffSbellard else if (STF_OP(opcode))
36800406dffSbellard {
36900406dffSbellard nRc = PerformSTF(opcode);
37000406dffSbellard }
37100406dffSbellard else if (SFM_OP(opcode))
37200406dffSbellard {
37300406dffSbellard nRc = PerformSFM(opcode);
37400406dffSbellard }
37500406dffSbellard else
37600406dffSbellard {
37700406dffSbellard nRc = 0;
37800406dffSbellard }
37900406dffSbellard
38000406dffSbellard return nRc;
38100406dffSbellard }
38200406dffSbellard #endif
383