vfp.cc revision 10037
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 12610037SARM gem5 DevelopersFpRegRegRegRegOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const 12710037SARM gem5 Developers{ 12810037SARM gem5 Developers std::stringstream ss; 12910037SARM gem5 Developers printMnemonic(ss); 13010037SARM gem5 Developers printReg(ss, dest + FP_Reg_Base); 13110037SARM gem5 Developers ss << ", "; 13210037SARM gem5 Developers printReg(ss, op1 + FP_Reg_Base); 13310037SARM gem5 Developers ss << ", "; 13410037SARM gem5 Developers printReg(ss, op2 + FP_Reg_Base); 13510037SARM gem5 Developers ss << ", "; 13610037SARM gem5 Developers printReg(ss, op3 + FP_Reg_Base); 13710037SARM gem5 Developers return ss.str(); 13810037SARM gem5 Developers} 13910037SARM gem5 Developers 14010037SARM gem5 Developersstd::string 1417639Sgblack@eecs.umich.eduFpRegRegRegImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const 1427639Sgblack@eecs.umich.edu{ 1437639Sgblack@eecs.umich.edu std::stringstream ss; 1447639Sgblack@eecs.umich.edu printMnemonic(ss); 1459918Ssteve.reinhardt@amd.com printReg(ss, dest + FP_Reg_Base); 1467639Sgblack@eecs.umich.edu ss << ", "; 1479918Ssteve.reinhardt@amd.com printReg(ss, op1 + FP_Reg_Base); 1487639Sgblack@eecs.umich.edu ss << ", "; 1499918Ssteve.reinhardt@amd.com printReg(ss, op2 + FP_Reg_Base); 1507639Sgblack@eecs.umich.edu ccprintf(ss, ", #%d", imm); 1517639Sgblack@eecs.umich.edu return ss.str(); 1527639Sgblack@eecs.umich.edu} 1537639Sgblack@eecs.umich.edu 1547430Sgblack@eecs.umich.edunamespace ArmISA 1557430Sgblack@eecs.umich.edu{ 1567430Sgblack@eecs.umich.edu 1577430Sgblack@eecs.umich.eduVfpSavedState 1587430Sgblack@eecs.umich.eduprepFpState(uint32_t rMode) 1597430Sgblack@eecs.umich.edu{ 1607430Sgblack@eecs.umich.edu int roundingMode = fegetround(); 1617430Sgblack@eecs.umich.edu feclearexcept(FeAllExceptions); 1627430Sgblack@eecs.umich.edu switch (rMode) { 1637430Sgblack@eecs.umich.edu case VfpRoundNearest: 1647430Sgblack@eecs.umich.edu fesetround(FeRoundNearest); 1657430Sgblack@eecs.umich.edu break; 1667430Sgblack@eecs.umich.edu case VfpRoundUpward: 1677430Sgblack@eecs.umich.edu fesetround(FeRoundUpward); 1687430Sgblack@eecs.umich.edu break; 1697430Sgblack@eecs.umich.edu case VfpRoundDown: 1707430Sgblack@eecs.umich.edu fesetround(FeRoundDown); 1717430Sgblack@eecs.umich.edu break; 1727430Sgblack@eecs.umich.edu case VfpRoundZero: 1737430Sgblack@eecs.umich.edu fesetround(FeRoundZero); 1747430Sgblack@eecs.umich.edu break; 1757430Sgblack@eecs.umich.edu } 1767430Sgblack@eecs.umich.edu return roundingMode; 1777430Sgblack@eecs.umich.edu} 1787430Sgblack@eecs.umich.edu 1797430Sgblack@eecs.umich.eduvoid 18010037SARM gem5 DevelopersfinishVfp(FPSCR &fpscr, VfpSavedState state, bool flush, FPSCR mask) 1817430Sgblack@eecs.umich.edu{ 1827430Sgblack@eecs.umich.edu int exceptions = fetestexcept(FeAllExceptions); 1837430Sgblack@eecs.umich.edu bool underflow = false; 18410037SARM gem5 Developers if ((exceptions & FeInvalid) && mask.ioc) { 1857430Sgblack@eecs.umich.edu fpscr.ioc = 1; 1867430Sgblack@eecs.umich.edu } 18710037SARM gem5 Developers if ((exceptions & FeDivByZero) && mask.dzc) { 1887430Sgblack@eecs.umich.edu fpscr.dzc = 1; 1897430Sgblack@eecs.umich.edu } 19010037SARM gem5 Developers if ((exceptions & FeOverflow) && mask.ofc) { 1917430Sgblack@eecs.umich.edu fpscr.ofc = 1; 1927430Sgblack@eecs.umich.edu } 1937430Sgblack@eecs.umich.edu if (exceptions & FeUnderflow) { 1947430Sgblack@eecs.umich.edu underflow = true; 19510037SARM gem5 Developers if (mask.ufc) 19610037SARM gem5 Developers fpscr.ufc = 1; 1977430Sgblack@eecs.umich.edu } 19810037SARM gem5 Developers if ((exceptions & FeInexact) && !(underflow && flush) && mask.ixc) { 1997430Sgblack@eecs.umich.edu fpscr.ixc = 1; 2007430Sgblack@eecs.umich.edu } 2017430Sgblack@eecs.umich.edu fesetround(state); 2027430Sgblack@eecs.umich.edu} 2037430Sgblack@eecs.umich.edu 2047430Sgblack@eecs.umich.edutemplate <class fpType> 2057430Sgblack@eecs.umich.edufpType 2067639Sgblack@eecs.umich.edufixDest(bool flush, bool defaultNan, fpType val, fpType op1) 2077430Sgblack@eecs.umich.edu{ 2087430Sgblack@eecs.umich.edu int fpClass = std::fpclassify(val); 2097430Sgblack@eecs.umich.edu fpType junk = 0.0; 2107430Sgblack@eecs.umich.edu if (fpClass == FP_NAN) { 2117430Sgblack@eecs.umich.edu const bool single = (sizeof(val) == sizeof(float)); 2127430Sgblack@eecs.umich.edu const uint64_t qnan = single ? 0x7fc00000 : ULL(0x7ff8000000000000); 2137430Sgblack@eecs.umich.edu const bool nan = std::isnan(op1); 2147639Sgblack@eecs.umich.edu if (!nan || defaultNan) { 2157430Sgblack@eecs.umich.edu val = bitsToFp(qnan, junk); 2167430Sgblack@eecs.umich.edu } else if (nan) { 2177430Sgblack@eecs.umich.edu val = bitsToFp(fpToBits(op1) | qnan, junk); 2187430Sgblack@eecs.umich.edu } 2197639Sgblack@eecs.umich.edu } else if (fpClass == FP_SUBNORMAL && flush == 1) { 2207430Sgblack@eecs.umich.edu // Turn val into a zero with the correct sign; 2217430Sgblack@eecs.umich.edu uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1); 2227430Sgblack@eecs.umich.edu val = bitsToFp(fpToBits(val) & bitMask, junk); 2237430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 2247430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 2257430Sgblack@eecs.umich.edu } 2267430Sgblack@eecs.umich.edu return val; 2277430Sgblack@eecs.umich.edu} 2287430Sgblack@eecs.umich.edu 2297430Sgblack@eecs.umich.edutemplate 2307639Sgblack@eecs.umich.edufloat fixDest<float>(bool flush, bool defaultNan, float val, float op1); 2317430Sgblack@eecs.umich.edutemplate 2327639Sgblack@eecs.umich.edudouble fixDest<double>(bool flush, bool defaultNan, double val, double op1); 2337430Sgblack@eecs.umich.edu 2347430Sgblack@eecs.umich.edutemplate <class fpType> 2357430Sgblack@eecs.umich.edufpType 2367639Sgblack@eecs.umich.edufixDest(bool flush, bool defaultNan, fpType val, fpType op1, fpType op2) 2377430Sgblack@eecs.umich.edu{ 2387430Sgblack@eecs.umich.edu int fpClass = std::fpclassify(val); 2397430Sgblack@eecs.umich.edu fpType junk = 0.0; 2407430Sgblack@eecs.umich.edu if (fpClass == FP_NAN) { 2417430Sgblack@eecs.umich.edu const bool single = (sizeof(val) == sizeof(float)); 2427430Sgblack@eecs.umich.edu const uint64_t qnan = single ? 0x7fc00000 : ULL(0x7ff8000000000000); 2437430Sgblack@eecs.umich.edu const bool nan1 = std::isnan(op1); 2447430Sgblack@eecs.umich.edu const bool nan2 = std::isnan(op2); 2457430Sgblack@eecs.umich.edu const bool signal1 = nan1 && ((fpToBits(op1) & qnan) != qnan); 2467430Sgblack@eecs.umich.edu const bool signal2 = nan2 && ((fpToBits(op2) & qnan) != qnan); 2477639Sgblack@eecs.umich.edu if ((!nan1 && !nan2) || defaultNan) { 2487430Sgblack@eecs.umich.edu val = bitsToFp(qnan, junk); 2497430Sgblack@eecs.umich.edu } else if (signal1) { 2507430Sgblack@eecs.umich.edu val = bitsToFp(fpToBits(op1) | qnan, junk); 2517430Sgblack@eecs.umich.edu } else if (signal2) { 2527430Sgblack@eecs.umich.edu val = bitsToFp(fpToBits(op2) | qnan, junk); 2537430Sgblack@eecs.umich.edu } else if (nan1) { 2547430Sgblack@eecs.umich.edu val = op1; 2557430Sgblack@eecs.umich.edu } else if (nan2) { 2567430Sgblack@eecs.umich.edu val = op2; 2577430Sgblack@eecs.umich.edu } 2587639Sgblack@eecs.umich.edu } else if (fpClass == FP_SUBNORMAL && flush) { 2597430Sgblack@eecs.umich.edu // Turn val into a zero with the correct sign; 2607430Sgblack@eecs.umich.edu uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1); 2617430Sgblack@eecs.umich.edu val = bitsToFp(fpToBits(val) & bitMask, junk); 2627430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 2637430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 2647430Sgblack@eecs.umich.edu } 2657430Sgblack@eecs.umich.edu return val; 2667430Sgblack@eecs.umich.edu} 2677430Sgblack@eecs.umich.edu 2687430Sgblack@eecs.umich.edutemplate 2697639Sgblack@eecs.umich.edufloat fixDest<float>(bool flush, bool defaultNan, 2707639Sgblack@eecs.umich.edu float val, float op1, float op2); 2717430Sgblack@eecs.umich.edutemplate 2727639Sgblack@eecs.umich.edudouble fixDest<double>(bool flush, bool defaultNan, 2737639Sgblack@eecs.umich.edu double val, double op1, double op2); 2747430Sgblack@eecs.umich.edu 2757430Sgblack@eecs.umich.edutemplate <class fpType> 2767430Sgblack@eecs.umich.edufpType 2777639Sgblack@eecs.umich.edufixDivDest(bool flush, bool defaultNan, fpType val, fpType op1, fpType op2) 2787430Sgblack@eecs.umich.edu{ 2797639Sgblack@eecs.umich.edu fpType mid = fixDest(flush, defaultNan, val, op1, op2); 2807430Sgblack@eecs.umich.edu const bool single = (sizeof(fpType) == sizeof(float)); 2817430Sgblack@eecs.umich.edu const fpType junk = 0.0; 2827430Sgblack@eecs.umich.edu if ((single && (val == bitsToFp(0x00800000, junk) || 2837430Sgblack@eecs.umich.edu val == bitsToFp(0x80800000, junk))) || 2847430Sgblack@eecs.umich.edu (!single && (val == bitsToFp(ULL(0x0010000000000000), junk) || 2857430Sgblack@eecs.umich.edu val == bitsToFp(ULL(0x8010000000000000), junk))) 2867430Sgblack@eecs.umich.edu ) { 2877430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (op1) : "m" (op1)); 2887430Sgblack@eecs.umich.edu fesetround(FeRoundZero); 2897430Sgblack@eecs.umich.edu fpType temp = 0.0; 2907430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (temp) : "m" (temp)); 2917430Sgblack@eecs.umich.edu temp = op1 / op2; 2927430Sgblack@eecs.umich.edu if (flushToZero(temp)) { 2937430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 2947639Sgblack@eecs.umich.edu if (flush) { 2957430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 2967430Sgblack@eecs.umich.edu mid = temp; 2977430Sgblack@eecs.umich.edu } 2987430Sgblack@eecs.umich.edu } 2997430Sgblack@eecs.umich.edu __asm__ __volatile__("" :: "m" (temp)); 3007430Sgblack@eecs.umich.edu } 3017430Sgblack@eecs.umich.edu return mid; 3027430Sgblack@eecs.umich.edu} 3037430Sgblack@eecs.umich.edu 3047430Sgblack@eecs.umich.edutemplate 3057639Sgblack@eecs.umich.edufloat fixDivDest<float>(bool flush, bool defaultNan, 3067639Sgblack@eecs.umich.edu float val, float op1, float op2); 3077430Sgblack@eecs.umich.edutemplate 3087639Sgblack@eecs.umich.edudouble fixDivDest<double>(bool flush, bool defaultNan, 3097639Sgblack@eecs.umich.edu double val, double op1, double op2); 3107430Sgblack@eecs.umich.edu 3117430Sgblack@eecs.umich.edufloat 3127430Sgblack@eecs.umich.edufixFpDFpSDest(FPSCR fpscr, double val) 3137430Sgblack@eecs.umich.edu{ 3147430Sgblack@eecs.umich.edu const float junk = 0.0; 3157430Sgblack@eecs.umich.edu float op1 = 0.0; 3167430Sgblack@eecs.umich.edu if (std::isnan(val)) { 3177430Sgblack@eecs.umich.edu uint64_t valBits = fpToBits(val); 3187430Sgblack@eecs.umich.edu uint32_t op1Bits = bits(valBits, 50, 29) | 3197430Sgblack@eecs.umich.edu (mask(9) << 22) | 3207430Sgblack@eecs.umich.edu (bits(valBits, 63) << 31); 3217430Sgblack@eecs.umich.edu op1 = bitsToFp(op1Bits, junk); 3227430Sgblack@eecs.umich.edu } 3237639Sgblack@eecs.umich.edu float mid = fixDest(fpscr.fz, fpscr.dn, (float)val, op1); 3247430Sgblack@eecs.umich.edu if (fpscr.fz && fetestexcept(FeUnderflow | FeInexact) == 3257430Sgblack@eecs.umich.edu (FeUnderflow | FeInexact)) { 3267430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 3277430Sgblack@eecs.umich.edu } 3287430Sgblack@eecs.umich.edu if (mid == bitsToFp(0x00800000, junk) || 3297430Sgblack@eecs.umich.edu mid == bitsToFp(0x80800000, junk)) { 3307430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (val) : "m" (val)); 3317430Sgblack@eecs.umich.edu fesetround(FeRoundZero); 3327430Sgblack@eecs.umich.edu float temp = 0.0; 3337430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (temp) : "m" (temp)); 3347430Sgblack@eecs.umich.edu temp = val; 3357430Sgblack@eecs.umich.edu if (flushToZero(temp)) { 3367430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 3377430Sgblack@eecs.umich.edu if (fpscr.fz) { 3387430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 3397430Sgblack@eecs.umich.edu mid = temp; 3407430Sgblack@eecs.umich.edu } 3417430Sgblack@eecs.umich.edu } 3427430Sgblack@eecs.umich.edu __asm__ __volatile__("" :: "m" (temp)); 3437430Sgblack@eecs.umich.edu } 3447430Sgblack@eecs.umich.edu return mid; 3457430Sgblack@eecs.umich.edu} 3467430Sgblack@eecs.umich.edu 3477430Sgblack@eecs.umich.edudouble 3487430Sgblack@eecs.umich.edufixFpSFpDDest(FPSCR fpscr, float val) 3497430Sgblack@eecs.umich.edu{ 3507430Sgblack@eecs.umich.edu const double junk = 0.0; 3517430Sgblack@eecs.umich.edu double op1 = 0.0; 3527430Sgblack@eecs.umich.edu if (std::isnan(val)) { 3537430Sgblack@eecs.umich.edu uint32_t valBits = fpToBits(val); 3547430Sgblack@eecs.umich.edu uint64_t op1Bits = ((uint64_t)bits(valBits, 21, 0) << 29) | 3557430Sgblack@eecs.umich.edu (mask(12) << 51) | 3567430Sgblack@eecs.umich.edu ((uint64_t)bits(valBits, 31) << 63); 3577430Sgblack@eecs.umich.edu op1 = bitsToFp(op1Bits, junk); 3587430Sgblack@eecs.umich.edu } 3597639Sgblack@eecs.umich.edu double mid = fixDest(fpscr.fz, fpscr.dn, (double)val, op1); 3607430Sgblack@eecs.umich.edu if (mid == bitsToFp(ULL(0x0010000000000000), junk) || 3617430Sgblack@eecs.umich.edu mid == bitsToFp(ULL(0x8010000000000000), junk)) { 3627430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (val) : "m" (val)); 3637430Sgblack@eecs.umich.edu fesetround(FeRoundZero); 3647430Sgblack@eecs.umich.edu double temp = 0.0; 3657430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (temp) : "m" (temp)); 3667430Sgblack@eecs.umich.edu temp = val; 3677430Sgblack@eecs.umich.edu if (flushToZero(temp)) { 3687430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 3697430Sgblack@eecs.umich.edu if (fpscr.fz) { 3707430Sgblack@eecs.umich.edu feclearexcept(FeInexact); 3717430Sgblack@eecs.umich.edu mid = temp; 3727430Sgblack@eecs.umich.edu } 3737430Sgblack@eecs.umich.edu } 3747430Sgblack@eecs.umich.edu __asm__ __volatile__("" :: "m" (temp)); 3757430Sgblack@eecs.umich.edu } 3767430Sgblack@eecs.umich.edu return mid; 3777430Sgblack@eecs.umich.edu} 3787430Sgblack@eecs.umich.edu 37910037SARM gem5 Developersstatic inline uint16_t 38010037SARM gem5 DevelopersvcvtFpFpH(FPSCR &fpscr, bool flush, bool defaultNan, 38110037SARM gem5 Developers uint32_t rMode, bool ahp, uint64_t opBits, bool isDouble) 3827430Sgblack@eecs.umich.edu{ 38310037SARM gem5 Developers uint32_t mWidth; 38410037SARM gem5 Developers uint32_t eWidth; 38510037SARM gem5 Developers uint32_t eHalfRange; 38610037SARM gem5 Developers uint32_t sBitPos; 38710037SARM gem5 Developers 38810037SARM gem5 Developers if (isDouble) { 38910037SARM gem5 Developers mWidth = 52; 39010037SARM gem5 Developers eWidth = 11; 39110037SARM gem5 Developers } else { 39210037SARM gem5 Developers mWidth = 23; 39310037SARM gem5 Developers eWidth = 8; 39410037SARM gem5 Developers } 39510037SARM gem5 Developers sBitPos = eWidth + mWidth; 39610037SARM gem5 Developers eHalfRange = (1 << (eWidth-1)) - 1; 39710037SARM gem5 Developers 3987430Sgblack@eecs.umich.edu // Extract the operand. 39910037SARM gem5 Developers bool neg = bits(opBits, sBitPos); 40010037SARM gem5 Developers uint32_t exponent = bits(opBits, sBitPos-1, mWidth); 40110037SARM gem5 Developers uint64_t oldMantissa = bits(opBits, mWidth-1, 0); 40210037SARM gem5 Developers uint32_t mantissa = oldMantissa >> (mWidth - 10); 4037430Sgblack@eecs.umich.edu // Do the conversion. 40410037SARM gem5 Developers uint64_t extra = oldMantissa & mask(mWidth - 10); 40510037SARM gem5 Developers if (exponent == mask(eWidth)) { 4067430Sgblack@eecs.umich.edu if (oldMantissa != 0) { 4077430Sgblack@eecs.umich.edu // Nans. 4087430Sgblack@eecs.umich.edu if (bits(mantissa, 9) == 0) { 4097430Sgblack@eecs.umich.edu // Signalling nan. 4107430Sgblack@eecs.umich.edu fpscr.ioc = 1; 4117430Sgblack@eecs.umich.edu } 4127639Sgblack@eecs.umich.edu if (ahp) { 4137430Sgblack@eecs.umich.edu mantissa = 0; 4147430Sgblack@eecs.umich.edu exponent = 0; 4157430Sgblack@eecs.umich.edu fpscr.ioc = 1; 4167639Sgblack@eecs.umich.edu } else if (defaultNan) { 4177430Sgblack@eecs.umich.edu mantissa = (1 << 9); 4187430Sgblack@eecs.umich.edu exponent = 0x1f; 4197430Sgblack@eecs.umich.edu neg = false; 4207430Sgblack@eecs.umich.edu } else { 4217430Sgblack@eecs.umich.edu exponent = 0x1f; 4227430Sgblack@eecs.umich.edu mantissa |= (1 << 9); 4237430Sgblack@eecs.umich.edu } 4247430Sgblack@eecs.umich.edu } else { 4257430Sgblack@eecs.umich.edu // Infinities. 4267430Sgblack@eecs.umich.edu exponent = 0x1F; 4277639Sgblack@eecs.umich.edu if (ahp) { 4287430Sgblack@eecs.umich.edu fpscr.ioc = 1; 4297430Sgblack@eecs.umich.edu mantissa = 0x3ff; 4307430Sgblack@eecs.umich.edu } else { 4317430Sgblack@eecs.umich.edu mantissa = 0; 4327430Sgblack@eecs.umich.edu } 4337430Sgblack@eecs.umich.edu } 4347430Sgblack@eecs.umich.edu } else if (exponent == 0 && oldMantissa == 0) { 4357430Sgblack@eecs.umich.edu // Zero, don't need to do anything. 4367430Sgblack@eecs.umich.edu } else { 4377430Sgblack@eecs.umich.edu // Normalized or denormalized numbers. 4387430Sgblack@eecs.umich.edu 4397430Sgblack@eecs.umich.edu bool inexact = (extra != 0); 4407430Sgblack@eecs.umich.edu 4417430Sgblack@eecs.umich.edu if (exponent == 0) { 4427430Sgblack@eecs.umich.edu // Denormalized. 4437430Sgblack@eecs.umich.edu // If flush to zero is on, this shouldn't happen. 4447639Sgblack@eecs.umich.edu assert(!flush); 4457430Sgblack@eecs.umich.edu 4467430Sgblack@eecs.umich.edu // Check for underflow 4477430Sgblack@eecs.umich.edu if (inexact || fpscr.ufe) 4487430Sgblack@eecs.umich.edu fpscr.ufc = 1; 4497430Sgblack@eecs.umich.edu 4507430Sgblack@eecs.umich.edu // Handle rounding. 4517639Sgblack@eecs.umich.edu unsigned mode = rMode; 4527430Sgblack@eecs.umich.edu if ((mode == VfpRoundUpward && !neg && extra) || 4537430Sgblack@eecs.umich.edu (mode == VfpRoundDown && neg && extra) || 4547430Sgblack@eecs.umich.edu (mode == VfpRoundNearest && 4557430Sgblack@eecs.umich.edu (extra > (1 << 9) || 4567430Sgblack@eecs.umich.edu (extra == (1 << 9) && bits(mantissa, 0))))) { 4577430Sgblack@eecs.umich.edu mantissa++; 4587430Sgblack@eecs.umich.edu } 4597430Sgblack@eecs.umich.edu 4607430Sgblack@eecs.umich.edu // See if the number became normalized after rounding. 4617430Sgblack@eecs.umich.edu if (mantissa == (1 << 10)) { 4627430Sgblack@eecs.umich.edu mantissa = 0; 4637430Sgblack@eecs.umich.edu exponent = 1; 4647430Sgblack@eecs.umich.edu } 4657430Sgblack@eecs.umich.edu } else { 4667430Sgblack@eecs.umich.edu // Normalized. 4677430Sgblack@eecs.umich.edu 4687430Sgblack@eecs.umich.edu // We need to track the dropped bits differently since 4697430Sgblack@eecs.umich.edu // more can be dropped by denormalizing. 47010037SARM gem5 Developers bool topOne = bits(extra, mWidth - 10 - 1); 47110037SARM gem5 Developers bool restZeros = bits(extra, mWidth - 10 - 2, 0) == 0; 4727430Sgblack@eecs.umich.edu 47310037SARM gem5 Developers if (exponent <= (eHalfRange - 15)) { 4747430Sgblack@eecs.umich.edu // The result is too small. Denormalize. 4757430Sgblack@eecs.umich.edu mantissa |= (1 << 10); 47610037SARM gem5 Developers while (mantissa && exponent <= (eHalfRange - 15)) { 4777430Sgblack@eecs.umich.edu restZeros = restZeros && !topOne; 4787430Sgblack@eecs.umich.edu topOne = bits(mantissa, 0); 4797430Sgblack@eecs.umich.edu mantissa = mantissa >> 1; 4807430Sgblack@eecs.umich.edu exponent++; 4817430Sgblack@eecs.umich.edu } 4827430Sgblack@eecs.umich.edu if (topOne || !restZeros) 4837430Sgblack@eecs.umich.edu inexact = true; 4847430Sgblack@eecs.umich.edu exponent = 0; 4857430Sgblack@eecs.umich.edu } else { 4867430Sgblack@eecs.umich.edu // Change bias. 48710037SARM gem5 Developers exponent -= (eHalfRange - 15); 4887430Sgblack@eecs.umich.edu } 4897430Sgblack@eecs.umich.edu 4907430Sgblack@eecs.umich.edu if (exponent == 0 && (inexact || fpscr.ufe)) { 4917430Sgblack@eecs.umich.edu // Underflow 4927430Sgblack@eecs.umich.edu fpscr.ufc = 1; 4937430Sgblack@eecs.umich.edu } 4947430Sgblack@eecs.umich.edu 4957430Sgblack@eecs.umich.edu // Handle rounding. 4967639Sgblack@eecs.umich.edu unsigned mode = rMode; 4977430Sgblack@eecs.umich.edu bool nonZero = topOne || !restZeros; 4987430Sgblack@eecs.umich.edu if ((mode == VfpRoundUpward && !neg && nonZero) || 4997430Sgblack@eecs.umich.edu (mode == VfpRoundDown && neg && nonZero) || 5007430Sgblack@eecs.umich.edu (mode == VfpRoundNearest && topOne && 5017430Sgblack@eecs.umich.edu (!restZeros || bits(mantissa, 0)))) { 5027430Sgblack@eecs.umich.edu mantissa++; 5037430Sgblack@eecs.umich.edu } 5047430Sgblack@eecs.umich.edu 5057430Sgblack@eecs.umich.edu // See if we rounded up and need to bump the exponent. 5067430Sgblack@eecs.umich.edu if (mantissa == (1 << 10)) { 5077430Sgblack@eecs.umich.edu mantissa = 0; 5087430Sgblack@eecs.umich.edu exponent++; 5097430Sgblack@eecs.umich.edu } 5107430Sgblack@eecs.umich.edu 5117430Sgblack@eecs.umich.edu // Deal with overflow 5127639Sgblack@eecs.umich.edu if (ahp) { 5137430Sgblack@eecs.umich.edu if (exponent >= 0x20) { 5147430Sgblack@eecs.umich.edu exponent = 0x1f; 5157430Sgblack@eecs.umich.edu mantissa = 0x3ff; 5167430Sgblack@eecs.umich.edu fpscr.ioc = 1; 5177430Sgblack@eecs.umich.edu // Supress inexact exception. 5187430Sgblack@eecs.umich.edu inexact = false; 5197430Sgblack@eecs.umich.edu } 5207430Sgblack@eecs.umich.edu } else { 5217430Sgblack@eecs.umich.edu if (exponent >= 0x1f) { 5227430Sgblack@eecs.umich.edu if ((mode == VfpRoundNearest) || 5237430Sgblack@eecs.umich.edu (mode == VfpRoundUpward && !neg) || 5247430Sgblack@eecs.umich.edu (mode == VfpRoundDown && neg)) { 5257430Sgblack@eecs.umich.edu // Overflow to infinity. 5267430Sgblack@eecs.umich.edu exponent = 0x1f; 5277430Sgblack@eecs.umich.edu mantissa = 0; 5287430Sgblack@eecs.umich.edu } else { 5297430Sgblack@eecs.umich.edu // Overflow to max normal. 5307430Sgblack@eecs.umich.edu exponent = 0x1e; 5317430Sgblack@eecs.umich.edu mantissa = 0x3ff; 5327430Sgblack@eecs.umich.edu } 5337430Sgblack@eecs.umich.edu fpscr.ofc = 1; 5347430Sgblack@eecs.umich.edu inexact = true; 5357430Sgblack@eecs.umich.edu } 5367430Sgblack@eecs.umich.edu } 5377430Sgblack@eecs.umich.edu } 5387430Sgblack@eecs.umich.edu 5397430Sgblack@eecs.umich.edu if (inexact) { 5407430Sgblack@eecs.umich.edu fpscr.ixc = 1; 5417430Sgblack@eecs.umich.edu } 5427430Sgblack@eecs.umich.edu } 5437430Sgblack@eecs.umich.edu // Reassemble and install the result. 5447430Sgblack@eecs.umich.edu uint32_t result = bits(mantissa, 9, 0); 5457430Sgblack@eecs.umich.edu replaceBits(result, 14, 10, exponent); 5467430Sgblack@eecs.umich.edu if (neg) 5477430Sgblack@eecs.umich.edu result |= (1 << 15); 5487639Sgblack@eecs.umich.edu return result; 5497430Sgblack@eecs.umich.edu} 5507430Sgblack@eecs.umich.edu 55110037SARM gem5 Developersuint16_t 55210037SARM gem5 DevelopersvcvtFpSFpH(FPSCR &fpscr, bool flush, bool defaultNan, 55310037SARM gem5 Developers uint32_t rMode, bool ahp, float op) 5547430Sgblack@eecs.umich.edu{ 55510037SARM gem5 Developers uint64_t opBits = fpToBits(op); 55610037SARM gem5 Developers return vcvtFpFpH(fpscr, flush, defaultNan, rMode, ahp, opBits, false); 55710037SARM gem5 Developers} 55810037SARM gem5 Developers 55910037SARM gem5 Developersuint16_t 56010037SARM gem5 DevelopersvcvtFpDFpH(FPSCR &fpscr, bool flush, bool defaultNan, 56110037SARM gem5 Developers uint32_t rMode, bool ahp, double op) 56210037SARM gem5 Developers{ 56310037SARM gem5 Developers uint64_t opBits = fpToBits(op); 56410037SARM gem5 Developers return vcvtFpFpH(fpscr, flush, defaultNan, rMode, ahp, opBits, true); 56510037SARM gem5 Developers} 56610037SARM gem5 Developers 56710037SARM gem5 Developersstatic inline uint64_t 56810037SARM gem5 DevelopersvcvtFpHFp(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op, bool isDouble) 56910037SARM gem5 Developers{ 57010037SARM gem5 Developers uint32_t mWidth; 57110037SARM gem5 Developers uint32_t eWidth; 57210037SARM gem5 Developers uint32_t eHalfRange; 57310037SARM gem5 Developers uint32_t sBitPos; 57410037SARM gem5 Developers 57510037SARM gem5 Developers if (isDouble) { 57610037SARM gem5 Developers mWidth = 52; 57710037SARM gem5 Developers eWidth = 11; 57810037SARM gem5 Developers } else { 57910037SARM gem5 Developers mWidth = 23; 58010037SARM gem5 Developers eWidth = 8; 58110037SARM gem5 Developers } 58210037SARM gem5 Developers sBitPos = eWidth + mWidth; 58310037SARM gem5 Developers eHalfRange = (1 << (eWidth-1)) - 1; 58410037SARM gem5 Developers 5857430Sgblack@eecs.umich.edu // Extract the bitfields. 5867639Sgblack@eecs.umich.edu bool neg = bits(op, 15); 5877639Sgblack@eecs.umich.edu uint32_t exponent = bits(op, 14, 10); 58810037SARM gem5 Developers uint64_t mantissa = bits(op, 9, 0); 5897430Sgblack@eecs.umich.edu // Do the conversion. 5907430Sgblack@eecs.umich.edu if (exponent == 0) { 5917430Sgblack@eecs.umich.edu if (mantissa != 0) { 5927430Sgblack@eecs.umich.edu // Normalize the value. 59310037SARM gem5 Developers exponent = exponent + (eHalfRange - 15) + 1; 5947430Sgblack@eecs.umich.edu while (mantissa < (1 << 10)) { 5957430Sgblack@eecs.umich.edu mantissa = mantissa << 1; 5967430Sgblack@eecs.umich.edu exponent--; 5977430Sgblack@eecs.umich.edu } 5987430Sgblack@eecs.umich.edu } 59910037SARM gem5 Developers mantissa = mantissa << (mWidth - 10); 6007639Sgblack@eecs.umich.edu } else if (exponent == 0x1f && !ahp) { 6017430Sgblack@eecs.umich.edu // Infinities and nans. 60210037SARM gem5 Developers exponent = mask(eWidth); 6037430Sgblack@eecs.umich.edu if (mantissa != 0) { 6047430Sgblack@eecs.umich.edu // Nans. 60510037SARM gem5 Developers mantissa = mantissa << (mWidth - 10); 60610037SARM gem5 Developers if (bits(mantissa, mWidth-1) == 0) { 6077430Sgblack@eecs.umich.edu // Signalling nan. 6087430Sgblack@eecs.umich.edu fpscr.ioc = 1; 60910037SARM gem5 Developers mantissa |= (((uint64_t) 1) << (mWidth-1)); 6107430Sgblack@eecs.umich.edu } 6117639Sgblack@eecs.umich.edu if (defaultNan) { 61210037SARM gem5 Developers mantissa &= ~mask(mWidth-1); 6137430Sgblack@eecs.umich.edu neg = false; 6147430Sgblack@eecs.umich.edu } 6157430Sgblack@eecs.umich.edu } 6167430Sgblack@eecs.umich.edu } else { 61710037SARM gem5 Developers exponent = exponent + (eHalfRange - 15); 61810037SARM gem5 Developers mantissa = mantissa << (mWidth - 10); 6197430Sgblack@eecs.umich.edu } 6207430Sgblack@eecs.umich.edu // Reassemble the result. 62110037SARM gem5 Developers uint64_t result = bits(mantissa, mWidth-1, 0); 62210037SARM gem5 Developers replaceBits(result, sBitPos-1, mWidth, exponent); 62310037SARM gem5 Developers if (neg) { 62410037SARM gem5 Developers result |= (((uint64_t) 1) << sBitPos); 62510037SARM gem5 Developers } 62610037SARM gem5 Developers return result; 62710037SARM gem5 Developers} 62810037SARM gem5 Developers 62910037SARM gem5 Developersdouble 63010037SARM gem5 DevelopersvcvtFpHFpD(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op) 63110037SARM gem5 Developers{ 63210037SARM gem5 Developers double junk = 0.0; 63310037SARM gem5 Developers uint64_t result; 63410037SARM gem5 Developers 63510037SARM gem5 Developers result = vcvtFpHFp(fpscr, defaultNan, ahp, op, true); 6367430Sgblack@eecs.umich.edu return bitsToFp(result, junk); 6377430Sgblack@eecs.umich.edu} 6387430Sgblack@eecs.umich.edu 63910037SARM gem5 Developersfloat 64010037SARM gem5 DevelopersvcvtFpHFpS(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op) 6417430Sgblack@eecs.umich.edu{ 64210037SARM gem5 Developers float junk = 0.0; 64310037SARM gem5 Developers uint64_t result; 6447430Sgblack@eecs.umich.edu 64510037SARM gem5 Developers result = vcvtFpHFp(fpscr, defaultNan, ahp, op, false); 64610037SARM gem5 Developers return bitsToFp(result, junk); 6477430Sgblack@eecs.umich.edu} 6487430Sgblack@eecs.umich.edu 6497430Sgblack@eecs.umich.edufloat 6507639Sgblack@eecs.umich.eduvfpUFixedToFpS(bool flush, bool defaultNan, 65110037SARM gem5 Developers uint64_t val, uint8_t width, uint8_t imm) 6527430Sgblack@eecs.umich.edu{ 6537430Sgblack@eecs.umich.edu fesetround(FeRoundNearest); 65410037SARM gem5 Developers if (width == 16) 6557430Sgblack@eecs.umich.edu val = (uint16_t)val; 65610037SARM gem5 Developers else if (width == 32) 65710037SARM gem5 Developers val = (uint32_t)val; 65810037SARM gem5 Developers else if (width != 64) 65910037SARM gem5 Developers panic("Unsupported width %d", width); 6607430Sgblack@eecs.umich.edu float scale = powf(2.0, imm); 6617430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 6627430Sgblack@eecs.umich.edu feclearexcept(FeAllExceptions); 6637430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 6647639Sgblack@eecs.umich.edu return fixDivDest(flush, defaultNan, val / scale, (float)val, scale); 6657430Sgblack@eecs.umich.edu} 6667430Sgblack@eecs.umich.edu 6677430Sgblack@eecs.umich.edufloat 6687639Sgblack@eecs.umich.eduvfpSFixedToFpS(bool flush, bool defaultNan, 66910037SARM gem5 Developers int64_t val, uint8_t width, uint8_t imm) 6707430Sgblack@eecs.umich.edu{ 6717430Sgblack@eecs.umich.edu fesetround(FeRoundNearest); 67210037SARM gem5 Developers if (width == 16) 6737430Sgblack@eecs.umich.edu val = sext<16>(val & mask(16)); 67410037SARM gem5 Developers else if (width == 32) 67510037SARM gem5 Developers val = sext<32>(val & mask(32)); 67610037SARM gem5 Developers else if (width != 64) 67710037SARM gem5 Developers panic("Unsupported width %d", width); 67810037SARM gem5 Developers 6797430Sgblack@eecs.umich.edu float scale = powf(2.0, imm); 6807430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 6817430Sgblack@eecs.umich.edu feclearexcept(FeAllExceptions); 6827430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 6837639Sgblack@eecs.umich.edu return fixDivDest(flush, defaultNan, val / scale, (float)val, scale); 6847430Sgblack@eecs.umich.edu} 6857430Sgblack@eecs.umich.edu 6867430Sgblack@eecs.umich.edu 6877430Sgblack@eecs.umich.edudouble 6887639Sgblack@eecs.umich.eduvfpUFixedToFpD(bool flush, bool defaultNan, 68910037SARM gem5 Developers uint64_t val, uint8_t width, uint8_t imm) 6907430Sgblack@eecs.umich.edu{ 6917430Sgblack@eecs.umich.edu fesetround(FeRoundNearest); 69210037SARM gem5 Developers if (width == 16) 6937430Sgblack@eecs.umich.edu val = (uint16_t)val; 69410037SARM gem5 Developers else if (width == 32) 69510037SARM gem5 Developers val = (uint32_t)val; 69610037SARM gem5 Developers else if (width != 64) 69710037SARM gem5 Developers panic("Unsupported width %d", width); 69810037SARM gem5 Developers 6997430Sgblack@eecs.umich.edu double scale = pow(2.0, imm); 7007430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 7017430Sgblack@eecs.umich.edu feclearexcept(FeAllExceptions); 7027430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 7037639Sgblack@eecs.umich.edu return fixDivDest(flush, defaultNan, val / scale, (double)val, scale); 7047430Sgblack@eecs.umich.edu} 7057430Sgblack@eecs.umich.edu 7067430Sgblack@eecs.umich.edudouble 7077639Sgblack@eecs.umich.eduvfpSFixedToFpD(bool flush, bool defaultNan, 70810037SARM gem5 Developers int64_t val, uint8_t width, uint8_t imm) 7097430Sgblack@eecs.umich.edu{ 7107430Sgblack@eecs.umich.edu fesetround(FeRoundNearest); 71110037SARM gem5 Developers if (width == 16) 7127430Sgblack@eecs.umich.edu val = sext<16>(val & mask(16)); 71310037SARM gem5 Developers else if (width == 32) 71410037SARM gem5 Developers val = sext<32>(val & mask(32)); 71510037SARM gem5 Developers else if (width != 64) 71610037SARM gem5 Developers panic("Unsupported width %d", width); 71710037SARM gem5 Developers 7187430Sgblack@eecs.umich.edu double scale = pow(2.0, imm); 7197430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 7207430Sgblack@eecs.umich.edu feclearexcept(FeAllExceptions); 7217430Sgblack@eecs.umich.edu __asm__ __volatile__("" : "=m" (scale) : "m" (scale)); 7227639Sgblack@eecs.umich.edu return fixDivDest(flush, defaultNan, val / scale, (double)val, scale); 7237430Sgblack@eecs.umich.edu} 7247430Sgblack@eecs.umich.edu 7257639Sgblack@eecs.umich.edu// This function implements a magic formula taken from the architecture 7267639Sgblack@eecs.umich.edu// reference manual. It was originally called recip_sqrt_estimate. 7277639Sgblack@eecs.umich.edustatic double 7287639Sgblack@eecs.umich.edurecipSqrtEstimate(double a) 7297639Sgblack@eecs.umich.edu{ 7307639Sgblack@eecs.umich.edu int64_t q0, q1, s; 7317639Sgblack@eecs.umich.edu double r; 7327639Sgblack@eecs.umich.edu if (a < 0.5) { 7337639Sgblack@eecs.umich.edu q0 = (int64_t)(a * 512.0); 7347639Sgblack@eecs.umich.edu r = 1.0 / sqrt(((double)q0 + 0.5) / 512.0); 7357639Sgblack@eecs.umich.edu } else { 7367639Sgblack@eecs.umich.edu q1 = (int64_t)(a * 256.0); 7377639Sgblack@eecs.umich.edu r = 1.0 / sqrt(((double)q1 + 0.5) / 256.0); 7387639Sgblack@eecs.umich.edu } 7397639Sgblack@eecs.umich.edu s = (int64_t)(256.0 * r + 0.5); 7407639Sgblack@eecs.umich.edu return (double)s / 256.0; 7417639Sgblack@eecs.umich.edu} 7427639Sgblack@eecs.umich.edu 7437639Sgblack@eecs.umich.edu// This function is only intended for use in Neon instructions because 7447639Sgblack@eecs.umich.edu// it ignores certain bits in the FPSCR. 7457639Sgblack@eecs.umich.edufloat 7467639Sgblack@eecs.umich.edufprSqrtEstimate(FPSCR &fpscr, float op) 7477639Sgblack@eecs.umich.edu{ 7487639Sgblack@eecs.umich.edu const uint32_t qnan = 0x7fc00000; 7497639Sgblack@eecs.umich.edu float junk = 0.0; 7507639Sgblack@eecs.umich.edu int fpClass = std::fpclassify(op); 7517639Sgblack@eecs.umich.edu if (fpClass == FP_NAN) { 7527639Sgblack@eecs.umich.edu if ((fpToBits(op) & qnan) != qnan) 7537639Sgblack@eecs.umich.edu fpscr.ioc = 1; 7547639Sgblack@eecs.umich.edu return bitsToFp(qnan, junk); 7557639Sgblack@eecs.umich.edu } else if (fpClass == FP_ZERO) { 7567639Sgblack@eecs.umich.edu fpscr.dzc = 1; 7577639Sgblack@eecs.umich.edu // Return infinity with the same sign as the operand. 7587639Sgblack@eecs.umich.edu return bitsToFp((std::signbit(op) << 31) | 7597639Sgblack@eecs.umich.edu (0xFF << 23) | (0 << 0), junk); 7607639Sgblack@eecs.umich.edu } else if (std::signbit(op)) { 7617639Sgblack@eecs.umich.edu // Set invalid op bit. 7627639Sgblack@eecs.umich.edu fpscr.ioc = 1; 7637639Sgblack@eecs.umich.edu return bitsToFp(qnan, junk); 7647639Sgblack@eecs.umich.edu } else if (fpClass == FP_INFINITE) { 7657639Sgblack@eecs.umich.edu return 0.0; 7667639Sgblack@eecs.umich.edu } else { 7677639Sgblack@eecs.umich.edu uint64_t opBits = fpToBits(op); 7687639Sgblack@eecs.umich.edu double scaled; 7697639Sgblack@eecs.umich.edu if (bits(opBits, 23)) { 7707639Sgblack@eecs.umich.edu scaled = bitsToFp((0 << 0) | (bits(opBits, 22, 0) << 29) | 7717639Sgblack@eecs.umich.edu (ULL(0x3fd) << 52) | (bits(opBits, 31) << 63), 7727639Sgblack@eecs.umich.edu (double)0.0); 7737639Sgblack@eecs.umich.edu } else { 7747639Sgblack@eecs.umich.edu scaled = bitsToFp((0 << 0) | (bits(opBits, 22, 0) << 29) | 7757639Sgblack@eecs.umich.edu (ULL(0x3fe) << 52) | (bits(opBits, 31) << 63), 7767639Sgblack@eecs.umich.edu (double)0.0); 7777639Sgblack@eecs.umich.edu } 7787639Sgblack@eecs.umich.edu uint64_t resultExp = (380 - bits(opBits, 30, 23)) / 2; 7797639Sgblack@eecs.umich.edu 7807639Sgblack@eecs.umich.edu uint64_t estimate = fpToBits(recipSqrtEstimate(scaled)); 7817639Sgblack@eecs.umich.edu 7827639Sgblack@eecs.umich.edu return bitsToFp((bits(estimate, 63) << 31) | 7837639Sgblack@eecs.umich.edu (bits(resultExp, 7, 0) << 23) | 7847639Sgblack@eecs.umich.edu (bits(estimate, 51, 29) << 0), junk); 7857639Sgblack@eecs.umich.edu } 7867639Sgblack@eecs.umich.edu} 7877639Sgblack@eecs.umich.edu 7887639Sgblack@eecs.umich.eduuint32_t 7897639Sgblack@eecs.umich.eduunsignedRSqrtEstimate(uint32_t op) 7907639Sgblack@eecs.umich.edu{ 7917639Sgblack@eecs.umich.edu if (bits(op, 31, 30) == 0) { 7927639Sgblack@eecs.umich.edu return -1; 7937639Sgblack@eecs.umich.edu } else { 7947639Sgblack@eecs.umich.edu double dpOp; 7957639Sgblack@eecs.umich.edu if (bits(op, 31)) { 7967639Sgblack@eecs.umich.edu dpOp = bitsToFp((ULL(0) << 63) | 7977639Sgblack@eecs.umich.edu (ULL(0x3fe) << 52) | 7987639Sgblack@eecs.umich.edu (bits((uint64_t)op, 30, 0) << 21) | 7997639Sgblack@eecs.umich.edu (0 << 0), (double)0.0); 8007639Sgblack@eecs.umich.edu } else { 8017639Sgblack@eecs.umich.edu dpOp = bitsToFp((ULL(0) << 63) | 8027639Sgblack@eecs.umich.edu (ULL(0x3fd) << 52) | 8037639Sgblack@eecs.umich.edu (bits((uint64_t)op, 29, 0) << 22) | 8047639Sgblack@eecs.umich.edu (0 << 0), (double)0.0); 8057639Sgblack@eecs.umich.edu } 8067639Sgblack@eecs.umich.edu uint64_t estimate = fpToBits(recipSqrtEstimate(dpOp)); 8077639Sgblack@eecs.umich.edu return (1 << 31) | bits(estimate, 51, 21); 8087639Sgblack@eecs.umich.edu } 8097639Sgblack@eecs.umich.edu} 8107639Sgblack@eecs.umich.edu 8117639Sgblack@eecs.umich.edu// This function implements a magic formula taken from the architecture 8127639Sgblack@eecs.umich.edu// reference manual. It was originally called recip_estimate. 8137639Sgblack@eecs.umich.edu 8147639Sgblack@eecs.umich.edustatic double 8157639Sgblack@eecs.umich.edurecipEstimate(double a) 8167639Sgblack@eecs.umich.edu{ 8177639Sgblack@eecs.umich.edu int64_t q, s; 8187639Sgblack@eecs.umich.edu double r; 8197639Sgblack@eecs.umich.edu q = (int64_t)(a * 512.0); 8207639Sgblack@eecs.umich.edu r = 1.0 / (((double)q + 0.5) / 512.0); 8217639Sgblack@eecs.umich.edu s = (int64_t)(256.0 * r + 0.5); 8227639Sgblack@eecs.umich.edu return (double)s / 256.0; 8237639Sgblack@eecs.umich.edu} 8247639Sgblack@eecs.umich.edu 8257639Sgblack@eecs.umich.edu// This function is only intended for use in Neon instructions because 8267639Sgblack@eecs.umich.edu// it ignores certain bits in the FPSCR. 8277639Sgblack@eecs.umich.edufloat 8287639Sgblack@eecs.umich.edufpRecipEstimate(FPSCR &fpscr, float op) 8297639Sgblack@eecs.umich.edu{ 8307639Sgblack@eecs.umich.edu const uint32_t qnan = 0x7fc00000; 8317639Sgblack@eecs.umich.edu float junk = 0.0; 8327639Sgblack@eecs.umich.edu int fpClass = std::fpclassify(op); 8337639Sgblack@eecs.umich.edu if (fpClass == FP_NAN) { 8347639Sgblack@eecs.umich.edu if ((fpToBits(op) & qnan) != qnan) 8357639Sgblack@eecs.umich.edu fpscr.ioc = 1; 8367639Sgblack@eecs.umich.edu return bitsToFp(qnan, junk); 8377639Sgblack@eecs.umich.edu } else if (fpClass == FP_INFINITE) { 8387639Sgblack@eecs.umich.edu return bitsToFp(std::signbit(op) << 31, junk); 8397639Sgblack@eecs.umich.edu } else if (fpClass == FP_ZERO) { 8407639Sgblack@eecs.umich.edu fpscr.dzc = 1; 8417639Sgblack@eecs.umich.edu // Return infinity with the same sign as the operand. 8427639Sgblack@eecs.umich.edu return bitsToFp((std::signbit(op) << 31) | 8437639Sgblack@eecs.umich.edu (0xFF << 23) | (0 << 0), junk); 8447639Sgblack@eecs.umich.edu } else if (fabs(op) >= pow(2.0, 126)) { 8457639Sgblack@eecs.umich.edu fpscr.ufc = 1; 8467639Sgblack@eecs.umich.edu return bitsToFp(std::signbit(op) << 31, junk); 8477639Sgblack@eecs.umich.edu } else { 8487639Sgblack@eecs.umich.edu uint64_t opBits = fpToBits(op); 8497639Sgblack@eecs.umich.edu double scaled; 8507639Sgblack@eecs.umich.edu scaled = bitsToFp((0 << 0) | (bits(opBits, 22, 0) << 29) | 8517639Sgblack@eecs.umich.edu (ULL(0x3fe) << 52) | (ULL(0) << 63), 8527639Sgblack@eecs.umich.edu (double)0.0); 8537639Sgblack@eecs.umich.edu uint64_t resultExp = 253 - bits(opBits, 30, 23); 8547639Sgblack@eecs.umich.edu 8557639Sgblack@eecs.umich.edu uint64_t estimate = fpToBits(recipEstimate(scaled)); 8567639Sgblack@eecs.umich.edu 8577639Sgblack@eecs.umich.edu return bitsToFp((bits(opBits, 31) << 31) | 8587639Sgblack@eecs.umich.edu (bits(resultExp, 7, 0) << 23) | 8597639Sgblack@eecs.umich.edu (bits(estimate, 51, 29) << 0), junk); 8607639Sgblack@eecs.umich.edu } 8617639Sgblack@eecs.umich.edu} 8627639Sgblack@eecs.umich.edu 8637639Sgblack@eecs.umich.eduuint32_t 8647639Sgblack@eecs.umich.eduunsignedRecipEstimate(uint32_t op) 8657639Sgblack@eecs.umich.edu{ 8667639Sgblack@eecs.umich.edu if (bits(op, 31) == 0) { 8677639Sgblack@eecs.umich.edu return -1; 8687639Sgblack@eecs.umich.edu } else { 8697639Sgblack@eecs.umich.edu double dpOp; 8707639Sgblack@eecs.umich.edu dpOp = bitsToFp((ULL(0) << 63) | 8717639Sgblack@eecs.umich.edu (ULL(0x3fe) << 52) | 8727639Sgblack@eecs.umich.edu (bits((uint64_t)op, 30, 0) << 21) | 8737639Sgblack@eecs.umich.edu (0 << 0), (double)0.0); 8747639Sgblack@eecs.umich.edu uint64_t estimate = fpToBits(recipEstimate(dpOp)); 8757639Sgblack@eecs.umich.edu return (1 << 31) | bits(estimate, 51, 21); 8767639Sgblack@eecs.umich.edu } 8777639Sgblack@eecs.umich.edu} 8787639Sgblack@eecs.umich.edu 8797639Sgblack@eecs.umich.edutemplate <class fpType> 8807639Sgblack@eecs.umich.edufpType 8817639Sgblack@eecs.umich.eduFpOp::processNans(FPSCR &fpscr, bool &done, bool defaultNan, 8827639Sgblack@eecs.umich.edu fpType op1, fpType op2) const 8837639Sgblack@eecs.umich.edu{ 8847639Sgblack@eecs.umich.edu done = true; 8857639Sgblack@eecs.umich.edu fpType junk = 0.0; 8867639Sgblack@eecs.umich.edu fpType dest = 0.0; 8877639Sgblack@eecs.umich.edu const bool single = (sizeof(fpType) == sizeof(float)); 8887639Sgblack@eecs.umich.edu const uint64_t qnan = 8897639Sgblack@eecs.umich.edu single ? 0x7fc00000 : ULL(0x7ff8000000000000); 8907639Sgblack@eecs.umich.edu const bool nan1 = std::isnan(op1); 8917639Sgblack@eecs.umich.edu const bool nan2 = std::isnan(op2); 8927639Sgblack@eecs.umich.edu const bool signal1 = nan1 && ((fpToBits(op1) & qnan) != qnan); 8937639Sgblack@eecs.umich.edu const bool signal2 = nan2 && ((fpToBits(op2) & qnan) != qnan); 8947639Sgblack@eecs.umich.edu if (nan1 || nan2) { 8957639Sgblack@eecs.umich.edu if (defaultNan) { 8967639Sgblack@eecs.umich.edu dest = bitsToFp(qnan, junk); 8977639Sgblack@eecs.umich.edu } else if (signal1) { 8987639Sgblack@eecs.umich.edu dest = bitsToFp(fpToBits(op1) | qnan, junk); 8997639Sgblack@eecs.umich.edu } else if (signal2) { 9007639Sgblack@eecs.umich.edu dest = bitsToFp(fpToBits(op2) | qnan, junk); 9017639Sgblack@eecs.umich.edu } else if (nan1) { 9027639Sgblack@eecs.umich.edu dest = op1; 9037639Sgblack@eecs.umich.edu } else if (nan2) { 9047639Sgblack@eecs.umich.edu dest = op2; 9057639Sgblack@eecs.umich.edu } 9067639Sgblack@eecs.umich.edu if (signal1 || signal2) { 9077639Sgblack@eecs.umich.edu fpscr.ioc = 1; 9087639Sgblack@eecs.umich.edu } 9097639Sgblack@eecs.umich.edu } else { 9107639Sgblack@eecs.umich.edu done = false; 9117639Sgblack@eecs.umich.edu } 9127639Sgblack@eecs.umich.edu return dest; 9137639Sgblack@eecs.umich.edu} 9147639Sgblack@eecs.umich.edu 9157639Sgblack@eecs.umich.edutemplate 9167639Sgblack@eecs.umich.edufloat FpOp::processNans(FPSCR &fpscr, bool &done, bool defaultNan, 9177639Sgblack@eecs.umich.edu float op1, float op2) const; 9187639Sgblack@eecs.umich.edutemplate 9197639Sgblack@eecs.umich.edudouble FpOp::processNans(FPSCR &fpscr, bool &done, bool defaultNan, 9207639Sgblack@eecs.umich.edu double op1, double op2) const; 9217639Sgblack@eecs.umich.edu 92210037SARM gem5 Developers// @TODO remove this function when we've finished switching all FMA code to use the new FPLIB 92310037SARM gem5 Developerstemplate <class fpType> 92410037SARM gem5 DevelopersfpType 92510037SARM gem5 DevelopersFpOp::ternaryOp(FPSCR &fpscr, fpType op1, fpType op2, fpType op3, 92610037SARM gem5 Developers fpType (*func)(fpType, fpType, fpType), 92710037SARM gem5 Developers bool flush, bool defaultNan, uint32_t rMode) const 92810037SARM gem5 Developers{ 92910037SARM gem5 Developers const bool single = (sizeof(fpType) == sizeof(float)); 93010037SARM gem5 Developers fpType junk = 0.0; 93110037SARM gem5 Developers 93210037SARM gem5 Developers if (flush && (flushToZero(op1, op2) || flushToZero(op3))) 93310037SARM gem5 Developers fpscr.idc = 1; 93410037SARM gem5 Developers VfpSavedState state = prepFpState(rMode); 93510037SARM gem5 Developers __asm__ __volatile__ ("" : "=m" (op1), "=m" (op2), "=m" (op3), "=m" (state) 93610037SARM gem5 Developers : "m" (op1), "m" (op2), "m" (op3), "m" (state)); 93710037SARM gem5 Developers fpType dest = func(op1, op2, op3); 93810037SARM gem5 Developers __asm__ __volatile__ ("" : "=m" (dest) : "m" (dest)); 93910037SARM gem5 Developers 94010037SARM gem5 Developers int fpClass = std::fpclassify(dest); 94110037SARM gem5 Developers // Get NAN behavior right. This varies between x86 and ARM. 94210037SARM gem5 Developers if (fpClass == FP_NAN) { 94310037SARM gem5 Developers const uint64_t qnan = 94410037SARM gem5 Developers single ? 0x7fc00000 : ULL(0x7ff8000000000000); 94510037SARM gem5 Developers const bool nan1 = std::isnan(op1); 94610037SARM gem5 Developers const bool nan2 = std::isnan(op2); 94710037SARM gem5 Developers const bool nan3 = std::isnan(op3); 94810037SARM gem5 Developers const bool signal1 = nan1 && ((fpToBits(op1) & qnan) != qnan); 94910037SARM gem5 Developers const bool signal2 = nan2 && ((fpToBits(op2) & qnan) != qnan); 95010037SARM gem5 Developers const bool signal3 = nan3 && ((fpToBits(op3) & qnan) != qnan); 95110037SARM gem5 Developers if ((!nan1 && !nan2 && !nan3) || (defaultNan == 1)) { 95210037SARM gem5 Developers dest = bitsToFp(qnan, junk); 95310037SARM gem5 Developers } else if (signal1) { 95410037SARM gem5 Developers dest = bitsToFp(fpToBits(op1) | qnan, junk); 95510037SARM gem5 Developers } else if (signal2) { 95610037SARM gem5 Developers dest = bitsToFp(fpToBits(op2) | qnan, junk); 95710037SARM gem5 Developers } else if (signal3) { 95810037SARM gem5 Developers dest = bitsToFp(fpToBits(op3) | qnan, junk); 95910037SARM gem5 Developers } else if (nan1) { 96010037SARM gem5 Developers dest = op1; 96110037SARM gem5 Developers } else if (nan2) { 96210037SARM gem5 Developers dest = op2; 96310037SARM gem5 Developers } else if (nan3) { 96410037SARM gem5 Developers dest = op3; 96510037SARM gem5 Developers } 96610037SARM gem5 Developers } else if (flush && flushToZero(dest)) { 96710037SARM gem5 Developers feraiseexcept(FeUnderflow); 96810037SARM gem5 Developers } else if (( 96910037SARM gem5 Developers (single && (dest == bitsToFp(0x00800000, junk) || 97010037SARM gem5 Developers dest == bitsToFp(0x80800000, junk))) || 97110037SARM gem5 Developers (!single && 97210037SARM gem5 Developers (dest == bitsToFp(ULL(0x0010000000000000), junk) || 97310037SARM gem5 Developers dest == bitsToFp(ULL(0x8010000000000000), junk))) 97410037SARM gem5 Developers ) && rMode != VfpRoundZero) { 97510037SARM gem5 Developers /* 97610037SARM gem5 Developers * Correct for the fact that underflow is detected -before- rounding 97710037SARM gem5 Developers * in ARM and -after- rounding in x86. 97810037SARM gem5 Developers */ 97910037SARM gem5 Developers fesetround(FeRoundZero); 98010037SARM gem5 Developers __asm__ __volatile__ ("" : "=m" (op1), "=m" (op2), "=m" (op3) 98110037SARM gem5 Developers : "m" (op1), "m" (op2), "m" (op3)); 98210037SARM gem5 Developers fpType temp = func(op1, op2, op2); 98310037SARM gem5 Developers __asm__ __volatile__ ("" : "=m" (temp) : "m" (temp)); 98410037SARM gem5 Developers if (flush && flushToZero(temp)) { 98510037SARM gem5 Developers dest = temp; 98610037SARM gem5 Developers } 98710037SARM gem5 Developers } 98810037SARM gem5 Developers finishVfp(fpscr, state, flush); 98910037SARM gem5 Developers return dest; 99010037SARM gem5 Developers} 99110037SARM gem5 Developers 99210037SARM gem5 Developerstemplate 99310037SARM gem5 Developersfloat FpOp::ternaryOp(FPSCR &fpscr, float op1, float op2, float op3, 99410037SARM gem5 Developers float (*func)(float, float, float), 99510037SARM gem5 Developers bool flush, bool defaultNan, uint32_t rMode) const; 99610037SARM gem5 Developerstemplate 99710037SARM gem5 Developersdouble FpOp::ternaryOp(FPSCR &fpscr, double op1, double op2, double op3, 99810037SARM gem5 Developers double (*func)(double, double, double), 99910037SARM gem5 Developers bool flush, bool defaultNan, uint32_t rMode) const; 100010037SARM gem5 Developers 10017430Sgblack@eecs.umich.edutemplate <class fpType> 10027430Sgblack@eecs.umich.edufpType 10037430Sgblack@eecs.umich.eduFpOp::binaryOp(FPSCR &fpscr, fpType op1, fpType op2, 10047430Sgblack@eecs.umich.edu fpType (*func)(fpType, fpType), 10057639Sgblack@eecs.umich.edu bool flush, bool defaultNan, uint32_t rMode) const 10067430Sgblack@eecs.umich.edu{ 10077430Sgblack@eecs.umich.edu const bool single = (sizeof(fpType) == sizeof(float)); 10087430Sgblack@eecs.umich.edu fpType junk = 0.0; 10097430Sgblack@eecs.umich.edu 10107430Sgblack@eecs.umich.edu if (flush && flushToZero(op1, op2)) 10117430Sgblack@eecs.umich.edu fpscr.idc = 1; 10127430Sgblack@eecs.umich.edu VfpSavedState state = prepFpState(rMode); 10137430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (op1), "=m" (op2), "=m" (state) 10147430Sgblack@eecs.umich.edu : "m" (op1), "m" (op2), "m" (state)); 10157430Sgblack@eecs.umich.edu fpType dest = func(op1, op2); 10167430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (dest) : "m" (dest)); 10177430Sgblack@eecs.umich.edu 10187430Sgblack@eecs.umich.edu // Get NAN behavior right. This varies between x86 and ARM. 10199515SAli.Saidi@ARM.com if (std::isnan(dest)) { 10207430Sgblack@eecs.umich.edu const uint64_t qnan = 10217430Sgblack@eecs.umich.edu single ? 0x7fc00000 : ULL(0x7ff8000000000000); 10227430Sgblack@eecs.umich.edu const bool nan1 = std::isnan(op1); 10237430Sgblack@eecs.umich.edu const bool nan2 = std::isnan(op2); 10247430Sgblack@eecs.umich.edu const bool signal1 = nan1 && ((fpToBits(op1) & qnan) != qnan); 10257430Sgblack@eecs.umich.edu const bool signal2 = nan2 && ((fpToBits(op2) & qnan) != qnan); 10267639Sgblack@eecs.umich.edu if ((!nan1 && !nan2) || (defaultNan == 1)) { 10277430Sgblack@eecs.umich.edu dest = bitsToFp(qnan, junk); 10287430Sgblack@eecs.umich.edu } else if (signal1) { 10297430Sgblack@eecs.umich.edu dest = bitsToFp(fpToBits(op1) | qnan, junk); 10307430Sgblack@eecs.umich.edu } else if (signal2) { 10317430Sgblack@eecs.umich.edu dest = bitsToFp(fpToBits(op2) | qnan, junk); 10327430Sgblack@eecs.umich.edu } else if (nan1) { 10337430Sgblack@eecs.umich.edu dest = op1; 10347430Sgblack@eecs.umich.edu } else if (nan2) { 10357430Sgblack@eecs.umich.edu dest = op2; 10367430Sgblack@eecs.umich.edu } 10377430Sgblack@eecs.umich.edu } else if (flush && flushToZero(dest)) { 10387430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 10397430Sgblack@eecs.umich.edu } else if (( 10407430Sgblack@eecs.umich.edu (single && (dest == bitsToFp(0x00800000, junk) || 10417430Sgblack@eecs.umich.edu dest == bitsToFp(0x80800000, junk))) || 10427430Sgblack@eecs.umich.edu (!single && 10437430Sgblack@eecs.umich.edu (dest == bitsToFp(ULL(0x0010000000000000), junk) || 10447430Sgblack@eecs.umich.edu dest == bitsToFp(ULL(0x8010000000000000), junk))) 10457430Sgblack@eecs.umich.edu ) && rMode != VfpRoundZero) { 10467430Sgblack@eecs.umich.edu /* 10477430Sgblack@eecs.umich.edu * Correct for the fact that underflow is detected -before- rounding 10487430Sgblack@eecs.umich.edu * in ARM and -after- rounding in x86. 10497430Sgblack@eecs.umich.edu */ 10507430Sgblack@eecs.umich.edu fesetround(FeRoundZero); 10517430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (op1), "=m" (op2) 10527430Sgblack@eecs.umich.edu : "m" (op1), "m" (op2)); 10537430Sgblack@eecs.umich.edu fpType temp = func(op1, op2); 10547430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (temp) : "m" (temp)); 10557430Sgblack@eecs.umich.edu if (flush && flushToZero(temp)) { 10567430Sgblack@eecs.umich.edu dest = temp; 10577430Sgblack@eecs.umich.edu } 10587430Sgblack@eecs.umich.edu } 10597639Sgblack@eecs.umich.edu finishVfp(fpscr, state, flush); 10607430Sgblack@eecs.umich.edu return dest; 10617430Sgblack@eecs.umich.edu} 10627430Sgblack@eecs.umich.edu 10637430Sgblack@eecs.umich.edutemplate 10647430Sgblack@eecs.umich.edufloat FpOp::binaryOp(FPSCR &fpscr, float op1, float op2, 10657430Sgblack@eecs.umich.edu float (*func)(float, float), 10667639Sgblack@eecs.umich.edu bool flush, bool defaultNan, uint32_t rMode) const; 10677430Sgblack@eecs.umich.edutemplate 10687430Sgblack@eecs.umich.edudouble FpOp::binaryOp(FPSCR &fpscr, double op1, double op2, 10697430Sgblack@eecs.umich.edu double (*func)(double, double), 10707639Sgblack@eecs.umich.edu bool flush, bool defaultNan, uint32_t rMode) const; 10717430Sgblack@eecs.umich.edu 10727430Sgblack@eecs.umich.edutemplate <class fpType> 10737430Sgblack@eecs.umich.edufpType 10747430Sgblack@eecs.umich.eduFpOp::unaryOp(FPSCR &fpscr, fpType op1, fpType (*func)(fpType), 10757430Sgblack@eecs.umich.edu bool flush, uint32_t rMode) const 10767430Sgblack@eecs.umich.edu{ 10777430Sgblack@eecs.umich.edu const bool single = (sizeof(fpType) == sizeof(float)); 10787430Sgblack@eecs.umich.edu fpType junk = 0.0; 10797430Sgblack@eecs.umich.edu 10807430Sgblack@eecs.umich.edu if (flush && flushToZero(op1)) 10817430Sgblack@eecs.umich.edu fpscr.idc = 1; 10827430Sgblack@eecs.umich.edu VfpSavedState state = prepFpState(rMode); 10837430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (op1), "=m" (state) 10847430Sgblack@eecs.umich.edu : "m" (op1), "m" (state)); 10857430Sgblack@eecs.umich.edu fpType dest = func(op1); 10867430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (dest) : "m" (dest)); 10877430Sgblack@eecs.umich.edu 10887430Sgblack@eecs.umich.edu // Get NAN behavior right. This varies between x86 and ARM. 10899515SAli.Saidi@ARM.com if (std::isnan(dest)) { 10907430Sgblack@eecs.umich.edu const uint64_t qnan = 10917430Sgblack@eecs.umich.edu single ? 0x7fc00000 : ULL(0x7ff8000000000000); 10927430Sgblack@eecs.umich.edu const bool nan = std::isnan(op1); 10937430Sgblack@eecs.umich.edu if (!nan || fpscr.dn == 1) { 10947430Sgblack@eecs.umich.edu dest = bitsToFp(qnan, junk); 10957430Sgblack@eecs.umich.edu } else if (nan) { 10967430Sgblack@eecs.umich.edu dest = bitsToFp(fpToBits(op1) | qnan, junk); 10977430Sgblack@eecs.umich.edu } 10987430Sgblack@eecs.umich.edu } else if (flush && flushToZero(dest)) { 10997430Sgblack@eecs.umich.edu feraiseexcept(FeUnderflow); 11007430Sgblack@eecs.umich.edu } else if (( 11017430Sgblack@eecs.umich.edu (single && (dest == bitsToFp(0x00800000, junk) || 11027430Sgblack@eecs.umich.edu dest == bitsToFp(0x80800000, junk))) || 11037430Sgblack@eecs.umich.edu (!single && 11047430Sgblack@eecs.umich.edu (dest == bitsToFp(ULL(0x0010000000000000), junk) || 11057430Sgblack@eecs.umich.edu dest == bitsToFp(ULL(0x8010000000000000), junk))) 11067430Sgblack@eecs.umich.edu ) && rMode != VfpRoundZero) { 11077430Sgblack@eecs.umich.edu /* 11087430Sgblack@eecs.umich.edu * Correct for the fact that underflow is detected -before- rounding 11097430Sgblack@eecs.umich.edu * in ARM and -after- rounding in x86. 11107430Sgblack@eecs.umich.edu */ 11117430Sgblack@eecs.umich.edu fesetround(FeRoundZero); 11127430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (op1) : "m" (op1)); 11137430Sgblack@eecs.umich.edu fpType temp = func(op1); 11147430Sgblack@eecs.umich.edu __asm__ __volatile__ ("" : "=m" (temp) : "m" (temp)); 11157430Sgblack@eecs.umich.edu if (flush && flushToZero(temp)) { 11167430Sgblack@eecs.umich.edu dest = temp; 11177430Sgblack@eecs.umich.edu } 11187430Sgblack@eecs.umich.edu } 11197639Sgblack@eecs.umich.edu finishVfp(fpscr, state, flush); 11207430Sgblack@eecs.umich.edu return dest; 11217430Sgblack@eecs.umich.edu} 11227430Sgblack@eecs.umich.edu 11237430Sgblack@eecs.umich.edutemplate 11247430Sgblack@eecs.umich.edufloat FpOp::unaryOp(FPSCR &fpscr, float op1, float (*func)(float), 11257430Sgblack@eecs.umich.edu bool flush, uint32_t rMode) const; 11267430Sgblack@eecs.umich.edutemplate 11277430Sgblack@eecs.umich.edudouble FpOp::unaryOp(FPSCR &fpscr, double op1, double (*func)(double), 11287430Sgblack@eecs.umich.edu bool flush, uint32_t rMode) const; 11297430Sgblack@eecs.umich.edu 11307430Sgblack@eecs.umich.eduIntRegIndex 11317430Sgblack@eecs.umich.eduVfpMacroOp::addStride(IntRegIndex idx, unsigned stride) 11327430Sgblack@eecs.umich.edu{ 11337430Sgblack@eecs.umich.edu if (wide) { 11347430Sgblack@eecs.umich.edu stride *= 2; 11357430Sgblack@eecs.umich.edu } 11367430Sgblack@eecs.umich.edu unsigned offset = idx % 8; 11377430Sgblack@eecs.umich.edu idx = (IntRegIndex)(idx - offset); 11387430Sgblack@eecs.umich.edu offset += stride; 11397430Sgblack@eecs.umich.edu idx = (IntRegIndex)(idx + (offset % 8)); 11407430Sgblack@eecs.umich.edu return idx; 11417430Sgblack@eecs.umich.edu} 11427430Sgblack@eecs.umich.edu 11437430Sgblack@eecs.umich.eduvoid 11447430Sgblack@eecs.umich.eduVfpMacroOp::nextIdxs(IntRegIndex &dest, IntRegIndex &op1, IntRegIndex &op2) 11457430Sgblack@eecs.umich.edu{ 11467430Sgblack@eecs.umich.edu unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2; 11477430Sgblack@eecs.umich.edu assert(!inScalarBank(dest)); 11487430Sgblack@eecs.umich.edu dest = addStride(dest, stride); 11497430Sgblack@eecs.umich.edu op1 = addStride(op1, stride); 11507430Sgblack@eecs.umich.edu if (!inScalarBank(op2)) { 11517430Sgblack@eecs.umich.edu op2 = addStride(op2, stride); 11527430Sgblack@eecs.umich.edu } 11537430Sgblack@eecs.umich.edu} 11547430Sgblack@eecs.umich.edu 11557430Sgblack@eecs.umich.eduvoid 11567430Sgblack@eecs.umich.eduVfpMacroOp::nextIdxs(IntRegIndex &dest, IntRegIndex &op1) 11577430Sgblack@eecs.umich.edu{ 11587430Sgblack@eecs.umich.edu unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2; 11597430Sgblack@eecs.umich.edu assert(!inScalarBank(dest)); 11607430Sgblack@eecs.umich.edu dest = addStride(dest, stride); 11617430Sgblack@eecs.umich.edu if (!inScalarBank(op1)) { 11627430Sgblack@eecs.umich.edu op1 = addStride(op1, stride); 11637430Sgblack@eecs.umich.edu } 11647430Sgblack@eecs.umich.edu} 11657430Sgblack@eecs.umich.edu 11667430Sgblack@eecs.umich.eduvoid 11677430Sgblack@eecs.umich.eduVfpMacroOp::nextIdxs(IntRegIndex &dest) 11687430Sgblack@eecs.umich.edu{ 11697430Sgblack@eecs.umich.edu unsigned stride = (machInst.fpscrStride == 0) ? 1 : 2; 11707430Sgblack@eecs.umich.edu assert(!inScalarBank(dest)); 11717430Sgblack@eecs.umich.edu dest = addStride(dest, stride); 11727430Sgblack@eecs.umich.edu} 11737430Sgblack@eecs.umich.edu 11747430Sgblack@eecs.umich.edu} 1175