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