diff options
Diffstat (limited to 'qemu/linux-user/arm/nwfpe/fpa11_cpdt.c')
-rw-r--r-- | qemu/linux-user/arm/nwfpe/fpa11_cpdt.c | 381 |
1 files changed, 381 insertions, 0 deletions
diff --git a/qemu/linux-user/arm/nwfpe/fpa11_cpdt.c b/qemu/linux-user/arm/nwfpe/fpa11_cpdt.c new file mode 100644 index 000000000..007a3d650 --- /dev/null +++ b/qemu/linux-user/arm/nwfpe/fpa11_cpdt.c @@ -0,0 +1,381 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.com, 1998-1999 + (c) Philip Blundell, 1998 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "fpa11.h" +#include "fpu/softfloat.h" +#include "fpopcode.h" +//#include "fpmodule.h" +//#include "fpmodule.inl" + +//#include <asm/uaccess.h> + +static inline +void loadSingle(const unsigned int Fn, target_ulong addr) +{ + FPA11 *fpa11 = GET_FPA11(); + fpa11->fType[Fn] = typeSingle; + /* FIXME - handle failure of get_user() */ + get_user_u32(float32_val(fpa11->fpreg[Fn].fSingle), addr); +} + +static inline +void loadDouble(const unsigned int Fn, target_ulong addr) +{ + FPA11 *fpa11 = GET_FPA11(); + unsigned int *p; + p = (unsigned int*)&fpa11->fpreg[Fn].fDouble; + fpa11->fType[Fn] = typeDouble; +#ifdef HOST_WORDS_BIGENDIAN + /* FIXME - handle failure of get_user() */ + get_user_u32(p[0], addr); /* sign & exponent */ + get_user_u32(p[1], addr + 4); +#else + /* FIXME - handle failure of get_user() */ + get_user_u32(p[0], addr + 4); + get_user_u32(p[1], addr); /* sign & exponent */ +#endif +} + +static inline +void loadExtended(const unsigned int Fn, target_ulong addr) +{ + FPA11 *fpa11 = GET_FPA11(); + unsigned int *p; + p = (unsigned int*)&fpa11->fpreg[Fn].fExtended; + fpa11->fType[Fn] = typeExtended; + /* FIXME - handle failure of get_user() */ + get_user_u32(p[0], addr); /* sign & exponent */ + get_user_u32(p[1], addr + 8); /* ls bits */ + get_user_u32(p[2], addr + 4); /* ms bits */ +} + +static inline +void loadMultiple(const unsigned int Fn, target_ulong addr) +{ + FPA11 *fpa11 = GET_FPA11(); + register unsigned int *p; + unsigned long x; + + p = (unsigned int*)&(fpa11->fpreg[Fn]); + /* FIXME - handle failure of get_user() */ + get_user_u32(x, addr); + fpa11->fType[Fn] = (x >> 14) & 0x00000003; + + switch (fpa11->fType[Fn]) + { + case typeSingle: + case typeDouble: + { + /* FIXME - handle failure of get_user() */ + get_user_u32(p[0], addr + 8); /* Single */ + get_user_u32(p[1], addr + 4); /* double msw */ + p[2] = 0; /* empty */ + } + break; + + case typeExtended: + { + /* FIXME - handle failure of get_user() */ + get_user_u32(p[1], addr + 8); + get_user_u32(p[2], addr + 4); /* msw */ + p[0] = (x & 0x80003fff); + } + break; + } +} + +static inline +void storeSingle(const unsigned int Fn, target_ulong addr) +{ + FPA11 *fpa11 = GET_FPA11(); + float32 val; + register unsigned int *p = (unsigned int*)&val; + + switch (fpa11->fType[Fn]) + { + case typeDouble: + val = float64_to_float32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); + break; + + case typeExtended: + val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status); + break; + + default: val = fpa11->fpreg[Fn].fSingle; + } + + /* FIXME - handle put_user() failures */ + put_user_u32(p[0], addr); +} + +static inline +void storeDouble(const unsigned int Fn, target_ulong addr) +{ + FPA11 *fpa11 = GET_FPA11(); + float64 val; + register unsigned int *p = (unsigned int*)&val; + + switch (fpa11->fType[Fn]) + { + case typeSingle: + val = float32_to_float64(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); + break; + + case typeExtended: + val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status); + break; + + default: val = fpa11->fpreg[Fn].fDouble; + } + /* FIXME - handle put_user() failures */ +#ifdef HOST_WORDS_BIGENDIAN + put_user_u32(p[0], addr); /* msw */ + put_user_u32(p[1], addr + 4); /* lsw */ +#else + put_user_u32(p[1], addr); /* msw */ + put_user_u32(p[0], addr + 4); /* lsw */ +#endif +} + +static inline +void storeExtended(const unsigned int Fn, target_ulong addr) +{ + FPA11 *fpa11 = GET_FPA11(); + floatx80 val; + register unsigned int *p = (unsigned int*)&val; + + switch (fpa11->fType[Fn]) + { + case typeSingle: + val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); + break; + + case typeDouble: + val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); + break; + + default: val = fpa11->fpreg[Fn].fExtended; + } + + /* FIXME - handle put_user() failures */ + put_user_u32(p[0], addr); /* sign & exp */ + put_user_u32(p[1], addr + 8); + put_user_u32(p[2], addr + 4); /* msw */ +} + +static inline +void storeMultiple(const unsigned int Fn, target_ulong addr) +{ + FPA11 *fpa11 = GET_FPA11(); + register unsigned int nType, *p; + + p = (unsigned int*)&(fpa11->fpreg[Fn]); + nType = fpa11->fType[Fn]; + + switch (nType) + { + case typeSingle: + case typeDouble: + { + put_user_u32(p[0], addr + 8); /* single */ + put_user_u32(p[1], addr + 4); /* double msw */ + put_user_u32(nType << 14, addr); + } + break; + + case typeExtended: + { + put_user_u32(p[2], addr + 4); /* msw */ + put_user_u32(p[1], addr + 8); + put_user_u32((p[0] & 0x80003fff) | (nType << 14), addr); + } + break; + } +} + +static unsigned int PerformLDF(const unsigned int opcode) +{ + target_ulong pBase, pAddress, pFinal; + unsigned int nRc = 1, + write_back = WRITE_BACK(opcode); + + //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); + + pBase = readRegister(getRn(opcode)); + if (ARM_REG_PC == getRn(opcode)) + { + pBase += 8; + write_back = 0; + } + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode) * 4; + else + pFinal -= getOffset(opcode) * 4; + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + switch (opcode & MASK_TRANSFER_LENGTH) + { + case TRANSFER_SINGLE : loadSingle(getFd(opcode),pAddress); break; + case TRANSFER_DOUBLE : loadDouble(getFd(opcode),pAddress); break; + case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break; + default: nRc = 0; + } + + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); + return nRc; +} + +static unsigned int PerformSTF(const unsigned int opcode) +{ + target_ulong pBase, pAddress, pFinal; + unsigned int nRc = 1, + write_back = WRITE_BACK(opcode); + + //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); + SetRoundingMode(ROUND_TO_NEAREST); + + pBase = readRegister(getRn(opcode)); + if (ARM_REG_PC == getRn(opcode)) + { + pBase += 8; + write_back = 0; + } + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode) * 4; + else + pFinal -= getOffset(opcode) * 4; + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + switch (opcode & MASK_TRANSFER_LENGTH) + { + case TRANSFER_SINGLE : storeSingle(getFd(opcode),pAddress); break; + case TRANSFER_DOUBLE : storeDouble(getFd(opcode),pAddress); break; + case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break; + default: nRc = 0; + } + + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); + return nRc; +} + +static unsigned int PerformLFM(const unsigned int opcode) +{ + unsigned int i, Fd, + write_back = WRITE_BACK(opcode); + target_ulong pBase, pAddress, pFinal; + + pBase = readRegister(getRn(opcode)); + if (ARM_REG_PC == getRn(opcode)) + { + pBase += 8; + write_back = 0; + } + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode) * 4; + else + pFinal -= getOffset(opcode) * 4; + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + Fd = getFd(opcode); + for (i=getRegisterCount(opcode);i>0;i--) + { + loadMultiple(Fd,pAddress); + pAddress += 12; Fd++; + if (Fd == 8) Fd = 0; + } + + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); + return 1; +} + +static unsigned int PerformSFM(const unsigned int opcode) +{ + unsigned int i, Fd, + write_back = WRITE_BACK(opcode); + target_ulong pBase, pAddress, pFinal; + + pBase = readRegister(getRn(opcode)); + if (ARM_REG_PC == getRn(opcode)) + { + pBase += 8; + write_back = 0; + } + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode) * 4; + else + pFinal -= getOffset(opcode) * 4; + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + Fd = getFd(opcode); + for (i=getRegisterCount(opcode);i>0;i--) + { + storeMultiple(Fd,pAddress); + pAddress += 12; Fd++; + if (Fd == 8) Fd = 0; + } + + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); + return 1; +} + +#if 1 +unsigned int EmulateCPDT(const unsigned int opcode) +{ + unsigned int nRc = 0; + + //printk("EmulateCPDT(0x%08x)\n",opcode); + + if (LDF_OP(opcode)) + { + nRc = PerformLDF(opcode); + } + else if (LFM_OP(opcode)) + { + nRc = PerformLFM(opcode); + } + else if (STF_OP(opcode)) + { + nRc = PerformSTF(opcode); + } + else if (SFM_OP(opcode)) + { + nRc = PerformSFM(opcode); + } + else + { + nRc = 0; + } + + return nRc; +} +#endif |