vfp.hh revision 7397
12623SN/A/*
22623SN/A * Copyright (c) 2010 ARM Limited
32623SN/A * All rights reserved
42623SN/A *
52623SN/A * The license below extends only to copyright in the software and shall
62623SN/A * not be construed as granting a license to any other intellectual
72623SN/A * property including but not limited to intellectual property relating
82623SN/A * to a hardware implementation of the functionality of the software
92623SN/A * licensed hereunder.  You may use the software subject to the license
102623SN/A * terms below provided that you ensure that this notice is replicated
112623SN/A * unmodified and in its entirety in all distributions of the software,
122623SN/A * modified or unmodified, in source code or in binary form.
132623SN/A *
142623SN/A * Redistribution and use in source and binary forms, with or without
152623SN/A * modification, are permitted provided that the following conditions are
162623SN/A * met: redistributions of source code must retain the above copyright
172623SN/A * notice, this list of conditions and the following disclaimer;
182623SN/A * redistributions in binary form must reproduce the above copyright
192623SN/A * notice, this list of conditions and the following disclaimer in the
202623SN/A * documentation and/or other materials provided with the distribution;
212623SN/A * neither the name of the copyright holders nor the names of its
222623SN/A * contributors may be used to endorse or promote products derived from
232623SN/A * this software without specific prior written permission.
242623SN/A *
252623SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
262623SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
272665Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
282665Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
292623SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
302623SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
313170Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
323806Ssaidi@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
332623SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
344040Ssaidi@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
352623SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
362623SN/A *
373348Sbinkertn@umich.edu * Authors: Gabe Black
383348Sbinkertn@umich.edu */
394762Snate@binkert.org
402901Ssaidi@eecs.umich.edu#ifndef __ARCH_ARM_INSTS_VFP_HH__
412623SN/A#define __ARCH_ARM_INSTS_VFP_HH__
422623SN/A
432623SN/A#include "arch/arm/insts/misc.hh"
442623SN/A#include "arch/arm/miscregs.hh"
452623SN/A#include <fenv.h>
465606Snate@binkert.org#include <cmath>
472623SN/A
482623SN/Anamespace ArmISA
492623SN/A{
502623SN/A
512623SN/Aenum VfpMicroMode {
522623SN/A    VfpNotAMicroop,
532623SN/A    VfpMicroop,
542623SN/A    VfpFirstMicroop,
552623SN/A    VfpLastMicroop
562623SN/A};
572623SN/A
585336Shines@cs.fsu.edutemplate<class T>
592623SN/Astatic inline void
604873Sstever@eecs.umich.edusetVfpMicroFlags(VfpMicroMode mode, T &flags)
612623SN/A{
622623SN/A    switch (mode) {
632856Srdreslin@umich.edu      case VfpMicroop:
642856Srdreslin@umich.edu        flags[StaticInst::IsMicroop] = true;
652856Srdreslin@umich.edu        break;
662856Srdreslin@umich.edu      case VfpFirstMicroop:
672856Srdreslin@umich.edu        flags[StaticInst::IsMicroop] =
682856Srdreslin@umich.edu            flags[StaticInst::IsFirstMicroop] = true;
692856Srdreslin@umich.edu        break;
704968Sacolyte@umich.edu      case VfpLastMicroop:
714968Sacolyte@umich.edu        flags[StaticInst::IsMicroop] =
724968Sacolyte@umich.edu            flags[StaticInst::IsLastMicroop] = true;
734968Sacolyte@umich.edu        break;
742856Srdreslin@umich.edu      case VfpNotAMicroop:
752856Srdreslin@umich.edu        break;
762856Srdreslin@umich.edu    }
772623SN/A    if (mode == VfpMicroop || mode == VfpFirstMicroop) {
782623SN/A        flags[StaticInst::IsDelayedCommit] = true;
792623SN/A    }
802623SN/A}
812623SN/A
822623SN/Aenum FeExceptionBit
832680Sktlim@umich.edu{
842680Sktlim@umich.edu    FeDivByZero = FE_DIVBYZERO,
852623SN/A    FeInexact = FE_INEXACT,
862623SN/A    FeInvalid = FE_INVALID,
875714Shsul@eecs.umich.edu    FeOverflow = FE_OVERFLOW,
882623SN/A    FeUnderflow = FE_UNDERFLOW,
892623SN/A    FeAllExceptions = FE_ALL_EXCEPT
904968Sacolyte@umich.edu};
914968Sacolyte@umich.edu
924968Sacolyte@umich.eduenum FeRoundingMode
934968Sacolyte@umich.edu{
944968Sacolyte@umich.edu    FeRoundDown = FE_DOWNWARD,
954968Sacolyte@umich.edu    FeRoundNearest = FE_TONEAREST,
965714Shsul@eecs.umich.edu    FeRoundZero = FE_TOWARDZERO,
975712Shsul@eecs.umich.edu    FeRoundUpward = FE_UPWARD
985712Shsul@eecs.umich.edu};
995712Shsul@eecs.umich.edu
1002623SN/Aenum VfpRoundingMode
1012623SN/A{
1022623SN/A    VfpRoundNearest = 0,
1033349Sbinkertn@umich.edu    VfpRoundUpward = 1,
1042623SN/A    VfpRoundDown = 2,
1053184Srdreslin@umich.edu    VfpRoundZero = 3
1062623SN/A};
1072623SN/A
1082623SN/Atemplate <class fpType>
1092623SN/Astatic inline bool
1103349Sbinkertn@umich.eduflushToZero(fpType &op)
1112623SN/A{
1123310Srdreslin@umich.edu    fpType junk = 0.0;
1133649Srdreslin@umich.edu    if (std::fpclassify(op) == FP_SUBNORMAL) {
1142623SN/A        uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1);
1152623SN/A        op = bitsToFp(fpToBits(op) & bitMask, junk);
1162623SN/A        return true;
1173349Sbinkertn@umich.edu    }
1182623SN/A    return false;
1193184Srdreslin@umich.edu}
1203184Srdreslin@umich.edu
1212623SN/Atemplate <class fpType>
1222623SN/Astatic inline bool
1232623SN/AflushToZero(fpType &op1, fpType &op2)
1242623SN/A{
1252623SN/A    bool flush1 = flushToZero(op1);
1263647Srdreslin@umich.edu    bool flush2 = flushToZero(op2);
1273647Srdreslin@umich.edu    return flush1 || flush2;
1283647Srdreslin@umich.edu}
1293647Srdreslin@umich.edu
1303647Srdreslin@umich.edutemplate <class fpType>
1312626SN/Astatic inline void
1323647Srdreslin@umich.eduvfpFlushToZero(FPSCR &fpscr, fpType &op)
1332626SN/A{
1342623SN/A    if (fpscr.fz == 1 && flushToZero(op)) {
1352623SN/A        fpscr.idc = 1;
1362623SN/A    }
1372657Ssaidi@eecs.umich.edu}
1382623SN/A
1392623SN/Atemplate <class fpType>
1402623SN/Astatic inline void
1412623SN/AvfpFlushToZero(FPSCR &fpscr, fpType &op1, fpType &op2)
1422623SN/A{
1434192Sktlim@umich.edu    vfpFlushToZero(fpscr, op1);
1444192Sktlim@umich.edu    vfpFlushToZero(fpscr, op2);
1454192Sktlim@umich.edu}
1464192Sktlim@umich.edu
1474192Sktlim@umich.edustatic inline uint32_t
1484192Sktlim@umich.edufpToBits(float fp)
1494192Sktlim@umich.edu{
1504192Sktlim@umich.edu    union
1515497Ssaidi@eecs.umich.edu    {
1524192Sktlim@umich.edu        float fp;
1534192Sktlim@umich.edu        uint32_t bits;
1542623SN/A    } val;
1555529Snate@binkert.org    val.fp = fp;
1565487Snate@binkert.org    return val.bits;
1575487Snate@binkert.org}
1585487Snate@binkert.org
1594968Sacolyte@umich.edustatic inline uint64_t
1604968Sacolyte@umich.edufpToBits(double fp)
1612623SN/A{
1622623SN/A    union
1632623SN/A    {
1643647Srdreslin@umich.edu        double fp;
1653647Srdreslin@umich.edu        uint64_t bits;
1663647Srdreslin@umich.edu    } val;
1672623SN/A    val.fp = fp;
1682623SN/A    return val.bits;
1692623SN/A}
1702623SN/A
1712623SN/Astatic inline float
1722623SN/AbitsToFp(uint64_t bits, float junk)
1732623SN/A{
1742623SN/A    union
1752623SN/A    {
1762623SN/A        float fp;
1772915Sktlim@umich.edu        uint32_t bits;
1782915Sktlim@umich.edu    } val;
1793145Shsul@eecs.umich.edu    val.bits = bits;
1802623SN/A    return val.fp;
1812623SN/A}
1822623SN/A
1832623SN/Astatic inline double
1842623SN/AbitsToFp(uint64_t bits, double junk)
1852623SN/A{
1862623SN/A    union
1872915Sktlim@umich.edu    {
1882915Sktlim@umich.edu        double fp;
1893145Shsul@eecs.umich.edu        uint64_t bits;
1902915Sktlim@umich.edu    } val;
1912915Sktlim@umich.edu    val.bits = bits;
1922915Sktlim@umich.edu    return val.fp;
1932915Sktlim@umich.edu}
1942915Sktlim@umich.edu
1952915Sktlim@umich.edutypedef int VfpSavedState;
1965220Ssaidi@eecs.umich.edu
1975220Ssaidi@eecs.umich.edustatic inline VfpSavedState
1985220Ssaidi@eecs.umich.eduprepFpState(uint32_t rMode)
1994940Snate@binkert.org{
2005220Ssaidi@eecs.umich.edu    int roundingMode = fegetround();
2013324Shsul@eecs.umich.edu    feclearexcept(FeAllExceptions);
2025220Ssaidi@eecs.umich.edu    switch (rMode) {
2035220Ssaidi@eecs.umich.edu      case VfpRoundNearest:
2045606Snate@binkert.org        fesetround(FeRoundNearest);
2055606Snate@binkert.org        break;
2062915Sktlim@umich.edu      case VfpRoundUpward:
2072623SN/A        fesetround(FeRoundUpward);
2082623SN/A        break;
2092623SN/A      case VfpRoundDown:
2102798Sktlim@umich.edu        fesetround(FeRoundDown);
2112623SN/A        break;
2125496Ssaidi@eecs.umich.edu      case VfpRoundZero:
2132798Sktlim@umich.edu        fesetround(FeRoundZero);
2142623SN/A        break;
2152798Sktlim@umich.edu    }
2162623SN/A    return roundingMode;
2172623SN/A}
2182623SN/A
2192623SN/Astatic inline void
2202623SN/AfinishVfp(FPSCR &fpscr, VfpSavedState state)
2212623SN/A{
2224192Sktlim@umich.edu    int exceptions = fetestexcept(FeAllExceptions);
2232623SN/A    bool underflow = false;
2242623SN/A    if (exceptions & FeInvalid) {
2252623SN/A        fpscr.ioc = 1;
2262680Sktlim@umich.edu    }
2272623SN/A    if (exceptions & FeDivByZero) {
2282680Sktlim@umich.edu        fpscr.dzc = 1;
2292680Sktlim@umich.edu    }
2302680Sktlim@umich.edu    if (exceptions & FeOverflow) {
2312623SN/A        fpscr.ofc = 1;
2325606Snate@binkert.org    }
2332623SN/A    if (exceptions & FeUnderflow) {
2342623SN/A        underflow = true;
2352623SN/A        fpscr.ufc = 1;
2363512Sktlim@umich.edu    }
2373512Sktlim@umich.edu    if ((exceptions & FeInexact) && !(underflow && fpscr.fz)) {
2383512Sktlim@umich.edu        fpscr.ixc = 1;
2395169Ssaidi@eecs.umich.edu    }
2405712Shsul@eecs.umich.edu    fesetround(state);
2415712Shsul@eecs.umich.edu}
2425712Shsul@eecs.umich.edu
2432623SN/Atemplate <class fpType>
2442623SN/Astatic inline fpType
2452623SN/AfixDest(FPSCR fpscr, fpType val, fpType op1)
2462623SN/A{
2472623SN/A    int fpClass = std::fpclassify(val);
2482623SN/A    fpType junk = 0.0;
2494940Snate@binkert.org    if (fpClass == FP_NAN) {
2504940Snate@binkert.org        const bool single = (sizeof(val) == sizeof(float));
2512623SN/A        const uint64_t qnan = single ? 0x7fc00000 : ULL(0x7ff8000000000000);
2522683Sktlim@umich.edu        const bool nan = std::isnan(op1);
2532623SN/A        if (!nan || (fpscr.dn == 1)) {
2542623SN/A            val = bitsToFp(qnan, junk);
2552623SN/A        } else if (nan) {
2562623SN/A            val = bitsToFp(fpToBits(op1) | qnan, junk);
2572623SN/A        }
2585101Ssaidi@eecs.umich.edu    } else if (fpClass == FP_SUBNORMAL && fpscr.fz == 1) {
2593686Sktlim@umich.edu        // Turn val into a zero with the correct sign;
2603430Sgblack@eecs.umich.edu        uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1);
2615606Snate@binkert.org        val = bitsToFp(fpToBits(val) & bitMask, junk);
2622623SN/A        feclearexcept(FeInexact);
2632623SN/A        feraiseexcept(FeUnderflow);
2642623SN/A    }
2652623SN/A    return val;
2662623SN/A}
2672623SN/A
2682623SN/Atemplate <class fpType>
2694940Snate@binkert.orgstatic inline fpType
2704940Snate@binkert.orgfixDest(FPSCR fpscr, fpType val, fpType op1, fpType op2)
2712623SN/A{
2722683Sktlim@umich.edu    int fpClass = std::fpclassify(val);
2732623SN/A    fpType junk = 0.0;
2742623SN/A    if (fpClass == FP_NAN) {
2752626SN/A        const bool single = (sizeof(val) == sizeof(float));
2762626SN/A        const uint64_t qnan = single ? 0x7fc00000 : ULL(0x7ff8000000000000);
2772626SN/A        const bool nan1 = std::isnan(op1);
2782626SN/A        const bool nan2 = std::isnan(op2);
2795606Snate@binkert.org        const bool signal1 = nan1 && ((fpToBits(op1) & qnan) != qnan);
2802623SN/A        const bool signal2 = nan2 && ((fpToBits(op2) & qnan) != qnan);
2812623SN/A        if ((!nan1 && !nan2) || (fpscr.dn == 1)) {
2822623SN/A            val = bitsToFp(qnan, junk);
2832623SN/A        } else if (signal1) {
2842623SN/A            val = bitsToFp(fpToBits(op1) | qnan, junk);
2852623SN/A        } else if (signal2) {
2862623SN/A            val = bitsToFp(fpToBits(op2) | qnan, junk);
2872623SN/A        } else if (nan1) {
2882623SN/A            val = op1;
2892623SN/A        } else if (nan2) {
2903169Sstever@eecs.umich.edu            val = op2;
2914870Sstever@eecs.umich.edu        }
2922623SN/A    } else if (fpClass == FP_SUBNORMAL && fpscr.fz == 1) {
2932623SN/A        // Turn val into a zero with the correct sign;
2942623SN/A        uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1);
2952623SN/A        val = bitsToFp(fpToBits(val) & bitMask, junk);
2962623SN/A        feclearexcept(FeInexact);
2974999Sgblack@eecs.umich.edu        feraiseexcept(FeUnderflow);
2984999Sgblack@eecs.umich.edu    }
2994999Sgblack@eecs.umich.edu    return val;
3004999Sgblack@eecs.umich.edu}
3012623SN/A
3024999Sgblack@eecs.umich.edutemplate <class fpType>
3032623SN/Astatic inline fpType
3044999Sgblack@eecs.umich.edufixDivDest(FPSCR fpscr, fpType val, fpType op1, fpType op2)
3054999Sgblack@eecs.umich.edu{
3064999Sgblack@eecs.umich.edu    fpType mid = fixDest(fpscr, val, op1, op2);
3074999Sgblack@eecs.umich.edu    const bool single = (sizeof(fpType) == sizeof(float));
3084999Sgblack@eecs.umich.edu    const fpType junk = 0.0;
3094999Sgblack@eecs.umich.edu    if ((single && (val == bitsToFp(0x00800000, junk) ||
3104999Sgblack@eecs.umich.edu                    val == bitsToFp(0x80800000, junk))) ||
3114999Sgblack@eecs.umich.edu        (!single && (val == bitsToFp(ULL(0x0010000000000000), junk) ||
3124999Sgblack@eecs.umich.edu                     val == bitsToFp(ULL(0x8010000000000000), junk)))
3134999Sgblack@eecs.umich.edu        ) {
3144999Sgblack@eecs.umich.edu        __asm__ __volatile__("" : "=m" (op1) : "m" (op1));
3154999Sgblack@eecs.umich.edu        fesetround(FeRoundZero);
3164999Sgblack@eecs.umich.edu        fpType temp = 0.0;
3175891Sgblack@eecs.umich.edu        __asm__ __volatile__("" : "=m" (temp) : "m" (temp));
3184999Sgblack@eecs.umich.edu        temp = op1 / op2;
3194999Sgblack@eecs.umich.edu        if (flushToZero(temp)) {
3204999Sgblack@eecs.umich.edu            feraiseexcept(FeUnderflow);
3214999Sgblack@eecs.umich.edu            if (fpscr.fz) {
3224999Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
3234999Sgblack@eecs.umich.edu                mid = temp;
3244999Sgblack@eecs.umich.edu            }
3254999Sgblack@eecs.umich.edu        }
3264999Sgblack@eecs.umich.edu        __asm__ __volatile__("" :: "m" (temp));
3274999Sgblack@eecs.umich.edu    }
3284999Sgblack@eecs.umich.edu    return mid;
3294999Sgblack@eecs.umich.edu}
3304999Sgblack@eecs.umich.edu
3314999Sgblack@eecs.umich.edustatic inline float
3324999Sgblack@eecs.umich.edufixFpDFpSDest(FPSCR fpscr, double val)
3334999Sgblack@eecs.umich.edu{
3344999Sgblack@eecs.umich.edu    const float junk = 0.0;
3355012Sgblack@eecs.umich.edu    float op1 = 0.0;
3364999Sgblack@eecs.umich.edu    if (std::isnan(val)) {
3374999Sgblack@eecs.umich.edu        uint64_t valBits = fpToBits(val);
3384999Sgblack@eecs.umich.edu        uint32_t op1Bits = bits(valBits, 50, 29) |
3394999Sgblack@eecs.umich.edu                           (mask(9) << 22) |
3404999Sgblack@eecs.umich.edu                           (bits(valBits, 63) << 31);
3414968Sacolyte@umich.edu        op1 = bitsToFp(op1Bits, junk);
3424986Ssaidi@eecs.umich.edu    }
3434999Sgblack@eecs.umich.edu    float mid = fixDest(fpscr, (float)val, op1);
3444999Sgblack@eecs.umich.edu    if (fpscr.fz && fetestexcept(FeUnderflow | FeInexact) ==
3454999Sgblack@eecs.umich.edu                    (FeUnderflow | FeInexact)) {
3464762Snate@binkert.org        feclearexcept(FeInexact);
3474999Sgblack@eecs.umich.edu    }
3484999Sgblack@eecs.umich.edu    if (mid == bitsToFp(0x00800000, junk) ||
3494999Sgblack@eecs.umich.edu        mid == bitsToFp(0x80800000, junk)) {
3504999Sgblack@eecs.umich.edu        __asm__ __volatile__("" : "=m" (val) : "m" (val));
3514999Sgblack@eecs.umich.edu        fesetround(FeRoundZero);
3524999Sgblack@eecs.umich.edu        float temp = 0.0;
3534999Sgblack@eecs.umich.edu        __asm__ __volatile__("" : "=m" (temp) : "m" (temp));
3545408Sgblack@eecs.umich.edu        temp = val;
3555408Sgblack@eecs.umich.edu        if (flushToZero(temp)) {
3565408Sgblack@eecs.umich.edu            feraiseexcept(FeUnderflow);
3574999Sgblack@eecs.umich.edu            if (fpscr.fz) {
3584968Sacolyte@umich.edu                feclearexcept(FeInexact);
3593170Sstever@eecs.umich.edu                mid = temp;
3604999Sgblack@eecs.umich.edu            }
3614999Sgblack@eecs.umich.edu        }
3624999Sgblack@eecs.umich.edu        __asm__ __volatile__("" :: "m" (temp));
3634999Sgblack@eecs.umich.edu    }
3644999Sgblack@eecs.umich.edu    return mid;
3654999Sgblack@eecs.umich.edu}
3664999Sgblack@eecs.umich.edu
3674999Sgblack@eecs.umich.edustatic inline double
3684999Sgblack@eecs.umich.edufixFpSFpDDest(FPSCR fpscr, float val)
3694999Sgblack@eecs.umich.edu{
3702623SN/A    const double junk = 0.0;
3712623SN/A    double op1 = 0.0;
3722623SN/A    if (std::isnan(val)) {
3732623SN/A        uint32_t valBits = fpToBits(val);
3742623SN/A        uint64_t op1Bits = ((uint64_t)bits(valBits, 21, 0) << 29) |
3752623SN/A                           (mask(12) << 51) |
3762623SN/A                           ((uint64_t)bits(valBits, 31) << 63);
3774115Ssaidi@eecs.umich.edu        op1 = bitsToFp(op1Bits, junk);
3784115Ssaidi@eecs.umich.edu    }
3794115Ssaidi@eecs.umich.edu    double mid = fixDest(fpscr, (double)val, op1);
3804115Ssaidi@eecs.umich.edu    if (mid == bitsToFp(ULL(0x0010000000000000), junk) ||
3814040Ssaidi@eecs.umich.edu        mid == bitsToFp(ULL(0x8010000000000000), junk)) {
3824040Ssaidi@eecs.umich.edu        __asm__ __volatile__("" : "=m" (val) : "m" (val));
3834040Ssaidi@eecs.umich.edu        fesetround(FeRoundZero);
3844040Ssaidi@eecs.umich.edu        double temp = 0.0;
3852623SN/A        __asm__ __volatile__("" : "=m" (temp) : "m" (temp));
3862623SN/A        temp = val;
3872623SN/A        if (flushToZero(temp)) {
3882623SN/A            feraiseexcept(FeUnderflow);
3892623SN/A            if (fpscr.fz) {
3902623SN/A                feclearexcept(FeInexact);
3912623SN/A                mid = temp;
3922623SN/A            }
3932623SN/A        }
3942623SN/A        __asm__ __volatile__("" :: "m" (temp));
3952623SN/A    }
3962623SN/A    return mid;
3972623SN/A}
3982623SN/A
3992623SN/Astatic inline double
4002623SN/AmakeDouble(uint32_t low, uint32_t high)
4012623SN/A{
4022623SN/A    double junk = 0.0;
4032623SN/A    return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk);
4042623SN/A}
4052623SN/A
4062623SN/Astatic inline uint32_t
4072623SN/AlowFromDouble(double val)
4082623SN/A{
4092623SN/A    return fpToBits(val);
4102623SN/A}
4112623SN/A
4122623SN/Astatic inline uint32_t
4132623SN/AhighFromDouble(double val)
4142623SN/A{
4152623SN/A    return fpToBits(val) >> 32;
4162623SN/A}
4172623SN/A
4182623SN/Astatic inline uint64_t
4192623SN/AvfpFpSToFixed(float val, bool isSigned, bool half,
4202623SN/A              uint8_t imm, bool rzero = true)
4212623SN/A{
4222623SN/A    int rmode = rzero ? FeRoundZero : fegetround();
4232623SN/A    __asm__ __volatile__("" : "=m" (rmode) : "m" (rmode));
4242623SN/A    fesetround(FeRoundNearest);
4252623SN/A    val = val * powf(2.0, imm);
4262623SN/A    __asm__ __volatile__("" : "=m" (val) : "m" (val));
4272623SN/A    fesetround(rmode);
4283169Sstever@eecs.umich.edu    feclearexcept(FeAllExceptions);
4294870Sstever@eecs.umich.edu    __asm__ __volatile__("" : "=m" (val) : "m" (val));
4302623SN/A    float origVal = val;
4312623SN/A    val = rintf(val);
4322623SN/A    int fpType = std::fpclassify(val);
4332623SN/A    if (fpType == FP_SUBNORMAL || fpType == FP_NAN) {
4342623SN/A        if (fpType == FP_NAN) {
4354999Sgblack@eecs.umich.edu            feraiseexcept(FeInvalid);
4364999Sgblack@eecs.umich.edu        }
4374999Sgblack@eecs.umich.edu        val = 0.0;
4384999Sgblack@eecs.umich.edu    } else if (origVal != val) {
4392623SN/A        switch (rmode) {
4404999Sgblack@eecs.umich.edu          case FeRoundNearest:
4412623SN/A            if (origVal - val > 0.5)
4424999Sgblack@eecs.umich.edu                val += 1.0;
4434999Sgblack@eecs.umich.edu            else if (val - origVal > 0.5)
4444999Sgblack@eecs.umich.edu                val -= 1.0;
4454999Sgblack@eecs.umich.edu            break;
4464999Sgblack@eecs.umich.edu          case FeRoundDown:
4474999Sgblack@eecs.umich.edu            if (origVal < val)
4484999Sgblack@eecs.umich.edu                val -= 1.0;
4494999Sgblack@eecs.umich.edu            break;
4504999Sgblack@eecs.umich.edu          case FeRoundUpward:
4514999Sgblack@eecs.umich.edu            if (origVal > val)
4524999Sgblack@eecs.umich.edu                val += 1.0;
4534999Sgblack@eecs.umich.edu            break;
4544999Sgblack@eecs.umich.edu        }
4555891Sgblack@eecs.umich.edu        feraiseexcept(FeInexact);
4564999Sgblack@eecs.umich.edu    }
4574999Sgblack@eecs.umich.edu
4584999Sgblack@eecs.umich.edu    if (isSigned) {
4594999Sgblack@eecs.umich.edu        if (half) {
4604999Sgblack@eecs.umich.edu            if ((double)val < (int16_t)(1 << 15)) {
4614999Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
4624999Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
4634999Sgblack@eecs.umich.edu                return (int16_t)(1 << 15);
4644999Sgblack@eecs.umich.edu            }
4654999Sgblack@eecs.umich.edu            if ((double)val > (int16_t)mask(15)) {
4664999Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
4674999Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
4684999Sgblack@eecs.umich.edu                return (int16_t)mask(15);
4694999Sgblack@eecs.umich.edu            }
4704999Sgblack@eecs.umich.edu            return (int16_t)val;
4714999Sgblack@eecs.umich.edu        } else {
4724999Sgblack@eecs.umich.edu            if ((double)val < (int32_t)(1 << 31)) {
4734999Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
4744999Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
4754999Sgblack@eecs.umich.edu                return (int32_t)(1 << 31);
4764999Sgblack@eecs.umich.edu            }
4774999Sgblack@eecs.umich.edu            if ((double)val > (int32_t)mask(31)) {
4784999Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
4794999Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
4804999Sgblack@eecs.umich.edu                return (int32_t)mask(31);
4814999Sgblack@eecs.umich.edu            }
4824999Sgblack@eecs.umich.edu            return (int32_t)val;
4834999Sgblack@eecs.umich.edu        }
4844999Sgblack@eecs.umich.edu    } else {
4854999Sgblack@eecs.umich.edu        if (half) {
4864999Sgblack@eecs.umich.edu            if ((double)val < 0) {
4874999Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
4884999Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
4894999Sgblack@eecs.umich.edu                return 0;
4904999Sgblack@eecs.umich.edu            }
4914999Sgblack@eecs.umich.edu            if ((double)val > (mask(16))) {
4924999Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
4934999Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
4944999Sgblack@eecs.umich.edu                return mask(16);
4954999Sgblack@eecs.umich.edu            }
4964999Sgblack@eecs.umich.edu            return (uint16_t)val;
4974999Sgblack@eecs.umich.edu        } else {
4984999Sgblack@eecs.umich.edu            if ((double)val < 0) {
4994999Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
5004999Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
5014878Sstever@eecs.umich.edu                return 0;
5024040Ssaidi@eecs.umich.edu            }
5034040Ssaidi@eecs.umich.edu            if ((double)val > (mask(32))) {
5044999Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
5054999Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
5064999Sgblack@eecs.umich.edu                return mask(32);
5072631SN/A            }
5084999Sgblack@eecs.umich.edu            return (uint32_t)val;
5094999Sgblack@eecs.umich.edu        }
5104999Sgblack@eecs.umich.edu    }
5114999Sgblack@eecs.umich.edu}
5124999Sgblack@eecs.umich.edu
5134999Sgblack@eecs.umich.edustatic inline float
5144999Sgblack@eecs.umich.eduvfpUFixedToFpS(FPSCR fpscr, uint32_t val, bool half, uint8_t imm)
5155408Sgblack@eecs.umich.edu{
5165408Sgblack@eecs.umich.edu    fesetround(FeRoundNearest);
5175408Sgblack@eecs.umich.edu    if (half)
5184999Sgblack@eecs.umich.edu        val = (uint16_t)val;
5193170Sstever@eecs.umich.edu    float scale = powf(2.0, imm);
5203170Sstever@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
5214999Sgblack@eecs.umich.edu    feclearexcept(FeAllExceptions);
5224999Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
5234999Sgblack@eecs.umich.edu    return fixDivDest(fpscr, val / scale, (float)val, scale);
5244999Sgblack@eecs.umich.edu}
5254999Sgblack@eecs.umich.edu
5264999Sgblack@eecs.umich.edustatic inline float
5274999Sgblack@eecs.umich.eduvfpSFixedToFpS(FPSCR fpscr, int32_t val, bool half, uint8_t imm)
5284999Sgblack@eecs.umich.edu{
5294999Sgblack@eecs.umich.edu    fesetround(FeRoundNearest);
5304999Sgblack@eecs.umich.edu    if (half)
5312623SN/A        val = sext<16>(val & mask(16));
5322623SN/A    float scale = powf(2.0, imm);
5332623SN/A    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
5342623SN/A    feclearexcept(FeAllExceptions);
5352623SN/A    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
5364224Sgblack@eecs.umich.edu    return fixDivDest(fpscr, val / scale, (float)val, scale);
5374224Sgblack@eecs.umich.edu}
5384224Sgblack@eecs.umich.edu
5394224Sgblack@eecs.umich.edustatic inline uint64_t
5404224Sgblack@eecs.umich.eduvfpFpDToFixed(double val, bool isSigned, bool half,
5414224Sgblack@eecs.umich.edu              uint8_t imm, bool rzero = true)
5424224Sgblack@eecs.umich.edu{
5434224Sgblack@eecs.umich.edu    int rmode = rzero ? FeRoundZero : fegetround();
5444224Sgblack@eecs.umich.edu    fesetround(FeRoundNearest);
5454224Sgblack@eecs.umich.edu    val = val * pow(2.0, imm);
5464224Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (val) : "m" (val));
5472623SN/A    fesetround(rmode);
5482623SN/A    feclearexcept(FeAllExceptions);
5492623SN/A    __asm__ __volatile__("" : "=m" (val) : "m" (val));
5502623SN/A    double origVal = val;
5512623SN/A    val = rint(val);
5522623SN/A    int fpType = std::fpclassify(val);
5532623SN/A    if (fpType == FP_SUBNORMAL || fpType == FP_NAN) {
5542623SN/A        if (fpType == FP_NAN) {
5552623SN/A            feraiseexcept(FeInvalid);
5562623SN/A        }
5572623SN/A        val = 0.0;
5582623SN/A    } else if (origVal != val) {
5592623SN/A        switch (rmode) {
5602623SN/A          case FeRoundNearest:
5612623SN/A            if (origVal - val > 0.5)
5622623SN/A                val += 1.0;
5632623SN/A            else if (val - origVal > 0.5)
5642623SN/A                val -= 1.0;
5652623SN/A            break;
5662623SN/A          case FeRoundDown:
5672623SN/A            if (origVal < val)
5682623SN/A                val -= 1.0;
5692623SN/A            break;
5702623SN/A          case FeRoundUpward:
5712623SN/A            if (origVal > val)
5722623SN/A                val += 1.0;
5732623SN/A            break;
5742623SN/A        }
5752623SN/A        feraiseexcept(FeInexact);
5762623SN/A    }
5772623SN/A    if (isSigned) {
5782623SN/A        if (half) {
5792623SN/A            if (val < (int16_t)(1 << 15)) {
5802623SN/A                feraiseexcept(FeInvalid);
5812623SN/A                feclearexcept(FeInexact);
5822623SN/A                return (int16_t)(1 << 15);
5832623SN/A            }
5842623SN/A            if (val > (int16_t)mask(15)) {
5852623SN/A                feraiseexcept(FeInvalid);
5862623SN/A                feclearexcept(FeInexact);
5872623SN/A                return (int16_t)mask(15);
5882623SN/A            }
5892623SN/A            return (int16_t)val;
5902623SN/A        } else {
5912623SN/A            if (val < (int32_t)(1 << 31)) {
5922623SN/A                feraiseexcept(FeInvalid);
5932623SN/A                feclearexcept(FeInexact);
5942623SN/A                return (int32_t)(1 << 31);
5954940Snate@binkert.org            }
5964940Snate@binkert.org            if (val > (int32_t)mask(31)) {
5975487Snate@binkert.org                feraiseexcept(FeInvalid);
5982623SN/A                feclearexcept(FeInexact);
5992623SN/A                return (int32_t)mask(31);
6002623SN/A            }
6012623SN/A            return (int32_t)val;
6023387Sgblack@eecs.umich.edu        }
6033387Sgblack@eecs.umich.edu    } else {
6042626SN/A        if (half) {
6055348Ssaidi@eecs.umich.edu            if (val < 0) {
6065348Ssaidi@eecs.umich.edu                feraiseexcept(FeInvalid);
6075669Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
6085669Sgblack@eecs.umich.edu                return 0;
6095669Sgblack@eecs.umich.edu            }
6105914Sgblack@eecs.umich.edu            if (val > mask(16)) {
6115894Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
6125894Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
6135894Sgblack@eecs.umich.edu                return mask(16);
6142623SN/A            }
6152623SN/A            return (uint16_t)val;
6164182Sgblack@eecs.umich.edu        } else {
6174182Sgblack@eecs.umich.edu            if (val < 0) {
6184182Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
6192662Sstever@eecs.umich.edu                feclearexcept(FeInexact);
6205914Sgblack@eecs.umich.edu                return 0;
6215694Sgblack@eecs.umich.edu            }
6225694Sgblack@eecs.umich.edu            if (val > mask(32)) {
6235694Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
6245694Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
6255669Sgblack@eecs.umich.edu                return mask(32);
6265669Sgblack@eecs.umich.edu            }
6275669Sgblack@eecs.umich.edu            return (uint32_t)val;
6285669Sgblack@eecs.umich.edu        }
6295669Sgblack@eecs.umich.edu    }
6305669Sgblack@eecs.umich.edu}
6315669Sgblack@eecs.umich.edu
6322623SN/Astatic inline double
6335669Sgblack@eecs.umich.eduvfpUFixedToFpD(FPSCR fpscr, uint32_t val, bool half, uint8_t imm)
6345669Sgblack@eecs.umich.edu{
6355669Sgblack@eecs.umich.edu    fesetround(FeRoundNearest);
6365669Sgblack@eecs.umich.edu    if (half)
6374968Sacolyte@umich.edu        val = (uint16_t)val;
6385669Sgblack@eecs.umich.edu    double scale = pow(2.0, imm);
6394968Sacolyte@umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
6405669Sgblack@eecs.umich.edu    feclearexcept(FeAllExceptions);
6415669Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
6425669Sgblack@eecs.umich.edu    return fixDivDest(fpscr, val / scale, (double)val, scale);
6435669Sgblack@eecs.umich.edu}
6444182Sgblack@eecs.umich.edu
6452623SN/Astatic inline double
6463814Ssaidi@eecs.umich.eduvfpSFixedToFpD(FPSCR fpscr, int32_t val, bool half, uint8_t imm)
6475001Sgblack@eecs.umich.edu{
6484182Sgblack@eecs.umich.edu    fesetround(FeRoundNearest);
6494998Sgblack@eecs.umich.edu    if (half)
6504998Sgblack@eecs.umich.edu        val = sext<16>(val & mask(16));
6514998Sgblack@eecs.umich.edu    double scale = pow(2.0, imm);
6524998Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
6535001Sgblack@eecs.umich.edu    feclearexcept(FeAllExceptions);
6545001Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
6555001Sgblack@eecs.umich.edu    return fixDivDest(fpscr, val / scale, (double)val, scale);
6565001Sgblack@eecs.umich.edu}
6575001Sgblack@eecs.umich.edu
6584998Sgblack@eecs.umich.educlass VfpMacroOp : public PredMacroOp
6594182Sgblack@eecs.umich.edu{
6604182Sgblack@eecs.umich.edu  public:
6612623SN/A    static bool
6623814Ssaidi@eecs.umich.edu    inScalarBank(IntRegIndex idx)
6634539Sgblack@eecs.umich.edu    {
6644539Sgblack@eecs.umich.edu        return (idx % 32) < 8;
6653814Ssaidi@eecs.umich.edu    }
6663814Ssaidi@eecs.umich.edu
6675487Snate@binkert.org  protected:
6685487Snate@binkert.org    bool wide;
6695487Snate@binkert.org
6705487Snate@binkert.org    VfpMacroOp(const char *mnem, ExtMachInst _machInst,
6715487Snate@binkert.org            OpClass __opClass, bool _wide) :
6725487Snate@binkert.org        PredMacroOp(mnem, _machInst, __opClass), wide(_wide)
6735487Snate@binkert.org    {}
6745487Snate@binkert.org
6755487Snate@binkert.org    IntRegIndex
6765487Snate@binkert.org    addStride(IntRegIndex idx, unsigned stride)
6775487Snate@binkert.org    {
6785487Snate@binkert.org        if (wide) {
6795487Snate@binkert.org            stride *= 2;
6805487Snate@binkert.org        }
6815487Snate@binkert.org        unsigned offset = idx % 8;
6822623SN/A        idx = (IntRegIndex)(idx - offset);
6832623SN/A        offset += stride;
6842623SN/A        idx = (IntRegIndex)(idx + (offset % 8));
6854377Sgblack@eecs.umich.edu        return idx;
6864182Sgblack@eecs.umich.edu    }
6872623SN/A
6882623SN/A    void
6895487Snate@binkert.org    nextIdxs(IntRegIndex &dest, IntRegIndex &op1, IntRegIndex &op2)
6905487Snate@binkert.org    {
6915487Snate@binkert.org        unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2;
6925487Snate@binkert.org        assert(!inScalarBank(dest));
6932626SN/A        dest = addStride(dest, stride);
6945606Snate@binkert.org        op1 = addStride(op1, stride);
6952623SN/A        if (!inScalarBank(op2)) {
6962623SN/A            op2 = addStride(op2, stride);
6972623SN/A        }
6985315Sstever@gmail.com    }
6995315Sstever@gmail.com
7005315Sstever@gmail.com    void
7015315Sstever@gmail.com    nextIdxs(IntRegIndex &dest, IntRegIndex &op1)
7025315Sstever@gmail.com    {
7035315Sstever@gmail.com        unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2;
7045315Sstever@gmail.com        assert(!inScalarBank(dest));
7052623SN/A        dest = addStride(dest, stride);
7062623SN/A        if (!inScalarBank(op1)) {
7072623SN/A            op1 = addStride(op1, stride);
7082623SN/A        }
7094762Snate@binkert.org    }
7104762Snate@binkert.org
7112623SN/A    void
7125529Snate@binkert.org    nextIdxs(IntRegIndex &dest)
7135529Snate@binkert.org    {
7144762Snate@binkert.org        unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2;
7154762Snate@binkert.org        assert(!inScalarBank(dest));
7162623SN/A        dest = addStride(dest, stride);
7175529Snate@binkert.org    }
7182623SN/A};
719
720static inline float
721fpAddS(float a, float b)
722{
723    return a + b;
724}
725
726static inline double
727fpAddD(double a, double b)
728{
729    return a + b;
730}
731
732static inline float
733fpSubS(float a, float b)
734{
735    return a - b;
736}
737
738static inline double
739fpSubD(double a, double b)
740{
741    return a - b;
742}
743
744static inline float
745fpDivS(float a, float b)
746{
747    return a / b;
748}
749
750static inline double
751fpDivD(double a, double b)
752{
753    return a / b;
754}
755
756static inline float
757fpMulS(float a, float b)
758{
759    return a * b;
760}
761
762static inline double
763fpMulD(double a, double b)
764{
765    return a * b;
766}
767
768class FpOp : public PredOp
769{
770  protected:
771    FpOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
772        PredOp(mnem, _machInst, __opClass)
773    {}
774
775    virtual float
776    doOp(float op1, float op2) const
777    {
778        panic("Unimplemented version of doOp called.\n");
779    }
780
781    virtual float
782    doOp(float op1) const
783    {
784        panic("Unimplemented version of doOp called.\n");
785    }
786
787    virtual double
788    doOp(double op1, double op2) const
789    {
790        panic("Unimplemented version of doOp called.\n");
791    }
792
793    virtual double
794    doOp(double op1) const
795    {
796        panic("Unimplemented version of doOp called.\n");
797    }
798
799    double
800    dbl(uint32_t low, uint32_t high) const
801    {
802        double junk = 0.0;
803        return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk);
804    }
805
806    uint32_t
807    dblLow(double val) const
808    {
809        return fpToBits(val);
810    }
811
812    uint32_t
813    dblHi(double val) const
814    {
815        return fpToBits(val) >> 32;
816    }
817
818    template <class fpType>
819    fpType
820    binaryOp(FPSCR &fpscr, fpType op1, fpType op2,
821            fpType (*func)(fpType, fpType),
822            bool flush, uint32_t rMode) const
823    {
824        const bool single = (sizeof(fpType) == sizeof(float));
825        fpType junk = 0.0;
826
827        if (flush && flushToZero(op1, op2))
828            fpscr.idc = 1;
829        VfpSavedState state = prepFpState(rMode);
830        __asm__ __volatile__ ("" : "=m" (op1), "=m" (op2), "=m" (state)
831                                 : "m" (op1), "m" (op2), "m" (state));
832        fpType dest = func(op1, op2);
833        __asm__ __volatile__ ("" : "=m" (dest) : "m" (dest));
834
835        int fpClass = std::fpclassify(dest);
836        // Get NAN behavior right. This varies between x86 and ARM.
837        if (fpClass == FP_NAN) {
838            const bool single = (sizeof(fpType) == sizeof(float));
839            const uint64_t qnan =
840                single ? 0x7fc00000 : ULL(0x7ff8000000000000);
841            const bool nan1 = std::isnan(op1);
842            const bool nan2 = std::isnan(op2);
843            const bool signal1 = nan1 && ((fpToBits(op1) & qnan) != qnan);
844            const bool signal2 = nan2 && ((fpToBits(op2) & qnan) != qnan);
845            if ((!nan1 && !nan2) || (fpscr.dn == 1)) {
846                dest = bitsToFp(qnan, junk);
847            } else if (signal1) {
848                dest = bitsToFp(fpToBits(op1) | qnan, junk);
849            } else if (signal2) {
850                dest = bitsToFp(fpToBits(op2) | qnan, junk);
851            } else if (nan1) {
852                dest = op1;
853            } else if (nan2) {
854                dest = op2;
855            }
856        } else if (flush && flushToZero(dest)) {
857            feraiseexcept(FeUnderflow);
858        } else if ((
859                    (single && (dest == bitsToFp(0x00800000, junk) ||
860                         dest == bitsToFp(0x80800000, junk))) ||
861                    (!single &&
862                        (dest == bitsToFp(ULL(0x0010000000000000), junk) ||
863                         dest == bitsToFp(ULL(0x8010000000000000), junk)))
864                   ) && rMode != VfpRoundZero) {
865            /*
866             * Correct for the fact that underflow is detected -before- rounding
867             * in ARM and -after- rounding in x86.
868             */
869            fesetround(FeRoundZero);
870            __asm__ __volatile__ ("" : "=m" (op1), "=m" (op2)
871                                     : "m" (op1), "m" (op2));
872            fpType temp = func(op1, op2);
873            __asm__ __volatile__ ("" : "=m" (temp) : "m" (temp));
874            if (flush && flushToZero(temp)) {
875                dest = temp;
876            }
877        }
878        finishVfp(fpscr, state);
879        return dest;
880    }
881
882    template <class fpType>
883    fpType
884    unaryOp(FPSCR &fpscr, fpType op1,
885            fpType (*func)(fpType),
886            bool flush, uint32_t rMode) const
887    {
888        const bool single = (sizeof(fpType) == sizeof(float));
889        fpType junk = 0.0;
890
891        if (flush && flushToZero(op1))
892            fpscr.idc = 1;
893        VfpSavedState state = prepFpState(rMode);
894        __asm__ __volatile__ ("" : "=m" (op1), "=m" (state)
895                                 : "m" (op1), "m" (state));
896        fpType dest = func(op1);
897        __asm__ __volatile__ ("" : "=m" (dest) : "m" (dest));
898
899        int fpClass = std::fpclassify(dest);
900        // Get NAN behavior right. This varies between x86 and ARM.
901        if (fpClass == FP_NAN) {
902            const bool single = (sizeof(fpType) == sizeof(float));
903            const uint64_t qnan =
904                single ? 0x7fc00000 : ULL(0x7ff8000000000000);
905            const bool nan = std::isnan(op1);
906            if (!nan || fpscr.dn == 1) {
907                dest = bitsToFp(qnan, junk);
908            } else if (nan) {
909                dest = bitsToFp(fpToBits(op1) | qnan, junk);
910            }
911        } else if (flush && flushToZero(dest)) {
912            feraiseexcept(FeUnderflow);
913        } else if ((
914                    (single && (dest == bitsToFp(0x00800000, junk) ||
915                         dest == bitsToFp(0x80800000, junk))) ||
916                    (!single &&
917                        (dest == bitsToFp(ULL(0x0010000000000000), junk) ||
918                         dest == bitsToFp(ULL(0x8010000000000000), junk)))
919                   ) && rMode != VfpRoundZero) {
920            /*
921             * Correct for the fact that underflow is detected -before- rounding
922             * in ARM and -after- rounding in x86.
923             */
924            fesetround(FeRoundZero);
925            __asm__ __volatile__ ("" : "=m" (op1) : "m" (op1));
926            fpType temp = func(op1);
927            __asm__ __volatile__ ("" : "=m" (temp) : "m" (temp));
928            if (flush && flushToZero(temp)) {
929                dest = temp;
930            }
931        }
932        finishVfp(fpscr, state);
933        return dest;
934    }
935};
936
937class FpRegRegOp : public FpOp
938{
939  protected:
940    IntRegIndex dest;
941    IntRegIndex op1;
942
943    FpRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
944               IntRegIndex _dest, IntRegIndex _op1,
945               VfpMicroMode mode = VfpNotAMicroop) :
946        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1)
947    {
948        setVfpMicroFlags(mode, flags);
949    }
950
951    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
952};
953
954class FpRegImmOp : public FpOp
955{
956  protected:
957    IntRegIndex dest;
958    uint64_t imm;
959
960    FpRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
961               IntRegIndex _dest, uint64_t _imm,
962               VfpMicroMode mode = VfpNotAMicroop) :
963        FpOp(mnem, _machInst, __opClass), dest(_dest), imm(_imm)
964    {
965        setVfpMicroFlags(mode, flags);
966    }
967
968    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
969};
970
971class FpRegRegImmOp : public FpOp
972{
973  protected:
974    IntRegIndex dest;
975    IntRegIndex op1;
976    uint64_t imm;
977
978    FpRegRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
979                  IntRegIndex _dest, IntRegIndex _op1,
980                  uint64_t _imm, VfpMicroMode mode = VfpNotAMicroop) :
981        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), imm(_imm)
982    {
983        setVfpMicroFlags(mode, flags);
984    }
985
986    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
987};
988
989class FpRegRegRegOp : public FpOp
990{
991  protected:
992    IntRegIndex dest;
993    IntRegIndex op1;
994    IntRegIndex op2;
995
996    FpRegRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
997                  IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2,
998                  VfpMicroMode mode = VfpNotAMicroop) :
999        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), op2(_op2)
1000    {
1001        setVfpMicroFlags(mode, flags);
1002    }
1003
1004    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
1005};
1006
1007}
1008
1009#endif //__ARCH_ARM_INSTS_VFP_HH__
1010