xref: /openbmc/qemu/linux-user/arm/nwfpe/fpa11_cpdt.c (revision e03b5686)
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