vfp.hh revision 7397
13096SN/A/*
23096SN/A * Copyright (c) 2010 ARM Limited
33096SN/A * All rights reserved
49988Snilay@cs.wisc.edu *
58835SAli.Saidi@ARM.com * The license below extends only to copyright in the software and shall
69988Snilay@cs.wisc.edu * not be construed as granting a license to any other intellectual
77935SN/A * property including but not limited to intellectual property relating
87935SN/A * to a hardware implementation of the functionality of the software
97935SN/A * licensed hereunder.  You may use the software subject to the license
103096SN/A * terms below provided that you ensure that this notice is replicated
113096SN/A * unmodified and in its entirety in all distributions of the software,
123096SN/A * modified or unmodified, in source code or in binary form.
1310315Snilay@cs.wisc.edu *
148835SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without
159885Sstever@gmail.com * modification, are permitted provided that the following conditions are
169885Sstever@gmail.com * met: redistributions of source code must retain the above copyright
1711570SCurtis.Dunham@arm.com * notice, this list of conditions and the following disclaimer;
189988Snilay@cs.wisc.edu * redistributions in binary form must reproduce the above copyright
1911312Santhony.gutierrez@amd.com * notice, this list of conditions and the following disclaimer in the
208835SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution;
218835SAli.Saidi@ARM.com * neither the name of the copyright holders nor the names of its
2210315Snilay@cs.wisc.edu * contributors may be used to endorse or promote products derived from
238835SAli.Saidi@ARM.com * this software without specific prior written permission.
2410242Ssteve.reinhardt@amd.com *
259481Snilay@cs.wisc.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
269481Snilay@cs.wisc.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
278464SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2810736Snilay@cs.wisc.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2911219Snilay@cs.wisc.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
308721SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3111570SCurtis.Dunham@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3211570SCurtis.Dunham@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3311570SCurtis.Dunham@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3411570SCurtis.Dunham@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
358835SAli.Saidi@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
368835SAli.Saidi@ARM.com *
3711440SCurtis.Dunham@arm.com * Authors: Gabe Black
3811440SCurtis.Dunham@arm.com */
397935SN/A
407935SN/A#ifndef __ARCH_ARM_INSTS_VFP_HH__
417935SN/A#define __ARCH_ARM_INSTS_VFP_HH__
427935SN/A
437935SN/A#include "arch/arm/insts/misc.hh"
447935SN/A#include "arch/arm/miscregs.hh"
457935SN/A#include <fenv.h>
468983Snate@binkert.org#include <cmath>
473096SN/A
489885Sstever@gmail.comnamespace ArmISA
499885Sstever@gmail.com{
509885Sstever@gmail.com
5110315Snilay@cs.wisc.eduenum VfpMicroMode {
529988Snilay@cs.wisc.edu    VfpNotAMicroop,
5310315Snilay@cs.wisc.edu    VfpMicroop,
549885Sstever@gmail.com    VfpFirstMicroop,
559885Sstever@gmail.com    VfpLastMicroop
563096SN/A};
573096SN/A
589481Snilay@cs.wisc.edutemplate<class T>
593096SN/Astatic inline void
603096SN/AsetVfpMicroFlags(VfpMicroMode mode, T &flags)
618241SN/A{
628241SN/A    switch (mode) {
633096SN/A      case VfpMicroop:
643096SN/A        flags[StaticInst::IsMicroop] = true;
653096SN/A        break;
663096SN/A      case VfpFirstMicroop:
679481Snilay@cs.wisc.edu        flags[StaticInst::IsMicroop] =
684657SN/A            flags[StaticInst::IsFirstMicroop] = true;
695876SN/A        break;
709885Sstever@gmail.com      case VfpLastMicroop:
713096SN/A        flags[StaticInst::IsMicroop] =
723096SN/A            flags[StaticInst::IsLastMicroop] = true;
733096SN/A        break;
743096SN/A      case VfpNotAMicroop:
753096SN/A        break;
764289SN/A    }
773096SN/A    if (mode == VfpMicroop || mode == VfpFirstMicroop) {
783096SN/A        flags[StaticInst::IsDelayedCommit] = true;
793096SN/A    }
8011570SCurtis.Dunham@arm.com}
813096SN/A
825876SN/Aenum FeExceptionBit
838835SAli.Saidi@ARM.com{
845876SN/A    FeDivByZero = FE_DIVBYZERO,
855000SN/A    FeInexact = FE_INEXACT,
869988Snilay@cs.wisc.edu    FeInvalid = FE_INVALID,
879988Snilay@cs.wisc.edu    FeOverflow = FE_OVERFLOW,
8810451Snilay@cs.wisc.edu    FeUnderflow = FE_UNDERFLOW,
893096SN/A    FeAllExceptions = FE_ALL_EXCEPT
903096SN/A};
913096SN/A
923096SN/Aenum FeRoundingMode
933096SN/A{
943096SN/A    FeRoundDown = FE_DOWNWARD,
953096SN/A    FeRoundNearest = FE_TONEAREST,
963096SN/A    FeRoundZero = FE_TOWARDZERO,
973096SN/A    FeRoundUpward = FE_UPWARD
983096SN/A};
993096SN/A
1008835SAli.Saidi@ARM.comenum VfpRoundingMode
1019348SAli.Saidi@ARM.com{
1023096SN/A    VfpRoundNearest = 0,
1033096SN/A    VfpRoundUpward = 1,
1045000SN/A    VfpRoundDown = 2,
1053096SN/A    VfpRoundZero = 3
1063096SN/A};
1073096SN/A
1083096SN/Atemplate <class fpType>
1098835SAli.Saidi@ARM.comstatic inline bool
1103096SN/AflushToZero(fpType &op)
1119924Ssteve.reinhardt@amd.com{
1123096SN/A    fpType junk = 0.0;
1133096SN/A    if (std::fpclassify(op) == FP_SUBNORMAL) {
1143096SN/A        uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1);
1153096SN/A        op = bitsToFp(fpToBits(op) & bitMask, junk);
1163096SN/A        return true;
11711570SCurtis.Dunham@arm.com    }
11811570SCurtis.Dunham@arm.com    return false;
11911570SCurtis.Dunham@arm.com}
12011570SCurtis.Dunham@arm.com
1218835SAli.Saidi@ARM.comtemplate <class fpType>
1223147SN/Astatic inline bool
1233096SN/AflushToZero(fpType &op1, fpType &op2)
1243096SN/A{
1253096SN/A    bool flush1 = flushToZero(op1);
1263096SN/A    bool flush2 = flushToZero(op2);
1273096SN/A    return flush1 || flush2;
1289885Sstever@gmail.com}
1294657SN/A
1304657SN/Atemplate <class fpType>
1314657SN/Astatic inline void
1324657SN/AvfpFlushToZero(FPSCR &fpscr, fpType &op)
1334657SN/A{
1344657SN/A    if (fpscr.fz == 1 && flushToZero(op)) {
1354657SN/A        fpscr.idc = 1;
1364657SN/A    }
1374657SN/A}
13810242Ssteve.reinhardt@amd.com
1393096SN/Atemplate <class fpType>
1408546SN/Astatic inline void
1419481Snilay@cs.wisc.eduvfpFlushToZero(FPSCR &fpscr, fpType &op1, fpType &op2)
1423096SN/A{
1434938SN/A    vfpFlushToZero(fpscr, op1);
1443096SN/A    vfpFlushToZero(fpscr, op2);
1453096SN/A}
1463096SN/A
1473104SN/Astatic inline uint32_t
1483104SN/AfpToBits(float fp)
1493096SN/A{
1509481Snilay@cs.wisc.edu    union
15110798Ssteve.reinhardt@amd.com    {
1529481Snilay@cs.wisc.edu        float fp;
1539481Snilay@cs.wisc.edu        uint32_t bits;
1549481Snilay@cs.wisc.edu    } val;
1559481Snilay@cs.wisc.edu    val.fp = fp;
1569481Snilay@cs.wisc.edu    return val.bits;
1579988Snilay@cs.wisc.edu}
1589481Snilay@cs.wisc.edu
1599481Snilay@cs.wisc.edustatic inline uint64_t
16011440SCurtis.Dunham@arm.comfpToBits(double fp)
16111440SCurtis.Dunham@arm.com{
16211440SCurtis.Dunham@arm.com    union
16311440SCurtis.Dunham@arm.com    {
16411440SCurtis.Dunham@arm.com        double fp;
16511440SCurtis.Dunham@arm.com        uint64_t bits;
1669481Snilay@cs.wisc.edu    } val;
1679481Snilay@cs.wisc.edu    val.fp = fp;
1689481Snilay@cs.wisc.edu    return val.bits;
1699481Snilay@cs.wisc.edu}
1709481Snilay@cs.wisc.edu
17111440SCurtis.Dunham@arm.comstatic inline float
1729481Snilay@cs.wisc.edubitsToFp(uint64_t bits, float junk)
1733096SN/A{
17411066Snilay@cs.wisc.edu    union
1759885Sstever@gmail.com    {
17611680SCurtis.Dunham@arm.com        float fp;
1773096SN/A        uint32_t bits;
1789885Sstever@gmail.com    } val;
17911219Snilay@cs.wisc.edu    val.bits = bits;
18011731Sjason@lowepower.com    return val.fp;
18111570SCurtis.Dunham@arm.com}
18210636Snilay@cs.wisc.edu
1839988Snilay@cs.wisc.edustatic inline double
18411066Snilay@cs.wisc.edubitsToFp(uint64_t bits, double junk)
1853096SN/A{
1869348SAli.Saidi@ARM.com    union
18711570SCurtis.Dunham@arm.com    {
18811570SCurtis.Dunham@arm.com        double fp;
18911570SCurtis.Dunham@arm.com        uint64_t bits;
19011570SCurtis.Dunham@arm.com    } val;
1915876SN/A    val.bits = bits;
1928835SAli.Saidi@ARM.com    return val.fp;
1939348SAli.Saidi@ARM.com}
19410036SAli.Saidi@ARM.com
1953096SN/Atypedef int VfpSavedState;
1968835SAli.Saidi@ARM.com
19711731Sjason@lowepower.comstatic inline VfpSavedState
1989885Sstever@gmail.comprepFpState(uint32_t rMode)
1994316SN/A{
2003096SN/A    int roundingMode = fegetround();
20111219Snilay@cs.wisc.edu    feclearexcept(FeAllExceptions);
2023104SN/A    switch (rMode) {
2038983Snate@binkert.org      case VfpRoundNearest:
2043096SN/A        fesetround(FeRoundNearest);
2059885Sstever@gmail.com        break;
2069885Sstever@gmail.com      case VfpRoundUpward:
2079885Sstever@gmail.com        fesetround(FeRoundUpward);
2089885Sstever@gmail.com        break;
2099885Sstever@gmail.com      case VfpRoundDown:
21011731Sjason@lowepower.com        fesetround(FeRoundDown);
21111570SCurtis.Dunham@arm.com        break;
2129988Snilay@cs.wisc.edu      case VfpRoundZero:
21311570SCurtis.Dunham@arm.com        fesetround(FeRoundZero);
21411570SCurtis.Dunham@arm.com        break;
21511570SCurtis.Dunham@arm.com    }
21611570SCurtis.Dunham@arm.com    return roundingMode;
21710036SAli.Saidi@ARM.com}
2189885Sstever@gmail.com
21911731Sjason@lowepower.comstatic inline void
2209885Sstever@gmail.comfinishVfp(FPSCR &fpscr, VfpSavedState state)
2215000SN/A{
2226024SN/A    int exceptions = fetestexcept(FeAllExceptions);
2239988Snilay@cs.wisc.edu    bool underflow = false;
2245000SN/A    if (exceptions & FeInvalid) {
2255000SN/A        fpscr.ioc = 1;
2263096SN/A    }
2273096SN/A    if (exceptions & FeDivByZero) {
2287761SN/A        fpscr.dzc = 1;
2297761SN/A    }
2309988Snilay@cs.wisc.edu    if (exceptions & FeOverflow) {
2313096SN/A        fpscr.ofc = 1;
2323096SN/A    }
2333096SN/A    if (exceptions & FeUnderflow) {
2344938SN/A        underflow = true;
2353096SN/A        fpscr.ufc = 1;
2369988Snilay@cs.wisc.edu    }
2374938SN/A    if ((exceptions & FeInexact) && !(underflow && fpscr.fz)) {
2383096SN/A        fpscr.ixc = 1;
2394938SN/A    }
2403096SN/A    fesetround(state);
2419988Snilay@cs.wisc.edu}
2423096SN/A
2433096SN/Atemplate <class fpType>
24411066Snilay@cs.wisc.edustatic inline fpType
2453096SN/AfixDest(FPSCR fpscr, fpType val, fpType op1)
2463096SN/A{
2473096SN/A    int fpClass = std::fpclassify(val);
2483096SN/A    fpType junk = 0.0;
2493096SN/A    if (fpClass == FP_NAN) {
2509988Snilay@cs.wisc.edu        const bool single = (sizeof(val) == sizeof(float));
2513096SN/A        const uint64_t qnan = single ? 0x7fc00000 : ULL(0x7ff8000000000000);
2523096SN/A        const bool nan = std::isnan(op1);
2533096SN/A        if (!nan || (fpscr.dn == 1)) {
2543096SN/A            val = bitsToFp(qnan, junk);
2559988Snilay@cs.wisc.edu        } else if (nan) {
2563096SN/A            val = bitsToFp(fpToBits(op1) | qnan, junk);
2573096SN/A        }
25811066Snilay@cs.wisc.edu    } else if (fpClass == FP_SUBNORMAL && fpscr.fz == 1) {
2593096SN/A        // Turn val into a zero with the correct sign;
2603096SN/A        uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1);
2613096SN/A        val = bitsToFp(fpToBits(val) & bitMask, junk);
2629988Snilay@cs.wisc.edu        feclearexcept(FeInexact);
2633096SN/A        feraiseexcept(FeUnderflow);
2643096SN/A    }
26511066Snilay@cs.wisc.edu    return val;
2663096SN/A}
2673096SN/A
2683096SN/Atemplate <class fpType>
2693096SN/Astatic inline fpType
2703096SN/AfixDest(FPSCR fpscr, fpType val, fpType op1, fpType op2)
2719988Snilay@cs.wisc.edu{
2723096SN/A    int fpClass = std::fpclassify(val);
2733096SN/A    fpType junk = 0.0;
2743096SN/A    if (fpClass == FP_NAN) {
2753096SN/A        const bool single = (sizeof(val) == sizeof(float));
2769988Snilay@cs.wisc.edu        const uint64_t qnan = single ? 0x7fc00000 : ULL(0x7ff8000000000000);
2773096SN/A        const bool nan1 = std::isnan(op1);
2783096SN/A        const bool nan2 = std::isnan(op2);
27911066Snilay@cs.wisc.edu        const bool signal1 = nan1 && ((fpToBits(op1) & qnan) != qnan);
2803096SN/A        const bool signal2 = nan2 && ((fpToBits(op2) & qnan) != qnan);
2813096SN/A        if ((!nan1 && !nan2) || (fpscr.dn == 1)) {
2823096SN/A            val = bitsToFp(qnan, junk);
2839988Snilay@cs.wisc.edu        } else if (signal1) {
2843096SN/A            val = bitsToFp(fpToBits(op1) | qnan, junk);
2853096SN/A        } else if (signal2) {
28611066Snilay@cs.wisc.edu            val = bitsToFp(fpToBits(op2) | qnan, junk);
2873096SN/A        } else if (nan1) {
2883096SN/A            val = op1;
2893096SN/A        } else if (nan2) {
2909988Snilay@cs.wisc.edu            val = op2;
2913096SN/A        }
2923096SN/A    } else if (fpClass == FP_SUBNORMAL && fpscr.fz == 1) {
29311066Snilay@cs.wisc.edu        // Turn val into a zero with the correct sign;
2943096SN/A        uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1);
2953096SN/A        val = bitsToFp(fpToBits(val) & bitMask, junk);
2963096SN/A        feclearexcept(FeInexact);
29711731Sjason@lowepower.com        feraiseexcept(FeUnderflow);
2983096SN/A    }
2999988Snilay@cs.wisc.edu    return val;
30011731Sjason@lowepower.com}
3013096SN/A
3023096SN/Atemplate <class fpType>
3033096SN/Astatic inline fpType
3049988Snilay@cs.wisc.edufixDivDest(FPSCR fpscr, fpType val, fpType op1, fpType op2)
3053096SN/A{
3063096SN/A    fpType mid = fixDest(fpscr, val, op1, op2);
30711066Snilay@cs.wisc.edu    const bool single = (sizeof(fpType) == sizeof(float));
3083096SN/A    const fpType junk = 0.0;
3093096SN/A    if ((single && (val == bitsToFp(0x00800000, junk) ||
3103096SN/A                    val == bitsToFp(0x80800000, junk))) ||
3119988Snilay@cs.wisc.edu        (!single && (val == bitsToFp(ULL(0x0010000000000000), junk) ||
31211731Sjason@lowepower.com                     val == bitsToFp(ULL(0x8010000000000000), junk)))
31311731Sjason@lowepower.com        ) {
31411731Sjason@lowepower.com        __asm__ __volatile__("" : "=m" (op1) : "m" (op1));
31511731Sjason@lowepower.com        fesetround(FeRoundZero);
31611731Sjason@lowepower.com        fpType temp = 0.0;
31711731Sjason@lowepower.com        __asm__ __volatile__("" : "=m" (temp) : "m" (temp));
31811731Sjason@lowepower.com        temp = op1 / op2;
31911731Sjason@lowepower.com        if (flushToZero(temp)) {
32011731Sjason@lowepower.com            feraiseexcept(FeUnderflow);
32111731Sjason@lowepower.com            if (fpscr.fz) {
32211731Sjason@lowepower.com                feclearexcept(FeInexact);
32311731Sjason@lowepower.com                mid = temp;
32411731Sjason@lowepower.com            }
32511731Sjason@lowepower.com        }
3263096SN/A        __asm__ __volatile__("" :: "m" (temp));
3273096SN/A    }
32811066Snilay@cs.wisc.edu    return mid;
3293096SN/A}
33011731Sjason@lowepower.com
3313096SN/Astatic inline float
3329988Snilay@cs.wisc.edufixFpDFpSDest(FPSCR fpscr, double val)
3333096SN/A{
3343096SN/A    const float junk = 0.0;
33511066Snilay@cs.wisc.edu    float op1 = 0.0;
3363096SN/A    if (std::isnan(val)) {
3373096SN/A        uint64_t valBits = fpToBits(val);
3383096SN/A        uint32_t op1Bits = bits(valBits, 50, 29) |
33911731Sjason@lowepower.com                           (mask(9) << 22) |
3403096SN/A                           (bits(valBits, 63) << 31);
3419988Snilay@cs.wisc.edu        op1 = bitsToFp(op1Bits, junk);
34211731Sjason@lowepower.com    }
3433096SN/A    float mid = fixDest(fpscr, (float)val, op1);
34411731Sjason@lowepower.com    if (fpscr.fz && fetestexcept(FeUnderflow | FeInexact) ==
3453096SN/A                    (FeUnderflow | FeInexact)) {
3469988Snilay@cs.wisc.edu        feclearexcept(FeInexact);
3473096SN/A    }
3483096SN/A    if (mid == bitsToFp(0x00800000, junk) ||
34911066Snilay@cs.wisc.edu        mid == bitsToFp(0x80800000, junk)) {
3503096SN/A        __asm__ __volatile__("" : "=m" (val) : "m" (val));
35111731Sjason@lowepower.com        fesetround(FeRoundZero);
35211731Sjason@lowepower.com        float temp = 0.0;
35311731Sjason@lowepower.com        __asm__ __volatile__("" : "=m" (temp) : "m" (temp));
35411731Sjason@lowepower.com        temp = val;
35511731Sjason@lowepower.com        if (flushToZero(temp)) {
35611731Sjason@lowepower.com            feraiseexcept(FeUnderflow);
35711731Sjason@lowepower.com            if (fpscr.fz) {
3583096SN/A                feclearexcept(FeInexact);
3593096SN/A                mid = temp;
3607761SN/A            }
3617761SN/A        }
3629988Snilay@cs.wisc.edu        __asm__ __volatile__("" :: "m" (temp));
3637761SN/A    }
3643096SN/A    return mid;
3657761SN/A}
3663096SN/A
3679988Snilay@cs.wisc.edustatic inline double
3687761SN/AfixFpSFpDDest(FPSCR fpscr, float val)
3697761SN/A{
37011066Snilay@cs.wisc.edu    const double junk = 0.0;
3717761SN/A    double op1 = 0.0;
3727761SN/A    if (std::isnan(val)) {
3737761SN/A        uint32_t valBits = fpToBits(val);
3749988Snilay@cs.wisc.edu        uint64_t op1Bits = ((uint64_t)bits(valBits, 21, 0) << 29) |
3757761SN/A                           (mask(12) << 51) |
3767761SN/A                           ((uint64_t)bits(valBits, 31) << 63);
37711066Snilay@cs.wisc.edu        op1 = bitsToFp(op1Bits, junk);
3787761SN/A    }
3797761SN/A    double mid = fixDest(fpscr, (double)val, op1);
3807761SN/A    if (mid == bitsToFp(ULL(0x0010000000000000), junk) ||
3819988Snilay@cs.wisc.edu        mid == bitsToFp(ULL(0x8010000000000000), junk)) {
3827761SN/A        __asm__ __volatile__("" : "=m" (val) : "m" (val));
3837761SN/A        fesetround(FeRoundZero);
38411066Snilay@cs.wisc.edu        double temp = 0.0;
3857761SN/A        __asm__ __volatile__("" : "=m" (temp) : "m" (temp));
3867761SN/A        temp = val;
3877761SN/A        if (flushToZero(temp)) {
3889988Snilay@cs.wisc.edu            feraiseexcept(FeUnderflow);
3897761SN/A            if (fpscr.fz) {
3907761SN/A                feclearexcept(FeInexact);
39111066Snilay@cs.wisc.edu                mid = temp;
3927761SN/A            }
3937761SN/A        }
3947761SN/A        __asm__ __volatile__("" :: "m" (temp));
3959988Snilay@cs.wisc.edu    }
3967761SN/A    return mid;
3977761SN/A}
39811066Snilay@cs.wisc.edu
3997761SN/Astatic inline double
4007761SN/AmakeDouble(uint32_t low, uint32_t high)
4017761SN/A{
4029988Snilay@cs.wisc.edu    double junk = 0.0;
4037761SN/A    return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk);
4047761SN/A}
40511066Snilay@cs.wisc.edu
4067761SN/Astatic inline uint32_t
4077761SN/AlowFromDouble(double val)
4087761SN/A{
4099988Snilay@cs.wisc.edu    return fpToBits(val);
4107761SN/A}
4117761SN/A
41211066Snilay@cs.wisc.edustatic inline uint32_t
4137761SN/AhighFromDouble(double val)
4147761SN/A{
4157761SN/A    return fpToBits(val) >> 32;
4169988Snilay@cs.wisc.edu}
4177761SN/A
4187761SN/Astatic inline uint64_t
41911066Snilay@cs.wisc.eduvfpFpSToFixed(float val, bool isSigned, bool half,
4207761SN/A              uint8_t imm, bool rzero = true)
4217761SN/A{
4227761SN/A    int rmode = rzero ? FeRoundZero : fegetround();
4239988Snilay@cs.wisc.edu    __asm__ __volatile__("" : "=m" (rmode) : "m" (rmode));
4247761SN/A    fesetround(FeRoundNearest);
4257761SN/A    val = val * powf(2.0, imm);
42611066Snilay@cs.wisc.edu    __asm__ __volatile__("" : "=m" (val) : "m" (val));
4277761SN/A    fesetround(rmode);
4287761SN/A    feclearexcept(FeAllExceptions);
4297761SN/A    __asm__ __volatile__("" : "=m" (val) : "m" (val));
4309988Snilay@cs.wisc.edu    float origVal = val;
4317761SN/A    val = rintf(val);
4327761SN/A    int fpType = std::fpclassify(val);
43311066Snilay@cs.wisc.edu    if (fpType == FP_SUBNORMAL || fpType == FP_NAN) {
4347761SN/A        if (fpType == FP_NAN) {
4357761SN/A            feraiseexcept(FeInvalid);
4367761SN/A        }
4379988Snilay@cs.wisc.edu        val = 0.0;
4387761SN/A    } else if (origVal != val) {
4397761SN/A        switch (rmode) {
44011066Snilay@cs.wisc.edu          case FeRoundNearest:
4417761SN/A            if (origVal - val > 0.5)
4427761SN/A                val += 1.0;
4437761SN/A            else if (val - origVal > 0.5)
4449988Snilay@cs.wisc.edu                val -= 1.0;
4457761SN/A            break;
4467761SN/A          case FeRoundDown:
44711066Snilay@cs.wisc.edu            if (origVal < val)
4487761SN/A                val -= 1.0;
4497761SN/A            break;
4507761SN/A          case FeRoundUpward:
4519988Snilay@cs.wisc.edu            if (origVal > val)
4527761SN/A                val += 1.0;
4537761SN/A            break;
45411066Snilay@cs.wisc.edu        }
4557761SN/A        feraiseexcept(FeInexact);
4567761SN/A    }
4577761SN/A
4589988Snilay@cs.wisc.edu    if (isSigned) {
4597761SN/A        if (half) {
4607761SN/A            if ((double)val < (int16_t)(1 << 15)) {
46111066Snilay@cs.wisc.edu                feraiseexcept(FeInvalid);
4627761SN/A                feclearexcept(FeInexact);
4637761SN/A                return (int16_t)(1 << 15);
4647761SN/A            }
4659988Snilay@cs.wisc.edu            if ((double)val > (int16_t)mask(15)) {
4667761SN/A                feraiseexcept(FeInvalid);
4677761SN/A                feclearexcept(FeInexact);
46811066Snilay@cs.wisc.edu                return (int16_t)mask(15);
4697761SN/A            }
4707761SN/A            return (int16_t)val;
4717761SN/A        } else {
4729988Snilay@cs.wisc.edu            if ((double)val < (int32_t)(1 << 31)) {
4737761SN/A                feraiseexcept(FeInvalid);
4747761SN/A                feclearexcept(FeInexact);
47511066Snilay@cs.wisc.edu                return (int32_t)(1 << 31);
4767761SN/A            }
4777761SN/A            if ((double)val > (int32_t)mask(31)) {
4787761SN/A                feraiseexcept(FeInvalid);
4799988Snilay@cs.wisc.edu                feclearexcept(FeInexact);
4807761SN/A                return (int32_t)mask(31);
4817761SN/A            }
48211066Snilay@cs.wisc.edu            return (int32_t)val;
4837761SN/A        }
4847761SN/A    } else {
4857761SN/A        if (half) {
4869988Snilay@cs.wisc.edu            if ((double)val < 0) {
4877761SN/A                feraiseexcept(FeInvalid);
4887761SN/A                feclearexcept(FeInexact);
48911066Snilay@cs.wisc.edu                return 0;
4907761SN/A            }
4917761SN/A            if ((double)val > (mask(16))) {
4927761SN/A                feraiseexcept(FeInvalid);
4939988Snilay@cs.wisc.edu                feclearexcept(FeInexact);
4947761SN/A                return mask(16);
4957761SN/A            }
49611066Snilay@cs.wisc.edu            return (uint16_t)val;
4977761SN/A        } else {
4987761SN/A            if ((double)val < 0) {
4997761SN/A                feraiseexcept(FeInvalid);
5009988Snilay@cs.wisc.edu                feclearexcept(FeInexact);
5017761SN/A                return 0;
5023096SN/A            }
50311066Snilay@cs.wisc.edu            if ((double)val > (mask(32))) {
5043096SN/A                feraiseexcept(FeInvalid);
5053096SN/A                feclearexcept(FeInexact);
5063096SN/A                return mask(32);
50711731Sjason@lowepower.com            }
5087761SN/A            return (uint32_t)val;
5099988Snilay@cs.wisc.edu        }
51011731Sjason@lowepower.com    }
5113096SN/A}
51211731Sjason@lowepower.com
5133096SN/Astatic inline float
5149988Snilay@cs.wisc.eduvfpUFixedToFpS(FPSCR fpscr, uint32_t val, bool half, uint8_t imm)
5153096SN/A{
5163096SN/A    fesetround(FeRoundNearest);
51711066Snilay@cs.wisc.edu    if (half)
5183096SN/A        val = (uint16_t)val;
51911731Sjason@lowepower.com    float scale = powf(2.0, imm);
52011731Sjason@lowepower.com    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
52111731Sjason@lowepower.com    feclearexcept(FeAllExceptions);
52211731Sjason@lowepower.com    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
52311731Sjason@lowepower.com    return fixDivDest(fpscr, val / scale, (float)val, scale);
52411731Sjason@lowepower.com}
52511731Sjason@lowepower.com
5263096SN/Astatic inline float
5273096SN/AvfpSFixedToFpS(FPSCR fpscr, int32_t val, bool half, uint8_t imm)
52811731Sjason@lowepower.com{
5297761SN/A    fesetround(FeRoundNearest);
5309988Snilay@cs.wisc.edu    if (half)
53111731Sjason@lowepower.com        val = sext<16>(val & mask(16));
5327761SN/A    float scale = powf(2.0, imm);
5337761SN/A    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
5347761SN/A    feclearexcept(FeAllExceptions);
5359988Snilay@cs.wisc.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
5367761SN/A    return fixDivDest(fpscr, val / scale, (float)val, scale);
5377761SN/A}
53811066Snilay@cs.wisc.edu
5397761SN/Astatic inline uint64_t
5407761SN/AvfpFpDToFixed(double val, bool isSigned, bool half,
5417761SN/A              uint8_t imm, bool rzero = true)
5429988Snilay@cs.wisc.edu{
5437761SN/A    int rmode = rzero ? FeRoundZero : fegetround();
5447761SN/A    fesetround(FeRoundNearest);
54511066Snilay@cs.wisc.edu    val = val * pow(2.0, imm);
5467761SN/A    __asm__ __volatile__("" : "=m" (val) : "m" (val));
54711731Sjason@lowepower.com    fesetround(rmode);
54811731Sjason@lowepower.com    feclearexcept(FeAllExceptions);
54911731Sjason@lowepower.com    __asm__ __volatile__("" : "=m" (val) : "m" (val));
55011731Sjason@lowepower.com    double origVal = val;
55111731Sjason@lowepower.com    val = rint(val);
55211731Sjason@lowepower.com    int fpType = std::fpclassify(val);
55311731Sjason@lowepower.com    if (fpType == FP_SUBNORMAL || fpType == FP_NAN) {
55411731Sjason@lowepower.com        if (fpType == FP_NAN) {
55511731Sjason@lowepower.com            feraiseexcept(FeInvalid);
55611731Sjason@lowepower.com        }
55711731Sjason@lowepower.com        val = 0.0;
55811731Sjason@lowepower.com    } else if (origVal != val) {
55911731Sjason@lowepower.com        switch (rmode) {
56011731Sjason@lowepower.com          case FeRoundNearest:
5617761SN/A            if (origVal - val > 0.5)
5627761SN/A                val += 1.0;
5634938SN/A            else if (val - origVal > 0.5)
5643096SN/A                val -= 1.0;
5659988Snilay@cs.wisc.edu            break;
5667761SN/A          case FeRoundDown:
5673096SN/A            if (origVal < val)
5687761SN/A                val -= 1.0;
5693096SN/A            break;
5709988Snilay@cs.wisc.edu          case FeRoundUpward:
5713096SN/A            if (origVal > val)
5723096SN/A                val += 1.0;
57311066Snilay@cs.wisc.edu            break;
5743096SN/A        }
5753096SN/A        feraiseexcept(FeInexact);
57611066Snilay@cs.wisc.edu    }
5779885Sstever@gmail.com    if (isSigned) {
57811680SCurtis.Dunham@arm.com        if (half) {
5793096SN/A            if (val < (int16_t)(1 << 15)) {
5809885Sstever@gmail.com                feraiseexcept(FeInvalid);
58111219Snilay@cs.wisc.edu                feclearexcept(FeInexact);
58211731Sjason@lowepower.com                return (int16_t)(1 << 15);
58311570SCurtis.Dunham@arm.com            }
58410636Snilay@cs.wisc.edu            if (val > (int16_t)mask(15)) {
5859988Snilay@cs.wisc.edu                feraiseexcept(FeInvalid);
58611066Snilay@cs.wisc.edu                feclearexcept(FeInexact);
5873096SN/A                return (int16_t)mask(15);
5889348SAli.Saidi@ARM.com            }
58911570SCurtis.Dunham@arm.com            return (int16_t)val;
59011570SCurtis.Dunham@arm.com        } else {
59111570SCurtis.Dunham@arm.com            if (val < (int32_t)(1 << 31)) {
59211570SCurtis.Dunham@arm.com                feraiseexcept(FeInvalid);
5935876SN/A                feclearexcept(FeInexact);
5948835SAli.Saidi@ARM.com                return (int32_t)(1 << 31);
5959348SAli.Saidi@ARM.com            }
59610036SAli.Saidi@ARM.com            if (val > (int32_t)mask(31)) {
5973096SN/A                feraiseexcept(FeInvalid);
5988835SAli.Saidi@ARM.com                feclearexcept(FeInexact);
59911731Sjason@lowepower.com                return (int32_t)mask(31);
6009885Sstever@gmail.com            }
6014316SN/A            return (int32_t)val;
6023096SN/A        }
60311219Snilay@cs.wisc.edu    } else {
6043104SN/A        if (half) {
6058983Snate@binkert.org            if (val < 0) {
6063096SN/A                feraiseexcept(FeInvalid);
6079885Sstever@gmail.com                feclearexcept(FeInexact);
6089885Sstever@gmail.com                return 0;
6099885Sstever@gmail.com            }
6109885Sstever@gmail.com            if (val > mask(16)) {
6119885Sstever@gmail.com                feraiseexcept(FeInvalid);
61211731Sjason@lowepower.com                feclearexcept(FeInexact);
61311570SCurtis.Dunham@arm.com                return mask(16);
6149988Snilay@cs.wisc.edu            }
61511570SCurtis.Dunham@arm.com            return (uint16_t)val;
61611570SCurtis.Dunham@arm.com        } else {
61711570SCurtis.Dunham@arm.com            if (val < 0) {
61811570SCurtis.Dunham@arm.com                feraiseexcept(FeInvalid);
61910036SAli.Saidi@ARM.com                feclearexcept(FeInexact);
6209885Sstever@gmail.com                return 0;
62111731Sjason@lowepower.com            }
6229885Sstever@gmail.com            if (val > mask(32)) {
6238835SAli.Saidi@ARM.com                feraiseexcept(FeInvalid);
6248835SAli.Saidi@ARM.com                feclearexcept(FeInexact);
6259988Snilay@cs.wisc.edu                return mask(32);
6268835SAli.Saidi@ARM.com            }
6279348SAli.Saidi@ARM.com            return (uint32_t)val;
6289348SAli.Saidi@ARM.com        }
6299988Snilay@cs.wisc.edu    }
63010036SAli.Saidi@ARM.com}
6319348SAli.Saidi@ARM.com
6325000SN/Astatic inline double
6336024SN/AvfpUFixedToFpD(FPSCR fpscr, uint32_t val, bool half, uint8_t imm)
6349988Snilay@cs.wisc.edu{
6355000SN/A    fesetround(FeRoundNearest);
6365000SN/A    if (half)
6373096SN/A        val = (uint16_t)val;
63811066Snilay@cs.wisc.edu    double scale = pow(2.0, imm);
6399885Sstever@gmail.com    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
64011680SCurtis.Dunham@arm.com    feclearexcept(FeAllExceptions);
6419348SAli.Saidi@ARM.com    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
6429885Sstever@gmail.com    return fixDivDest(fpscr, val / scale, (double)val, scale);
64311219Snilay@cs.wisc.edu}
64411731Sjason@lowepower.com
64511570SCurtis.Dunham@arm.comstatic inline double
64610636Snilay@cs.wisc.eduvfpSFixedToFpD(FPSCR fpscr, int32_t val, bool half, uint8_t imm)
6479988Snilay@cs.wisc.edu{
64811066Snilay@cs.wisc.edu    fesetround(FeRoundNearest);
6493096SN/A    if (half)
6509348SAli.Saidi@ARM.com        val = sext<16>(val & mask(16));
65111570SCurtis.Dunham@arm.com    double scale = pow(2.0, imm);
65211570SCurtis.Dunham@arm.com    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
65311570SCurtis.Dunham@arm.com    feclearexcept(FeAllExceptions);
65411570SCurtis.Dunham@arm.com    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
6555876SN/A    return fixDivDest(fpscr, val / scale, (double)val, scale);
6568835SAli.Saidi@ARM.com}
6579348SAli.Saidi@ARM.com
65810036SAli.Saidi@ARM.comclass VfpMacroOp : public PredMacroOp
6593096SN/A{
6608835SAli.Saidi@ARM.com  public:
66111731Sjason@lowepower.com    static bool
6629885Sstever@gmail.com    inScalarBank(IntRegIndex idx)
6639348SAli.Saidi@ARM.com    {
6643096SN/A        return (idx % 32) < 8;
66511219Snilay@cs.wisc.edu    }
6668983Snate@binkert.org
6678983Snate@binkert.org  protected:
6683096SN/A    bool wide;
6699885Sstever@gmail.com
6709885Sstever@gmail.com    VfpMacroOp(const char *mnem, ExtMachInst _machInst,
6719885Sstever@gmail.com            OpClass __opClass, bool _wide) :
6729885Sstever@gmail.com        PredMacroOp(mnem, _machInst, __opClass), wide(_wide)
6739885Sstever@gmail.com    {}
67411731Sjason@lowepower.com
67511570SCurtis.Dunham@arm.com    IntRegIndex
6769988Snilay@cs.wisc.edu    addStride(IntRegIndex idx, unsigned stride)
67711570SCurtis.Dunham@arm.com    {
67811570SCurtis.Dunham@arm.com        if (wide) {
67911570SCurtis.Dunham@arm.com            stride *= 2;
68011570SCurtis.Dunham@arm.com        }
68110036SAli.Saidi@ARM.com        unsigned offset = idx % 8;
6829885Sstever@gmail.com        idx = (IntRegIndex)(idx - offset);
68311731Sjason@lowepower.com        offset += stride;
6849885Sstever@gmail.com        idx = (IntRegIndex)(idx + (offset % 8));
6853096SN/A        return idx;
68610451Snilay@cs.wisc.edu    }
68711219Snilay@cs.wisc.edu
6889885Sstever@gmail.com    void
68911570SCurtis.Dunham@arm.com    nextIdxs(IntRegIndex &dest, IntRegIndex &op1, IntRegIndex &op2)
6909988Snilay@cs.wisc.edu    {
69110736Snilay@cs.wisc.edu        unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2;
69210736Snilay@cs.wisc.edu        assert(!inScalarBank(dest));
69311570SCurtis.Dunham@arm.com        dest = addStride(dest, stride);
69411570SCurtis.Dunham@arm.com        op1 = addStride(op1, stride);
69511570SCurtis.Dunham@arm.com        if (!inScalarBank(op2)) {
69611384Ssteve.reinhardt@amd.com            op2 = addStride(op2, stride);
69711570SCurtis.Dunham@arm.com        }
69810736Snilay@cs.wisc.edu    }
69911219Snilay@cs.wisc.edu
70010736Snilay@cs.wisc.edu    void
7019578Snilay@cs.wisc.edu    nextIdxs(IntRegIndex &dest, IntRegIndex &op1)
7027524SN/A    {
7039348SAli.Saidi@ARM.com        unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2;
7048983Snate@binkert.org        assert(!inScalarBank(dest));
7058983Snate@binkert.org        dest = addStride(dest, stride);
7063096SN/A        if (!inScalarBank(op1)) {
70711219Snilay@cs.wisc.edu            op1 = addStride(op1, stride);
70811219Snilay@cs.wisc.edu        }
70911219Snilay@cs.wisc.edu    }
71011219Snilay@cs.wisc.edu
71111219Snilay@cs.wisc.edu    void
71211219Snilay@cs.wisc.edu    nextIdxs(IntRegIndex &dest)
71311219Snilay@cs.wisc.edu    {
7144938SN/A        unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2;
7154938SN/A        assert(!inScalarBank(dest));
7169988Snilay@cs.wisc.edu        dest = addStride(dest, stride);
7174938SN/A    }
7183096SN/A};
7193096SN/A
7203096SN/Astatic inline float
7213974SN/AfpAddS(float a, float b)
72210636Snilay@cs.wisc.edu{
7233147SN/A    return a + b;
7243096SN/A}
7255516SN/A
7263147SN/Astatic inline double
7279988Snilay@cs.wisc.edufpAddD(double a, double b)
72811731Sjason@lowepower.com{
7293147SN/A    return a + b;
7303096SN/A}
73110636Snilay@cs.wisc.edu
7325328SN/Astatic inline float
7333096SN/AfpSubS(float a, float b)
7343147SN/A{
7353147SN/A    return a - b;
7365509SN/A}
7373096SN/A
7383147SN/Astatic inline double
73910451Snilay@cs.wisc.edufpSubD(double a, double b)
7403096SN/A{
7419885Sstever@gmail.com    return a - b;
7429885Sstever@gmail.com}
7439885Sstever@gmail.com
74410315Snilay@cs.wisc.edustatic inline float
7459988Snilay@cs.wisc.edufpDivS(float a, float b)
74610315Snilay@cs.wisc.edu{
7479885Sstever@gmail.com    return a / b;
7489885Sstever@gmail.com}
74910315Snilay@cs.wisc.edu
75010315Snilay@cs.wisc.edustatic inline double
75110315Snilay@cs.wisc.edufpDivD(double a, double b)
75210315Snilay@cs.wisc.edu{
75310315Snilay@cs.wisc.edu    return a / b;
75410315Snilay@cs.wisc.edu}
75510315Snilay@cs.wisc.edu
75610315Snilay@cs.wisc.edustatic inline float
7573096SN/AfpMulS(float a, float b)
75810451Snilay@cs.wisc.edu{
75911680SCurtis.Dunham@arm.com    return a * b;
7609885Sstever@gmail.com}
76111570SCurtis.Dunham@arm.com
7629988Snilay@cs.wisc.edustatic inline double
76310736Snilay@cs.wisc.edufpMulD(double a, double b)
76410736Snilay@cs.wisc.edu{
76511570SCurtis.Dunham@arm.com    return a * b;
76611570SCurtis.Dunham@arm.com}
76711570SCurtis.Dunham@arm.com
76811384Ssteve.reinhardt@amd.comclass FpOp : public PredOp
76911570SCurtis.Dunham@arm.com{
77010736Snilay@cs.wisc.edu  protected:
77111680SCurtis.Dunham@arm.com    FpOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
77210736Snilay@cs.wisc.edu        PredOp(mnem, _machInst, __opClass)
7739578Snilay@cs.wisc.edu    {}
7747524SN/A
77510736Snilay@cs.wisc.edu    virtual float
7769150SAli.Saidi@ARM.com    doOp(float op1, float op2) const
7778983Snate@binkert.org    {
7783096SN/A        panic("Unimplemented version of doOp called.\n");
77911680SCurtis.Dunham@arm.com    }
78011680SCurtis.Dunham@arm.com
78111680SCurtis.Dunham@arm.com    virtual float
78211680SCurtis.Dunham@arm.com    doOp(float op1) const
78311680SCurtis.Dunham@arm.com    {
78411680SCurtis.Dunham@arm.com        panic("Unimplemented version of doOp called.\n");
78511680SCurtis.Dunham@arm.com    }
7863096SN/A
78710242Ssteve.reinhardt@amd.com    virtual double
78811680SCurtis.Dunham@arm.com    doOp(double op1, double op2) const
78910451Snilay@cs.wisc.edu    {
79011680SCurtis.Dunham@arm.com        panic("Unimplemented version of doOp called.\n");
79110451Snilay@cs.wisc.edu    }
79210451Snilay@cs.wisc.edu
79310451Snilay@cs.wisc.edu    virtual double
79411680SCurtis.Dunham@arm.com    doOp(double op1) const
79510451Snilay@cs.wisc.edu    {
79611680SCurtis.Dunham@arm.com        panic("Unimplemented version of doOp called.\n");
79710451Snilay@cs.wisc.edu    }
79810451Snilay@cs.wisc.edu
79910451Snilay@cs.wisc.edu    double
80011680SCurtis.Dunham@arm.com    dbl(uint32_t low, uint32_t high) const
80110451Snilay@cs.wisc.edu    {
80211680SCurtis.Dunham@arm.com        double junk = 0.0;
80310451Snilay@cs.wisc.edu        return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk);
80411680SCurtis.Dunham@arm.com    }
80510451Snilay@cs.wisc.edu
80611680SCurtis.Dunham@arm.com    uint32_t
80710451Snilay@cs.wisc.edu    dblLow(double val) const
80811680SCurtis.Dunham@arm.com    {
80910451Snilay@cs.wisc.edu        return fpToBits(val);
81010451Snilay@cs.wisc.edu    }
81110451Snilay@cs.wisc.edu
8129578Snilay@cs.wisc.edu    uint32_t
81310736Snilay@cs.wisc.edu    dblHi(double val) const
81410451Snilay@cs.wisc.edu    {
8159348SAli.Saidi@ARM.com        return fpToBits(val) >> 32;
8169885Sstever@gmail.com    }
8179578Snilay@cs.wisc.edu
8189885Sstever@gmail.com    template <class fpType>
8199885Sstever@gmail.com    fpType
82011570SCurtis.Dunham@arm.com    binaryOp(FPSCR &fpscr, fpType op1, fpType op2,
8219885Sstever@gmail.com            fpType (*func)(fpType, fpType),
8229885Sstever@gmail.com            bool flush, uint32_t rMode) const
82310636Snilay@cs.wisc.edu    {
8249885Sstever@gmail.com        const bool single = (sizeof(fpType) == sizeof(float));
82510451Snilay@cs.wisc.edu        fpType junk = 0.0;
8269988Snilay@cs.wisc.edu
8278983Snate@binkert.org        if (flush && flushToZero(op1, op2))
82811680SCurtis.Dunham@arm.com            fpscr.idc = 1;
82910242Ssteve.reinhardt@amd.com        VfpSavedState state = prepFpState(rMode);
8309578Snilay@cs.wisc.edu        __asm__ __volatile__ ("" : "=m" (op1), "=m" (op2), "=m" (state)
83110242Ssteve.reinhardt@amd.com                                 : "m" (op1), "m" (op2), "m" (state));
8325509SN/A        fpType dest = func(op1, op2);
83311570SCurtis.Dunham@arm.com        __asm__ __volatile__ ("" : "=m" (dest) : "m" (dest));
83411570SCurtis.Dunham@arm.com
83511570SCurtis.Dunham@arm.com        int fpClass = std::fpclassify(dest);
83610242Ssteve.reinhardt@amd.com        // Get NAN behavior right. This varies between x86 and ARM.
83711570SCurtis.Dunham@arm.com        if (fpClass == FP_NAN) {
83811680SCurtis.Dunham@arm.com            const bool single = (sizeof(fpType) == sizeof(float));
8399348SAli.Saidi@ARM.com            const uint64_t qnan =
8409348SAli.Saidi@ARM.com                single ? 0x7fc00000 : ULL(0x7ff8000000000000);
8419885Sstever@gmail.com            const bool nan1 = std::isnan(op1);
8429885Sstever@gmail.com            const bool nan2 = std::isnan(op2);
8439578Snilay@cs.wisc.edu            const bool signal1 = nan1 && ((fpToBits(op1) & qnan) != qnan);
84410451Snilay@cs.wisc.edu            const bool signal2 = nan2 && ((fpToBits(op2) & qnan) != qnan);
84510242Ssteve.reinhardt@amd.com            if ((!nan1 && !nan2) || (fpscr.dn == 1)) {
8469578Snilay@cs.wisc.edu                dest = bitsToFp(qnan, junk);
84710451Snilay@cs.wisc.edu            } else if (signal1) {
8489988Snilay@cs.wisc.edu                dest = bitsToFp(fpToBits(op1) | qnan, junk);
8499578Snilay@cs.wisc.edu            } else if (signal2) {
8509348SAli.Saidi@ARM.com                dest = bitsToFp(fpToBits(op2) | qnan, junk);
85110242Ssteve.reinhardt@amd.com            } else if (nan1) {
8529578Snilay@cs.wisc.edu                dest = op1;
85310242Ssteve.reinhardt@amd.com            } else if (nan2) {
85410451Snilay@cs.wisc.edu                dest = op2;
85510242Ssteve.reinhardt@amd.com            }
85610242Ssteve.reinhardt@amd.com        } else if (flush && flushToZero(dest)) {
85710242Ssteve.reinhardt@amd.com            feraiseexcept(FeUnderflow);
8589578Snilay@cs.wisc.edu        } else if ((
85910242Ssteve.reinhardt@amd.com                    (single && (dest == bitsToFp(0x00800000, junk) ||
86011680SCurtis.Dunham@arm.com                         dest == bitsToFp(0x80800000, junk))) ||
86110451Snilay@cs.wisc.edu                    (!single &&
86211680SCurtis.Dunham@arm.com                        (dest == bitsToFp(ULL(0x0010000000000000), junk) ||
86310451Snilay@cs.wisc.edu                         dest == bitsToFp(ULL(0x8010000000000000), junk)))
86410242Ssteve.reinhardt@amd.com                   ) && rMode != VfpRoundZero) {
86510242Ssteve.reinhardt@amd.com            /*
86610242Ssteve.reinhardt@amd.com             * Correct for the fact that underflow is detected -before- rounding
8678983Snate@binkert.org             * in ARM and -after- rounding in x86.
8683096SN/A             */
8699885Sstever@gmail.com            fesetround(FeRoundZero);
8709885Sstever@gmail.com            __asm__ __volatile__ ("" : "=m" (op1), "=m" (op2)
8719988Snilay@cs.wisc.edu                                     : "m" (op1), "m" (op2));
8729885Sstever@gmail.com            fpType temp = func(op1, op2);
8739885Sstever@gmail.com            __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