vfp.hh revision 7398
1955SN/A/*
2955SN/A * Copyright (c) 2010 ARM Limited
31762SN/A * All rights reserved
4955SN/A *
5955SN/A * The license below extends only to copyright in the software and shall
6955SN/A * not be construed as granting a license to any other intellectual
7955SN/A * property including but not limited to intellectual property relating
8955SN/A * to a hardware implementation of the functionality of the software
9955SN/A * licensed hereunder.  You may use the software subject to the license
10955SN/A * terms below provided that you ensure that this notice is replicated
11955SN/A * unmodified and in its entirety in all distributions of the software,
12955SN/A * modified or unmodified, in source code or in binary form.
13955SN/A *
14955SN/A * Redistribution and use in source and binary forms, with or without
15955SN/A * modification, are permitted provided that the following conditions are
16955SN/A * met: redistributions of source code must retain the above copyright
17955SN/A * notice, this list of conditions and the following disclaimer;
18955SN/A * redistributions in binary form must reproduce the above copyright
19955SN/A * notice, this list of conditions and the following disclaimer in the
20955SN/A * documentation and/or other materials provided with the distribution;
21955SN/A * neither the name of the copyright holders nor the names of its
22955SN/A * contributors may be used to endorse or promote products derived from
23955SN/A * this software without specific prior written permission.
24955SN/A *
25955SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26955SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27955SN/A * 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
294762Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30955SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
315522Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
326143Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
334762Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
345522Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35955SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
365522Snate@binkert.org *
37955SN/A * Authors: Gabe Black
385522Snate@binkert.org */
394202Sbinkertn@umich.edu
405742Snate@binkert.org#ifndef __ARCH_ARM_INSTS_VFP_HH__
41955SN/A#define __ARCH_ARM_INSTS_VFP_HH__
424381Sbinkertn@umich.edu
434381Sbinkertn@umich.edu#include "arch/arm/insts/misc.hh"
44955SN/A#include "arch/arm/miscregs.hh"
45955SN/A#include <fenv.h>
46955SN/A#include <cmath>
474202Sbinkertn@umich.edu
48955SN/Anamespace ArmISA
494382Sbinkertn@umich.edu{
504382Sbinkertn@umich.edu
514382Sbinkertn@umich.eduenum VfpMicroMode {
526654Snate@binkert.org    VfpNotAMicroop,
535517Snate@binkert.org    VfpMicroop,
547674Snate@binkert.org    VfpFirstMicroop,
557674Snate@binkert.org    VfpLastMicroop
566143Snate@binkert.org};
576143Snate@binkert.org
586143Snate@binkert.orgtemplate<class T>
596143Snate@binkert.orgstatic inline void
606143Snate@binkert.orgsetVfpMicroFlags(VfpMicroMode mode, T &flags)
616143Snate@binkert.org{
626143Snate@binkert.org    switch (mode) {
636143Snate@binkert.org      case VfpMicroop:
646143Snate@binkert.org        flags[StaticInst::IsMicroop] = true;
656143Snate@binkert.org        break;
666143Snate@binkert.org      case VfpFirstMicroop:
676143Snate@binkert.org        flags[StaticInst::IsMicroop] =
686143Snate@binkert.org            flags[StaticInst::IsFirstMicroop] = true;
696143Snate@binkert.org        break;
706143Snate@binkert.org      case VfpLastMicroop:
714762Snate@binkert.org        flags[StaticInst::IsMicroop] =
726143Snate@binkert.org            flags[StaticInst::IsLastMicroop] = true;
736143Snate@binkert.org        break;
746143Snate@binkert.org      case VfpNotAMicroop:
756143Snate@binkert.org        break;
766143Snate@binkert.org    }
776143Snate@binkert.org    if (mode == VfpMicroop || mode == VfpFirstMicroop) {
786143Snate@binkert.org        flags[StaticInst::IsDelayedCommit] = true;
796143Snate@binkert.org    }
806143Snate@binkert.org}
816143Snate@binkert.org
826143Snate@binkert.orgenum FeExceptionBit
836143Snate@binkert.org{
846143Snate@binkert.org    FeDivByZero = FE_DIVBYZERO,
856143Snate@binkert.org    FeInexact = FE_INEXACT,
866143Snate@binkert.org    FeInvalid = FE_INVALID,
876143Snate@binkert.org    FeOverflow = FE_OVERFLOW,
886143Snate@binkert.org    FeUnderflow = FE_UNDERFLOW,
896143Snate@binkert.org    FeAllExceptions = FE_ALL_EXCEPT
906143Snate@binkert.org};
916143Snate@binkert.org
926143Snate@binkert.orgenum FeRoundingMode
937065Snate@binkert.org{
946143Snate@binkert.org    FeRoundDown = FE_DOWNWARD,
956143Snate@binkert.org    FeRoundNearest = FE_TONEAREST,
966143Snate@binkert.org    FeRoundZero = FE_TOWARDZERO,
976143Snate@binkert.org    FeRoundUpward = FE_UPWARD
986143Snate@binkert.org};
996143Snate@binkert.org
1006143Snate@binkert.orgenum VfpRoundingMode
1016143Snate@binkert.org{
1026143Snate@binkert.org    VfpRoundNearest = 0,
1036143Snate@binkert.org    VfpRoundUpward = 1,
1046143Snate@binkert.org    VfpRoundDown = 2,
1056143Snate@binkert.org    VfpRoundZero = 3
1066143Snate@binkert.org};
1076143Snate@binkert.org
1086143Snate@binkert.orgtemplate <class fpType>
1096143Snate@binkert.orgstatic inline bool
1106143Snate@binkert.orgflushToZero(fpType &op)
1116143Snate@binkert.org{
1126143Snate@binkert.org    fpType junk = 0.0;
1136143Snate@binkert.org    if (std::fpclassify(op) == FP_SUBNORMAL) {
1146143Snate@binkert.org        uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1);
1155522Snate@binkert.org        op = bitsToFp(fpToBits(op) & bitMask, junk);
1166143Snate@binkert.org        return true;
1176143Snate@binkert.org    }
1186143Snate@binkert.org    return false;
1196143Snate@binkert.org}
1206143Snate@binkert.org
1216143Snate@binkert.orgtemplate <class fpType>
1226143Snate@binkert.orgstatic inline bool
1236143Snate@binkert.orgflushToZero(fpType &op1, fpType &op2)
1246143Snate@binkert.org{
1256143Snate@binkert.org    bool flush1 = flushToZero(op1);
1265522Snate@binkert.org    bool flush2 = flushToZero(op2);
1275522Snate@binkert.org    return flush1 || flush2;
1285522Snate@binkert.org}
1295522Snate@binkert.org
1305604Snate@binkert.orgtemplate <class fpType>
1315604Snate@binkert.orgstatic inline void
1326143Snate@binkert.orgvfpFlushToZero(FPSCR &fpscr, fpType &op)
1336143Snate@binkert.org{
1344762Snate@binkert.org    if (fpscr.fz == 1 && flushToZero(op)) {
1354762Snate@binkert.org        fpscr.idc = 1;
1366143Snate@binkert.org    }
1376727Ssteve.reinhardt@amd.com}
1386727Ssteve.reinhardt@amd.com
1396727Ssteve.reinhardt@amd.comtemplate <class fpType>
1404762Snate@binkert.orgstatic inline void
1416143Snate@binkert.orgvfpFlushToZero(FPSCR &fpscr, fpType &op1, fpType &op2)
1426143Snate@binkert.org{
1436143Snate@binkert.org    vfpFlushToZero(fpscr, op1);
1446143Snate@binkert.org    vfpFlushToZero(fpscr, op2);
1456727Ssteve.reinhardt@amd.com}
1466143Snate@binkert.org
1477674Snate@binkert.orgstatic inline uint32_t
1487674Snate@binkert.orgfpToBits(float fp)
1495604Snate@binkert.org{
1506143Snate@binkert.org    union
1516143Snate@binkert.org    {
1526143Snate@binkert.org        float fp;
1534762Snate@binkert.org        uint32_t bits;
1546143Snate@binkert.org    } val;
1554762Snate@binkert.org    val.fp = fp;
1564762Snate@binkert.org    return val.bits;
1574762Snate@binkert.org}
1586143Snate@binkert.org
1596143Snate@binkert.orgstatic inline uint64_t
1604762Snate@binkert.orgfpToBits(double fp)
1616143Snate@binkert.org{
1626143Snate@binkert.org    union
1636143Snate@binkert.org    {
1646143Snate@binkert.org        double fp;
1654762Snate@binkert.org        uint64_t bits;
1666143Snate@binkert.org    } val;
1674762Snate@binkert.org    val.fp = fp;
1686143Snate@binkert.org    return val.bits;
1694762Snate@binkert.org}
1706143Snate@binkert.org
1716143Snate@binkert.orgstatic inline float
1726143Snate@binkert.orgbitsToFp(uint64_t bits, float junk)
1736143Snate@binkert.org{
1746143Snate@binkert.org    union
1756143Snate@binkert.org    {
1766143Snate@binkert.org        float fp;
1776143Snate@binkert.org        uint32_t bits;
1786143Snate@binkert.org    } val;
1796143Snate@binkert.org    val.bits = bits;
1806143Snate@binkert.org    return val.fp;
1816143Snate@binkert.org}
1826143Snate@binkert.org
183955SN/Astatic inline double
1845584Snate@binkert.orgbitsToFp(uint64_t bits, double junk)
1855584Snate@binkert.org{
1865584Snate@binkert.org    union
1875584Snate@binkert.org    {
1886143Snate@binkert.org        double fp;
1896143Snate@binkert.org        uint64_t bits;
1906143Snate@binkert.org    } val;
1915584Snate@binkert.org    val.bits = bits;
1924382Sbinkertn@umich.edu    return val.fp;
1934202Sbinkertn@umich.edu}
1944382Sbinkertn@umich.edu
1954382Sbinkertn@umich.edutypedef int VfpSavedState;
1964382Sbinkertn@umich.edu
1975584Snate@binkert.orgstatic inline VfpSavedState
1984382Sbinkertn@umich.eduprepFpState(uint32_t rMode)
1994382Sbinkertn@umich.edu{
2004382Sbinkertn@umich.edu    int roundingMode = fegetround();
2015192Ssaidi@eecs.umich.edu    feclearexcept(FeAllExceptions);
2025192Ssaidi@eecs.umich.edu    switch (rMode) {
2035799Snate@binkert.org      case VfpRoundNearest:
2045799Snate@binkert.org        fesetround(FeRoundNearest);
2055799Snate@binkert.org        break;
2065192Ssaidi@eecs.umich.edu      case VfpRoundUpward:
2075799Snate@binkert.org        fesetround(FeRoundUpward);
2085192Ssaidi@eecs.umich.edu        break;
2095799Snate@binkert.org      case VfpRoundDown:
2105799Snate@binkert.org        fesetround(FeRoundDown);
2115192Ssaidi@eecs.umich.edu        break;
2125192Ssaidi@eecs.umich.edu      case VfpRoundZero:
2135192Ssaidi@eecs.umich.edu        fesetround(FeRoundZero);
2145799Snate@binkert.org        break;
2155192Ssaidi@eecs.umich.edu    }
2165192Ssaidi@eecs.umich.edu    return roundingMode;
2175192Ssaidi@eecs.umich.edu}
2185192Ssaidi@eecs.umich.edu
2195192Ssaidi@eecs.umich.edustatic inline void
2205192Ssaidi@eecs.umich.edufinishVfp(FPSCR &fpscr, VfpSavedState state)
2214382Sbinkertn@umich.edu{
2224382Sbinkertn@umich.edu    int exceptions = fetestexcept(FeAllExceptions);
2234382Sbinkertn@umich.edu    bool underflow = false;
2242667Sstever@eecs.umich.edu    if (exceptions & FeInvalid) {
2252667Sstever@eecs.umich.edu        fpscr.ioc = 1;
2262667Sstever@eecs.umich.edu    }
2272667Sstever@eecs.umich.edu    if (exceptions & FeDivByZero) {
2282667Sstever@eecs.umich.edu        fpscr.dzc = 1;
2292667Sstever@eecs.umich.edu    }
2305742Snate@binkert.org    if (exceptions & FeOverflow) {
2315742Snate@binkert.org        fpscr.ofc = 1;
2325742Snate@binkert.org    }
2335793Snate@binkert.org    if (exceptions & FeUnderflow) {
2345793Snate@binkert.org        underflow = true;
2355793Snate@binkert.org        fpscr.ufc = 1;
2365793Snate@binkert.org    }
2375793Snate@binkert.org    if ((exceptions & FeInexact) && !(underflow && fpscr.fz)) {
2384382Sbinkertn@umich.edu        fpscr.ixc = 1;
2394762Snate@binkert.org    }
2405344Sstever@gmail.com    fesetround(state);
2414382Sbinkertn@umich.edu}
2425341Sstever@gmail.com
2435742Snate@binkert.orgtemplate <class fpType>
2445742Snate@binkert.orgstatic inline fpType
2455742Snate@binkert.orgfixDest(FPSCR fpscr, fpType val, fpType op1)
2465742Snate@binkert.org{
2475742Snate@binkert.org    int fpClass = std::fpclassify(val);
2484762Snate@binkert.org    fpType junk = 0.0;
2495742Snate@binkert.org    if (fpClass == FP_NAN) {
2505742Snate@binkert.org        const bool single = (sizeof(val) == sizeof(float));
2517722Sgblack@eecs.umich.edu        const uint64_t qnan = single ? 0x7fc00000 : ULL(0x7ff8000000000000);
2525742Snate@binkert.org        const bool nan = std::isnan(op1);
2535742Snate@binkert.org        if (!nan || (fpscr.dn == 1)) {
2545742Snate@binkert.org            val = bitsToFp(qnan, junk);
2555742Snate@binkert.org        } else if (nan) {
2565341Sstever@gmail.com            val = bitsToFp(fpToBits(op1) | qnan, junk);
2575742Snate@binkert.org        }
2587722Sgblack@eecs.umich.edu    } else if (fpClass == FP_SUBNORMAL && fpscr.fz == 1) {
2594773Snate@binkert.org        // Turn val into a zero with the correct sign;
2606108Snate@binkert.org        uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1);
2611858SN/A        val = bitsToFp(fpToBits(val) & bitMask, junk);
2621085SN/A        feclearexcept(FeInexact);
2636658Snate@binkert.org        feraiseexcept(FeUnderflow);
2646658Snate@binkert.org    }
2657673Snate@binkert.org    return val;
2666658Snate@binkert.org}
2676658Snate@binkert.org
2686658Snate@binkert.orgtemplate <class fpType>
2696658Snate@binkert.orgstatic inline fpType
2706658Snate@binkert.orgfixDest(FPSCR fpscr, fpType val, fpType op1, fpType op2)
2716658Snate@binkert.org{
2726658Snate@binkert.org    int fpClass = std::fpclassify(val);
2737673Snate@binkert.org    fpType junk = 0.0;
2747673Snate@binkert.org    if (fpClass == FP_NAN) {
2757673Snate@binkert.org        const bool single = (sizeof(val) == sizeof(float));
2767673Snate@binkert.org        const uint64_t qnan = single ? 0x7fc00000 : ULL(0x7ff8000000000000);
2777673Snate@binkert.org        const bool nan1 = std::isnan(op1);
2787673Snate@binkert.org        const bool nan2 = std::isnan(op2);
2797673Snate@binkert.org        const bool signal1 = nan1 && ((fpToBits(op1) & qnan) != qnan);
2806658Snate@binkert.org        const bool signal2 = nan2 && ((fpToBits(op2) & qnan) != qnan);
2817673Snate@binkert.org        if ((!nan1 && !nan2) || (fpscr.dn == 1)) {
2827673Snate@binkert.org            val = bitsToFp(qnan, junk);
2837673Snate@binkert.org        } else if (signal1) {
2847673Snate@binkert.org            val = bitsToFp(fpToBits(op1) | qnan, junk);
2857673Snate@binkert.org        } else if (signal2) {
2867673Snate@binkert.org            val = bitsToFp(fpToBits(op2) | qnan, junk);
2877673Snate@binkert.org        } else if (nan1) {
2887673Snate@binkert.org            val = op1;
2897673Snate@binkert.org        } else if (nan2) {
2907673Snate@binkert.org            val = op2;
2916658Snate@binkert.org        }
2927756SAli.Saidi@ARM.com    } else if (fpClass == FP_SUBNORMAL && fpscr.fz == 1) {
2937756SAli.Saidi@ARM.com        // Turn val into a zero with the correct sign;
2946658Snate@binkert.org        uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1);
2954382Sbinkertn@umich.edu        val = bitsToFp(fpToBits(val) & bitMask, junk);
2964382Sbinkertn@umich.edu        feclearexcept(FeInexact);
2974762Snate@binkert.org        feraiseexcept(FeUnderflow);
2984762Snate@binkert.org    }
2994762Snate@binkert.org    return val;
3006654Snate@binkert.org}
3016654Snate@binkert.org
3025517Snate@binkert.orgtemplate <class fpType>
3035517Snate@binkert.orgstatic inline fpType
3045517Snate@binkert.orgfixDivDest(FPSCR fpscr, fpType val, fpType op1, fpType op2)
3055517Snate@binkert.org{
3065517Snate@binkert.org    fpType mid = fixDest(fpscr, val, op1, op2);
3075517Snate@binkert.org    const bool single = (sizeof(fpType) == sizeof(float));
3085517Snate@binkert.org    const fpType junk = 0.0;
3095517Snate@binkert.org    if ((single && (val == bitsToFp(0x00800000, junk) ||
3105517Snate@binkert.org                    val == bitsToFp(0x80800000, junk))) ||
3115517Snate@binkert.org        (!single && (val == bitsToFp(ULL(0x0010000000000000), junk) ||
3125517Snate@binkert.org                     val == bitsToFp(ULL(0x8010000000000000), junk)))
3135517Snate@binkert.org        ) {
3145517Snate@binkert.org        __asm__ __volatile__("" : "=m" (op1) : "m" (op1));
3155517Snate@binkert.org        fesetround(FeRoundZero);
3165517Snate@binkert.org        fpType temp = 0.0;
3175517Snate@binkert.org        __asm__ __volatile__("" : "=m" (temp) : "m" (temp));
3185517Snate@binkert.org        temp = op1 / op2;
3196654Snate@binkert.org        if (flushToZero(temp)) {
3205517Snate@binkert.org            feraiseexcept(FeUnderflow);
3215517Snate@binkert.org            if (fpscr.fz) {
3225517Snate@binkert.org                feclearexcept(FeInexact);
3235517Snate@binkert.org                mid = temp;
3245517Snate@binkert.org            }
3255517Snate@binkert.org        }
3265517Snate@binkert.org        __asm__ __volatile__("" :: "m" (temp));
3275517Snate@binkert.org    }
3286143Snate@binkert.org    return mid;
3296654Snate@binkert.org}
3305517Snate@binkert.org
3315517Snate@binkert.orgstatic inline float
3325517Snate@binkert.orgfixFpDFpSDest(FPSCR fpscr, double val)
3335517Snate@binkert.org{
3345517Snate@binkert.org    const float junk = 0.0;
3355517Snate@binkert.org    float op1 = 0.0;
3365517Snate@binkert.org    if (std::isnan(val)) {
3375517Snate@binkert.org        uint64_t valBits = fpToBits(val);
3385517Snate@binkert.org        uint32_t op1Bits = bits(valBits, 50, 29) |
3395517Snate@binkert.org                           (mask(9) << 22) |
3405517Snate@binkert.org                           (bits(valBits, 63) << 31);
3415517Snate@binkert.org        op1 = bitsToFp(op1Bits, junk);
3425517Snate@binkert.org    }
3435517Snate@binkert.org    float mid = fixDest(fpscr, (float)val, op1);
3446654Snate@binkert.org    if (fpscr.fz && fetestexcept(FeUnderflow | FeInexact) ==
3456654Snate@binkert.org                    (FeUnderflow | FeInexact)) {
3465517Snate@binkert.org        feclearexcept(FeInexact);
3475517Snate@binkert.org    }
3486143Snate@binkert.org    if (mid == bitsToFp(0x00800000, junk) ||
3496143Snate@binkert.org        mid == bitsToFp(0x80800000, junk)) {
3506143Snate@binkert.org        __asm__ __volatile__("" : "=m" (val) : "m" (val));
3516727Ssteve.reinhardt@amd.com        fesetround(FeRoundZero);
3525517Snate@binkert.org        float temp = 0.0;
3536727Ssteve.reinhardt@amd.com        __asm__ __volatile__("" : "=m" (temp) : "m" (temp));
3545517Snate@binkert.org        temp = val;
3555517Snate@binkert.org        if (flushToZero(temp)) {
3565517Snate@binkert.org            feraiseexcept(FeUnderflow);
3576654Snate@binkert.org            if (fpscr.fz) {
3586654Snate@binkert.org                feclearexcept(FeInexact);
3597673Snate@binkert.org                mid = temp;
3606654Snate@binkert.org            }
3616654Snate@binkert.org        }
3626654Snate@binkert.org        __asm__ __volatile__("" :: "m" (temp));
3636654Snate@binkert.org    }
3645517Snate@binkert.org    return mid;
3655517Snate@binkert.org}
3665517Snate@binkert.org
3676143Snate@binkert.orgstatic inline double
3685517Snate@binkert.orgfixFpSFpDDest(FPSCR fpscr, float val)
3694762Snate@binkert.org{
3705517Snate@binkert.org    const double junk = 0.0;
3715517Snate@binkert.org    double op1 = 0.0;
3726143Snate@binkert.org    if (std::isnan(val)) {
3736143Snate@binkert.org        uint32_t valBits = fpToBits(val);
3745517Snate@binkert.org        uint64_t op1Bits = ((uint64_t)bits(valBits, 21, 0) << 29) |
3755517Snate@binkert.org                           (mask(12) << 51) |
3765517Snate@binkert.org                           ((uint64_t)bits(valBits, 31) << 63);
3775517Snate@binkert.org        op1 = bitsToFp(op1Bits, junk);
3785517Snate@binkert.org    }
3795517Snate@binkert.org    double mid = fixDest(fpscr, (double)val, op1);
3805517Snate@binkert.org    if (mid == bitsToFp(ULL(0x0010000000000000), junk) ||
3815517Snate@binkert.org        mid == bitsToFp(ULL(0x8010000000000000), junk)) {
3825517Snate@binkert.org        __asm__ __volatile__("" : "=m" (val) : "m" (val));
3835517Snate@binkert.org        fesetround(FeRoundZero);
3846143Snate@binkert.org        double temp = 0.0;
3855517Snate@binkert.org        __asm__ __volatile__("" : "=m" (temp) : "m" (temp));
3866654Snate@binkert.org        temp = val;
3876654Snate@binkert.org        if (flushToZero(temp)) {
3886654Snate@binkert.org            feraiseexcept(FeUnderflow);
3896654Snate@binkert.org            if (fpscr.fz) {
3906654Snate@binkert.org                feclearexcept(FeInexact);
3916654Snate@binkert.org                mid = temp;
3925517Snate@binkert.org            }
3935517Snate@binkert.org        }
3945517Snate@binkert.org        __asm__ __volatile__("" :: "m" (temp));
3955517Snate@binkert.org    }
3965517Snate@binkert.org    return mid;
3974762Snate@binkert.org}
3984762Snate@binkert.org
3994762Snate@binkert.orgstatic inline float
4004762Snate@binkert.orgvcvtFpSFpH(FPSCR &fpscr, float op, float dest, bool top)
4014762Snate@binkert.org{
4024762Snate@binkert.org    float junk = 0.0;
4037675Snate@binkert.org    uint32_t destBits = fpToBits(dest);
4044762Snate@binkert.org    uint32_t opBits = fpToBits(op);
4054762Snate@binkert.org    // Extract the operand.
4064762Snate@binkert.org    bool neg = bits(opBits, 31);
4074762Snate@binkert.org    uint32_t exponent = bits(opBits, 30, 23);
4084382Sbinkertn@umich.edu    uint32_t oldMantissa = bits(opBits, 22, 0);
4094382Sbinkertn@umich.edu    uint32_t mantissa = oldMantissa >> (23 - 10);
4105517Snate@binkert.org    // Do the conversion.
4116654Snate@binkert.org    uint32_t extra = oldMantissa & mask(23 - 10);
4125517Snate@binkert.org    if (exponent == 0xff) {
4135798Snate@binkert.org        if (oldMantissa != 0) {
4146654Snate@binkert.org            // Nans.
4157673Snate@binkert.org            if (bits(mantissa, 9) == 0) {
4166654Snate@binkert.org                // Signalling nan.
4176654Snate@binkert.org                fpscr.ioc = 1;
4186654Snate@binkert.org            }
4196654Snate@binkert.org            if (fpscr.ahp) {
4206654Snate@binkert.org                mantissa = 0;
4216654Snate@binkert.org                exponent = 0;
4226654Snate@binkert.org                fpscr.ioc = 1;
4236654Snate@binkert.org            } else if (fpscr.dn) {
4246669Snate@binkert.org                mantissa = (1 << 9);
4256669Snate@binkert.org                exponent = 0x1f;
4266669Snate@binkert.org                neg = false;
4276669Snate@binkert.org            } else {
4286669Snate@binkert.org                exponent = 0x1f;
4296669Snate@binkert.org                mantissa |= (1 << 9);
4306654Snate@binkert.org            }
4317673Snate@binkert.org        } else {
4325517Snate@binkert.org            // Infinities.
4335863Snate@binkert.org            exponent = 0x1F;
4345798Snate@binkert.org            if (fpscr.ahp) {
4357756SAli.Saidi@ARM.com                fpscr.ioc = 1;
4367756SAli.Saidi@ARM.com                mantissa = 0x3ff;
4375798Snate@binkert.org            } else {
4385798Snate@binkert.org                mantissa = 0;
4395517Snate@binkert.org            }
4405517Snate@binkert.org        }
4417673Snate@binkert.org    } else if (exponent == 0 && oldMantissa == 0) {
4425517Snate@binkert.org        // Zero, don't need to do anything.
4435517Snate@binkert.org    } else {
4447673Snate@binkert.org        // Normalized or denormalized numbers.
4457673Snate@binkert.org
4465517Snate@binkert.org        bool inexact = (extra != 0);
4475798Snate@binkert.org
4485798Snate@binkert.org        if (exponent == 0) {
4495798Snate@binkert.org            // Denormalized.
4507756SAli.Saidi@ARM.com
4515798Snate@binkert.org            // If flush to zero is on, this shouldn't happen.
4525798Snate@binkert.org            assert(fpscr.fz == 0);
4534762Snate@binkert.org
4544762Snate@binkert.org            // Check for underflow
4554762Snate@binkert.org            if (inexact || fpscr.ufe)
4564762Snate@binkert.org                fpscr.ufc = 1;
4574762Snate@binkert.org
4585517Snate@binkert.org            // Handle rounding.
4595517Snate@binkert.org            unsigned mode = fpscr.rMode;
4605517Snate@binkert.org            if ((mode == VfpRoundUpward && !neg && extra) ||
4615517Snate@binkert.org                (mode == VfpRoundDown && neg && extra) ||
4625517Snate@binkert.org                (mode == VfpRoundNearest &&
4635517Snate@binkert.org                 (extra > (1 << 9) ||
4647673Snate@binkert.org                  (extra == (1 << 9) && bits(mantissa, 0))))) {
4657673Snate@binkert.org                mantissa++;
4667673Snate@binkert.org            }
4675517Snate@binkert.org
4685517Snate@binkert.org            // See if the number became normalized after rounding.
4695517Snate@binkert.org            if (mantissa == (1 << 10)) {
4705517Snate@binkert.org                mantissa = 0;
4715517Snate@binkert.org                exponent = 1;
4725517Snate@binkert.org            }
4735517Snate@binkert.org        } else {
4747673Snate@binkert.org            // Normalized.
4757677Snate@binkert.org
4767673Snate@binkert.org            // We need to track the dropped bits differently since
4777673Snate@binkert.org            // more can be dropped by denormalizing.
4785517Snate@binkert.org            bool topOne = bits(extra, 12);
4795517Snate@binkert.org            bool restZeros = bits(extra, 11, 0) == 0;
4805517Snate@binkert.org
4815517Snate@binkert.org            if (exponent <= (127 - 15)) {
4825517Snate@binkert.org                // The result is too small. Denormalize.
4835517Snate@binkert.org                mantissa |= (1 << 10);
4845517Snate@binkert.org                while (mantissa && exponent <= (127 - 15)) {
4857673Snate@binkert.org                    restZeros = restZeros && !topOne;
4867673Snate@binkert.org                    topOne = bits(mantissa, 0);
4877673Snate@binkert.org                    mantissa = mantissa >> 1;
4885517Snate@binkert.org                    exponent++;
4895517Snate@binkert.org                }
4905517Snate@binkert.org                if (topOne || !restZeros)
4915517Snate@binkert.org                    inexact = true;
4925517Snate@binkert.org                exponent = 0;
4935517Snate@binkert.org            } else {
4945517Snate@binkert.org                // Change bias.
4957673Snate@binkert.org                exponent -= (127 - 15);
4967673Snate@binkert.org            }
4977673Snate@binkert.org
4985517Snate@binkert.org            if (exponent == 0 && (inexact || fpscr.ufe)) {
4997675Snate@binkert.org                // Underflow
5007675Snate@binkert.org                fpscr.ufc = 1;
5017675Snate@binkert.org            }
5027675Snate@binkert.org
5037675Snate@binkert.org            // Handle rounding.
5047675Snate@binkert.org            unsigned mode = fpscr.rMode;
5057675Snate@binkert.org            bool nonZero = topOne || !restZeros;
5067675Snate@binkert.org            if ((mode == VfpRoundUpward && !neg && nonZero) ||
5077677Snate@binkert.org                (mode == VfpRoundDown && neg && nonZero) ||
5087675Snate@binkert.org                (mode == VfpRoundNearest && topOne &&
5097675Snate@binkert.org                 (!restZeros || bits(mantissa, 0)))) {
5107675Snate@binkert.org                mantissa++;
5117675Snate@binkert.org            }
5127675Snate@binkert.org
5137675Snate@binkert.org            // See if we rounded up and need to bump the exponent.
5147675Snate@binkert.org            if (mantissa == (1 << 10)) {
5157675Snate@binkert.org                mantissa = 0;
5167675Snate@binkert.org                exponent++;
5174762Snate@binkert.org            }
5184762Snate@binkert.org
5196143Snate@binkert.org            // Deal with overflow
5206143Snate@binkert.org            if (fpscr.ahp) {
5216143Snate@binkert.org                if (exponent >= 0x20) {
5224762Snate@binkert.org                    exponent = 0x1f;
5234762Snate@binkert.org                    mantissa = 0x3ff;
5244762Snate@binkert.org                    fpscr.ioc = 1;
5257756SAli.Saidi@ARM.com                    // Supress inexact exception.
5267756SAli.Saidi@ARM.com                    inexact = false;
5274762Snate@binkert.org                }
5284762Snate@binkert.org            } else {
5294762Snate@binkert.org                if (exponent >= 0x1f) {
5305463Snate@binkert.org                    if ((mode == VfpRoundNearest) ||
5315517Snate@binkert.org                        (mode == VfpRoundUpward && !neg) ||
5327677Snate@binkert.org                        (mode == VfpRoundDown && neg)) {
5335463Snate@binkert.org                        // Overflow to infinity.
5347756SAli.Saidi@ARM.com                        exponent = 0x1f;
5357756SAli.Saidi@ARM.com                        mantissa = 0;
5364762Snate@binkert.org                    } else {
5377677Snate@binkert.org                        // Overflow to max normal.
5384762Snate@binkert.org                        exponent = 0x1e;
5394762Snate@binkert.org                        mantissa = 0x3ff;
5406143Snate@binkert.org                    }
5416143Snate@binkert.org                    fpscr.ofc = 1;
5426143Snate@binkert.org                    inexact = true;
5434762Snate@binkert.org                }
5444762Snate@binkert.org            }
5457756SAli.Saidi@ARM.com        }
5467756SAli.Saidi@ARM.com
5474762Snate@binkert.org        if (inexact) {
5484762Snate@binkert.org            fpscr.ixc = 1;
5494762Snate@binkert.org        }
5504762Snate@binkert.org    }
5517756SAli.Saidi@ARM.com    // Reassemble and install the result.
5527756SAli.Saidi@ARM.com    uint32_t result = bits(mantissa, 9, 0);
5534762Snate@binkert.org    replaceBits(result, 14, 10, exponent);
5544762Snate@binkert.org    if (neg)
5557677Snate@binkert.org        result |= (1 << 15);
5567756SAli.Saidi@ARM.com    if (top)
5577756SAli.Saidi@ARM.com        replaceBits(destBits, 31, 16, result);
5587675Snate@binkert.org    else
5597677Snate@binkert.org        replaceBits(destBits, 15, 0, result);
5605517Snate@binkert.org    return bitsToFp(destBits, junk);
5617675Snate@binkert.org}
5627675Snate@binkert.org
5637675Snate@binkert.orgstatic inline float
5647675Snate@binkert.orgvcvtFpHFpS(FPSCR &fpscr, float op, bool top)
5657675Snate@binkert.org{
5667675Snate@binkert.org    float junk = 0.0;
5677675Snate@binkert.org    uint32_t opBits = fpToBits(op);
5685517Snate@binkert.org    // Extract the operand.
5697673Snate@binkert.org    if (top)
5705517Snate@binkert.org        opBits = bits(opBits, 31, 16);
5717677Snate@binkert.org    else
5727675Snate@binkert.org        opBits = bits(opBits, 15, 0);
5737673Snate@binkert.org    // Extract the bitfields.
5747675Snate@binkert.org    bool neg = bits(opBits, 15);
5757675Snate@binkert.org    uint32_t exponent = bits(opBits, 14, 10);
5767675Snate@binkert.org    uint32_t mantissa = bits(opBits, 9, 0);
5777673Snate@binkert.org    // Do the conversion.
5787675Snate@binkert.org    if (exponent == 0) {
5795517Snate@binkert.org        if (mantissa != 0) {
5807675Snate@binkert.org            // Normalize the value.
5817675Snate@binkert.org            exponent = exponent + (127 - 15) + 1;
5827673Snate@binkert.org            while (mantissa < (1 << 10)) {
5837675Snate@binkert.org                mantissa = mantissa << 1;
5847675Snate@binkert.org                exponent--;
5857677Snate@binkert.org            }
5867675Snate@binkert.org        }
5877675Snate@binkert.org        mantissa = mantissa << (23 - 10);
5887675Snate@binkert.org    } else if (exponent == 0x1f && !fpscr.ahp) {
5895517Snate@binkert.org        // Infinities and nans.
5907675Snate@binkert.org        exponent = 0xff;
5915517Snate@binkert.org        if (mantissa != 0) {
5927673Snate@binkert.org            // Nans.
5935517Snate@binkert.org            mantissa = mantissa << (23 - 10);
5947675Snate@binkert.org            if (bits(mantissa, 22) == 0) {
5957677Snate@binkert.org                // Signalling nan.
5967756SAli.Saidi@ARM.com                fpscr.ioc = 1;
5977756SAli.Saidi@ARM.com                mantissa |= (1 << 22);
5987675Snate@binkert.org            }
5997677Snate@binkert.org            if (fpscr.dn) {
6004762Snate@binkert.org                mantissa &= ~mask(22);
6017674Snate@binkert.org                neg = false;
6027674Snate@binkert.org            }
6037674Snate@binkert.org        }
6047674Snate@binkert.org    } else {
6057674Snate@binkert.org        exponent = exponent + (127 - 15);
6067674Snate@binkert.org        mantissa = mantissa << (23 - 10);
6077674Snate@binkert.org    }
6087674Snate@binkert.org    // Reassemble the result.
6097674Snate@binkert.org    uint32_t result = bits(mantissa, 22, 0);
6107674Snate@binkert.org    replaceBits(result, 30, 23, exponent);
6117674Snate@binkert.org    if (neg)
6127674Snate@binkert.org        result |= (1 << 31);
6137674Snate@binkert.org    return bitsToFp(result, junk);
6147674Snate@binkert.org}
6157674Snate@binkert.org
6164762Snate@binkert.orgstatic inline double
6176143Snate@binkert.orgmakeDouble(uint32_t low, uint32_t high)
6186143Snate@binkert.org{
6197756SAli.Saidi@ARM.com    double junk = 0.0;
6207756SAli.Saidi@ARM.com    return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk);
6217674Snate@binkert.org}
6227756SAli.Saidi@ARM.com
6237756SAli.Saidi@ARM.comstatic inline uint32_t
6247674Snate@binkert.orglowFromDouble(double val)
6254382Sbinkertn@umich.edu{
6266229Snate@binkert.org    return fpToBits(val);
6276229Snate@binkert.org}
6286229Snate@binkert.org
6296229Snate@binkert.orgstatic inline uint32_t
6306229Snate@binkert.orghighFromDouble(double val)
6316229Snate@binkert.org{
6326229Snate@binkert.org    return fpToBits(val) >> 32;
6336229Snate@binkert.org}
6346229Snate@binkert.org
6356229Snate@binkert.orgstatic inline uint64_t
6366229Snate@binkert.orgvfpFpSToFixed(float val, bool isSigned, bool half,
6376229Snate@binkert.org              uint8_t imm, bool rzero = true)
6386229Snate@binkert.org{
6396229Snate@binkert.org    int rmode = rzero ? FeRoundZero : fegetround();
6406229Snate@binkert.org    __asm__ __volatile__("" : "=m" (rmode) : "m" (rmode));
6416229Snate@binkert.org    fesetround(FeRoundNearest);
6426229Snate@binkert.org    val = val * powf(2.0, imm);
6436229Snate@binkert.org    __asm__ __volatile__("" : "=m" (val) : "m" (val));
6446229Snate@binkert.org    fesetround(rmode);
6456229Snate@binkert.org    feclearexcept(FeAllExceptions);
6466229Snate@binkert.org    __asm__ __volatile__("" : "=m" (val) : "m" (val));
6475192Ssaidi@eecs.umich.edu    float origVal = val;
6485517Snate@binkert.org    val = rintf(val);
6495517Snate@binkert.org    int fpType = std::fpclassify(val);
6507673Snate@binkert.org    if (fpType == FP_SUBNORMAL || fpType == FP_NAN) {
6515517Snate@binkert.org        if (fpType == FP_NAN) {
6526229Snate@binkert.org            feraiseexcept(FeInvalid);
6535799Snate@binkert.org        }
6547673Snate@binkert.org        val = 0.0;
6557673Snate@binkert.org    } else if (origVal != val) {
6565517Snate@binkert.org        switch (rmode) {
6575517Snate@binkert.org          case FeRoundNearest:
6587673Snate@binkert.org            if (origVal - val > 0.5)
6597673Snate@binkert.org                val += 1.0;
6607673Snate@binkert.org            else if (val - origVal > 0.5)
6617673Snate@binkert.org                val -= 1.0;
6625517Snate@binkert.org            break;
6637673Snate@binkert.org          case FeRoundDown:
6647673Snate@binkert.org            if (origVal < val)
6657673Snate@binkert.org                val -= 1.0;
6665517Snate@binkert.org            break;
6675517Snate@binkert.org          case FeRoundUpward:
6687673Snate@binkert.org            if (origVal > val)
6697673Snate@binkert.org                val += 1.0;
6707673Snate@binkert.org            break;
6717673Snate@binkert.org        }
6725517Snate@binkert.org        feraiseexcept(FeInexact);
6737673Snate@binkert.org    }
6747673Snate@binkert.org
6755517Snate@binkert.org    if (isSigned) {
6767673Snate@binkert.org        if (half) {
6777673Snate@binkert.org            if ((double)val < (int16_t)(1 << 15)) {
6785517Snate@binkert.org                feraiseexcept(FeInvalid);
6797673Snate@binkert.org                feclearexcept(FeInexact);
6805517Snate@binkert.org                return (int16_t)(1 << 15);
6815517Snate@binkert.org            }
6827673Snate@binkert.org            if ((double)val > (int16_t)mask(15)) {
6837673Snate@binkert.org                feraiseexcept(FeInvalid);
6847673Snate@binkert.org                feclearexcept(FeInexact);
6857673Snate@binkert.org                return (int16_t)mask(15);
6865517Snate@binkert.org            }
6877673Snate@binkert.org            return (int16_t)val;
6887673Snate@binkert.org        } else {
6897673Snate@binkert.org            if ((double)val < (int32_t)(1 << 31)) {
6905517Snate@binkert.org                feraiseexcept(FeInvalid);
6917673Snate@binkert.org                feclearexcept(FeInexact);
6927673Snate@binkert.org                return (int32_t)(1 << 31);
6937673Snate@binkert.org            }
6945517Snate@binkert.org            if ((double)val > (int32_t)mask(31)) {
6957673Snate@binkert.org                feraiseexcept(FeInvalid);
6965517Snate@binkert.org                feclearexcept(FeInexact);
6975517Snate@binkert.org                return (int32_t)mask(31);
6985517Snate@binkert.org            }
6995517Snate@binkert.org            return (int32_t)val;
7006229Snate@binkert.org        }
7017673Snate@binkert.org    } else {
7025517Snate@binkert.org        if (half) {
7035517Snate@binkert.org            if ((double)val < 0) {
7047673Snate@binkert.org                feraiseexcept(FeInvalid);
7055517Snate@binkert.org                feclearexcept(FeInexact);
7065517Snate@binkert.org                return 0;
7075517Snate@binkert.org            }
7085517Snate@binkert.org            if ((double)val > (mask(16))) {
7095517Snate@binkert.org                feraiseexcept(FeInvalid);
7105517Snate@binkert.org                feclearexcept(FeInexact);
7115517Snate@binkert.org                return mask(16);
7125517Snate@binkert.org            }
7135517Snate@binkert.org            return (uint16_t)val;
7147673Snate@binkert.org        } else {
7155517Snate@binkert.org            if ((double)val < 0) {
7167673Snate@binkert.org                feraiseexcept(FeInvalid);
7175517Snate@binkert.org                feclearexcept(FeInexact);
7185517Snate@binkert.org                return 0;
7195517Snate@binkert.org            }
7205517Snate@binkert.org            if ((double)val > (mask(32))) {
7217673Snate@binkert.org                feraiseexcept(FeInvalid);
7225517Snate@binkert.org                feclearexcept(FeInexact);
7237673Snate@binkert.org                return mask(32);
7245517Snate@binkert.org            }
7255517Snate@binkert.org            return (uint32_t)val;
7267673Snate@binkert.org        }
7277673Snate@binkert.org    }
7285517Snate@binkert.org}
7297673Snate@binkert.org
7307673Snate@binkert.orgstatic inline float
7315517Snate@binkert.orgvfpUFixedToFpS(FPSCR fpscr, uint32_t val, bool half, uint8_t imm)
7327673Snate@binkert.org{
7337673Snate@binkert.org    fesetround(FeRoundNearest);
7347673Snate@binkert.org    if (half)
7357673Snate@binkert.org        val = (uint16_t)val;
7365517Snate@binkert.org    float scale = powf(2.0, imm);
7375517Snate@binkert.org    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
7385517Snate@binkert.org    feclearexcept(FeAllExceptions);
7397673Snate@binkert.org    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
7407673Snate@binkert.org    return fixDivDest(fpscr, val / scale, (float)val, scale);
7415517Snate@binkert.org}
7425517Snate@binkert.org
7437673Snate@binkert.orgstatic inline float
7447673Snate@binkert.orgvfpSFixedToFpS(FPSCR fpscr, int32_t val, bool half, uint8_t imm)
7457673Snate@binkert.org{
7467673Snate@binkert.org    fesetround(FeRoundNearest);
7475517Snate@binkert.org    if (half)
7485517Snate@binkert.org        val = sext<16>(val & mask(16));
7495517Snate@binkert.org    float scale = powf(2.0, imm);
7505517Snate@binkert.org    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
7517673Snate@binkert.org    feclearexcept(FeAllExceptions);
7527673Snate@binkert.org    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
7535517Snate@binkert.org    return fixDivDest(fpscr, val / scale, (float)val, scale);
7547673Snate@binkert.org}
7557673Snate@binkert.org
7567673Snate@binkert.orgstatic inline uint64_t
7577673Snate@binkert.orgvfpFpDToFixed(double val, bool isSigned, bool half,
7587673Snate@binkert.org              uint8_t imm, bool rzero = true)
7595517Snate@binkert.org{
7605517Snate@binkert.org    int rmode = rzero ? FeRoundZero : fegetround();
7615517Snate@binkert.org    fesetround(FeRoundNearest);
7627673Snate@binkert.org    val = val * pow(2.0, imm);
7637673Snate@binkert.org    __asm__ __volatile__("" : "=m" (val) : "m" (val));
7647673Snate@binkert.org    fesetround(rmode);
7655517Snate@binkert.org    feclearexcept(FeAllExceptions);
7665517Snate@binkert.org    __asm__ __volatile__("" : "=m" (val) : "m" (val));
7677673Snate@binkert.org    double origVal = val;
7685517Snate@binkert.org    val = rint(val);
7697673Snate@binkert.org    int fpType = std::fpclassify(val);
7707673Snate@binkert.org    if (fpType == FP_SUBNORMAL || fpType == FP_NAN) {
7715517Snate@binkert.org        if (fpType == FP_NAN) {
7727673Snate@binkert.org            feraiseexcept(FeInvalid);
7735517Snate@binkert.org        }
7745517Snate@binkert.org        val = 0.0;
7755517Snate@binkert.org    } else if (origVal != val) {
7765517Snate@binkert.org        switch (rmode) {
7776229Snate@binkert.org          case FeRoundNearest:
7787673Snate@binkert.org            if (origVal - val > 0.5)
7795517Snate@binkert.org                val += 1.0;
7805517Snate@binkert.org            else if (val - origVal > 0.5)
7817673Snate@binkert.org                val -= 1.0;
7825517Snate@binkert.org            break;
7835517Snate@binkert.org          case FeRoundDown:
7845517Snate@binkert.org            if (origVal < val)
7855517Snate@binkert.org                val -= 1.0;
7865517Snate@binkert.org            break;
7875517Snate@binkert.org          case FeRoundUpward:
7885517Snate@binkert.org            if (origVal > val)
7895517Snate@binkert.org                val += 1.0;
7905517Snate@binkert.org            break;
7915517Snate@binkert.org        }
7925517Snate@binkert.org        feraiseexcept(FeInexact);
7937673Snate@binkert.org    }
7945517Snate@binkert.org    if (isSigned) {
7955517Snate@binkert.org        if (half) {
7965517Snate@binkert.org            if (val < (int16_t)(1 << 15)) {
7977673Snate@binkert.org                feraiseexcept(FeInvalid);
7985517Snate@binkert.org                feclearexcept(FeInexact);
7995517Snate@binkert.org                return (int16_t)(1 << 15);
8007673Snate@binkert.org            }
8015517Snate@binkert.org            if (val > (int16_t)mask(15)) {
8025517Snate@binkert.org                feraiseexcept(FeInvalid);
8035517Snate@binkert.org                feclearexcept(FeInexact);
8047673Snate@binkert.org                return (int16_t)mask(15);
8057673Snate@binkert.org            }
8067673Snate@binkert.org            return (int16_t)val;
8075517Snate@binkert.org        } else {
8085517Snate@binkert.org            if (val < (int32_t)(1 << 31)) {
8097673Snate@binkert.org                feraiseexcept(FeInvalid);
8105517Snate@binkert.org                feclearexcept(FeInexact);
8115517Snate@binkert.org                return (int32_t)(1 << 31);
8127673Snate@binkert.org            }
8135517Snate@binkert.org            if (val > (int32_t)mask(31)) {
8147673Snate@binkert.org                feraiseexcept(FeInvalid);
8157673Snate@binkert.org                feclearexcept(FeInexact);
8165517Snate@binkert.org                return (int32_t)mask(31);
8175517Snate@binkert.org            }
8185517Snate@binkert.org            return (int32_t)val;
8197673Snate@binkert.org        }
8205517Snate@binkert.org    } else {
8215517Snate@binkert.org        if (half) {
8225517Snate@binkert.org            if (val < 0) {
8237673Snate@binkert.org                feraiseexcept(FeInvalid);
8247673Snate@binkert.org                feclearexcept(FeInexact);
8255517Snate@binkert.org                return 0;
8265517Snate@binkert.org            }
8277673Snate@binkert.org            if (val > mask(16)) {
8285517Snate@binkert.org                feraiseexcept(FeInvalid);
8295517Snate@binkert.org                feclearexcept(FeInexact);
8305517Snate@binkert.org                return mask(16);
8315517Snate@binkert.org            }
8325517Snate@binkert.org            return (uint16_t)val;
8335517Snate@binkert.org        } else {
8345517Snate@binkert.org            if (val < 0) {
8355517Snate@binkert.org                feraiseexcept(FeInvalid);
8365517Snate@binkert.org                feclearexcept(FeInexact);
8375517Snate@binkert.org                return 0;
8387811Ssteve.reinhardt@amd.com            }
8395517Snate@binkert.org            if (val > mask(32)) {
8405517Snate@binkert.org                feraiseexcept(FeInvalid);
8417673Snate@binkert.org                feclearexcept(FeInexact);
8425517Snate@binkert.org                return mask(32);
8437673Snate@binkert.org            }
8445517Snate@binkert.org            return (uint32_t)val;
8456143Snate@binkert.org        }
8467756SAli.Saidi@ARM.com    }
8477756SAli.Saidi@ARM.com}
8485192Ssaidi@eecs.umich.edu
8495192Ssaidi@eecs.umich.edustatic inline double
8507756SAli.Saidi@ARM.comvfpUFixedToFpD(FPSCR fpscr, uint32_t val, bool half, uint8_t imm)
8517756SAli.Saidi@ARM.com{
8527756SAli.Saidi@ARM.com    fesetround(FeRoundNearest);
8537756SAli.Saidi@ARM.com    if (half)
8545192Ssaidi@eecs.umich.edu        val = (uint16_t)val;
8555192Ssaidi@eecs.umich.edu    double scale = pow(2.0, imm);
8567674Snate@binkert.org    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
8575522Snate@binkert.org    feclearexcept(FeAllExceptions);
8585522Snate@binkert.org    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
8597674Snate@binkert.org    return fixDivDest(fpscr, val / scale, (double)val, scale);
8607674Snate@binkert.org}
8617674Snate@binkert.org
8627674Snate@binkert.orgstatic inline double
8637674Snate@binkert.orgvfpSFixedToFpD(FPSCR fpscr, int32_t val, bool half, uint8_t imm)
8647674Snate@binkert.org{
8657674Snate@binkert.org    fesetround(FeRoundNearest);
8667674Snate@binkert.org    if (half)
8675522Snate@binkert.org        val = sext<16>(val & mask(16));
8685522Snate@binkert.org    double scale = pow(2.0, imm);
8695522Snate@binkert.org    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
8705517Snate@binkert.org    feclearexcept(FeAllExceptions);
8715522Snate@binkert.org    __asm__ __volatile__("" : "=m" (scale) : "m" (scale));
8725517Snate@binkert.org    return fixDivDest(fpscr, val / scale, (double)val, scale);
8736143Snate@binkert.org}
8746727Ssteve.reinhardt@amd.com
8755522Snate@binkert.orgclass VfpMacroOp : public PredMacroOp
8765522Snate@binkert.org{
8775522Snate@binkert.org  public:
8787674Snate@binkert.org    static bool
8795517Snate@binkert.org    inScalarBank(IntRegIndex idx)
8807673Snate@binkert.org    {
8817673Snate@binkert.org        return (idx % 32) < 8;
8827674Snate@binkert.org    }
8837673Snate@binkert.org
8847674Snate@binkert.org  protected:
8857674Snate@binkert.org    bool wide;
8867674Snate@binkert.org
8877674Snate@binkert.org    VfpMacroOp(const char *mnem, ExtMachInst _machInst,
8887674Snate@binkert.org            OpClass __opClass, bool _wide) :
8897674Snate@binkert.org        PredMacroOp(mnem, _machInst, __opClass), wide(_wide)
8905522Snate@binkert.org    {}
8915522Snate@binkert.org
8927674Snate@binkert.org    IntRegIndex
8937674Snate@binkert.org    addStride(IntRegIndex idx, unsigned stride)
8947674Snate@binkert.org    {
8957674Snate@binkert.org        if (wide) {
8967673Snate@binkert.org            stride *= 2;
8977674Snate@binkert.org        }
8987674Snate@binkert.org        unsigned offset = idx % 8;
8997674Snate@binkert.org        idx = (IntRegIndex)(idx - offset);
9007674Snate@binkert.org        offset += stride;
9017674Snate@binkert.org        idx = (IntRegIndex)(idx + (offset % 8));
9027674Snate@binkert.org        return idx;
9037674Snate@binkert.org    }
9047674Snate@binkert.org
9057811Ssteve.reinhardt@amd.com    void
9067674Snate@binkert.org    nextIdxs(IntRegIndex &dest, IntRegIndex &op1, IntRegIndex &op2)
9077673Snate@binkert.org    {
9085522Snate@binkert.org        unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2;
9096143Snate@binkert.org        assert(!inScalarBank(dest));
9107756SAli.Saidi@ARM.com        dest = addStride(dest, stride);
9117756SAli.Saidi@ARM.com        op1 = addStride(op1, stride);
9127674Snate@binkert.org        if (!inScalarBank(op2)) {
9134382Sbinkertn@umich.edu            op2 = addStride(op2, stride);
9144382Sbinkertn@umich.edu        }
9154382Sbinkertn@umich.edu    }
9164382Sbinkertn@umich.edu
9174382Sbinkertn@umich.edu    void
9184382Sbinkertn@umich.edu    nextIdxs(IntRegIndex &dest, IntRegIndex &op1)
9194382Sbinkertn@umich.edu    {
9204382Sbinkertn@umich.edu        unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2;
9214382Sbinkertn@umich.edu        assert(!inScalarBank(dest));
9224382Sbinkertn@umich.edu        dest = addStride(dest, stride);
9236143Snate@binkert.org        if (!inScalarBank(op1)) {
924955SN/A            op1 = addStride(op1, stride);
9252655Sstever@eecs.umich.edu        }
9262655Sstever@eecs.umich.edu    }
9272655Sstever@eecs.umich.edu
9282655Sstever@eecs.umich.edu    void
9292655Sstever@eecs.umich.edu    nextIdxs(IntRegIndex &dest)
9305601Snate@binkert.org    {
9315601Snate@binkert.org        unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2;
9325601Snate@binkert.org        assert(!inScalarBank(dest));
9335601Snate@binkert.org        dest = addStride(dest, stride);
9345522Snate@binkert.org    }
9355863Snate@binkert.org};
9365601Snate@binkert.org
9375601Snate@binkert.orgstatic inline float
9385601Snate@binkert.orgfpAddS(float a, float b)
9395863Snate@binkert.org{
9406143Snate@binkert.org    return a + b;
9415559Snate@binkert.org}
9425559Snate@binkert.org
9435559Snate@binkert.orgstatic inline double
9445559Snate@binkert.orgfpAddD(double a, double b)
9455601Snate@binkert.org{
9466143Snate@binkert.org    return a + b;
9476143Snate@binkert.org}
9486143Snate@binkert.org
9496143Snate@binkert.orgstatic inline float
9506143Snate@binkert.orgfpSubS(float a, float b)
9516143Snate@binkert.org{
9526143Snate@binkert.org    return a - b;
9536143Snate@binkert.org}
9546143Snate@binkert.org
9556143Snate@binkert.orgstatic inline double
9566143Snate@binkert.orgfpSubD(double a, double b)
9576143Snate@binkert.org{
9586143Snate@binkert.org    return a - b;
9596143Snate@binkert.org}
9606143Snate@binkert.org
9616143Snate@binkert.orgstatic inline float
9626143Snate@binkert.orgfpDivS(float a, float b)
9636143Snate@binkert.org{
9646143Snate@binkert.org    return a / b;
9656143Snate@binkert.org}
9666143Snate@binkert.org
9676143Snate@binkert.orgstatic inline double
9686143Snate@binkert.orgfpDivD(double a, double b)
9696143Snate@binkert.org{
9706143Snate@binkert.org    return a / b;
9716143Snate@binkert.org}
9726143Snate@binkert.org
9736143Snate@binkert.orgstatic inline float
9746143Snate@binkert.orgfpMulS(float a, float b)
9756143Snate@binkert.org{
9766143Snate@binkert.org    return a * b;
9776143Snate@binkert.org}
9786240Snate@binkert.org
9795554Snate@binkert.orgstatic inline double
9805522Snate@binkert.orgfpMulD(double a, double b)
9815522Snate@binkert.org{
9825797Snate@binkert.org    return a * b;
9835797Snate@binkert.org}
9845522Snate@binkert.org
9855584Snate@binkert.orgclass FpOp : public PredOp
9866143Snate@binkert.org{
9875862Snate@binkert.org  protected:
9885584Snate@binkert.org    FpOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
9895601Snate@binkert.org        PredOp(mnem, _machInst, __opClass)
9906143Snate@binkert.org    {}
9916143Snate@binkert.org
9922655Sstever@eecs.umich.edu    virtual float
9936143Snate@binkert.org    doOp(float op1, float op2) const
9946143Snate@binkert.org    {
9956143Snate@binkert.org        panic("Unimplemented version of doOp called.\n");
9966143Snate@binkert.org    }
9976143Snate@binkert.org
9984007Ssaidi@eecs.umich.edu    virtual float
9994596Sbinkertn@umich.edu    doOp(float op1) const
10004007Ssaidi@eecs.umich.edu    {
10014596Sbinkertn@umich.edu        panic("Unimplemented version of doOp called.\n");
10027756SAli.Saidi@ARM.com    }
10037756SAli.Saidi@ARM.com
10045522Snate@binkert.org    virtual double
10055601Snate@binkert.org    doOp(double op1, double op2) const
10065601Snate@binkert.org    {
10072655Sstever@eecs.umich.edu        panic("Unimplemented version of doOp called.\n");
1008955SN/A    }
10093918Ssaidi@eecs.umich.edu
10103918Ssaidi@eecs.umich.edu    virtual double
10113918Ssaidi@eecs.umich.edu    doOp(double op1) const
10123918Ssaidi@eecs.umich.edu    {
10133918Ssaidi@eecs.umich.edu        panic("Unimplemented version of doOp called.\n");
10143918Ssaidi@eecs.umich.edu    }
10153918Ssaidi@eecs.umich.edu
10163918Ssaidi@eecs.umich.edu    double
10173918Ssaidi@eecs.umich.edu    dbl(uint32_t low, uint32_t high) const
10183918Ssaidi@eecs.umich.edu    {
10193918Ssaidi@eecs.umich.edu        double junk = 0.0;
10203918Ssaidi@eecs.umich.edu        return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk);
10213918Ssaidi@eecs.umich.edu    }
10223918Ssaidi@eecs.umich.edu
10233940Ssaidi@eecs.umich.edu    uint32_t
10243940Ssaidi@eecs.umich.edu    dblLow(double val) const
10253940Ssaidi@eecs.umich.edu    {
10263942Ssaidi@eecs.umich.edu        return fpToBits(val);
10273940Ssaidi@eecs.umich.edu    }
10283515Ssaidi@eecs.umich.edu
10293918Ssaidi@eecs.umich.edu    uint32_t
10304762Snate@binkert.org    dblHi(double val) const
10313515Ssaidi@eecs.umich.edu    {
10322655Sstever@eecs.umich.edu        return fpToBits(val) >> 32;
10333918Ssaidi@eecs.umich.edu    }
10343619Sbinkertn@umich.edu
1035955SN/A    template <class fpType>
1036955SN/A    fpType
10372655Sstever@eecs.umich.edu    binaryOp(FPSCR &fpscr, fpType op1, fpType op2,
10383918Ssaidi@eecs.umich.edu            fpType (*func)(fpType, fpType),
10393619Sbinkertn@umich.edu            bool flush, uint32_t rMode) const
1040955SN/A    {
1041955SN/A        const bool single = (sizeof(fpType) == sizeof(float));
10422655Sstever@eecs.umich.edu        fpType junk = 0.0;
10433918Ssaidi@eecs.umich.edu
10443619Sbinkertn@umich.edu        if (flush && flushToZero(op1, op2))
1045955SN/A            fpscr.idc = 1;
1046955SN/A        VfpSavedState state = prepFpState(rMode);
10472655Sstever@eecs.umich.edu        __asm__ __volatile__ ("" : "=m" (op1), "=m" (op2), "=m" (state)
10483918Ssaidi@eecs.umich.edu                                 : "m" (op1), "m" (op2), "m" (state));
10493683Sstever@eecs.umich.edu        fpType dest = func(op1, op2);
10502655Sstever@eecs.umich.edu        __asm__ __volatile__ ("" : "=m" (dest) : "m" (dest));
10511869SN/A
10521869SN/A        int fpClass = std::fpclassify(dest);
1053        // Get NAN behavior right. This varies between x86 and ARM.
1054        if (fpClass == FP_NAN) {
1055            const bool single = (sizeof(fpType) == sizeof(float));
1056            const uint64_t qnan =
1057                single ? 0x7fc00000 : ULL(0x7ff8000000000000);
1058            const bool nan1 = std::isnan(op1);
1059            const bool nan2 = std::isnan(op2);
1060            const bool signal1 = nan1 && ((fpToBits(op1) & qnan) != qnan);
1061            const bool signal2 = nan2 && ((fpToBits(op2) & qnan) != qnan);
1062            if ((!nan1 && !nan2) || (fpscr.dn == 1)) {
1063                dest = bitsToFp(qnan, junk);
1064            } else if (signal1) {
1065                dest = bitsToFp(fpToBits(op1) | qnan, junk);
1066            } else if (signal2) {
1067                dest = bitsToFp(fpToBits(op2) | qnan, junk);
1068            } else if (nan1) {
1069                dest = op1;
1070            } else if (nan2) {
1071                dest = op2;
1072            }
1073        } else if (flush && flushToZero(dest)) {
1074            feraiseexcept(FeUnderflow);
1075        } else if ((
1076                    (single && (dest == bitsToFp(0x00800000, junk) ||
1077                         dest == bitsToFp(0x80800000, junk))) ||
1078                    (!single &&
1079                        (dest == bitsToFp(ULL(0x0010000000000000), junk) ||
1080                         dest == bitsToFp(ULL(0x8010000000000000), junk)))
1081                   ) && rMode != VfpRoundZero) {
1082            /*
1083             * Correct for the fact that underflow is detected -before- rounding
1084             * in ARM and -after- rounding in x86.
1085             */
1086            fesetround(FeRoundZero);
1087            __asm__ __volatile__ ("" : "=m" (op1), "=m" (op2)
1088                                     : "m" (op1), "m" (op2));
1089            fpType temp = func(op1, op2);
1090            __asm__ __volatile__ ("" : "=m" (temp) : "m" (temp));
1091            if (flush && flushToZero(temp)) {
1092                dest = temp;
1093            }
1094        }
1095        finishVfp(fpscr, state);
1096        return dest;
1097    }
1098
1099    template <class fpType>
1100    fpType
1101    unaryOp(FPSCR &fpscr, fpType op1,
1102            fpType (*func)(fpType),
1103            bool flush, uint32_t rMode) const
1104    {
1105        const bool single = (sizeof(fpType) == sizeof(float));
1106        fpType junk = 0.0;
1107
1108        if (flush && flushToZero(op1))
1109            fpscr.idc = 1;
1110        VfpSavedState state = prepFpState(rMode);
1111        __asm__ __volatile__ ("" : "=m" (op1), "=m" (state)
1112                                 : "m" (op1), "m" (state));
1113        fpType dest = func(op1);
1114        __asm__ __volatile__ ("" : "=m" (dest) : "m" (dest));
1115
1116        int fpClass = std::fpclassify(dest);
1117        // Get NAN behavior right. This varies between x86 and ARM.
1118        if (fpClass == FP_NAN) {
1119            const bool single = (sizeof(fpType) == sizeof(float));
1120            const uint64_t qnan =
1121                single ? 0x7fc00000 : ULL(0x7ff8000000000000);
1122            const bool nan = std::isnan(op1);
1123            if (!nan || fpscr.dn == 1) {
1124                dest = bitsToFp(qnan, junk);
1125            } else if (nan) {
1126                dest = bitsToFp(fpToBits(op1) | qnan, junk);
1127            }
1128        } else if (flush && flushToZero(dest)) {
1129            feraiseexcept(FeUnderflow);
1130        } else if ((
1131                    (single && (dest == bitsToFp(0x00800000, junk) ||
1132                         dest == bitsToFp(0x80800000, junk))) ||
1133                    (!single &&
1134                        (dest == bitsToFp(ULL(0x0010000000000000), junk) ||
1135                         dest == bitsToFp(ULL(0x8010000000000000), junk)))
1136                   ) && rMode != VfpRoundZero) {
1137            /*
1138             * Correct for the fact that underflow is detected -before- rounding
1139             * in ARM and -after- rounding in x86.
1140             */
1141            fesetround(FeRoundZero);
1142            __asm__ __volatile__ ("" : "=m" (op1) : "m" (op1));
1143            fpType temp = func(op1);
1144            __asm__ __volatile__ ("" : "=m" (temp) : "m" (temp));
1145            if (flush && flushToZero(temp)) {
1146                dest = temp;
1147            }
1148        }
1149        finishVfp(fpscr, state);
1150        return dest;
1151    }
1152};
1153
1154class FpRegRegOp : public FpOp
1155{
1156  protected:
1157    IntRegIndex dest;
1158    IntRegIndex op1;
1159
1160    FpRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
1161               IntRegIndex _dest, IntRegIndex _op1,
1162               VfpMicroMode mode = VfpNotAMicroop) :
1163        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1)
1164    {
1165        setVfpMicroFlags(mode, flags);
1166    }
1167
1168    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
1169};
1170
1171class FpRegImmOp : public FpOp
1172{
1173  protected:
1174    IntRegIndex dest;
1175    uint64_t imm;
1176
1177    FpRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
1178               IntRegIndex _dest, uint64_t _imm,
1179               VfpMicroMode mode = VfpNotAMicroop) :
1180        FpOp(mnem, _machInst, __opClass), dest(_dest), imm(_imm)
1181    {
1182        setVfpMicroFlags(mode, flags);
1183    }
1184
1185    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
1186};
1187
1188class FpRegRegImmOp : public FpOp
1189{
1190  protected:
1191    IntRegIndex dest;
1192    IntRegIndex op1;
1193    uint64_t imm;
1194
1195    FpRegRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
1196                  IntRegIndex _dest, IntRegIndex _op1,
1197                  uint64_t _imm, VfpMicroMode mode = VfpNotAMicroop) :
1198        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), imm(_imm)
1199    {
1200        setVfpMicroFlags(mode, flags);
1201    }
1202
1203    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
1204};
1205
1206class FpRegRegRegOp : public FpOp
1207{
1208  protected:
1209    IntRegIndex dest;
1210    IntRegIndex op1;
1211    IntRegIndex op2;
1212
1213    FpRegRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
1214                  IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2,
1215                  VfpMicroMode mode = VfpNotAMicroop) :
1216        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), op2(_op2)
1217    {
1218        setVfpMicroFlags(mode, flags);
1219    }
1220
1221    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
1222};
1223
1224}
1225
1226#endif //__ARCH_ARM_INSTS_VFP_HH__
1227