linux/arch/arm/nwfpe/fpa11_cpdt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3    NetWinder Floating Point Emulator
   4    (c) Rebel.com, 1998-1999
   5    (c) Philip Blundell, 1998, 2001
   6
   7    Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
   8
   9*/
  10
  11#include "fpa11.h"
  12#include "softfloat.h"
  13#include "fpopcode.h"
  14#include "fpmodule.h"
  15#include "fpmodule.inl"
  16
  17#include <linux/uaccess.h>
  18
  19static inline void loadSingle(const unsigned int Fn, const unsigned int __user *pMem)
  20{
  21        FPA11 *fpa11 = GET_FPA11();
  22        fpa11->fType[Fn] = typeSingle;
  23        get_user(fpa11->fpreg[Fn].fSingle, pMem);
  24}
  25
  26static inline void loadDouble(const unsigned int Fn, const unsigned int __user *pMem)
  27{
  28        FPA11 *fpa11 = GET_FPA11();
  29        unsigned int *p;
  30        p = (unsigned int *) &fpa11->fpreg[Fn].fDouble;
  31        fpa11->fType[Fn] = typeDouble;
  32#ifdef __ARMEB__
  33        get_user(p[0], &pMem[0]);       /* sign & exponent */
  34        get_user(p[1], &pMem[1]);
  35#else
  36        get_user(p[0], &pMem[1]);
  37        get_user(p[1], &pMem[0]);       /* sign & exponent */
  38#endif
  39}
  40
  41#ifdef CONFIG_FPE_NWFPE_XP
  42static inline void loadExtended(const unsigned int Fn, const unsigned int __user *pMem)
  43{
  44        FPA11 *fpa11 = GET_FPA11();
  45        unsigned int *p;
  46        p = (unsigned int *) &fpa11->fpreg[Fn].fExtended;
  47        fpa11->fType[Fn] = typeExtended;
  48        get_user(p[0], &pMem[0]);       /* sign & exponent */
  49#ifdef __ARMEB__
  50        get_user(p[1], &pMem[1]);       /* ms bits */
  51        get_user(p[2], &pMem[2]);       /* ls bits */
  52#else
  53        get_user(p[1], &pMem[2]);       /* ls bits */
  54        get_user(p[2], &pMem[1]);       /* ms bits */
  55#endif
  56}
  57#endif
  58
  59static inline void loadMultiple(const unsigned int Fn, const unsigned int __user *pMem)
  60{
  61        FPA11 *fpa11 = GET_FPA11();
  62        register unsigned int *p;
  63        unsigned long x;
  64
  65        p = (unsigned int *) &(fpa11->fpreg[Fn]);
  66        get_user(x, &pMem[0]);
  67        fpa11->fType[Fn] = (x >> 14) & 0x00000003;
  68
  69        switch (fpa11->fType[Fn]) {
  70        case typeSingle:
  71        case typeDouble:
  72                {
  73                        get_user(p[0], &pMem[2]);       /* Single */
  74                        get_user(p[1], &pMem[1]);       /* double msw */
  75                        p[2] = 0;                       /* empty */
  76                }
  77                break;
  78
  79#ifdef CONFIG_FPE_NWFPE_XP
  80        case typeExtended:
  81                {
  82                        get_user(p[1], &pMem[2]);
  83                        get_user(p[2], &pMem[1]);       /* msw */
  84                        p[0] = (x & 0x80003fff);
  85                }
  86                break;
  87#endif
  88        }
  89}
  90
  91static inline void storeSingle(struct roundingData *roundData, const unsigned int Fn, unsigned int __user *pMem)
  92{
  93        FPA11 *fpa11 = GET_FPA11();
  94        union {
  95                float32 f;
  96                unsigned int i[1];
  97        } val;
  98
  99        switch (fpa11->fType[Fn]) {
 100        case typeDouble:
 101                val.f = float64_to_float32(roundData, fpa11->fpreg[Fn].fDouble);
 102                break;
 103
 104#ifdef CONFIG_FPE_NWFPE_XP
 105        case typeExtended:
 106                val.f = floatx80_to_float32(roundData, fpa11->fpreg[Fn].fExtended);
 107                break;
 108#endif
 109
 110        default:
 111                val.f = fpa11->fpreg[Fn].fSingle;
 112        }
 113
 114        put_user(val.i[0], pMem);
 115}
 116
 117static inline void storeDouble(struct roundingData *roundData, const unsigned int Fn, unsigned int __user *pMem)
 118{
 119        FPA11 *fpa11 = GET_FPA11();
 120        union {
 121                float64 f;
 122                unsigned int i[2];
 123        } val;
 124
 125        switch (fpa11->fType[Fn]) {
 126        case typeSingle:
 127                val.f = float32_to_float64(fpa11->fpreg[Fn].fSingle);
 128                break;
 129
 130#ifdef CONFIG_FPE_NWFPE_XP
 131        case typeExtended:
 132                val.f = floatx80_to_float64(roundData, fpa11->fpreg[Fn].fExtended);
 133                break;
 134#endif
 135
 136        default:
 137                val.f = fpa11->fpreg[Fn].fDouble;
 138        }
 139
 140#ifdef __ARMEB__
 141        put_user(val.i[0], &pMem[0]);   /* msw */
 142        put_user(val.i[1], &pMem[1]);   /* lsw */
 143#else
 144        put_user(val.i[1], &pMem[0]);   /* msw */
 145        put_user(val.i[0], &pMem[1]);   /* lsw */
 146#endif
 147}
 148
 149#ifdef CONFIG_FPE_NWFPE_XP
 150static inline void storeExtended(const unsigned int Fn, unsigned int __user *pMem)
 151{
 152        FPA11 *fpa11 = GET_FPA11();
 153        union {
 154                floatx80 f;
 155                unsigned int i[3];
 156        } val;
 157
 158        switch (fpa11->fType[Fn]) {
 159        case typeSingle:
 160                val.f = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
 161                break;
 162
 163        case typeDouble:
 164                val.f = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
 165                break;
 166
 167        default:
 168                val.f = fpa11->fpreg[Fn].fExtended;
 169        }
 170
 171        put_user(val.i[0], &pMem[0]);   /* sign & exp */
 172#ifdef __ARMEB__
 173        put_user(val.i[1], &pMem[1]);   /* msw */
 174        put_user(val.i[2], &pMem[2]);
 175#else
 176        put_user(val.i[1], &pMem[2]);
 177        put_user(val.i[2], &pMem[1]);   /* msw */
 178#endif
 179}
 180#endif
 181
 182static inline void storeMultiple(const unsigned int Fn, unsigned int __user *pMem)
 183{
 184        FPA11 *fpa11 = GET_FPA11();
 185        register unsigned int nType, *p;
 186
 187        p = (unsigned int *) &(fpa11->fpreg[Fn]);
 188        nType = fpa11->fType[Fn];
 189
 190        switch (nType) {
 191        case typeSingle:
 192        case typeDouble:
 193                {
 194                        put_user(p[0], &pMem[2]);       /* single */
 195                        put_user(p[1], &pMem[1]);       /* double msw */
 196                        put_user(nType << 14, &pMem[0]);
 197                }
 198                break;
 199
 200#ifdef CONFIG_FPE_NWFPE_XP
 201        case typeExtended:
 202                {
 203                        put_user(p[2], &pMem[1]);       /* msw */
 204                        put_user(p[1], &pMem[2]);
 205                        put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]);
 206                }
 207                break;
 208#endif
 209        }
 210}
 211
 212unsigned int PerformLDF(const unsigned int opcode)
 213{
 214        unsigned int __user *pBase, *pAddress, *pFinal;
 215        unsigned int nRc = 1, write_back = WRITE_BACK(opcode);
 216
 217        pBase = (unsigned int __user *) readRegister(getRn(opcode));
 218        if (REG_PC == getRn(opcode)) {
 219                pBase += 2;
 220                write_back = 0;
 221        }
 222
 223        pFinal = pBase;
 224        if (BIT_UP_SET(opcode))
 225                pFinal += getOffset(opcode);
 226        else
 227                pFinal -= getOffset(opcode);
 228
 229        if (PREINDEXED(opcode))
 230                pAddress = pFinal;
 231        else
 232                pAddress = pBase;
 233
 234        switch (opcode & MASK_TRANSFER_LENGTH) {
 235        case TRANSFER_SINGLE:
 236                loadSingle(getFd(opcode), pAddress);
 237                break;
 238        case TRANSFER_DOUBLE:
 239                loadDouble(getFd(opcode), pAddress);
 240                break;
 241#ifdef CONFIG_FPE_NWFPE_XP
 242        case TRANSFER_EXTENDED:
 243                loadExtended(getFd(opcode), pAddress);
 244                break;
 245#endif
 246        default:
 247                nRc = 0;
 248        }
 249
 250        if (write_back)
 251                writeRegister(getRn(opcode), (unsigned long) pFinal);
 252        return nRc;
 253}
 254
 255unsigned int PerformSTF(const unsigned int opcode)
 256{
 257        unsigned int __user *pBase, *pAddress, *pFinal;
 258        unsigned int nRc = 1, write_back = WRITE_BACK(opcode);
 259        struct roundingData roundData;
 260
 261        roundData.mode = SetRoundingMode(opcode);
 262        roundData.precision = SetRoundingPrecision(opcode);
 263        roundData.exception = 0;
 264
 265        pBase = (unsigned int __user *) readRegister(getRn(opcode));
 266        if (REG_PC == getRn(opcode)) {
 267                pBase += 2;
 268                write_back = 0;
 269        }
 270
 271        pFinal = pBase;
 272        if (BIT_UP_SET(opcode))
 273                pFinal += getOffset(opcode);
 274        else
 275                pFinal -= getOffset(opcode);
 276
 277        if (PREINDEXED(opcode))
 278                pAddress = pFinal;
 279        else
 280                pAddress = pBase;
 281
 282        switch (opcode & MASK_TRANSFER_LENGTH) {
 283        case TRANSFER_SINGLE:
 284                storeSingle(&roundData, getFd(opcode), pAddress);
 285                break;
 286        case TRANSFER_DOUBLE:
 287                storeDouble(&roundData, getFd(opcode), pAddress);
 288                break;
 289#ifdef CONFIG_FPE_NWFPE_XP
 290        case TRANSFER_EXTENDED:
 291                storeExtended(getFd(opcode), pAddress);
 292                break;
 293#endif
 294        default:
 295                nRc = 0;
 296        }
 297
 298        if (roundData.exception)
 299                float_raise(roundData.exception);
 300
 301        if (write_back)
 302                writeRegister(getRn(opcode), (unsigned long) pFinal);
 303        return nRc;
 304}
 305
 306unsigned int PerformLFM(const unsigned int opcode)
 307{
 308        unsigned int __user *pBase, *pAddress, *pFinal;
 309        unsigned int i, Fd, write_back = WRITE_BACK(opcode);
 310
 311        pBase = (unsigned int __user *) readRegister(getRn(opcode));
 312        if (REG_PC == getRn(opcode)) {
 313                pBase += 2;
 314                write_back = 0;
 315        }
 316
 317        pFinal = pBase;
 318        if (BIT_UP_SET(opcode))
 319                pFinal += getOffset(opcode);
 320        else
 321                pFinal -= getOffset(opcode);
 322
 323        if (PREINDEXED(opcode))
 324                pAddress = pFinal;
 325        else
 326                pAddress = pBase;
 327
 328        Fd = getFd(opcode);
 329        for (i = getRegisterCount(opcode); i > 0; i--) {
 330                loadMultiple(Fd, pAddress);
 331                pAddress += 3;
 332                Fd++;
 333                if (Fd == 8)
 334                        Fd = 0;
 335        }
 336
 337        if (write_back)
 338                writeRegister(getRn(opcode), (unsigned long) pFinal);
 339        return 1;
 340}
 341
 342unsigned int PerformSFM(const unsigned int opcode)
 343{
 344        unsigned int __user *pBase, *pAddress, *pFinal;
 345        unsigned int i, Fd, write_back = WRITE_BACK(opcode);
 346
 347        pBase = (unsigned int __user *) readRegister(getRn(opcode));
 348        if (REG_PC == getRn(opcode)) {
 349                pBase += 2;
 350                write_back = 0;
 351        }
 352
 353        pFinal = pBase;
 354        if (BIT_UP_SET(opcode))
 355                pFinal += getOffset(opcode);
 356        else
 357                pFinal -= getOffset(opcode);
 358
 359        if (PREINDEXED(opcode))
 360                pAddress = pFinal;
 361        else
 362                pAddress = pBase;
 363
 364        Fd = getFd(opcode);
 365        for (i = getRegisterCount(opcode); i > 0; i--) {
 366                storeMultiple(Fd, pAddress);
 367                pAddress += 3;
 368                Fd++;
 369                if (Fd == 8)
 370                        Fd = 0;
 371        }
 372
 373        if (write_back)
 374                writeRegister(getRn(opcode), (unsigned long) pFinal);
 375        return 1;
 376}
 377
 378unsigned int EmulateCPDT(const unsigned int opcode)
 379{
 380        unsigned int nRc = 0;
 381
 382        if (LDF_OP(opcode)) {
 383                nRc = PerformLDF(opcode);
 384        } else if (LFM_OP(opcode)) {
 385                nRc = PerformLFM(opcode);
 386        } else if (STF_OP(opcode)) {
 387                nRc = PerformSTF(opcode);
 388        } else if (SFM_OP(opcode)) {
 389                nRc = PerformSFM(opcode);
 390        } else {
 391                nRc = 0;
 392        }
 393
 394        return nRc;
 395}
 396