vfp.hh revision 7388
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 void
1103349Sbinkertn@umich.eduvfpFlushToZero(uint32_t &_fpscr, fpType &op)
1112623SN/A{
1123310Srdreslin@umich.edu    FPSCR fpscr = _fpscr;
1133649Srdreslin@umich.edu    if (fpscr.fz == 1 && (std::fpclassify(op) == FP_SUBNORMAL)) {
1142623SN/A        fpscr.idc = 1;
1152623SN/A        op = 0;
1162623SN/A    }
1173349Sbinkertn@umich.edu    _fpscr = fpscr;
1182623SN/A}
1193184Srdreslin@umich.edu
1203184Srdreslin@umich.edutemplate <class fpType>
1212623SN/Astatic inline void
1222623SN/AvfpFlushToZero(uint32_t &fpscr, fpType &op1, fpType &op2)
1232623SN/A{
1242623SN/A    vfpFlushToZero(fpscr, op1);
1252623SN/A    vfpFlushToZero(fpscr, op2);
1263647Srdreslin@umich.edu}
1273647Srdreslin@umich.edu
1283647Srdreslin@umich.edustatic inline uint32_t
1293647Srdreslin@umich.edufpToBits(float fp)
1303647Srdreslin@umich.edu{
1312626SN/A    union
1323647Srdreslin@umich.edu    {
1332626SN/A        float fp;
1342623SN/A        uint32_t bits;
1352623SN/A    } val;
1362623SN/A    val.fp = fp;
1372657Ssaidi@eecs.umich.edu    return val.bits;
1382623SN/A}
1392623SN/A
1402623SN/Astatic inline uint64_t
1412623SN/AfpToBits(double fp)
1422623SN/A{
1434192Sktlim@umich.edu    union
1444192Sktlim@umich.edu    {
1454192Sktlim@umich.edu        double fp;
1464192Sktlim@umich.edu        uint64_t bits;
1474192Sktlim@umich.edu    } val;
1484192Sktlim@umich.edu    val.fp = fp;
1494192Sktlim@umich.edu    return val.bits;
1504192Sktlim@umich.edu}
1515497Ssaidi@eecs.umich.edu
1524192Sktlim@umich.edustatic inline float
1534192Sktlim@umich.edubitsToFp(uint64_t bits, float junk)
1542623SN/A{
1555529Snate@binkert.org    union
1565487Snate@binkert.org    {
1575487Snate@binkert.org        float fp;
1585487Snate@binkert.org        uint32_t bits;
1594968Sacolyte@umich.edu    } val;
1604968Sacolyte@umich.edu    val.bits = bits;
1612623SN/A    return val.fp;
1622623SN/A}
1632623SN/A
1643647Srdreslin@umich.edustatic inline double
1653647Srdreslin@umich.edubitsToFp(uint64_t bits, double junk)
1663647Srdreslin@umich.edu{
1672623SN/A    union
1682623SN/A    {
1692623SN/A        double fp;
1702623SN/A        uint64_t bits;
1712623SN/A    } val;
1722623SN/A    val.bits = bits;
1732623SN/A    return val.fp;
1742623SN/A}
1752623SN/A
1762623SN/Atemplate <class fpType>
1772915Sktlim@umich.edustatic inline fpType
1782915Sktlim@umich.edufixDest(FPSCR fpscr, fpType val, fpType op1)
1793145Shsul@eecs.umich.edu{
1802623SN/A    int fpClass = std::fpclassify(val);
1812623SN/A    fpType junk = 0.0;
1822623SN/A    if (fpClass == FP_NAN) {
1832623SN/A        const bool single = (sizeof(val) == sizeof(float));
1842623SN/A        const uint64_t qnan = single ? 0x7fc00000 : ULL(0x7ff8000000000000);
1852623SN/A        const bool nan = std::isnan(op1);
1862623SN/A        if (!nan || (fpscr.dn == 1)) {
1872915Sktlim@umich.edu            val = bitsToFp(qnan, junk);
1882915Sktlim@umich.edu        } else if (nan) {
1893145Shsul@eecs.umich.edu            val = bitsToFp(fpToBits(op1) | qnan, junk);
1902915Sktlim@umich.edu        }
1912915Sktlim@umich.edu    } else if (fpClass == FP_SUBNORMAL && fpscr.fz == 1) {
1922915Sktlim@umich.edu        // Turn val into a zero with the correct sign;
1932915Sktlim@umich.edu        uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1);
1942915Sktlim@umich.edu        val = bitsToFp(fpToBits(val) & bitMask, junk);
1952915Sktlim@umich.edu        feraiseexcept(FeUnderflow);
1965220Ssaidi@eecs.umich.edu    }
1975220Ssaidi@eecs.umich.edu    return val;
1985220Ssaidi@eecs.umich.edu}
1994940Snate@binkert.org
2005220Ssaidi@eecs.umich.edutemplate <class fpType>
2013324Shsul@eecs.umich.edustatic inline fpType
2025220Ssaidi@eecs.umich.edufixDest(FPSCR fpscr, fpType val, fpType op1, fpType op2)
2035220Ssaidi@eecs.umich.edu{
2045606Snate@binkert.org    int fpClass = std::fpclassify(val);
2055606Snate@binkert.org    fpType junk = 0.0;
2062915Sktlim@umich.edu    if (fpClass == FP_NAN) {
2072623SN/A        const bool single = (sizeof(val) == sizeof(float));
2082623SN/A        const uint64_t qnan = single ? 0x7fc00000 : ULL(0x7ff8000000000000);
2092623SN/A        const bool nan1 = std::isnan(op1);
2102798Sktlim@umich.edu        const bool nan2 = std::isnan(op2);
2112623SN/A        const bool signal1 = nan1 && ((fpToBits(op1) & qnan) != qnan);
2125496Ssaidi@eecs.umich.edu        const bool signal2 = nan2 && ((fpToBits(op2) & qnan) != qnan);
2132798Sktlim@umich.edu        if ((!nan1 && !nan2) || (fpscr.dn == 1)) {
2142623SN/A            val = bitsToFp(qnan, junk);
2152798Sktlim@umich.edu        } else if (signal1) {
2162623SN/A            val = bitsToFp(fpToBits(op1) | qnan, junk);
2172623SN/A        } else if (signal2) {
2182623SN/A            val = bitsToFp(fpToBits(op2) | qnan, junk);
2192623SN/A        } else if (nan1) {
2202623SN/A            val = op1;
2212623SN/A        } else if (nan2) {
2224192Sktlim@umich.edu            val = op2;
2232623SN/A        }
2242623SN/A    } else if (fpClass == FP_SUBNORMAL && fpscr.fz == 1) {
2252623SN/A        // Turn val into a zero with the correct sign;
2262680Sktlim@umich.edu        uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1);
2272623SN/A        val = bitsToFp(fpToBits(val) & bitMask, junk);
2282680Sktlim@umich.edu        feraiseexcept(FeUnderflow);
2292680Sktlim@umich.edu    }
2302680Sktlim@umich.edu    return val;
2312623SN/A}
2325606Snate@binkert.org
2332623SN/Atemplate <class fpType>
2342623SN/Astatic inline fpType
2352623SN/AfixMultDest(FPSCR fpscr, fpType val, fpType op1, fpType op2)
2363512Sktlim@umich.edu{
2373512Sktlim@umich.edu    fpType mid = fixDest(fpscr, val, op1, op2);
2383512Sktlim@umich.edu    const bool single = (sizeof(fpType) == sizeof(float));
2395169Ssaidi@eecs.umich.edu    const fpType junk = 0.0;
2405712Shsul@eecs.umich.edu    if ((single && (val == bitsToFp(0x00800000, junk) ||
2415712Shsul@eecs.umich.edu                    val == bitsToFp(0x80800000, junk))) ||
2425712Shsul@eecs.umich.edu        (!single && (val == bitsToFp(ULL(0x0010000000000000), junk) ||
2432623SN/A                     val == bitsToFp(ULL(0x8010000000000000), junk)))
2442623SN/A        ) {
2452623SN/A        __asm__ __volatile__("" : "=m" (op1) : "m" (op1));
2462623SN/A        fesetround(FeRoundZero);
2472623SN/A        fpType temp = 0.0;
2482623SN/A        __asm__ __volatile__("" : "=m" (temp) : "m" (temp));
2494940Snate@binkert.org        temp = op1 * op2;
2504940Snate@binkert.org        if (!std::isnormal(temp)) {
2512623SN/A            feraiseexcept(FeUnderflow);
2522683Sktlim@umich.edu        }
2532623SN/A        __asm__ __volatile__("" :: "m" (temp));
2542623SN/A    }
2552623SN/A    return mid;
2562623SN/A}
2572623SN/A
2585101Ssaidi@eecs.umich.edutemplate <class fpType>
2593686Sktlim@umich.edustatic inline fpType
2603430Sgblack@eecs.umich.edufixDivDest(FPSCR fpscr, fpType val, fpType op1, fpType op2)
2615606Snate@binkert.org{
2622623SN/A    fpType mid = fixDest(fpscr, val, op1, op2);
2632623SN/A    const bool single = (sizeof(fpType) == sizeof(float));
2642623SN/A    const fpType junk = 0.0;
2652623SN/A    if ((single && (val == bitsToFp(0x00800000, junk) ||
2662623SN/A                    val == bitsToFp(0x80800000, junk))) ||
2672623SN/A        (!single && (val == bitsToFp(ULL(0x0010000000000000), junk) ||
2682623SN/A                     val == bitsToFp(ULL(0x8010000000000000), junk)))
2694940Snate@binkert.org        ) {
2704940Snate@binkert.org        __asm__ __volatile__("" : "=m" (op1) : "m" (op1));
2712623SN/A        fesetround(FeRoundZero);
2722683Sktlim@umich.edu        fpType temp = 0.0;
2732623SN/A        __asm__ __volatile__("" : "=m" (temp) : "m" (temp));
2742623SN/A        temp = op1 / op2;
2752626SN/A        if (!std::isnormal(temp)) {
2762626SN/A            feraiseexcept(FeUnderflow);
2772626SN/A        }
2782626SN/A        __asm__ __volatile__("" :: "m" (temp));
2795606Snate@binkert.org    }
2802623SN/A    return mid;
2812623SN/A}
2822623SN/A
2832623SN/Astatic inline float
2842623SN/AfixFpDFpSDest(FPSCR fpscr, double val)
2852623SN/A{
2862623SN/A    const float junk = 0.0;
2872623SN/A    float op1 = 0.0;
2882623SN/A    if (std::isnan(val)) {
2892623SN/A        uint64_t valBits = fpToBits(val);
2903169Sstever@eecs.umich.edu        uint32_t op1Bits = bits(valBits, 50, 29) |
2914870Sstever@eecs.umich.edu                           (mask(9) << 22) |
2922623SN/A                           (bits(valBits, 63) << 31);
2932623SN/A        op1 = bitsToFp(op1Bits, junk);
2942623SN/A    }
2952623SN/A    float mid = fixDest(fpscr, (float)val, op1);
2962623SN/A    if (mid == bitsToFp(0x00800000, junk) ||
2974999Sgblack@eecs.umich.edu        mid == bitsToFp(0x80800000, junk)) {
2984999Sgblack@eecs.umich.edu        __asm__ __volatile__("" : "=m" (val) : "m" (val));
2994999Sgblack@eecs.umich.edu        fesetround(FeRoundZero);
3004999Sgblack@eecs.umich.edu        float temp = 0.0;
3012623SN/A        __asm__ __volatile__("" : "=m" (temp) : "m" (temp));
3024999Sgblack@eecs.umich.edu        temp = val;
3032623SN/A        if (!std::isnormal(temp)) {
3044999Sgblack@eecs.umich.edu            feraiseexcept(FeUnderflow);
3054999Sgblack@eecs.umich.edu        }
3064999Sgblack@eecs.umich.edu        __asm__ __volatile__("" :: "m" (temp));
3074999Sgblack@eecs.umich.edu    }
3084999Sgblack@eecs.umich.edu    return mid;
3094999Sgblack@eecs.umich.edu}
3104999Sgblack@eecs.umich.edu
3114999Sgblack@eecs.umich.edustatic inline uint64_t
3124999Sgblack@eecs.umich.eduvfpFpSToFixed(float val, bool isSigned, bool half,
3134999Sgblack@eecs.umich.edu              uint8_t imm, bool rzero = true)
3144999Sgblack@eecs.umich.edu{
3154999Sgblack@eecs.umich.edu    int rmode = fegetround();
3164999Sgblack@eecs.umich.edu    fesetround(FeRoundNearest);
3174999Sgblack@eecs.umich.edu    val = val * powf(2.0, imm);
3184999Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (val) : "m" (val));
3194999Sgblack@eecs.umich.edu    if (rzero)
3204999Sgblack@eecs.umich.edu        fesetround(FeRoundZero);
3214999Sgblack@eecs.umich.edu    else
3224999Sgblack@eecs.umich.edu        fesetround(rmode);
3234999Sgblack@eecs.umich.edu    feclearexcept(FeAllExceptions);
3244999Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (val) : "m" (val));
3254999Sgblack@eecs.umich.edu    float origVal = val;
3264999Sgblack@eecs.umich.edu    val = rintf(val);
3274999Sgblack@eecs.umich.edu    int fpType = std::fpclassify(val);
3284999Sgblack@eecs.umich.edu    if (fpType == FP_SUBNORMAL || fpType == FP_NAN) {
3294999Sgblack@eecs.umich.edu        if (fpType == FP_NAN) {
3304999Sgblack@eecs.umich.edu            feraiseexcept(FeInvalid);
3314999Sgblack@eecs.umich.edu        }
3324999Sgblack@eecs.umich.edu        val = 0.0;
3334999Sgblack@eecs.umich.edu    } else if (origVal != val) {
3344999Sgblack@eecs.umich.edu        feraiseexcept(FeInexact);
3355012Sgblack@eecs.umich.edu    }
3364999Sgblack@eecs.umich.edu
3374999Sgblack@eecs.umich.edu    if (isSigned) {
3384999Sgblack@eecs.umich.edu        if (half) {
3394999Sgblack@eecs.umich.edu            if ((double)val < (int16_t)(1 << 15)) {
3404999Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
3414968Sacolyte@umich.edu                feclearexcept(FeInexact);
3424986Ssaidi@eecs.umich.edu                return (int16_t)(1 << 15);
3434999Sgblack@eecs.umich.edu            }
3444999Sgblack@eecs.umich.edu            if ((double)val > (int16_t)mask(15)) {
3454999Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
3464762Snate@binkert.org                feclearexcept(FeInexact);
3474999Sgblack@eecs.umich.edu                return (int16_t)mask(15);
3484999Sgblack@eecs.umich.edu            }
3494999Sgblack@eecs.umich.edu            return (int16_t)val;
3504999Sgblack@eecs.umich.edu        } else {
3514999Sgblack@eecs.umich.edu            if ((double)val < (int32_t)(1 << 31)) {
3524999Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
3534999Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
3545408Sgblack@eecs.umich.edu                return (int32_t)(1 << 31);
3555408Sgblack@eecs.umich.edu            }
3565408Sgblack@eecs.umich.edu            if ((double)val > (int32_t)mask(31)) {
3574999Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
3584968Sacolyte@umich.edu                feclearexcept(FeInexact);
3593170Sstever@eecs.umich.edu                return (int32_t)mask(31);
3604999Sgblack@eecs.umich.edu            }
3614999Sgblack@eecs.umich.edu            return (int32_t)val;
3624999Sgblack@eecs.umich.edu        }
3634999Sgblack@eecs.umich.edu    } else {
3644999Sgblack@eecs.umich.edu        if (half) {
3654999Sgblack@eecs.umich.edu            if ((double)val < 0) {
3664999Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
3674999Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
3684999Sgblack@eecs.umich.edu                return 0;
3694999Sgblack@eecs.umich.edu            }
3702623SN/A            if ((double)val > (mask(16))) {
3712623SN/A                feraiseexcept(FeInvalid);
3722623SN/A                feclearexcept(FeInexact);
3735177Sgblack@eecs.umich.edu                return mask(16);
3745177Sgblack@eecs.umich.edu            }
3755177Sgblack@eecs.umich.edu            return (uint16_t)val;
3765177Sgblack@eecs.umich.edu        } else {
3775177Sgblack@eecs.umich.edu            if ((double)val < 0) {
3785177Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
3795177Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
3805177Sgblack@eecs.umich.edu                return 0;
3815177Sgblack@eecs.umich.edu            }
3825177Sgblack@eecs.umich.edu            if ((double)val > (mask(32))) {
3835177Sgblack@eecs.umich.edu                feraiseexcept(FeInvalid);
3845177Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
3855177Sgblack@eecs.umich.edu                return mask(32);
3865177Sgblack@eecs.umich.edu            }
3875177Sgblack@eecs.umich.edu            return (uint32_t)val;
3885177Sgblack@eecs.umich.edu        }
3895177Sgblack@eecs.umich.edu    }
3905177Sgblack@eecs.umich.edu}
3915177Sgblack@eecs.umich.edu
3925177Sgblack@eecs.umich.edustatic inline float
3935177Sgblack@eecs.umich.eduvfpUFixedToFpS(FPSCR fpscr, uint32_t val, bool half, uint8_t imm)
3945177Sgblack@eecs.umich.edu{
3955177Sgblack@eecs.umich.edu    fesetround(FeRoundNearest);
3965177Sgblack@eecs.umich.edu    if (half)
3975177Sgblack@eecs.umich.edu        val = (uint16_t)val;
3985177Sgblack@eecs.umich.edu    float scale = powf(2.0, imm);
3995177Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
4005177Sgblack@eecs.umich.edu    feclearexcept(FeAllExceptions);
4015177Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
4025177Sgblack@eecs.umich.edu    return fixDivDest(fpscr, val / scale, (float)val, scale);
4035177Sgblack@eecs.umich.edu}
4045177Sgblack@eecs.umich.edu
4055177Sgblack@eecs.umich.edustatic inline float
4065177Sgblack@eecs.umich.eduvfpSFixedToFpS(FPSCR fpscr, int32_t val, bool half, uint8_t imm)
4075177Sgblack@eecs.umich.edu{
4085177Sgblack@eecs.umich.edu    fesetround(FeRoundNearest);
4095177Sgblack@eecs.umich.edu    if (half)
4105177Sgblack@eecs.umich.edu        val = sext<16>(val & mask(16));
4115177Sgblack@eecs.umich.edu    float scale = powf(2.0, imm);
4125177Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
4135177Sgblack@eecs.umich.edu    feclearexcept(FeAllExceptions);
4145177Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
4155177Sgblack@eecs.umich.edu    return fixDivDest(fpscr, val / scale, (float)val, scale);
4165177Sgblack@eecs.umich.edu}
4175177Sgblack@eecs.umich.edu
4185177Sgblack@eecs.umich.edustatic inline uint64_t
4195177Sgblack@eecs.umich.eduvfpFpDToFixed(double val, bool isSigned, bool half,
4205177Sgblack@eecs.umich.edu              uint8_t imm, bool rzero = true)
4215177Sgblack@eecs.umich.edu{
4225177Sgblack@eecs.umich.edu    int rmode = fegetround();
4235177Sgblack@eecs.umich.edu    fesetround(FeRoundNearest);
4245177Sgblack@eecs.umich.edu    val = val * pow(2.0, imm);
4255177Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (val) : "m" (val));
4265177Sgblack@eecs.umich.edu    if (rzero)
4275177Sgblack@eecs.umich.edu        fesetround(FeRoundZero);
4282623SN/A    else
4292623SN/A        fesetround(rmode);
4302623SN/A    feclearexcept(FeAllExceptions);
4312623SN/A    __asm__ __volatile__("" : "=m" (val) : "m" (val));
4324115Ssaidi@eecs.umich.edu    double origVal = val;
4334115Ssaidi@eecs.umich.edu    val = rint(val);
4344115Ssaidi@eecs.umich.edu    int fpType = std::fpclassify(val);
4354115Ssaidi@eecs.umich.edu    if (fpType == FP_SUBNORMAL || fpType == FP_NAN) {
4364040Ssaidi@eecs.umich.edu        if (fpType == FP_NAN) {
4374040Ssaidi@eecs.umich.edu            feraiseexcept(FeInvalid);
4384040Ssaidi@eecs.umich.edu        }
4394040Ssaidi@eecs.umich.edu        val = 0.0;
4402623SN/A    } else if (origVal != val) {
4412623SN/A        feraiseexcept(FeInexact);
4422623SN/A    }
4432623SN/A    if (isSigned) {
4442623SN/A        if (half) {
4452623SN/A            if (val < (int16_t)(1 << 15)) {
4462623SN/A                feraiseexcept(FeInvalid);
4472623SN/A                feclearexcept(FeInexact);
4482623SN/A                return (int16_t)(1 << 15);
4492623SN/A            }
4502623SN/A            if (val > (int16_t)mask(15)) {
4512623SN/A                feraiseexcept(FeInvalid);
4522623SN/A                feclearexcept(FeInexact);
4532623SN/A                return (int16_t)mask(15);
4542623SN/A            }
4552623SN/A            return (int16_t)val;
4562623SN/A        } else {
4572623SN/A            if (val < (int32_t)(1 << 31)) {
4582623SN/A                feraiseexcept(FeInvalid);
4592623SN/A                feclearexcept(FeInexact);
4602623SN/A                return (int32_t)(1 << 31);
4612623SN/A            }
4622623SN/A            if (val > (int32_t)mask(31)) {
4632623SN/A                feraiseexcept(FeInvalid);
4642623SN/A                feclearexcept(FeInexact);
4652623SN/A                return (int32_t)mask(31);
4662623SN/A            }
4672623SN/A            return (int32_t)val;
4682623SN/A        }
4692623SN/A    } else {
4702623SN/A        if (half) {
4712623SN/A            if (val < 0) {
4722623SN/A                feraiseexcept(FeInvalid);
4732623SN/A                feclearexcept(FeInexact);
4742623SN/A                return 0;
4752623SN/A            }
4762623SN/A            if (val > mask(16)) {
4772623SN/A                feraiseexcept(FeInvalid);
4782623SN/A                feclearexcept(FeInexact);
4792623SN/A                return mask(16);
4802623SN/A            }
4812623SN/A            return (uint16_t)val;
4822623SN/A        } else {
4833169Sstever@eecs.umich.edu            if (val < 0) {
4844870Sstever@eecs.umich.edu                feraiseexcept(FeInvalid);
4852623SN/A                feclearexcept(FeInexact);
4862623SN/A                return 0;
4872623SN/A            }
4882623SN/A            if (val > mask(32)) {
4892623SN/A                feraiseexcept(FeInvalid);
4904999Sgblack@eecs.umich.edu                feclearexcept(FeInexact);
4914999Sgblack@eecs.umich.edu                return mask(32);
4924999Sgblack@eecs.umich.edu            }
4934999Sgblack@eecs.umich.edu            return (uint32_t)val;
4942623SN/A        }
4954999Sgblack@eecs.umich.edu    }
4962623SN/A}
4974999Sgblack@eecs.umich.edu
4984999Sgblack@eecs.umich.edustatic inline double
4994999Sgblack@eecs.umich.eduvfpUFixedToFpD(FPSCR fpscr, uint32_t val, bool half, uint8_t imm)
5004999Sgblack@eecs.umich.edu{
5014999Sgblack@eecs.umich.edu    fesetround(FeRoundNearest);
5024999Sgblack@eecs.umich.edu    if (half)
5034999Sgblack@eecs.umich.edu        val = (uint16_t)val;
5044999Sgblack@eecs.umich.edu    double scale = pow(2.0, imm);
5054999Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
5064999Sgblack@eecs.umich.edu    feclearexcept(FeAllExceptions);
5074999Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
5084999Sgblack@eecs.umich.edu    return fixDivDest(fpscr, val / scale, (double)val, scale);
5094999Sgblack@eecs.umich.edu}
5104999Sgblack@eecs.umich.edu
5114999Sgblack@eecs.umich.edustatic inline double
5124999Sgblack@eecs.umich.eduvfpSFixedToFpD(FPSCR fpscr, int32_t val, bool half, uint8_t imm)
5134999Sgblack@eecs.umich.edu{
5144999Sgblack@eecs.umich.edu    fesetround(FeRoundNearest);
5154999Sgblack@eecs.umich.edu    if (half)
5164999Sgblack@eecs.umich.edu        val = sext<16>(val & mask(16));
5174999Sgblack@eecs.umich.edu    double scale = pow(2.0, imm);
5184999Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
5194999Sgblack@eecs.umich.edu    feclearexcept(FeAllExceptions);
5204999Sgblack@eecs.umich.edu    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
5214999Sgblack@eecs.umich.edu    return fixDivDest(fpscr, val / scale, (double)val, scale);
5224999Sgblack@eecs.umich.edu}
5234999Sgblack@eecs.umich.edu
5244999Sgblack@eecs.umich.edutypedef int VfpSavedState;
5254999Sgblack@eecs.umich.edu
5264999Sgblack@eecs.umich.edustatic inline VfpSavedState
5274999Sgblack@eecs.umich.eduprepVfpFpscr(FPSCR fpscr)
5284999Sgblack@eecs.umich.edu{
5294999Sgblack@eecs.umich.edu    int roundingMode = fegetround();
5304999Sgblack@eecs.umich.edu    feclearexcept(FeAllExceptions);
5314999Sgblack@eecs.umich.edu    switch (fpscr.rMode) {
5324999Sgblack@eecs.umich.edu      case VfpRoundNearest:
5334999Sgblack@eecs.umich.edu        fesetround(FeRoundNearest);
5344999Sgblack@eecs.umich.edu        break;
5354999Sgblack@eecs.umich.edu      case VfpRoundUpward:
5364999Sgblack@eecs.umich.edu        fesetround(FeRoundUpward);
5374999Sgblack@eecs.umich.edu        break;
5384999Sgblack@eecs.umich.edu      case VfpRoundDown:
5394999Sgblack@eecs.umich.edu        fesetround(FeRoundDown);
5404999Sgblack@eecs.umich.edu        break;
5414999Sgblack@eecs.umich.edu      case VfpRoundZero:
5424999Sgblack@eecs.umich.edu        fesetround(FeRoundZero);
5434999Sgblack@eecs.umich.edu        break;
5444999Sgblack@eecs.umich.edu    }
5454999Sgblack@eecs.umich.edu    return roundingMode;
5464999Sgblack@eecs.umich.edu}
5474999Sgblack@eecs.umich.edu
5484999Sgblack@eecs.umich.edustatic inline FPSCR
5494999Sgblack@eecs.umich.edusetVfpFpscr(FPSCR fpscr, VfpSavedState state)
5504999Sgblack@eecs.umich.edu{
5514999Sgblack@eecs.umich.edu    int exceptions = fetestexcept(FeAllExceptions);
5524999Sgblack@eecs.umich.edu    if (exceptions & FeInvalid) {
5534999Sgblack@eecs.umich.edu        fpscr.ioc = 1;
5544999Sgblack@eecs.umich.edu    }
5554999Sgblack@eecs.umich.edu    if (exceptions & FeDivByZero) {
5564878Sstever@eecs.umich.edu        fpscr.dzc = 1;
5574040Ssaidi@eecs.umich.edu    }
5584040Ssaidi@eecs.umich.edu    if (exceptions & FeOverflow) {
5594999Sgblack@eecs.umich.edu        fpscr.ofc = 1;
5604999Sgblack@eecs.umich.edu    }
5614999Sgblack@eecs.umich.edu    if (exceptions & FeUnderflow) {
5622631SN/A        fpscr.ufc = 1;
5634999Sgblack@eecs.umich.edu    }
5644999Sgblack@eecs.umich.edu    if (exceptions & FeInexact) {
5654999Sgblack@eecs.umich.edu        fpscr.ixc = 1;
5664999Sgblack@eecs.umich.edu    }
5674999Sgblack@eecs.umich.edu    fesetround(state);
5684999Sgblack@eecs.umich.edu    return fpscr;
5694999Sgblack@eecs.umich.edu}
5705408Sgblack@eecs.umich.edu
5715408Sgblack@eecs.umich.educlass VfpMacroOp : public PredMacroOp
5725408Sgblack@eecs.umich.edu{
5734999Sgblack@eecs.umich.edu  public:
5743170Sstever@eecs.umich.edu    static bool
5753170Sstever@eecs.umich.edu    inScalarBank(IntRegIndex idx)
5764999Sgblack@eecs.umich.edu    {
5774999Sgblack@eecs.umich.edu        return (idx % 32) < 8;
5784999Sgblack@eecs.umich.edu    }
5794999Sgblack@eecs.umich.edu
5804999Sgblack@eecs.umich.edu  protected:
5814999Sgblack@eecs.umich.edu    bool wide;
5824999Sgblack@eecs.umich.edu
5834999Sgblack@eecs.umich.edu    VfpMacroOp(const char *mnem, ExtMachInst _machInst,
5844999Sgblack@eecs.umich.edu            OpClass __opClass, bool _wide) :
5854999Sgblack@eecs.umich.edu        PredMacroOp(mnem, _machInst, __opClass), wide(_wide)
5862623SN/A    {}
5872623SN/A
5882623SN/A    IntRegIndex
5895177Sgblack@eecs.umich.edu    addStride(IntRegIndex idx, unsigned stride)
5905177Sgblack@eecs.umich.edu    {
5915177Sgblack@eecs.umich.edu        if (wide) {
5925177Sgblack@eecs.umich.edu            stride *= 2;
5935177Sgblack@eecs.umich.edu        }
5945177Sgblack@eecs.umich.edu        unsigned offset = idx % 8;
5955177Sgblack@eecs.umich.edu        idx = (IntRegIndex)(idx - offset);
5965177Sgblack@eecs.umich.edu        offset += stride;
5975177Sgblack@eecs.umich.edu        idx = (IntRegIndex)(idx + (offset % 8));
5985177Sgblack@eecs.umich.edu        return idx;
5995177Sgblack@eecs.umich.edu    }
6005177Sgblack@eecs.umich.edu
6015177Sgblack@eecs.umich.edu    void
6025177Sgblack@eecs.umich.edu    nextIdxs(IntRegIndex &dest, IntRegIndex &op1, IntRegIndex &op2)
6035177Sgblack@eecs.umich.edu    {
6045177Sgblack@eecs.umich.edu        unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2;
6055177Sgblack@eecs.umich.edu        assert(!inScalarBank(dest));
6065177Sgblack@eecs.umich.edu        dest = addStride(dest, stride);
6075177Sgblack@eecs.umich.edu        op1 = addStride(op1, stride);
6085177Sgblack@eecs.umich.edu        if (!inScalarBank(op2)) {
6095177Sgblack@eecs.umich.edu            op2 = addStride(op2, stride);
6105177Sgblack@eecs.umich.edu        }
6115177Sgblack@eecs.umich.edu    }
6125177Sgblack@eecs.umich.edu
6135177Sgblack@eecs.umich.edu    void
6145177Sgblack@eecs.umich.edu    nextIdxs(IntRegIndex &dest, IntRegIndex &op1)
6155177Sgblack@eecs.umich.edu    {
6165177Sgblack@eecs.umich.edu        unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2;
6175177Sgblack@eecs.umich.edu        assert(!inScalarBank(dest));
6185278Sgblack@eecs.umich.edu        dest = addStride(dest, stride);
6195177Sgblack@eecs.umich.edu        if (!inScalarBank(op1)) {
6205177Sgblack@eecs.umich.edu            op1 = addStride(op1, stride);
6215177Sgblack@eecs.umich.edu        }
6225177Sgblack@eecs.umich.edu    }
6235177Sgblack@eecs.umich.edu
6245177Sgblack@eecs.umich.edu    void
6255177Sgblack@eecs.umich.edu    nextIdxs(IntRegIndex &dest)
6265177Sgblack@eecs.umich.edu    {
6275177Sgblack@eecs.umich.edu        unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2;
6285177Sgblack@eecs.umich.edu        assert(!inScalarBank(dest));
6295177Sgblack@eecs.umich.edu        dest = addStride(dest, stride);
6305177Sgblack@eecs.umich.edu    }
6315177Sgblack@eecs.umich.edu};
6325177Sgblack@eecs.umich.edu
6335177Sgblack@eecs.umich.educlass VfpRegRegOp : public RegRegOp
6345177Sgblack@eecs.umich.edu{
6355177Sgblack@eecs.umich.edu  protected:
6365177Sgblack@eecs.umich.edu    VfpRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
6375177Sgblack@eecs.umich.edu                IntRegIndex _dest, IntRegIndex _op1,
6385177Sgblack@eecs.umich.edu                VfpMicroMode mode = VfpNotAMicroop) :
6395177Sgblack@eecs.umich.edu        RegRegOp(mnem, _machInst, __opClass, _dest, _op1)
6405177Sgblack@eecs.umich.edu    {
6415177Sgblack@eecs.umich.edu        setVfpMicroFlags(mode, flags);
6425177Sgblack@eecs.umich.edu    }
6435177Sgblack@eecs.umich.edu};
6445177Sgblack@eecs.umich.edu
6455177Sgblack@eecs.umich.educlass VfpRegImmOp : public RegImmOp
6465177Sgblack@eecs.umich.edu{
6472623SN/A  protected:
6482623SN/A    VfpRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
6494224Sgblack@eecs.umich.edu                IntRegIndex _dest, uint64_t _imm,
6504224Sgblack@eecs.umich.edu                VfpMicroMode mode = VfpNotAMicroop) :
6514224Sgblack@eecs.umich.edu        RegImmOp(mnem, _machInst, __opClass, _dest, _imm)
6524224Sgblack@eecs.umich.edu    {
6534224Sgblack@eecs.umich.edu        setVfpMicroFlags(mode, flags);
6544224Sgblack@eecs.umich.edu    }
6554224Sgblack@eecs.umich.edu};
6564224Sgblack@eecs.umich.edu
6574224Sgblack@eecs.umich.educlass VfpRegRegImmOp : public RegRegImmOp
6584224Sgblack@eecs.umich.edu{
6594224Sgblack@eecs.umich.edu  protected:
6602623SN/A    VfpRegRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
6612623SN/A                   IntRegIndex _dest, IntRegIndex _op1,
6622623SN/A                   uint64_t _imm, VfpMicroMode mode = VfpNotAMicroop) :
6632623SN/A        RegRegImmOp(mnem, _machInst, __opClass, _dest, _op1, _imm)
6642623SN/A    {
6652623SN/A        setVfpMicroFlags(mode, flags);
6662623SN/A    }
6672623SN/A};
6682623SN/A
6692623SN/Aclass VfpRegRegRegOp : public RegRegRegOp
6702623SN/A{
6712623SN/A  protected:
6722623SN/A    VfpRegRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
6732623SN/A                   IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2,
6742623SN/A                   VfpMicroMode mode = VfpNotAMicroop) :
6752623SN/A        RegRegRegOp(mnem, _machInst, __opClass, _dest, _op1, _op2)
6762623SN/A    {
6772623SN/A        setVfpMicroFlags(mode, flags);
6782623SN/A    }
6792623SN/A};
6802623SN/A
6812623SN/A}
6822623SN/A
6832623SN/A#endif //__ARCH_ARM_INSTS_VFP_HH__
6842623SN/A