vfp.hh revision 8737:770ccf3af571
1/* 2 * Copyright (c) 2010 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Gabe Black 38 */ 39 40#ifndef __ARCH_ARM_INSTS_VFP_HH__ 41#define __ARCH_ARM_INSTS_VFP_HH__ 42 43#include <fenv.h> 44 45#include <cmath> 46 47#include "arch/arm/insts/misc.hh" 48#include "arch/arm/miscregs.hh" 49 50namespace ArmISA 51{ 52 53enum VfpMicroMode { 54 VfpNotAMicroop, 55 VfpMicroop, 56 VfpFirstMicroop, 57 VfpLastMicroop 58}; 59 60template<class T> 61static inline void 62setVfpMicroFlags(VfpMicroMode mode, T &flags) 63{ 64 switch (mode) { 65 case VfpMicroop: 66 flags[StaticInst::IsMicroop] = true; 67 break; 68 case VfpFirstMicroop: 69 flags[StaticInst::IsMicroop] = 70 flags[StaticInst::IsFirstMicroop] = true; 71 break; 72 case VfpLastMicroop: 73 flags[StaticInst::IsMicroop] = 74 flags[StaticInst::IsLastMicroop] = true; 75 break; 76 case VfpNotAMicroop: 77 break; 78 } 79 if (mode == VfpMicroop || mode == VfpFirstMicroop) { 80 flags[StaticInst::IsDelayedCommit] = true; 81 } 82} 83 84enum FeExceptionBit 85{ 86 FeDivByZero = FE_DIVBYZERO, 87 FeInexact = FE_INEXACT, 88 FeInvalid = FE_INVALID, 89 FeOverflow = FE_OVERFLOW, 90 FeUnderflow = FE_UNDERFLOW, 91 FeAllExceptions = FE_ALL_EXCEPT 92}; 93 94enum FeRoundingMode 95{ 96 FeRoundDown = FE_DOWNWARD, 97 FeRoundNearest = FE_TONEAREST, 98 FeRoundZero = FE_TOWARDZERO, 99 FeRoundUpward = FE_UPWARD 100}; 101 102enum VfpRoundingMode 103{ 104 VfpRoundNearest = 0, 105 VfpRoundUpward = 1, 106 VfpRoundDown = 2, 107 VfpRoundZero = 3 108}; 109 110static inline float bitsToFp(uint64_t, float); 111static inline uint32_t fpToBits(float); 112 113template <class fpType> 114static inline bool 115flushToZero(fpType &op) 116{ 117 fpType junk = 0.0; 118 if (std::fpclassify(op) == FP_SUBNORMAL) { 119 uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1); 120 op = bitsToFp(fpToBits(op) & bitMask, junk); 121 return true; 122 } 123 return false; 124} 125 126template <class fpType> 127static inline bool 128flushToZero(fpType &op1, fpType &op2) 129{ 130 bool flush1 = flushToZero(op1); 131 bool flush2 = flushToZero(op2); 132 return flush1 || flush2; 133} 134 135template <class fpType> 136static inline void 137vfpFlushToZero(FPSCR &fpscr, fpType &op) 138{ 139 if (fpscr.fz == 1 && flushToZero(op)) { 140 fpscr.idc = 1; 141 } 142} 143 144template <class fpType> 145static inline void 146vfpFlushToZero(FPSCR &fpscr, fpType &op1, fpType &op2) 147{ 148 vfpFlushToZero(fpscr, op1); 149 vfpFlushToZero(fpscr, op2); 150} 151 152static inline uint32_t 153fpToBits(float fp) 154{ 155 union 156 { 157 float fp; 158 uint32_t bits; 159 } val; 160 val.fp = fp; 161 return val.bits; 162} 163 164static inline uint64_t 165fpToBits(double fp) 166{ 167 union 168 { 169 double fp; 170 uint64_t bits; 171 } val; 172 val.fp = fp; 173 return val.bits; 174} 175 176static inline float 177bitsToFp(uint64_t bits, float junk) 178{ 179 union 180 { 181 float fp; 182 uint32_t bits; 183 } val; 184 val.bits = bits; 185 return val.fp; 186} 187 188static inline double 189bitsToFp(uint64_t bits, double junk) 190{ 191 union 192 { 193 double fp; 194 uint64_t bits; 195 } val; 196 val.bits = bits; 197 return val.fp; 198} 199 200template <class fpType> 201static bool 202isSnan(fpType val) 203{ 204 const bool single = (sizeof(fpType) == sizeof(float)); 205 const uint64_t qnan = 206 single ? 0x7fc00000 : ULL(0x7ff8000000000000); 207 return std::isnan(val) && ((fpToBits(val) & qnan) != qnan); 208} 209 210typedef int VfpSavedState; 211 212VfpSavedState prepFpState(uint32_t rMode); 213void finishVfp(FPSCR &fpscr, VfpSavedState state, bool flush); 214 215template <class fpType> 216fpType fixDest(FPSCR fpscr, fpType val, fpType op1); 217 218template <class fpType> 219fpType fixDest(FPSCR fpscr, fpType val, fpType op1, fpType op2); 220 221template <class fpType> 222fpType fixDivDest(FPSCR fpscr, fpType val, fpType op1, fpType op2); 223 224float fixFpDFpSDest(FPSCR fpscr, double val); 225double fixFpSFpDDest(FPSCR fpscr, float val); 226 227uint16_t vcvtFpSFpH(FPSCR &fpscr, bool flush, bool defaultNan, 228 uint32_t rMode, bool ahp, float op); 229float vcvtFpHFpS(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op); 230 231static inline double 232makeDouble(uint32_t low, uint32_t high) 233{ 234 double junk = 0.0; 235 return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk); 236} 237 238static inline uint32_t 239lowFromDouble(double val) 240{ 241 return fpToBits(val); 242} 243 244static inline uint32_t 245highFromDouble(double val) 246{ 247 return fpToBits(val) >> 32; 248} 249 250uint64_t vfpFpSToFixed(float val, bool isSigned, bool half, 251 uint8_t imm, bool rzero = true); 252float vfpUFixedToFpS(bool flush, bool defaultNan, 253 uint32_t val, bool half, uint8_t imm); 254float vfpSFixedToFpS(bool flush, bool defaultNan, 255 int32_t val, bool half, uint8_t imm); 256 257uint64_t vfpFpDToFixed(double val, bool isSigned, bool half, 258 uint8_t imm, bool rzero = true); 259double vfpUFixedToFpD(bool flush, bool defaultNan, 260 uint32_t val, bool half, uint8_t imm); 261double vfpSFixedToFpD(bool flush, bool defaultNan, 262 int32_t val, bool half, uint8_t imm); 263 264float fprSqrtEstimate(FPSCR &fpscr, float op); 265uint32_t unsignedRSqrtEstimate(uint32_t op); 266 267float fpRecipEstimate(FPSCR &fpscr, float op); 268uint32_t unsignedRecipEstimate(uint32_t op); 269 270class VfpMacroOp : public PredMacroOp 271{ 272 public: 273 static bool 274 inScalarBank(IntRegIndex idx) 275 { 276 return (idx % 32) < 8; 277 } 278 279 protected: 280 bool wide; 281 282 VfpMacroOp(const char *mnem, ExtMachInst _machInst, 283 OpClass __opClass, bool _wide) : 284 PredMacroOp(mnem, _machInst, __opClass), wide(_wide) 285 {} 286 287 IntRegIndex addStride(IntRegIndex idx, unsigned stride); 288 void nextIdxs(IntRegIndex &dest, IntRegIndex &op1, IntRegIndex &op2); 289 void nextIdxs(IntRegIndex &dest, IntRegIndex &op1); 290 void nextIdxs(IntRegIndex &dest); 291}; 292 293static inline float 294fpAddS(float a, float b) 295{ 296 return a + b; 297} 298 299static inline double 300fpAddD(double a, double b) 301{ 302 return a + b; 303} 304 305static inline float 306fpSubS(float a, float b) 307{ 308 return a - b; 309} 310 311static inline double 312fpSubD(double a, double b) 313{ 314 return a - b; 315} 316 317static inline float 318fpDivS(float a, float b) 319{ 320 return a / b; 321} 322 323static inline double 324fpDivD(double a, double b) 325{ 326 return a / b; 327} 328 329static inline float 330fpMulS(float a, float b) 331{ 332 return a * b; 333} 334 335static inline double 336fpMulD(double a, double b) 337{ 338 return a * b; 339} 340 341static inline float 342fpMaxS(float a, float b) 343{ 344 // Handle comparisons of +0 and -0. 345 if (!std::signbit(a) && std::signbit(b)) 346 return a; 347 return fmaxf(a, b); 348} 349 350static inline float 351fpMinS(float a, float b) 352{ 353 // Handle comparisons of +0 and -0. 354 if (std::signbit(a) && !std::signbit(b)) 355 return a; 356 return fminf(a, b); 357} 358 359static inline float 360fpRSqrtsS(float a, float b) 361{ 362 int fpClassA = std::fpclassify(a); 363 int fpClassB = std::fpclassify(b); 364 float aXb; 365 int fpClassAxB; 366 367 if ((fpClassA == FP_ZERO && fpClassB == FP_INFINITE) || 368 (fpClassA == FP_INFINITE && fpClassB == FP_ZERO)) { 369 return 1.5; 370 } 371 aXb = a*b; 372 fpClassAxB = std::fpclassify(aXb); 373 if(fpClassAxB == FP_SUBNORMAL) { 374 feraiseexcept(FeUnderflow); 375 return 1.5; 376 } 377 return (3.0 - (a * b)) / 2.0; 378} 379 380static inline float 381fpRecpsS(float a, float b) 382{ 383 int fpClassA = std::fpclassify(a); 384 int fpClassB = std::fpclassify(b); 385 float aXb; 386 int fpClassAxB; 387 388 if ((fpClassA == FP_ZERO && fpClassB == FP_INFINITE) || 389 (fpClassA == FP_INFINITE && fpClassB == FP_ZERO)) { 390 return 2.0; 391 } 392 aXb = a*b; 393 fpClassAxB = std::fpclassify(aXb); 394 if(fpClassAxB == FP_SUBNORMAL) { 395 feraiseexcept(FeUnderflow); 396 return 2.0; 397 } 398 return 2.0 - (a * b); 399} 400 401class FpOp : public PredOp 402{ 403 protected: 404 FpOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) : 405 PredOp(mnem, _machInst, __opClass) 406 {} 407 408 virtual float 409 doOp(float op1, float op2) const 410 { 411 panic("Unimplemented version of doOp called.\n"); 412 } 413 414 virtual float 415 doOp(float op1) const 416 { 417 panic("Unimplemented version of doOp called.\n"); 418 } 419 420 virtual double 421 doOp(double op1, double op2) const 422 { 423 panic("Unimplemented version of doOp called.\n"); 424 } 425 426 virtual double 427 doOp(double op1) const 428 { 429 panic("Unimplemented version of doOp called.\n"); 430 } 431 432 double 433 dbl(uint32_t low, uint32_t high) const 434 { 435 double junk = 0.0; 436 return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk); 437 } 438 439 uint32_t 440 dblLow(double val) const 441 { 442 return fpToBits(val); 443 } 444 445 uint32_t 446 dblHi(double val) const 447 { 448 return fpToBits(val) >> 32; 449 } 450 451 template <class fpType> 452 fpType 453 processNans(FPSCR &fpscr, bool &done, bool defaultNan, 454 fpType op1, fpType op2) const; 455 456 template <class fpType> 457 fpType 458 binaryOp(FPSCR &fpscr, fpType op1, fpType op2, 459 fpType (*func)(fpType, fpType), 460 bool flush, bool defaultNan, uint32_t rMode) const; 461 462 template <class fpType> 463 fpType 464 unaryOp(FPSCR &fpscr, fpType op1, 465 fpType (*func)(fpType), 466 bool flush, uint32_t rMode) const; 467 468 void 469 advancePC(PCState &pcState) const 470 { 471 if (flags[IsLastMicroop]) { 472 pcState.uEnd(); 473 } else if (flags[IsMicroop]) { 474 pcState.uAdvance(); 475 } else { 476 pcState.advance(); 477 } 478 } 479}; 480 481class FpRegRegOp : public FpOp 482{ 483 protected: 484 IntRegIndex dest; 485 IntRegIndex op1; 486 487 FpRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, 488 IntRegIndex _dest, IntRegIndex _op1, 489 VfpMicroMode mode = VfpNotAMicroop) : 490 FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1) 491 { 492 setVfpMicroFlags(mode, flags); 493 } 494 495 std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; 496}; 497 498class FpRegImmOp : public FpOp 499{ 500 protected: 501 IntRegIndex dest; 502 uint64_t imm; 503 504 FpRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, 505 IntRegIndex _dest, uint64_t _imm, 506 VfpMicroMode mode = VfpNotAMicroop) : 507 FpOp(mnem, _machInst, __opClass), dest(_dest), imm(_imm) 508 { 509 setVfpMicroFlags(mode, flags); 510 } 511 512 std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; 513}; 514 515class FpRegRegImmOp : public FpOp 516{ 517 protected: 518 IntRegIndex dest; 519 IntRegIndex op1; 520 uint64_t imm; 521 522 FpRegRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, 523 IntRegIndex _dest, IntRegIndex _op1, 524 uint64_t _imm, VfpMicroMode mode = VfpNotAMicroop) : 525 FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), imm(_imm) 526 { 527 setVfpMicroFlags(mode, flags); 528 } 529 530 std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; 531}; 532 533class FpRegRegRegOp : public FpOp 534{ 535 protected: 536 IntRegIndex dest; 537 IntRegIndex op1; 538 IntRegIndex op2; 539 540 FpRegRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, 541 IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2, 542 VfpMicroMode mode = VfpNotAMicroop) : 543 FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), op2(_op2) 544 { 545 setVfpMicroFlags(mode, flags); 546 } 547 548 std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; 549}; 550 551class FpRegRegRegImmOp : public FpOp 552{ 553 protected: 554 IntRegIndex dest; 555 IntRegIndex op1; 556 IntRegIndex op2; 557 uint64_t imm; 558 559 FpRegRegRegImmOp(const char *mnem, ExtMachInst _machInst, 560 OpClass __opClass, IntRegIndex _dest, 561 IntRegIndex _op1, IntRegIndex _op2, 562 uint64_t _imm, VfpMicroMode mode = VfpNotAMicroop) : 563 FpOp(mnem, _machInst, __opClass), 564 dest(_dest), op1(_op1), op2(_op2), imm(_imm) 565 { 566 setVfpMicroFlags(mode, flags); 567 } 568 569 std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; 570}; 571 572} 573 574#endif //__ARCH_ARM_INSTS_VFP_HH__ 575