vfp.cc revision 11671
17396Sgblack@eecs.umich.edu/* 210037SARM gem5 Developers * Copyright (c) 2010-2013 ARM Limited 37396Sgblack@eecs.umich.edu * All rights reserved 47396Sgblack@eecs.umich.edu * 57396Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall 67396Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual 77396Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating 87396Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software 97396Sgblack@eecs.umich.edu * licensed hereunder. You may use the software subject to the license 107396Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated 117396Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software, 127396Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form. 137396Sgblack@eecs.umich.edu * 147396Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 157396Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 167396Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 177396Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 187396Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 197396Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 207396Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 217396Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 227396Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 237396Sgblack@eecs.umich.edu * this software without specific prior written permission. 247396Sgblack@eecs.umich.edu * 257396Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 267396Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 277396Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 287396Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 297396Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 307396Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 317396Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 327396Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 337396Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 347396Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 357396Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 367396Sgblack@eecs.umich.edu * 377396Sgblack@eecs.umich.edu * Authors: Gabe Black 387396Sgblack@eecs.umich.edu */ 397396Sgblack@eecs.umich.edu 407396Sgblack@eecs.umich.edu#include "arch/arm/insts/vfp.hh" 417396Sgblack@eecs.umich.edu 427434Sgblack@eecs.umich.edu/* 437434Sgblack@eecs.umich.edu * The asm statements below are to keep gcc from reordering code. Otherwise 447434Sgblack@eecs.umich.edu * the rounding mode might be set after the operation it was intended for, the 457434Sgblack@eecs.umich.edu * exception bits read before it, etc. 467434Sgblack@eecs.umich.edu */ 477434Sgblack@eecs.umich.edu 487396Sgblack@eecs.umich.edustd::string 4910037SARM gem5 DevelopersFpCondCompRegOp::generateDisassembly( 5010037SARM gem5 Developers Addr pc, const SymbolTable *symtab) const 5110037SARM gem5 Developers{ 5210037SARM gem5 Developers std::stringstream ss; 5310037SARM gem5 Developers printMnemonic(ss, "", false); 5410037SARM gem5 Developers printReg(ss, op1); 5510037SARM gem5 Developers ccprintf(ss, ", "); 5610037SARM gem5 Developers printReg(ss, op2); 5710037SARM gem5 Developers ccprintf(ss, ", #%d", defCc); 5810037SARM gem5 Developers ccprintf(ss, ", "); 5910037SARM gem5 Developers printCondition(ss, condCode, true); 6010037SARM gem5 Developers return ss.str(); 6110037SARM gem5 Developers} 6210037SARM gem5 Developers 6310037SARM gem5 Developersstd::string 6410037SARM gem5 DevelopersFpCondSelOp::generateDisassembly( 6510037SARM gem5 Developers Addr pc, const SymbolTable *symtab) const 6610037SARM gem5 Developers{ 6710037SARM gem5 Developers std::stringstream ss; 6810037SARM gem5 Developers printMnemonic(ss, "", false); 6910037SARM gem5 Developers printReg(ss, dest); 7010037SARM gem5 Developers ccprintf(ss, ", "); 7110037SARM gem5 Developers printReg(ss, op1); 7210037SARM gem5 Developers ccprintf(ss, ", "); 7310037SARM gem5 Developers printReg(ss, op2); 7410037SARM gem5 Developers ccprintf(ss, ", "); 7510037SARM gem5 Developers printCondition(ss, condCode, true); 7610037SARM gem5 Developers return ss.str(); 7710037SARM gem5 Developers} 7810037SARM gem5 Developers 7910037SARM gem5 Developersstd::string 807396Sgblack@eecs.umich.eduFpRegRegOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const 817396Sgblack@eecs.umich.edu{ 827396Sgblack@eecs.umich.edu std::stringstream ss; 837396Sgblack@eecs.umich.edu printMnemonic(ss); 849918Ssteve.reinhardt@amd.com printReg(ss, dest + FP_Reg_Base); 857396Sgblack@eecs.umich.edu ss << ", "; 869918Ssteve.reinhardt@amd.com printReg(ss, op1 + FP_Reg_Base); 877396Sgblack@eecs.umich.edu return ss.str(); 887396Sgblack@eecs.umich.edu} 897396Sgblack@eecs.umich.edu 907396Sgblack@eecs.umich.edustd::string 917396Sgblack@eecs.umich.eduFpRegImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const 927396Sgblack@eecs.umich.edu{ 937396Sgblack@eecs.umich.edu std::stringstream ss; 947396Sgblack@eecs.umich.edu printMnemonic(ss); 959918Ssteve.reinhardt@amd.com printReg(ss, dest + FP_Reg_Base); 967396Sgblack@eecs.umich.edu ccprintf(ss, ", #%d", imm); 977396Sgblack@eecs.umich.edu return ss.str(); 987396Sgblack@eecs.umich.edu} 997396Sgblack@eecs.umich.edu 1007396Sgblack@eecs.umich.edustd::string 1017396Sgblack@eecs.umich.eduFpRegRegImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const 1027396Sgblack@eecs.umich.edu{ 1037396Sgblack@eecs.umich.edu std::stringstream ss; 1047396Sgblack@eecs.umich.edu printMnemonic(ss); 1059918Ssteve.reinhardt@amd.com printReg(ss, dest + FP_Reg_Base); 1067396Sgblack@eecs.umich.edu ss << ", "; 1079918Ssteve.reinhardt@amd.com printReg(ss, op1 + FP_Reg_Base); 1087396Sgblack@eecs.umich.edu ccprintf(ss, ", #%d", imm); 1097396Sgblack@eecs.umich.edu return ss.str(); 1107396Sgblack@eecs.umich.edu} 1117396Sgblack@eecs.umich.edu 1127396Sgblack@eecs.umich.edustd::string 1137396Sgblack@eecs.umich.eduFpRegRegRegOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const 1147396Sgblack@eecs.umich.edu{ 1157396Sgblack@eecs.umich.edu std::stringstream ss; 1167396Sgblack@eecs.umich.edu printMnemonic(ss); 1179918Ssteve.reinhardt@amd.com printReg(ss, dest + FP_Reg_Base); 1187396Sgblack@eecs.umich.edu ss << ", "; 1199918Ssteve.reinhardt@amd.com printReg(ss, op1 + FP_Reg_Base); 1207396Sgblack@eecs.umich.edu ss << ", "; 1219918Ssteve.reinhardt@amd.com printReg(ss, op2 + FP_Reg_Base); 1227396Sgblack@eecs.umich.edu return ss.str(); 1237396Sgblack@eecs.umich.edu} 1247430Sgblack@eecs.umich.edu 1257639Sgblack@eecs.umich.edustd::string 12611671Smitch.hayenga@arm.comFpRegRegRegCondOp::generateDisassembly(Addr pc, const SymbolTable *symtab) 12711671Smitch.hayenga@arm.com const 12811671Smitch.hayenga@arm.com{ 12911671Smitch.hayenga@arm.com std::stringstream ss; 13011671Smitch.hayenga@arm.com printMnemonic(ss); 13111671Smitch.hayenga@arm.com printCondition(ss, cond); 13211671Smitch.hayenga@arm.com printReg(ss, dest + FP_Reg_Base); 13311671Smitch.hayenga@arm.com ss << ", "; 13411671Smitch.hayenga@arm.com printReg(ss, op1 + FP_Reg_Base); 13511671Smitch.hayenga@arm.com ss << ", "; 13611671Smitch.hayenga@arm.com printReg(ss, op2 + FP_Reg_Base); 13711671Smitch.hayenga@arm.com return ss.str(); 13811671Smitch.hayenga@arm.com} 13911671Smitch.hayenga@arm.com 14011671Smitch.hayenga@arm.comstd::string 14110037SARM gem5 DevelopersFpRegRegRegRegOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const 14210037SARM gem5 Developers{ 14310037SARM gem5 Developers std::stringstream ss; 14410037SARM gem5 Developers printMnemonic(ss); 14510037SARM gem5 Developers printReg(ss, dest + FP_Reg_Base); 14610037SARM gem5 Developers ss << ", "; 14710037SARM gem5 Developers printReg(ss, op1 + FP_Reg_Base); 14810037SARM gem5 Developers ss << ", "; 14910037SARM gem5 Developers printReg(ss, op2 + FP_Reg_Base); 15010037SARM gem5 Developers ss << ", "; 15110037SARM gem5 Developers printReg(ss, op3 + FP_Reg_Base); 15210037SARM gem5 Developers return ss.str(); 15310037SARM gem5 Developers} 15410037SARM gem5 Developers 15510037SARM gem5 Developersstd::string 1567639Sgblack@eecs.umich.eduFpRegRegRegImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const 1577639Sgblack@eecs.umich.edu{ 1587639Sgblack@eecs.umich.edu std::stringstream ss; 1597639Sgblack@eecs.umich.edu printMnemonic(ss); 1609918Ssteve.reinhardt@amd.com printReg(ss, dest + FP_Reg_Base); 1617639Sgblack@eecs.umich.edu ss << ", "; 1629918Ssteve.reinhardt@amd.com printReg(ss, op1 + FP_Reg_Base); 1637639Sgblack@eecs.umich.edu ss << ", "; 1649918Ssteve.reinhardt@amd.com printReg(ss, op2 + FP_Reg_Base); 1657639Sgblack@eecs.umich.edu ccprintf(ss, ", #%d", imm); 1667639Sgblack@eecs.umich.edu return ss.str(); 1677639Sgblack@eecs.umich.edu} 1687639Sgblack@eecs.umich.edu 1697430Sgblack@eecs.umich.edunamespace ArmISA 1707430Sgblack@eecs.umich.edu{ 1717430Sgblack@eecs.umich.edu 1727430Sgblack@eecs.umich.eduVfpSavedState 1737430Sgblack@eecs.umich.eduprepFpState(uint32_t rMode) 1747430Sgblack@eecs.umich.edu{ 1757430Sgblack@eecs.umich.edu int roundingMode = fegetround(); 1767430Sgblack@eecs.umich.edu feclearexcept(FeAllExceptions); 1777430Sgblack@eecs.umich.edu switch (rMode) { 1787430Sgblack@eecs.umich.edu case VfpRoundNearest: 1797430Sgblack@eecs.umich.edu fesetround(FeRoundNearest); 1807430Sgblack@eecs.umich.edu break; 1817430Sgblack@eecs.umich.edu case VfpRoundUpward: 1827430Sgblack@eecs.umich.edu fesetround(FeRoundUpward); 1837430Sgblack@eecs.umich.edu break; 1847430Sgblack@eecs.umich.edu case VfpRoundDown: 1857430Sgblack@eecs.umich.edu fesetround(FeRoundDown); 1867430Sgblack@eecs.umich.edu break; 1877430Sgblack@eecs.umich.edu case VfpRoundZero: 1887430Sgblack@eecs.umich.edu fesetround(FeRoundZero); 1897430Sgblack@eecs.umich.edu break; 1907430Sgblack@eecs.umich.edu } 1917430Sgblack@eecs.umich.edu return roundingMode; 1927430Sgblack@eecs.umich.edu} 1937430Sgblack@eecs.umich.edu 1947430Sgblack@eecs.umich.eduvoid 19510037SARM gem5 DevelopersfinishVfp(FPSCR &fpscr, VfpSavedState state, bool flush, FPSCR mask) 1967430Sgblack@eecs.umich.edu{ 1977430Sgblack@eecs.umich.edu int exceptions = fetestexcept(FeAllExceptions); 1987430Sgblack@eecs.umich.edu bool underflow = false; 19910037SARM gem5 Developers if ((exceptions & FeInvalid) && mask.ioc) { 2007430Sgblack@eecs.umich.edu fpscr.ioc = 1; 2017430Sgblack@eecs.umich.edu } 20210037SARM gem5 Developers if ((exceptions & FeDivByZero) && mask.dzc) { 2037430Sgblack@eecs.umich.edu fpscr.dzc = 1; 2047430Sgblack@eecs.umich.edu } 20510037SARM gem5 Developers if ((exceptions & FeOverflow) && mask.ofc) { 2067430Sgblack@eecs.umich.edu fpscr.ofc = 1; 2077430Sgblack@eecs.umich.edu } 2087430Sgblack@eecs.umich.edu if (exceptions & FeUnderflow) { 2097430Sgblack@eecs.umich.edu underflow = true; 21010037SARM gem5 Developers if (mask.ufc) 21110037SARM gem5 Developers fpscr.ufc = 1; 2127430Sgblack@eecs.umich.edu } 21310037SARM gem5 Developers if ((exceptions & FeInexact) && !(underflow && flush) && mask.ixc) { 2147430Sgblack@eecs.umich.edu fpscr.ixc = 1; 2157430Sgblack@eecs.umich.edu } 2167430Sgblack@eecs.umich.edu fesetround(state); 2177430Sgblack@eecs.umich.edu} 2187430Sgblack@eecs.umich.edu 2197430Sgblack@eecs.umich.edutemplate <class fpType> 2207430Sgblack@eecs.umich.edufpType 2217639Sgblack@eecs.umich.edufixDest(bool flush, bool defaultNan, fpType val, fpType op1) 2227430Sgblack@eecs.umich.edu{ 2237430Sgblack@eecs.umich.edu int fpClass = std::fpclassify(val); 2247430Sgblack@eecs.umich.edu fpType junk = 0.0; 2257430Sgblack@eecs.umich.edu if (fpClass == FP_NAN) { 2267430Sgblack@eecs.umich.edu const bool single = (sizeof(val) == sizeof(float)); 2277430Sgblack@eecs.umich.edu const uint64_t qnan = single ? 0x7fc00000 : ULL(0x7ff8000000000000); 2287430Sgblack@eecs.umich.edu const bool nan = std::isnan(op1); 2297639Sgblack@eecs.umich.edu if (!nan || defaultNan) { 2307430Sgblack@eecs.umich.edu val = bitsToFp(qnan, junk); 2317430Sgblack@eecs.umich.edu } else if (nan) { 2327430Sgblack@eecs.umich.edu val = bitsToFp(fpToBits(op1) | qnan, junk); 2337430Sgblack@eecs.umich.edu } 2347639Sgblack@eecs.umich.edu } else if (fpClass == FP_SUBNORMAL && flush == 1) { 2357430Sgblack@eecs.umich.edu // Turn val into a zero with the correct sign; 2367430Sgblack@eecs.umich.edu uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1); 2377430Sgblack@eecs.umich.edu val = bitsToFp(fpToBits(val) & bitMask, junk); 2387430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 2397430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 2407430Sgblack@eecs.umich.edu } 2417430Sgblack@eecs.umich.edu return val; 2427430Sgblack@eecs.umich.edu} 2437430Sgblack@eecs.umich.edu 2447430Sgblack@eecs.umich.edutemplate 2457639Sgblack@eecs.umich.edufloat fixDest<float>(bool flush, bool defaultNan, float val, float op1); 2467430Sgblack@eecs.umich.edutemplate 2477639Sgblack@eecs.umich.edudouble fixDest<double>(bool flush, bool defaultNan, double val, double op1); 2487430Sgblack@eecs.umich.edu 2497430Sgblack@eecs.umich.edutemplate <class fpType> 2507430Sgblack@eecs.umich.edufpType 2517639Sgblack@eecs.umich.edufixDest(bool flush, bool defaultNan, fpType val, fpType op1, fpType op2) 2527430Sgblack@eecs.umich.edu{ 2537430Sgblack@eecs.umich.edu int fpClass = std::fpclassify(val); 2547430Sgblack@eecs.umich.edu fpType junk = 0.0; 2557430Sgblack@eecs.umich.edu if (fpClass == FP_NAN) { 2567430Sgblack@eecs.umich.edu const bool single = (sizeof(val) == sizeof(float)); 2577430Sgblack@eecs.umich.edu const uint64_t qnan = single ? 0x7fc00000 : ULL(0x7ff8000000000000); 2587430Sgblack@eecs.umich.edu const bool nan1 = std::isnan(op1); 2597430Sgblack@eecs.umich.edu const bool nan2 = std::isnan(op2); 2607430Sgblack@eecs.umich.edu const bool signal1 = nan1 && ((fpToBits(op1) & qnan) != qnan); 2617430Sgblack@eecs.umich.edu const bool signal2 = nan2 && ((fpToBits(op2) & qnan) != qnan); 2627639Sgblack@eecs.umich.edu if ((!nan1 && !nan2) || defaultNan) { 2637430Sgblack@eecs.umich.edu val = bitsToFp(qnan, junk); 2647430Sgblack@eecs.umich.edu } else if (signal1) { 2657430Sgblack@eecs.umich.edu val = bitsToFp(fpToBits(op1) | qnan, junk); 2667430Sgblack@eecs.umich.edu } else if (signal2) { 2677430Sgblack@eecs.umich.edu val = bitsToFp(fpToBits(op2) | qnan, junk); 2687430Sgblack@eecs.umich.edu } else if (nan1) { 2697430Sgblack@eecs.umich.edu val = op1; 2707430Sgblack@eecs.umich.edu } else if (nan2) { 2717430Sgblack@eecs.umich.edu val = op2; 2727430Sgblack@eecs.umich.edu } 2737639Sgblack@eecs.umich.edu } else if (fpClass == FP_SUBNORMAL && flush) { 2747430Sgblack@eecs.umich.edu // Turn val into a zero with the correct sign; 2757430Sgblack@eecs.umich.edu uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1); 2767430Sgblack@eecs.umich.edu val = bitsToFp(fpToBits(val) & bitMask, junk); 2777430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 2787430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 2797430Sgblack@eecs.umich.edu } 2807430Sgblack@eecs.umich.edu return val; 2817430Sgblack@eecs.umich.edu} 2827430Sgblack@eecs.umich.edu 2837430Sgblack@eecs.umich.edutemplate 2847639Sgblack@eecs.umich.edufloat fixDest<float>(bool flush, bool defaultNan, 2857639Sgblack@eecs.umich.edu float val, float op1, float op2); 2867430Sgblack@eecs.umich.edutemplate 2877639Sgblack@eecs.umich.edudouble fixDest<double>(bool flush, bool defaultNan, 2887639Sgblack@eecs.umich.edu double val, double op1, double op2); 2897430Sgblack@eecs.umich.edu 2907430Sgblack@eecs.umich.edutemplate <class fpType> 2917430Sgblack@eecs.umich.edufpType 2927639Sgblack@eecs.umich.edufixDivDest(bool flush, bool defaultNan, fpType val, fpType op1, fpType op2) 2937430Sgblack@eecs.umich.edu{ 2947639Sgblack@eecs.umich.edu fpType mid = fixDest(flush, defaultNan, val, op1, op2); 2957430Sgblack@eecs.umich.edu const bool single = (sizeof(fpType) == sizeof(float)); 2967430Sgblack@eecs.umich.edu const fpType junk = 0.0; 2977430Sgblack@eecs.umich.edu if ((single && (val == bitsToFp(0x00800000, junk) || 2987430Sgblack@eecs.umich.edu val == bitsToFp(0x80800000, junk))) || 2997430Sgblack@eecs.umich.edu (!single && (val == bitsToFp(ULL(0x0010000000000000), junk) || 3007430Sgblack@eecs.umich.edu val == bitsToFp(ULL(0x8010000000000000), junk))) 3017430Sgblack@eecs.umich.edu ) { 3027430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (op1) : "m" (op1)); 3037430Sgblack@eecs.umich.edu fesetround(FeRoundZero); 3047430Sgblack@eecs.umich.edu fpType temp = 0.0; 3057430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (temp) : "m" (temp)); 3067430Sgblack@eecs.umich.edu temp = op1 / op2; 3077430Sgblack@eecs.umich.edu if (flushToZero(temp)) { 3087430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 3097639Sgblack@eecs.umich.edu if (flush) { 3107430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 3117430Sgblack@eecs.umich.edu mid = temp; 3127430Sgblack@eecs.umich.edu } 3137430Sgblack@eecs.umich.edu } 3147430Sgblack@eecs.umich.edu __asm__ __volatile__("" :: "m" (temp)); 3157430Sgblack@eecs.umich.edu } 3167430Sgblack@eecs.umich.edu return mid; 3177430Sgblack@eecs.umich.edu} 3187430Sgblack@eecs.umich.edu 3197430Sgblack@eecs.umich.edutemplate 3207639Sgblack@eecs.umich.edufloat fixDivDest<float>(bool flush, bool defaultNan, 3217639Sgblack@eecs.umich.edu float val, float op1, float op2); 3227430Sgblack@eecs.umich.edutemplate 3237639Sgblack@eecs.umich.edudouble fixDivDest<double>(bool flush, bool defaultNan, 3247639Sgblack@eecs.umich.edu double val, double op1, double op2); 3257430Sgblack@eecs.umich.edu 3267430Sgblack@eecs.umich.edufloat 3277430Sgblack@eecs.umich.edufixFpDFpSDest(FPSCR fpscr, double val) 3287430Sgblack@eecs.umich.edu{ 3297430Sgblack@eecs.umich.edu const float junk = 0.0; 3307430Sgblack@eecs.umich.edu float op1 = 0.0; 3317430Sgblack@eecs.umich.edu if (std::isnan(val)) { 3327430Sgblack@eecs.umich.edu uint64_t valBits = fpToBits(val); 3337430Sgblack@eecs.umich.edu uint32_t op1Bits = bits(valBits, 50, 29) | 3347430Sgblack@eecs.umich.edu (mask(9) << 22) | 3357430Sgblack@eecs.umich.edu (bits(valBits, 63) << 31); 3367430Sgblack@eecs.umich.edu op1 = bitsToFp(op1Bits, junk); 3377430Sgblack@eecs.umich.edu } 3387639Sgblack@eecs.umich.edu float mid = fixDest(fpscr.fz, fpscr.dn, (float)val, op1); 3397430Sgblack@eecs.umich.edu if (fpscr.fz && fetestexcept(FeUnderflow | FeInexact) == 3407430Sgblack@eecs.umich.edu (FeUnderflow | FeInexact)) { 3417430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 3427430Sgblack@eecs.umich.edu } 3437430Sgblack@eecs.umich.edu if (mid == bitsToFp(0x00800000, junk) || 3447430Sgblack@eecs.umich.edu mid == bitsToFp(0x80800000, junk)) { 3457430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (val) : "m" (val)); 3467430Sgblack@eecs.umich.edu fesetround(FeRoundZero); 3477430Sgblack@eecs.umich.edu float temp = 0.0; 3487430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (temp) : "m" (temp)); 3497430Sgblack@eecs.umich.edu temp = val; 3507430Sgblack@eecs.umich.edu if (flushToZero(temp)) { 3517430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 3527430Sgblack@eecs.umich.edu if (fpscr.fz) { 3537430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 3547430Sgblack@eecs.umich.edu mid = temp; 3557430Sgblack@eecs.umich.edu } 3567430Sgblack@eecs.umich.edu } 3577430Sgblack@eecs.umich.edu __asm__ __volatile__("" :: "m" (temp)); 3587430Sgblack@eecs.umich.edu } 3597430Sgblack@eecs.umich.edu return mid; 3607430Sgblack@eecs.umich.edu} 3617430Sgblack@eecs.umich.edu 3627430Sgblack@eecs.umich.edudouble 3637430Sgblack@eecs.umich.edufixFpSFpDDest(FPSCR fpscr, float val) 3647430Sgblack@eecs.umich.edu{ 3657430Sgblack@eecs.umich.edu const double junk = 0.0; 3667430Sgblack@eecs.umich.edu double op1 = 0.0; 3677430Sgblack@eecs.umich.edu if (std::isnan(val)) { 3687430Sgblack@eecs.umich.edu uint32_t valBits = fpToBits(val); 3697430Sgblack@eecs.umich.edu uint64_t op1Bits = ((uint64_t)bits(valBits, 21, 0) << 29) | 3707430Sgblack@eecs.umich.edu (mask(12) << 51) | 3717430Sgblack@eecs.umich.edu ((uint64_t)bits(valBits, 31) << 63); 3727430Sgblack@eecs.umich.edu op1 = bitsToFp(op1Bits, junk); 3737430Sgblack@eecs.umich.edu } 3747639Sgblack@eecs.umich.edu double mid = fixDest(fpscr.fz, fpscr.dn, (double)val, op1); 3757430Sgblack@eecs.umich.edu if (mid == bitsToFp(ULL(0x0010000000000000), junk) || 3767430Sgblack@eecs.umich.edu mid == bitsToFp(ULL(0x8010000000000000), junk)) { 3777430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (val) : "m" (val)); 3787430Sgblack@eecs.umich.edu fesetround(FeRoundZero); 3797430Sgblack@eecs.umich.edu double temp = 0.0; 3807430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (temp) : "m" (temp)); 3817430Sgblack@eecs.umich.edu temp = val; 3827430Sgblack@eecs.umich.edu if (flushToZero(temp)) { 3837430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 3847430Sgblack@eecs.umich.edu if (fpscr.fz) { 3857430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 3867430Sgblack@eecs.umich.edu mid = temp; 3877430Sgblack@eecs.umich.edu } 3887430Sgblack@eecs.umich.edu } 3897430Sgblack@eecs.umich.edu __asm__ __volatile__("" :: "m" (temp)); 3907430Sgblack@eecs.umich.edu } 3917430Sgblack@eecs.umich.edu return mid; 3927430Sgblack@eecs.umich.edu} 3937430Sgblack@eecs.umich.edu 39410037SARM gem5 Developersstatic inline uint16_t 39510037SARM gem5 DevelopersvcvtFpFpH(FPSCR &fpscr, bool flush, bool defaultNan, 39610037SARM gem5 Developers uint32_t rMode, bool ahp, uint64_t opBits, bool isDouble) 3977430Sgblack@eecs.umich.edu{ 39810037SARM gem5 Developers uint32_t mWidth; 39910037SARM gem5 Developers uint32_t eWidth; 40010037SARM gem5 Developers uint32_t eHalfRange; 40110037SARM gem5 Developers uint32_t sBitPos; 40210037SARM gem5 Developers 40310037SARM gem5 Developers if (isDouble) { 40410037SARM gem5 Developers mWidth = 52; 40510037SARM gem5 Developers eWidth = 11; 40610037SARM gem5 Developers } else { 40710037SARM gem5 Developers mWidth = 23; 40810037SARM gem5 Developers eWidth = 8; 40910037SARM gem5 Developers } 41010037SARM gem5 Developers sBitPos = eWidth + mWidth; 41110037SARM gem5 Developers eHalfRange = (1 << (eWidth-1)) - 1; 41210037SARM gem5 Developers 4137430Sgblack@eecs.umich.edu // Extract the operand. 41410037SARM gem5 Developers bool neg = bits(opBits, sBitPos); 41510037SARM gem5 Developers uint32_t exponent = bits(opBits, sBitPos-1, mWidth); 41610037SARM gem5 Developers uint64_t oldMantissa = bits(opBits, mWidth-1, 0); 41710037SARM gem5 Developers uint32_t mantissa = oldMantissa >> (mWidth - 10); 4187430Sgblack@eecs.umich.edu // Do the conversion. 41910037SARM gem5 Developers uint64_t extra = oldMantissa & mask(mWidth - 10); 42010037SARM gem5 Developers if (exponent == mask(eWidth)) { 4217430Sgblack@eecs.umich.edu if (oldMantissa != 0) { 4227430Sgblack@eecs.umich.edu // Nans. 4237430Sgblack@eecs.umich.edu if (bits(mantissa, 9) == 0) { 4247430Sgblack@eecs.umich.edu // Signalling nan. 4257430Sgblack@eecs.umich.edu fpscr.ioc = 1; 4267430Sgblack@eecs.umich.edu } 4277639Sgblack@eecs.umich.edu if (ahp) { 4287430Sgblack@eecs.umich.edu mantissa = 0; 4297430Sgblack@eecs.umich.edu exponent = 0; 4307430Sgblack@eecs.umich.edu fpscr.ioc = 1; 4317639Sgblack@eecs.umich.edu } else if (defaultNan) { 4327430Sgblack@eecs.umich.edu mantissa = (1 << 9); 4337430Sgblack@eecs.umich.edu exponent = 0x1f; 4347430Sgblack@eecs.umich.edu neg = false; 4357430Sgblack@eecs.umich.edu } else { 4367430Sgblack@eecs.umich.edu exponent = 0x1f; 4377430Sgblack@eecs.umich.edu mantissa |= (1 << 9); 4387430Sgblack@eecs.umich.edu } 4397430Sgblack@eecs.umich.edu } else { 4407430Sgblack@eecs.umich.edu // Infinities. 4417430Sgblack@eecs.umich.edu exponent = 0x1F; 4427639Sgblack@eecs.umich.edu if (ahp) { 4437430Sgblack@eecs.umich.edu fpscr.ioc = 1; 4447430Sgblack@eecs.umich.edu mantissa = 0x3ff; 4457430Sgblack@eecs.umich.edu } else { 4467430Sgblack@eecs.umich.edu mantissa = 0; 4477430Sgblack@eecs.umich.edu } 4487430Sgblack@eecs.umich.edu } 4497430Sgblack@eecs.umich.edu } else if (exponent == 0 && oldMantissa == 0) { 4507430Sgblack@eecs.umich.edu // Zero, don't need to do anything. 4517430Sgblack@eecs.umich.edu } else { 4527430Sgblack@eecs.umich.edu // Normalized or denormalized numbers. 4537430Sgblack@eecs.umich.edu 4547430Sgblack@eecs.umich.edu bool inexact = (extra != 0); 4557430Sgblack@eecs.umich.edu 4567430Sgblack@eecs.umich.edu if (exponent == 0) { 4577430Sgblack@eecs.umich.edu // Denormalized. 4587430Sgblack@eecs.umich.edu // If flush to zero is on, this shouldn't happen. 4597639Sgblack@eecs.umich.edu assert(!flush); 4607430Sgblack@eecs.umich.edu 4617430Sgblack@eecs.umich.edu // Check for underflow 4627430Sgblack@eecs.umich.edu if (inexact || fpscr.ufe) 4637430Sgblack@eecs.umich.edu fpscr.ufc = 1; 4647430Sgblack@eecs.umich.edu 4657430Sgblack@eecs.umich.edu // Handle rounding. 4667639Sgblack@eecs.umich.edu unsigned mode = rMode; 4677430Sgblack@eecs.umich.edu if ((mode == VfpRoundUpward && !neg && extra) || 4687430Sgblack@eecs.umich.edu (mode == VfpRoundDown && neg && extra) || 4697430Sgblack@eecs.umich.edu (mode == VfpRoundNearest && 4707430Sgblack@eecs.umich.edu (extra > (1 << 9) || 4717430Sgblack@eecs.umich.edu (extra == (1 << 9) && bits(mantissa, 0))))) { 4727430Sgblack@eecs.umich.edu mantissa++; 4737430Sgblack@eecs.umich.edu } 4747430Sgblack@eecs.umich.edu 4757430Sgblack@eecs.umich.edu // See if the number became normalized after rounding. 4767430Sgblack@eecs.umich.edu if (mantissa == (1 << 10)) { 4777430Sgblack@eecs.umich.edu mantissa = 0; 4787430Sgblack@eecs.umich.edu exponent = 1; 4797430Sgblack@eecs.umich.edu } 4807430Sgblack@eecs.umich.edu } else { 4817430Sgblack@eecs.umich.edu // Normalized. 4827430Sgblack@eecs.umich.edu 4837430Sgblack@eecs.umich.edu // We need to track the dropped bits differently since 4847430Sgblack@eecs.umich.edu // more can be dropped by denormalizing. 48510037SARM gem5 Developers bool topOne = bits(extra, mWidth - 10 - 1); 48610037SARM gem5 Developers bool restZeros = bits(extra, mWidth - 10 - 2, 0) == 0; 4877430Sgblack@eecs.umich.edu 48810037SARM gem5 Developers if (exponent <= (eHalfRange - 15)) { 4897430Sgblack@eecs.umich.edu // The result is too small. Denormalize. 4907430Sgblack@eecs.umich.edu mantissa |= (1 << 10); 49110037SARM gem5 Developers while (mantissa && exponent <= (eHalfRange - 15)) { 4927430Sgblack@eecs.umich.edu restZeros = restZeros && !topOne; 4937430Sgblack@eecs.umich.edu topOne = bits(mantissa, 0); 4947430Sgblack@eecs.umich.edu mantissa = mantissa >> 1; 4957430Sgblack@eecs.umich.edu exponent++; 4967430Sgblack@eecs.umich.edu } 4977430Sgblack@eecs.umich.edu if (topOne || !restZeros) 4987430Sgblack@eecs.umich.edu inexact = true; 4997430Sgblack@eecs.umich.edu exponent = 0; 5007430Sgblack@eecs.umich.edu } else { 5017430Sgblack@eecs.umich.edu // Change bias. 50210037SARM gem5 Developers exponent -= (eHalfRange - 15); 5037430Sgblack@eecs.umich.edu } 5047430Sgblack@eecs.umich.edu 5057430Sgblack@eecs.umich.edu if (exponent == 0 && (inexact || fpscr.ufe)) { 5067430Sgblack@eecs.umich.edu // Underflow 5077430Sgblack@eecs.umich.edu fpscr.ufc = 1; 5087430Sgblack@eecs.umich.edu } 5097430Sgblack@eecs.umich.edu 5107430Sgblack@eecs.umich.edu // Handle rounding. 5117639Sgblack@eecs.umich.edu unsigned mode = rMode; 5127430Sgblack@eecs.umich.edu bool nonZero = topOne || !restZeros; 5137430Sgblack@eecs.umich.edu if ((mode == VfpRoundUpward && !neg && nonZero) || 5147430Sgblack@eecs.umich.edu (mode == VfpRoundDown && neg && nonZero) || 5157430Sgblack@eecs.umich.edu (mode == VfpRoundNearest && topOne && 5167430Sgblack@eecs.umich.edu (!restZeros || bits(mantissa, 0)))) { 5177430Sgblack@eecs.umich.edu mantissa++; 5187430Sgblack@eecs.umich.edu } 5197430Sgblack@eecs.umich.edu 5207430Sgblack@eecs.umich.edu // See if we rounded up and need to bump the exponent. 5217430Sgblack@eecs.umich.edu if (mantissa == (1 << 10)) { 5227430Sgblack@eecs.umich.edu mantissa = 0; 5237430Sgblack@eecs.umich.edu exponent++; 5247430Sgblack@eecs.umich.edu } 5257430Sgblack@eecs.umich.edu 5267430Sgblack@eecs.umich.edu // Deal with overflow 5277639Sgblack@eecs.umich.edu if (ahp) { 5287430Sgblack@eecs.umich.edu if (exponent >= 0x20) { 5297430Sgblack@eecs.umich.edu exponent = 0x1f; 5307430Sgblack@eecs.umich.edu mantissa = 0x3ff; 5317430Sgblack@eecs.umich.edu fpscr.ioc = 1; 5327430Sgblack@eecs.umich.edu // Supress inexact exception. 5337430Sgblack@eecs.umich.edu inexact = false; 5347430Sgblack@eecs.umich.edu } 5357430Sgblack@eecs.umich.edu } else { 5367430Sgblack@eecs.umich.edu if (exponent >= 0x1f) { 5377430Sgblack@eecs.umich.edu if ((mode == VfpRoundNearest) || 5387430Sgblack@eecs.umich.edu (mode == VfpRoundUpward && !neg) || 5397430Sgblack@eecs.umich.edu (mode == VfpRoundDown && neg)) { 5407430Sgblack@eecs.umich.edu // Overflow to infinity. 5417430Sgblack@eecs.umich.edu exponent = 0x1f; 5427430Sgblack@eecs.umich.edu mantissa = 0; 5437430Sgblack@eecs.umich.edu } else { 5447430Sgblack@eecs.umich.edu // Overflow to max normal. 5457430Sgblack@eecs.umich.edu exponent = 0x1e; 5467430Sgblack@eecs.umich.edu mantissa = 0x3ff; 5477430Sgblack@eecs.umich.edu } 5487430Sgblack@eecs.umich.edu fpscr.ofc = 1; 5497430Sgblack@eecs.umich.edu inexact = true; 5507430Sgblack@eecs.umich.edu } 5517430Sgblack@eecs.umich.edu } 5527430Sgblack@eecs.umich.edu } 5537430Sgblack@eecs.umich.edu 5547430Sgblack@eecs.umich.edu if (inexact) { 5557430Sgblack@eecs.umich.edu fpscr.ixc = 1; 5567430Sgblack@eecs.umich.edu } 5577430Sgblack@eecs.umich.edu } 5587430Sgblack@eecs.umich.edu // Reassemble and install the result. 5597430Sgblack@eecs.umich.edu uint32_t result = bits(mantissa, 9, 0); 5607430Sgblack@eecs.umich.edu replaceBits(result, 14, 10, exponent); 5617430Sgblack@eecs.umich.edu if (neg) 5627430Sgblack@eecs.umich.edu result |= (1 << 15); 5637639Sgblack@eecs.umich.edu return result; 5647430Sgblack@eecs.umich.edu} 5657430Sgblack@eecs.umich.edu 56610037SARM gem5 Developersuint16_t 56710037SARM gem5 DevelopersvcvtFpSFpH(FPSCR &fpscr, bool flush, bool defaultNan, 56810037SARM gem5 Developers uint32_t rMode, bool ahp, float op) 5697430Sgblack@eecs.umich.edu{ 57010037SARM gem5 Developers uint64_t opBits = fpToBits(op); 57110037SARM gem5 Developers return vcvtFpFpH(fpscr, flush, defaultNan, rMode, ahp, opBits, false); 57210037SARM gem5 Developers} 57310037SARM gem5 Developers 57410037SARM gem5 Developersuint16_t 57510037SARM gem5 DevelopersvcvtFpDFpH(FPSCR &fpscr, bool flush, bool defaultNan, 57610037SARM gem5 Developers uint32_t rMode, bool ahp, double op) 57710037SARM gem5 Developers{ 57810037SARM gem5 Developers uint64_t opBits = fpToBits(op); 57910037SARM gem5 Developers return vcvtFpFpH(fpscr, flush, defaultNan, rMode, ahp, opBits, true); 58010037SARM gem5 Developers} 58110037SARM gem5 Developers 58210037SARM gem5 Developersstatic inline uint64_t 58310037SARM gem5 DevelopersvcvtFpHFp(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op, bool isDouble) 58410037SARM gem5 Developers{ 58510037SARM gem5 Developers uint32_t mWidth; 58610037SARM gem5 Developers uint32_t eWidth; 58710037SARM gem5 Developers uint32_t eHalfRange; 58810037SARM gem5 Developers uint32_t sBitPos; 58910037SARM gem5 Developers 59010037SARM gem5 Developers if (isDouble) { 59110037SARM gem5 Developers mWidth = 52; 59210037SARM gem5 Developers eWidth = 11; 59310037SARM gem5 Developers } else { 59410037SARM gem5 Developers mWidth = 23; 59510037SARM gem5 Developers eWidth = 8; 59610037SARM gem5 Developers } 59710037SARM gem5 Developers sBitPos = eWidth + mWidth; 59810037SARM gem5 Developers eHalfRange = (1 << (eWidth-1)) - 1; 59910037SARM gem5 Developers 6007430Sgblack@eecs.umich.edu // Extract the bitfields. 6017639Sgblack@eecs.umich.edu bool neg = bits(op, 15); 6027639Sgblack@eecs.umich.edu uint32_t exponent = bits(op, 14, 10); 60310037SARM gem5 Developers uint64_t mantissa = bits(op, 9, 0); 6047430Sgblack@eecs.umich.edu // Do the conversion. 6057430Sgblack@eecs.umich.edu if (exponent == 0) { 6067430Sgblack@eecs.umich.edu if (mantissa != 0) { 6077430Sgblack@eecs.umich.edu // Normalize the value. 60810037SARM gem5 Developers exponent = exponent + (eHalfRange - 15) + 1; 6097430Sgblack@eecs.umich.edu while (mantissa < (1 << 10)) { 6107430Sgblack@eecs.umich.edu mantissa = mantissa << 1; 6117430Sgblack@eecs.umich.edu exponent--; 6127430Sgblack@eecs.umich.edu } 6137430Sgblack@eecs.umich.edu } 61410037SARM gem5 Developers mantissa = mantissa << (mWidth - 10); 6157639Sgblack@eecs.umich.edu } else if (exponent == 0x1f && !ahp) { 6167430Sgblack@eecs.umich.edu // Infinities and nans. 61710037SARM gem5 Developers exponent = mask(eWidth); 6187430Sgblack@eecs.umich.edu if (mantissa != 0) { 6197430Sgblack@eecs.umich.edu // Nans. 62010037SARM gem5 Developers mantissa = mantissa << (mWidth - 10); 62110037SARM gem5 Developers if (bits(mantissa, mWidth-1) == 0) { 6227430Sgblack@eecs.umich.edu // Signalling nan. 6237430Sgblack@eecs.umich.edu fpscr.ioc = 1; 62410037SARM gem5 Developers mantissa |= (((uint64_t) 1) << (mWidth-1)); 6257430Sgblack@eecs.umich.edu } 6267639Sgblack@eecs.umich.edu if (defaultNan) { 62710037SARM gem5 Developers mantissa &= ~mask(mWidth-1); 6287430Sgblack@eecs.umich.edu neg = false; 6297430Sgblack@eecs.umich.edu } 6307430Sgblack@eecs.umich.edu } 6317430Sgblack@eecs.umich.edu } else { 63210037SARM gem5 Developers exponent = exponent + (eHalfRange - 15); 63310037SARM gem5 Developers mantissa = mantissa << (mWidth - 10); 6347430Sgblack@eecs.umich.edu } 6357430Sgblack@eecs.umich.edu // Reassemble the result. 63610037SARM gem5 Developers uint64_t result = bits(mantissa, mWidth-1, 0); 63710037SARM gem5 Developers replaceBits(result, sBitPos-1, mWidth, exponent); 63810037SARM gem5 Developers if (neg) { 63910037SARM gem5 Developers result |= (((uint64_t) 1) << sBitPos); 64010037SARM gem5 Developers } 64110037SARM gem5 Developers return result; 64210037SARM gem5 Developers} 64310037SARM gem5 Developers 64410037SARM gem5 Developersdouble 64510037SARM gem5 DevelopersvcvtFpHFpD(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op) 64610037SARM gem5 Developers{ 64710037SARM gem5 Developers double junk = 0.0; 64810037SARM gem5 Developers uint64_t result; 64910037SARM gem5 Developers 65010037SARM gem5 Developers result = vcvtFpHFp(fpscr, defaultNan, ahp, op, true); 6517430Sgblack@eecs.umich.edu return bitsToFp(result, junk); 6527430Sgblack@eecs.umich.edu} 6537430Sgblack@eecs.umich.edu 65410037SARM gem5 Developersfloat 65510037SARM gem5 DevelopersvcvtFpHFpS(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op) 6567430Sgblack@eecs.umich.edu{ 65710037SARM gem5 Developers float junk = 0.0; 65810037SARM gem5 Developers uint64_t result; 6597430Sgblack@eecs.umich.edu 66010037SARM gem5 Developers result = vcvtFpHFp(fpscr, defaultNan, ahp, op, false); 66110037SARM gem5 Developers return bitsToFp(result, junk); 6627430Sgblack@eecs.umich.edu} 6637430Sgblack@eecs.umich.edu 6647430Sgblack@eecs.umich.edufloat 6657639Sgblack@eecs.umich.eduvfpUFixedToFpS(bool flush, bool defaultNan, 66610037SARM gem5 Developers uint64_t val, uint8_t width, uint8_t imm) 6677430Sgblack@eecs.umich.edu{ 6687430Sgblack@eecs.umich.edu fesetround(FeRoundNearest); 66910037SARM gem5 Developers if (width == 16) 6707430Sgblack@eecs.umich.edu val = (uint16_t)val; 67110037SARM gem5 Developers else if (width == 32) 67210037SARM gem5 Developers val = (uint32_t)val; 67310037SARM gem5 Developers else if (width != 64) 67410037SARM gem5 Developers panic("Unsupported width %d", width); 6757430Sgblack@eecs.umich.edu float scale = powf(2.0, imm); 6767430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 6777430Sgblack@eecs.umich.edu feclearexcept(FeAllExceptions); 6787430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 6797639Sgblack@eecs.umich.edu return fixDivDest(flush, defaultNan, val / scale, (float)val, scale); 6807430Sgblack@eecs.umich.edu} 6817430Sgblack@eecs.umich.edu 6827430Sgblack@eecs.umich.edufloat 6837639Sgblack@eecs.umich.eduvfpSFixedToFpS(bool flush, bool defaultNan, 68410037SARM gem5 Developers int64_t val, uint8_t width, uint8_t imm) 6857430Sgblack@eecs.umich.edu{ 6867430Sgblack@eecs.umich.edu fesetround(FeRoundNearest); 68710037SARM gem5 Developers if (width == 16) 6887430Sgblack@eecs.umich.edu val = sext<16>(val & mask(16)); 68910037SARM gem5 Developers else if (width == 32) 69010037SARM gem5 Developers val = sext<32>(val & mask(32)); 69110037SARM gem5 Developers else if (width != 64) 69210037SARM gem5 Developers panic("Unsupported width %d", width); 69310037SARM gem5 Developers 6947430Sgblack@eecs.umich.edu float scale = powf(2.0, imm); 6957430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 6967430Sgblack@eecs.umich.edu feclearexcept(FeAllExceptions); 6977430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 6987639Sgblack@eecs.umich.edu return fixDivDest(flush, defaultNan, val / scale, (float)val, scale); 6997430Sgblack@eecs.umich.edu} 7007430Sgblack@eecs.umich.edu 7017430Sgblack@eecs.umich.edu 7027430Sgblack@eecs.umich.edudouble 7037639Sgblack@eecs.umich.eduvfpUFixedToFpD(bool flush, bool defaultNan, 70410037SARM gem5 Developers uint64_t val, uint8_t width, uint8_t imm) 7057430Sgblack@eecs.umich.edu{ 7067430Sgblack@eecs.umich.edu fesetround(FeRoundNearest); 70710037SARM gem5 Developers if (width == 16) 7087430Sgblack@eecs.umich.edu val = (uint16_t)val; 70910037SARM gem5 Developers else if (width == 32) 71010037SARM gem5 Developers val = (uint32_t)val; 71110037SARM gem5 Developers else if (width != 64) 71210037SARM gem5 Developers panic("Unsupported width %d", width); 71310037SARM gem5 Developers 7147430Sgblack@eecs.umich.edu double scale = pow(2.0, imm); 7157430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 7167430Sgblack@eecs.umich.edu feclearexcept(FeAllExceptions); 7177430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 7187639Sgblack@eecs.umich.edu return fixDivDest(flush, defaultNan, val / scale, (double)val, scale); 7197430Sgblack@eecs.umich.edu} 7207430Sgblack@eecs.umich.edu 7217430Sgblack@eecs.umich.edudouble 7227639Sgblack@eecs.umich.eduvfpSFixedToFpD(bool flush, bool defaultNan, 72310037SARM gem5 Developers int64_t val, uint8_t width, uint8_t imm) 7247430Sgblack@eecs.umich.edu{ 7257430Sgblack@eecs.umich.edu fesetround(FeRoundNearest); 72610037SARM gem5 Developers if (width == 16) 7277430Sgblack@eecs.umich.edu val = sext<16>(val & mask(16)); 72810037SARM gem5 Developers else if (width == 32) 72910037SARM gem5 Developers val = sext<32>(val & mask(32)); 73010037SARM gem5 Developers else if (width != 64) 73110037SARM gem5 Developers panic("Unsupported width %d", width); 73210037SARM gem5 Developers 7337430Sgblack@eecs.umich.edu double scale = pow(2.0, imm); 7347430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 7357430Sgblack@eecs.umich.edu feclearexcept(FeAllExceptions); 7367430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 7377639Sgblack@eecs.umich.edu return fixDivDest(flush, defaultNan, val / scale, (double)val, scale); 7387430Sgblack@eecs.umich.edu} 7397430Sgblack@eecs.umich.edu 7407639Sgblack@eecs.umich.edu// This function implements a magic formula taken from the architecture 7417639Sgblack@eecs.umich.edu// reference manual. It was originally called recip_sqrt_estimate. 7427639Sgblack@eecs.umich.edustatic double 7437639Sgblack@eecs.umich.edurecipSqrtEstimate(double a) 7447639Sgblack@eecs.umich.edu{ 7457639Sgblack@eecs.umich.edu int64_t q0, q1, s; 7467639Sgblack@eecs.umich.edu double r; 7477639Sgblack@eecs.umich.edu if (a < 0.5) { 7487639Sgblack@eecs.umich.edu q0 = (int64_t)(a * 512.0); 7497639Sgblack@eecs.umich.edu r = 1.0 / sqrt(((double)q0 + 0.5) / 512.0); 7507639Sgblack@eecs.umich.edu } else { 7517639Sgblack@eecs.umich.edu q1 = (int64_t)(a * 256.0); 7527639Sgblack@eecs.umich.edu r = 1.0 / sqrt(((double)q1 + 0.5) / 256.0); 7537639Sgblack@eecs.umich.edu } 7547639Sgblack@eecs.umich.edu s = (int64_t)(256.0 * r + 0.5); 7557639Sgblack@eecs.umich.edu return (double)s / 256.0; 7567639Sgblack@eecs.umich.edu} 7577639Sgblack@eecs.umich.edu 7587639Sgblack@eecs.umich.edu// This function is only intended for use in Neon instructions because 7597639Sgblack@eecs.umich.edu// it ignores certain bits in the FPSCR. 7607639Sgblack@eecs.umich.edufloat 7617639Sgblack@eecs.umich.edufprSqrtEstimate(FPSCR &fpscr, float op) 7627639Sgblack@eecs.umich.edu{ 7637639Sgblack@eecs.umich.edu const uint32_t qnan = 0x7fc00000; 7647639Sgblack@eecs.umich.edu float junk = 0.0; 7657639Sgblack@eecs.umich.edu int fpClass = std::fpclassify(op); 7667639Sgblack@eecs.umich.edu if (fpClass == FP_NAN) { 7677639Sgblack@eecs.umich.edu if ((fpToBits(op) & qnan) != qnan) 7687639Sgblack@eecs.umich.edu fpscr.ioc = 1; 7697639Sgblack@eecs.umich.edu return bitsToFp(qnan, junk); 7707639Sgblack@eecs.umich.edu } else if (fpClass == FP_ZERO) { 7717639Sgblack@eecs.umich.edu fpscr.dzc = 1; 7727639Sgblack@eecs.umich.edu // Return infinity with the same sign as the operand. 7737639Sgblack@eecs.umich.edu return bitsToFp((std::signbit(op) << 31) | 7747639Sgblack@eecs.umich.edu (0xFF << 23) | (0 << 0), junk); 7757639Sgblack@eecs.umich.edu } else if (std::signbit(op)) { 7767639Sgblack@eecs.umich.edu // Set invalid op bit. 7777639Sgblack@eecs.umich.edu fpscr.ioc = 1; 7787639Sgblack@eecs.umich.edu return bitsToFp(qnan, junk); 7797639Sgblack@eecs.umich.edu } else if (fpClass == FP_INFINITE) { 7807639Sgblack@eecs.umich.edu return 0.0; 7817639Sgblack@eecs.umich.edu } else { 7827639Sgblack@eecs.umich.edu uint64_t opBits = fpToBits(op); 7837639Sgblack@eecs.umich.edu double scaled; 7847639Sgblack@eecs.umich.edu if (bits(opBits, 23)) { 7857639Sgblack@eecs.umich.edu scaled = bitsToFp((0 << 0) | (bits(opBits, 22, 0) << 29) | 7867639Sgblack@eecs.umich.edu (ULL(0x3fd) << 52) | (bits(opBits, 31) << 63), 7877639Sgblack@eecs.umich.edu (double)0.0); 7887639Sgblack@eecs.umich.edu } else { 7897639Sgblack@eecs.umich.edu scaled = bitsToFp((0 << 0) | (bits(opBits, 22, 0) << 29) | 7907639Sgblack@eecs.umich.edu (ULL(0x3fe) << 52) | (bits(opBits, 31) << 63), 7917639Sgblack@eecs.umich.edu (double)0.0); 7927639Sgblack@eecs.umich.edu } 7937639Sgblack@eecs.umich.edu uint64_t resultExp = (380 - bits(opBits, 30, 23)) / 2; 7947639Sgblack@eecs.umich.edu 7957639Sgblack@eecs.umich.edu uint64_t estimate = fpToBits(recipSqrtEstimate(scaled)); 7967639Sgblack@eecs.umich.edu 7977639Sgblack@eecs.umich.edu return bitsToFp((bits(estimate, 63) << 31) | 7987639Sgblack@eecs.umich.edu (bits(resultExp, 7, 0) << 23) | 7997639Sgblack@eecs.umich.edu (bits(estimate, 51, 29) << 0), junk); 8007639Sgblack@eecs.umich.edu } 8017639Sgblack@eecs.umich.edu} 8027639Sgblack@eecs.umich.edu 8037639Sgblack@eecs.umich.eduuint32_t 8047639Sgblack@eecs.umich.eduunsignedRSqrtEstimate(uint32_t op) 8057639Sgblack@eecs.umich.edu{ 8067639Sgblack@eecs.umich.edu if (bits(op, 31, 30) == 0) { 8077639Sgblack@eecs.umich.edu return -1; 8087639Sgblack@eecs.umich.edu } else { 8097639Sgblack@eecs.umich.edu double dpOp; 8107639Sgblack@eecs.umich.edu if (bits(op, 31)) { 8117639Sgblack@eecs.umich.edu dpOp = bitsToFp((ULL(0) << 63) | 8127639Sgblack@eecs.umich.edu (ULL(0x3fe) << 52) | 8137639Sgblack@eecs.umich.edu (bits((uint64_t)op, 30, 0) << 21) | 8147639Sgblack@eecs.umich.edu (0 << 0), (double)0.0); 8157639Sgblack@eecs.umich.edu } else { 8167639Sgblack@eecs.umich.edu dpOp = bitsToFp((ULL(0) << 63) | 8177639Sgblack@eecs.umich.edu (ULL(0x3fd) << 52) | 8187639Sgblack@eecs.umich.edu (bits((uint64_t)op, 29, 0) << 22) | 8197639Sgblack@eecs.umich.edu (0 << 0), (double)0.0); 8207639Sgblack@eecs.umich.edu } 8217639Sgblack@eecs.umich.edu uint64_t estimate = fpToBits(recipSqrtEstimate(dpOp)); 8227639Sgblack@eecs.umich.edu return (1 << 31) | bits(estimate, 51, 21); 8237639Sgblack@eecs.umich.edu } 8247639Sgblack@eecs.umich.edu} 8257639Sgblack@eecs.umich.edu 8267639Sgblack@eecs.umich.edu// This function implements a magic formula taken from the architecture 8277639Sgblack@eecs.umich.edu// reference manual. It was originally called recip_estimate. 8287639Sgblack@eecs.umich.edu 8297639Sgblack@eecs.umich.edustatic double 8307639Sgblack@eecs.umich.edurecipEstimate(double a) 8317639Sgblack@eecs.umich.edu{ 8327639Sgblack@eecs.umich.edu int64_t q, s; 8337639Sgblack@eecs.umich.edu double r; 8347639Sgblack@eecs.umich.edu q = (int64_t)(a * 512.0); 8357639Sgblack@eecs.umich.edu r = 1.0 / (((double)q + 0.5) / 512.0); 8367639Sgblack@eecs.umich.edu s = (int64_t)(256.0 * r + 0.5); 8377639Sgblack@eecs.umich.edu return (double)s / 256.0; 8387639Sgblack@eecs.umich.edu} 8397639Sgblack@eecs.umich.edu 8407639Sgblack@eecs.umich.edu// This function is only intended for use in Neon instructions because 8417639Sgblack@eecs.umich.edu// it ignores certain bits in the FPSCR. 8427639Sgblack@eecs.umich.edufloat 8437639Sgblack@eecs.umich.edufpRecipEstimate(FPSCR &fpscr, float op) 8447639Sgblack@eecs.umich.edu{ 8457639Sgblack@eecs.umich.edu const uint32_t qnan = 0x7fc00000; 8467639Sgblack@eecs.umich.edu float junk = 0.0; 8477639Sgblack@eecs.umich.edu int fpClass = std::fpclassify(op); 8487639Sgblack@eecs.umich.edu if (fpClass == FP_NAN) { 8497639Sgblack@eecs.umich.edu if ((fpToBits(op) & qnan) != qnan) 8507639Sgblack@eecs.umich.edu fpscr.ioc = 1; 8517639Sgblack@eecs.umich.edu return bitsToFp(qnan, junk); 8527639Sgblack@eecs.umich.edu } else if (fpClass == FP_INFINITE) { 8537639Sgblack@eecs.umich.edu return bitsToFp(std::signbit(op) << 31, junk); 8547639Sgblack@eecs.umich.edu } else if (fpClass == FP_ZERO) { 8557639Sgblack@eecs.umich.edu fpscr.dzc = 1; 8567639Sgblack@eecs.umich.edu // Return infinity with the same sign as the operand. 8577639Sgblack@eecs.umich.edu return bitsToFp((std::signbit(op) << 31) | 8587639Sgblack@eecs.umich.edu (0xFF << 23) | (0 << 0), junk); 8597639Sgblack@eecs.umich.edu } else if (fabs(op) >= pow(2.0, 126)) { 8607639Sgblack@eecs.umich.edu fpscr.ufc = 1; 8617639Sgblack@eecs.umich.edu return bitsToFp(std::signbit(op) << 31, junk); 8627639Sgblack@eecs.umich.edu } else { 8637639Sgblack@eecs.umich.edu uint64_t opBits = fpToBits(op); 8647639Sgblack@eecs.umich.edu double scaled; 8657639Sgblack@eecs.umich.edu scaled = bitsToFp((0 << 0) | (bits(opBits, 22, 0) << 29) | 8667639Sgblack@eecs.umich.edu (ULL(0x3fe) << 52) | (ULL(0) << 63), 8677639Sgblack@eecs.umich.edu (double)0.0); 8687639Sgblack@eecs.umich.edu uint64_t resultExp = 253 - bits(opBits, 30, 23); 8697639Sgblack@eecs.umich.edu 8707639Sgblack@eecs.umich.edu uint64_t estimate = fpToBits(recipEstimate(scaled)); 8717639Sgblack@eecs.umich.edu 8727639Sgblack@eecs.umich.edu return bitsToFp((bits(opBits, 31) << 31) | 8737639Sgblack@eecs.umich.edu (bits(resultExp, 7, 0) << 23) | 8747639Sgblack@eecs.umich.edu (bits(estimate, 51, 29) << 0), junk); 8757639Sgblack@eecs.umich.edu } 8767639Sgblack@eecs.umich.edu} 8777639Sgblack@eecs.umich.edu 8787639Sgblack@eecs.umich.eduuint32_t 8797639Sgblack@eecs.umich.eduunsignedRecipEstimate(uint32_t op) 8807639Sgblack@eecs.umich.edu{ 8817639Sgblack@eecs.umich.edu if (bits(op, 31) == 0) { 8827639Sgblack@eecs.umich.edu return -1; 8837639Sgblack@eecs.umich.edu } else { 8847639Sgblack@eecs.umich.edu double dpOp; 8857639Sgblack@eecs.umich.edu dpOp = bitsToFp((ULL(0) << 63) | 8867639Sgblack@eecs.umich.edu (ULL(0x3fe) << 52) | 8877639Sgblack@eecs.umich.edu (bits((uint64_t)op, 30, 0) << 21) | 8887639Sgblack@eecs.umich.edu (0 << 0), (double)0.0); 8897639Sgblack@eecs.umich.edu uint64_t estimate = fpToBits(recipEstimate(dpOp)); 8907639Sgblack@eecs.umich.edu return (1 << 31) | bits(estimate, 51, 21); 8917639Sgblack@eecs.umich.edu } 8927639Sgblack@eecs.umich.edu} 8937639Sgblack@eecs.umich.edu 8947639Sgblack@eecs.umich.edutemplate <class fpType> 8957639Sgblack@eecs.umich.edufpType 8967639Sgblack@eecs.umich.eduFpOp::processNans(FPSCR &fpscr, bool &done, bool defaultNan, 8977639Sgblack@eecs.umich.edu fpType op1, fpType op2) const 8987639Sgblack@eecs.umich.edu{ 8997639Sgblack@eecs.umich.edu done = true; 9007639Sgblack@eecs.umich.edu fpType junk = 0.0; 9017639Sgblack@eecs.umich.edu fpType dest = 0.0; 9027639Sgblack@eecs.umich.edu const bool single = (sizeof(fpType) == sizeof(float)); 9037639Sgblack@eecs.umich.edu const uint64_t qnan = 9047639Sgblack@eecs.umich.edu single ? 0x7fc00000 : ULL(0x7ff8000000000000); 9057639Sgblack@eecs.umich.edu const bool nan1 = std::isnan(op1); 9067639Sgblack@eecs.umich.edu const bool nan2 = std::isnan(op2); 9077639Sgblack@eecs.umich.edu const bool signal1 = nan1 && ((fpToBits(op1) & qnan) != qnan); 9087639Sgblack@eecs.umich.edu const bool signal2 = nan2 && ((fpToBits(op2) & qnan) != qnan); 9097639Sgblack@eecs.umich.edu if (nan1 || nan2) { 9107639Sgblack@eecs.umich.edu if (defaultNan) { 9117639Sgblack@eecs.umich.edu dest = bitsToFp(qnan, junk); 9127639Sgblack@eecs.umich.edu } else if (signal1) { 9137639Sgblack@eecs.umich.edu dest = bitsToFp(fpToBits(op1) | qnan, junk); 9147639Sgblack@eecs.umich.edu } else if (signal2) { 9157639Sgblack@eecs.umich.edu dest = bitsToFp(fpToBits(op2) | qnan, junk); 9167639Sgblack@eecs.umich.edu } else if (nan1) { 9177639Sgblack@eecs.umich.edu dest = op1; 9187639Sgblack@eecs.umich.edu } else if (nan2) { 9197639Sgblack@eecs.umich.edu dest = op2; 9207639Sgblack@eecs.umich.edu } 9217639Sgblack@eecs.umich.edu if (signal1 || signal2) { 9227639Sgblack@eecs.umich.edu fpscr.ioc = 1; 9237639Sgblack@eecs.umich.edu } 9247639Sgblack@eecs.umich.edu } else { 9257639Sgblack@eecs.umich.edu done = false; 9267639Sgblack@eecs.umich.edu } 9277639Sgblack@eecs.umich.edu return dest; 9287639Sgblack@eecs.umich.edu} 9297639Sgblack@eecs.umich.edu 9307639Sgblack@eecs.umich.edutemplate 9317639Sgblack@eecs.umich.edufloat FpOp::processNans(FPSCR &fpscr, bool &done, bool defaultNan, 9327639Sgblack@eecs.umich.edu float op1, float op2) const; 9337639Sgblack@eecs.umich.edutemplate 9347639Sgblack@eecs.umich.edudouble FpOp::processNans(FPSCR &fpscr, bool &done, bool defaultNan, 9357639Sgblack@eecs.umich.edu double op1, double op2) const; 9367639Sgblack@eecs.umich.edu 93710037SARM gem5 Developers// @TODO remove this function when we've finished switching all FMA code to use the new FPLIB 93810037SARM gem5 Developerstemplate <class fpType> 93910037SARM gem5 DevelopersfpType 94010037SARM gem5 DevelopersFpOp::ternaryOp(FPSCR &fpscr, fpType op1, fpType op2, fpType op3, 94110037SARM gem5 Developers fpType (*func)(fpType, fpType, fpType), 94210037SARM gem5 Developers bool flush, bool defaultNan, uint32_t rMode) const 94310037SARM gem5 Developers{ 94410037SARM gem5 Developers const bool single = (sizeof(fpType) == sizeof(float)); 94510037SARM gem5 Developers fpType junk = 0.0; 94610037SARM gem5 Developers 94710037SARM gem5 Developers if (flush && (flushToZero(op1, op2) || flushToZero(op3))) 94810037SARM gem5 Developers fpscr.idc = 1; 94910037SARM gem5 Developers VfpSavedState state = prepFpState(rMode); 95010037SARM gem5 Developers __asm__ __volatile__ ("" : "=m" (op1), "=m" (op2), "=m" (op3), "=m" (state) 95110037SARM gem5 Developers : "m" (op1), "m" (op2), "m" (op3), "m" (state)); 95210037SARM gem5 Developers fpType dest = func(op1, op2, op3); 95310037SARM gem5 Developers __asm__ __volatile__ ("" : "=m" (dest) : "m" (dest)); 95410037SARM gem5 Developers 95510037SARM gem5 Developers int fpClass = std::fpclassify(dest); 95610037SARM gem5 Developers // Get NAN behavior right. This varies between x86 and ARM. 95710037SARM gem5 Developers if (fpClass == FP_NAN) { 95810037SARM gem5 Developers const uint64_t qnan = 95910037SARM gem5 Developers single ? 0x7fc00000 : ULL(0x7ff8000000000000); 96010037SARM gem5 Developers const bool nan1 = std::isnan(op1); 96110037SARM gem5 Developers const bool nan2 = std::isnan(op2); 96210037SARM gem5 Developers const bool nan3 = std::isnan(op3); 96310037SARM gem5 Developers const bool signal1 = nan1 && ((fpToBits(op1) & qnan) != qnan); 96410037SARM gem5 Developers const bool signal2 = nan2 && ((fpToBits(op2) & qnan) != qnan); 96510037SARM gem5 Developers const bool signal3 = nan3 && ((fpToBits(op3) & qnan) != qnan); 96610037SARM gem5 Developers if ((!nan1 && !nan2 && !nan3) || (defaultNan == 1)) { 96710037SARM gem5 Developers dest = bitsToFp(qnan, junk); 96810037SARM gem5 Developers } else if (signal1) { 96910037SARM gem5 Developers dest = bitsToFp(fpToBits(op1) | qnan, junk); 97010037SARM gem5 Developers } else if (signal2) { 97110037SARM gem5 Developers dest = bitsToFp(fpToBits(op2) | qnan, junk); 97210037SARM gem5 Developers } else if (signal3) { 97310037SARM gem5 Developers dest = bitsToFp(fpToBits(op3) | qnan, junk); 97410037SARM gem5 Developers } else if (nan1) { 97510037SARM gem5 Developers dest = op1; 97610037SARM gem5 Developers } else if (nan2) { 97710037SARM gem5 Developers dest = op2; 97810037SARM gem5 Developers } else if (nan3) { 97910037SARM gem5 Developers dest = op3; 98010037SARM gem5 Developers } 98110037SARM gem5 Developers } else if (flush && flushToZero(dest)) { 98210037SARM gem5 Developers feraiseexcept(FeUnderflow); 98310037SARM gem5 Developers } else if (( 98410037SARM gem5 Developers (single && (dest == bitsToFp(0x00800000, junk) || 98510037SARM gem5 Developers dest == bitsToFp(0x80800000, junk))) || 98610037SARM gem5 Developers (!single && 98710037SARM gem5 Developers (dest == bitsToFp(ULL(0x0010000000000000), junk) || 98810037SARM gem5 Developers dest == bitsToFp(ULL(0x8010000000000000), junk))) 98910037SARM gem5 Developers ) && rMode != VfpRoundZero) { 99010037SARM gem5 Developers /* 99110037SARM gem5 Developers * Correct for the fact that underflow is detected -before- rounding 99210037SARM gem5 Developers * in ARM and -after- rounding in x86. 99310037SARM gem5 Developers */ 99410037SARM gem5 Developers fesetround(FeRoundZero); 99510037SARM gem5 Developers __asm__ __volatile__ ("" : "=m" (op1), "=m" (op2), "=m" (op3) 99610037SARM gem5 Developers : "m" (op1), "m" (op2), "m" (op3)); 99710037SARM gem5 Developers fpType temp = func(op1, op2, op2); 99810037SARM gem5 Developers __asm__ __volatile__ ("" : "=m" (temp) : "m" (temp)); 99910037SARM gem5 Developers if (flush && flushToZero(temp)) { 100010037SARM gem5 Developers dest = temp; 100110037SARM gem5 Developers } 100210037SARM gem5 Developers } 100310037SARM gem5 Developers finishVfp(fpscr, state, flush); 100410037SARM gem5 Developers return dest; 100510037SARM gem5 Developers} 100610037SARM gem5 Developers 100710037SARM gem5 Developerstemplate 100810037SARM gem5 Developersfloat FpOp::ternaryOp(FPSCR &fpscr, float op1, float op2, float op3, 100910037SARM gem5 Developers float (*func)(float, float, float), 101010037SARM gem5 Developers bool flush, bool defaultNan, uint32_t rMode) const; 101110037SARM gem5 Developerstemplate 101210037SARM gem5 Developersdouble FpOp::ternaryOp(FPSCR &fpscr, double op1, double op2, double op3, 101310037SARM gem5 Developers double (*func)(double, double, double), 101410037SARM gem5 Developers bool flush, bool defaultNan, uint32_t rMode) const; 101510037SARM gem5 Developers 10167430Sgblack@eecs.umich.edutemplate <class fpType> 10177430Sgblack@eecs.umich.edufpType 10187430Sgblack@eecs.umich.eduFpOp::binaryOp(FPSCR &fpscr, fpType op1, fpType op2, 10197430Sgblack@eecs.umich.edu fpType (*func)(fpType, fpType), 10207639Sgblack@eecs.umich.edu bool flush, bool defaultNan, uint32_t rMode) const 10217430Sgblack@eecs.umich.edu{ 10227430Sgblack@eecs.umich.edu const bool single = (sizeof(fpType) == sizeof(float)); 10237430Sgblack@eecs.umich.edu fpType junk = 0.0; 10247430Sgblack@eecs.umich.edu 10257430Sgblack@eecs.umich.edu if (flush && flushToZero(op1, op2)) 10267430Sgblack@eecs.umich.edu fpscr.idc = 1; 10277430Sgblack@eecs.umich.edu VfpSavedState state = prepFpState(rMode); 10287430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (op1), "=m" (op2), "=m" (state) 10297430Sgblack@eecs.umich.edu : "m" (op1), "m" (op2), "m" (state)); 10307430Sgblack@eecs.umich.edu fpType dest = func(op1, op2); 10317430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (dest) : "m" (dest)); 10327430Sgblack@eecs.umich.edu 10337430Sgblack@eecs.umich.edu // Get NAN behavior right. This varies between x86 and ARM. 10349515SAli.Saidi@ARM.com if (std::isnan(dest)) { 10357430Sgblack@eecs.umich.edu const uint64_t qnan = 10367430Sgblack@eecs.umich.edu single ? 0x7fc00000 : ULL(0x7ff8000000000000); 10377430Sgblack@eecs.umich.edu const bool nan1 = std::isnan(op1); 10387430Sgblack@eecs.umich.edu const bool nan2 = std::isnan(op2); 10397430Sgblack@eecs.umich.edu const bool signal1 = nan1 && ((fpToBits(op1) & qnan) != qnan); 10407430Sgblack@eecs.umich.edu const bool signal2 = nan2 && ((fpToBits(op2) & qnan) != qnan); 10417639Sgblack@eecs.umich.edu if ((!nan1 && !nan2) || (defaultNan == 1)) { 10427430Sgblack@eecs.umich.edu dest = bitsToFp(qnan, junk); 10437430Sgblack@eecs.umich.edu } else if (signal1) { 10447430Sgblack@eecs.umich.edu dest = bitsToFp(fpToBits(op1) | qnan, junk); 10457430Sgblack@eecs.umich.edu } else if (signal2) { 10467430Sgblack@eecs.umich.edu dest = bitsToFp(fpToBits(op2) | qnan, junk); 10477430Sgblack@eecs.umich.edu } else if (nan1) { 10487430Sgblack@eecs.umich.edu dest = op1; 10497430Sgblack@eecs.umich.edu } else if (nan2) { 10507430Sgblack@eecs.umich.edu dest = op2; 10517430Sgblack@eecs.umich.edu } 10527430Sgblack@eecs.umich.edu } else if (flush && flushToZero(dest)) { 10537430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 10547430Sgblack@eecs.umich.edu } else if (( 10557430Sgblack@eecs.umich.edu (single && (dest == bitsToFp(0x00800000, junk) || 10567430Sgblack@eecs.umich.edu dest == bitsToFp(0x80800000, junk))) || 10577430Sgblack@eecs.umich.edu (!single && 10587430Sgblack@eecs.umich.edu (dest == bitsToFp(ULL(0x0010000000000000), junk) || 10597430Sgblack@eecs.umich.edu dest == bitsToFp(ULL(0x8010000000000000), junk))) 10607430Sgblack@eecs.umich.edu ) && rMode != VfpRoundZero) { 10617430Sgblack@eecs.umich.edu /* 10627430Sgblack@eecs.umich.edu * Correct for the fact that underflow is detected -before- rounding 10637430Sgblack@eecs.umich.edu * in ARM and -after- rounding in x86. 10647430Sgblack@eecs.umich.edu */ 10657430Sgblack@eecs.umich.edu fesetround(FeRoundZero); 10667430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (op1), "=m" (op2) 10677430Sgblack@eecs.umich.edu : "m" (op1), "m" (op2)); 10687430Sgblack@eecs.umich.edu fpType temp = func(op1, op2); 10697430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (temp) : "m" (temp)); 10707430Sgblack@eecs.umich.edu if (flush && flushToZero(temp)) { 10717430Sgblack@eecs.umich.edu dest = temp; 10727430Sgblack@eecs.umich.edu } 10737430Sgblack@eecs.umich.edu } 10747639Sgblack@eecs.umich.edu finishVfp(fpscr, state, flush); 10757430Sgblack@eecs.umich.edu return dest; 10767430Sgblack@eecs.umich.edu} 10777430Sgblack@eecs.umich.edu 10787430Sgblack@eecs.umich.edutemplate 10797430Sgblack@eecs.umich.edufloat FpOp::binaryOp(FPSCR &fpscr, float op1, float op2, 10807430Sgblack@eecs.umich.edu float (*func)(float, float), 10817639Sgblack@eecs.umich.edu bool flush, bool defaultNan, uint32_t rMode) const; 10827430Sgblack@eecs.umich.edutemplate 10837430Sgblack@eecs.umich.edudouble FpOp::binaryOp(FPSCR &fpscr, double op1, double op2, 10847430Sgblack@eecs.umich.edu double (*func)(double, double), 10857639Sgblack@eecs.umich.edu bool flush, bool defaultNan, uint32_t rMode) const; 10867430Sgblack@eecs.umich.edu 10877430Sgblack@eecs.umich.edutemplate <class fpType> 10887430Sgblack@eecs.umich.edufpType 10897430Sgblack@eecs.umich.eduFpOp::unaryOp(FPSCR &fpscr, fpType op1, fpType (*func)(fpType), 10907430Sgblack@eecs.umich.edu bool flush, uint32_t rMode) const 10917430Sgblack@eecs.umich.edu{ 10927430Sgblack@eecs.umich.edu const bool single = (sizeof(fpType) == sizeof(float)); 10937430Sgblack@eecs.umich.edu fpType junk = 0.0; 10947430Sgblack@eecs.umich.edu 10957430Sgblack@eecs.umich.edu if (flush && flushToZero(op1)) 10967430Sgblack@eecs.umich.edu fpscr.idc = 1; 10977430Sgblack@eecs.umich.edu VfpSavedState state = prepFpState(rMode); 10987430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (op1), "=m" (state) 10997430Sgblack@eecs.umich.edu : "m" (op1), "m" (state)); 11007430Sgblack@eecs.umich.edu fpType dest = func(op1); 11017430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (dest) : "m" (dest)); 11027430Sgblack@eecs.umich.edu 11037430Sgblack@eecs.umich.edu // Get NAN behavior right. This varies between x86 and ARM. 11049515SAli.Saidi@ARM.com if (std::isnan(dest)) { 11057430Sgblack@eecs.umich.edu const uint64_t qnan = 11067430Sgblack@eecs.umich.edu single ? 0x7fc00000 : ULL(0x7ff8000000000000); 11077430Sgblack@eecs.umich.edu const bool nan = std::isnan(op1); 11087430Sgblack@eecs.umich.edu if (!nan || fpscr.dn == 1) { 11097430Sgblack@eecs.umich.edu dest = bitsToFp(qnan, junk); 11107430Sgblack@eecs.umich.edu } else if (nan) { 11117430Sgblack@eecs.umich.edu dest = bitsToFp(fpToBits(op1) | qnan, junk); 11127430Sgblack@eecs.umich.edu } 11137430Sgblack@eecs.umich.edu } else if (flush && flushToZero(dest)) { 11147430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 11157430Sgblack@eecs.umich.edu } else if (( 11167430Sgblack@eecs.umich.edu (single && (dest == bitsToFp(0x00800000, junk) || 11177430Sgblack@eecs.umich.edu dest == bitsToFp(0x80800000, junk))) || 11187430Sgblack@eecs.umich.edu (!single && 11197430Sgblack@eecs.umich.edu (dest == bitsToFp(ULL(0x0010000000000000), junk) || 11207430Sgblack@eecs.umich.edu dest == bitsToFp(ULL(0x8010000000000000), junk))) 11217430Sgblack@eecs.umich.edu ) && rMode != VfpRoundZero) { 11227430Sgblack@eecs.umich.edu /* 11237430Sgblack@eecs.umich.edu * Correct for the fact that underflow is detected -before- rounding 11247430Sgblack@eecs.umich.edu * in ARM and -after- rounding in x86. 11257430Sgblack@eecs.umich.edu */ 11267430Sgblack@eecs.umich.edu fesetround(FeRoundZero); 11277430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (op1) : "m" (op1)); 11287430Sgblack@eecs.umich.edu fpType temp = func(op1); 11297430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (temp) : "m" (temp)); 11307430Sgblack@eecs.umich.edu if (flush && flushToZero(temp)) { 11317430Sgblack@eecs.umich.edu dest = temp; 11327430Sgblack@eecs.umich.edu } 11337430Sgblack@eecs.umich.edu } 11347639Sgblack@eecs.umich.edu finishVfp(fpscr, state, flush); 11357430Sgblack@eecs.umich.edu return dest; 11367430Sgblack@eecs.umich.edu} 11377430Sgblack@eecs.umich.edu 11387430Sgblack@eecs.umich.edutemplate 11397430Sgblack@eecs.umich.edufloat FpOp::unaryOp(FPSCR &fpscr, float op1, float (*func)(float), 11407430Sgblack@eecs.umich.edu bool flush, uint32_t rMode) const; 11417430Sgblack@eecs.umich.edutemplate 11427430Sgblack@eecs.umich.edudouble FpOp::unaryOp(FPSCR &fpscr, double op1, double (*func)(double), 11437430Sgblack@eecs.umich.edu bool flush, uint32_t rMode) const; 11447430Sgblack@eecs.umich.edu 11457430Sgblack@eecs.umich.eduIntRegIndex 11467430Sgblack@eecs.umich.eduVfpMacroOp::addStride(IntRegIndex idx, unsigned stride) 11477430Sgblack@eecs.umich.edu{ 11487430Sgblack@eecs.umich.edu if (wide) { 11497430Sgblack@eecs.umich.edu stride *= 2; 11507430Sgblack@eecs.umich.edu } 11517430Sgblack@eecs.umich.edu unsigned offset = idx % 8; 11527430Sgblack@eecs.umich.edu idx = (IntRegIndex)(idx - offset); 11537430Sgblack@eecs.umich.edu offset += stride; 11547430Sgblack@eecs.umich.edu idx = (IntRegIndex)(idx + (offset % 8)); 11557430Sgblack@eecs.umich.edu return idx; 11567430Sgblack@eecs.umich.edu} 11577430Sgblack@eecs.umich.edu 11587430Sgblack@eecs.umich.eduvoid 11597430Sgblack@eecs.umich.eduVfpMacroOp::nextIdxs(IntRegIndex &dest, IntRegIndex &op1, IntRegIndex &op2) 11607430Sgblack@eecs.umich.edu{ 11617430Sgblack@eecs.umich.edu unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2; 11627430Sgblack@eecs.umich.edu assert(!inScalarBank(dest)); 11637430Sgblack@eecs.umich.edu dest = addStride(dest, stride); 11647430Sgblack@eecs.umich.edu op1 = addStride(op1, stride); 11657430Sgblack@eecs.umich.edu if (!inScalarBank(op2)) { 11667430Sgblack@eecs.umich.edu op2 = addStride(op2, stride); 11677430Sgblack@eecs.umich.edu } 11687430Sgblack@eecs.umich.edu} 11697430Sgblack@eecs.umich.edu 11707430Sgblack@eecs.umich.eduvoid 11717430Sgblack@eecs.umich.eduVfpMacroOp::nextIdxs(IntRegIndex &dest, IntRegIndex &op1) 11727430Sgblack@eecs.umich.edu{ 11737430Sgblack@eecs.umich.edu unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2; 11747430Sgblack@eecs.umich.edu assert(!inScalarBank(dest)); 11757430Sgblack@eecs.umich.edu dest = addStride(dest, stride); 11767430Sgblack@eecs.umich.edu if (!inScalarBank(op1)) { 11777430Sgblack@eecs.umich.edu op1 = addStride(op1, stride); 11787430Sgblack@eecs.umich.edu } 11797430Sgblack@eecs.umich.edu} 11807430Sgblack@eecs.umich.edu 11817430Sgblack@eecs.umich.eduvoid 11827430Sgblack@eecs.umich.eduVfpMacroOp::nextIdxs(IntRegIndex &dest) 11837430Sgblack@eecs.umich.edu{ 11847430Sgblack@eecs.umich.edu unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2; 11857430Sgblack@eecs.umich.edu assert(!inScalarBank(dest)); 11867430Sgblack@eecs.umich.edu dest = addStride(dest, stride); 11877430Sgblack@eecs.umich.edu} 11887430Sgblack@eecs.umich.edu 11897430Sgblack@eecs.umich.edu} 1190