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