vfp.hh revision 8229
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 110template <class fpType> 111static inline bool 112flushToZero(fpType &op) 113{ 114 fpType junk = 0.0; 115 if (std::fpclassify(op) == FP_SUBNORMAL) { 116 uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1); 117 op = bitsToFp(fpToBits(op) & bitMask, junk); 118 return true; 119 } 120 return false; 121} 122 123template <class fpType> 124static inline bool 125flushToZero(fpType &op1, fpType &op2) 126{ 127 bool flush1 = flushToZero(op1); 128 bool flush2 = flushToZero(op2); 129 return flush1 || flush2; 130} 131 132template <class fpType> 133static inline void 134vfpFlushToZero(FPSCR &fpscr, fpType &op) 135{ 136 if (fpscr.fz == 1 && flushToZero(op)) { 137 fpscr.idc = 1; 138 } 139} 140 141template <class fpType> 142static inline void 143vfpFlushToZero(FPSCR &fpscr, fpType &op1, fpType &op2) 144{ 145 vfpFlushToZero(fpscr, op1); 146 vfpFlushToZero(fpscr, op2); 147} 148 149static inline uint32_t 150fpToBits(float fp) 151{ 152 union 153 { 154 float fp; 155 uint32_t bits; 156 } val; 157 val.fp = fp; 158 return val.bits; 159} 160 161static inline uint64_t 162fpToBits(double fp) 163{ 164 union 165 { 166 double fp; 167 uint64_t bits; 168 } val; 169 val.fp = fp; 170 return val.bits; 171} 172 173static inline float 174bitsToFp(uint64_t bits, float junk) 175{ 176 union 177 { 178 float fp; 179 uint32_t bits; 180 } val; 181 val.bits = bits; 182 return val.fp; 183} 184 185static inline double 186bitsToFp(uint64_t bits, double junk) 187{ 188 union 189 { 190 double fp; 191 uint64_t bits; 192 } val; 193 val.bits = bits; 194 return val.fp; 195} 196 197template <class fpType> 198static bool 199isSnan(fpType val) 200{ 201 const bool single = (sizeof(fpType) == sizeof(float)); 202 const uint64_t qnan = 203 single ? 0x7fc00000 : ULL(0x7ff8000000000000); 204 return std::isnan(val) && ((fpToBits(val) & qnan) != qnan); 205} 206 207typedef int VfpSavedState; 208 209VfpSavedState prepFpState(uint32_t rMode); 210void finishVfp(FPSCR &fpscr, VfpSavedState state, bool flush); 211 212template <class fpType> 213fpType fixDest(FPSCR fpscr, fpType val, fpType op1); 214 215template <class fpType> 216fpType fixDest(FPSCR fpscr, fpType val, fpType op1, fpType op2); 217 218template <class fpType> 219fpType fixDivDest(FPSCR fpscr, fpType val, fpType op1, fpType op2); 220 221float fixFpDFpSDest(FPSCR fpscr, double val); 222double fixFpSFpDDest(FPSCR fpscr, float val); 223 224uint16_t vcvtFpSFpH(FPSCR &fpscr, bool flush, bool defaultNan, 225 uint32_t rMode, bool ahp, float op); 226float vcvtFpHFpS(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op); 227 228static inline double 229makeDouble(uint32_t low, uint32_t high) 230{ 231 double junk = 0.0; 232 return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk); 233} 234 235static inline uint32_t 236lowFromDouble(double val) 237{ 238 return fpToBits(val); 239} 240 241static inline uint32_t 242highFromDouble(double val) 243{ 244 return fpToBits(val) >> 32; 245} 246 247uint64_t vfpFpSToFixed(float val, bool isSigned, bool half, 248 uint8_t imm, bool rzero = true); 249float vfpUFixedToFpS(bool flush, bool defaultNan, 250 uint32_t val, bool half, uint8_t imm); 251float vfpSFixedToFpS(bool flush, bool defaultNan, 252 int32_t val, bool half, uint8_t imm); 253 254uint64_t vfpFpDToFixed(double val, bool isSigned, bool half, 255 uint8_t imm, bool rzero = true); 256double vfpUFixedToFpD(bool flush, bool defaultNan, 257 uint32_t val, bool half, uint8_t imm); 258double vfpSFixedToFpD(bool flush, bool defaultNan, 259 int32_t val, bool half, uint8_t imm); 260 261float fprSqrtEstimate(FPSCR &fpscr, float op); 262uint32_t unsignedRSqrtEstimate(uint32_t op); 263 264float fpRecipEstimate(FPSCR &fpscr, float op); 265uint32_t unsignedRecipEstimate(uint32_t op); 266 267class VfpMacroOp : public PredMacroOp 268{ 269 public: 270 static bool 271 inScalarBank(IntRegIndex idx) 272 { 273 return (idx % 32) < 8; 274 } 275 276 protected: 277 bool wide; 278 279 VfpMacroOp(const char *mnem, ExtMachInst _machInst, 280 OpClass __opClass, bool _wide) : 281 PredMacroOp(mnem, _machInst, __opClass), wide(_wide) 282 {} 283 284 IntRegIndex addStride(IntRegIndex idx, unsigned stride); 285 void nextIdxs(IntRegIndex &dest, IntRegIndex &op1, IntRegIndex &op2); 286 void nextIdxs(IntRegIndex &dest, IntRegIndex &op1); 287 void nextIdxs(IntRegIndex &dest); 288}; 289 290static inline float 291fpAddS(float a, float b) 292{ 293 return a + b; 294} 295 296static inline double 297fpAddD(double a, double b) 298{ 299 return a + b; 300} 301 302static inline float 303fpSubS(float a, float b) 304{ 305 return a - b; 306} 307 308static inline double 309fpSubD(double a, double b) 310{ 311 return a - b; 312} 313 314static inline float 315fpDivS(float a, float b) 316{ 317 return a / b; 318} 319 320static inline double 321fpDivD(double a, double b) 322{ 323 return a / b; 324} 325 326static inline float 327fpMulS(float a, float b) 328{ 329 return a * b; 330} 331 332static inline double 333fpMulD(double a, double b) 334{ 335 return a * b; 336} 337 338static inline float 339fpMaxS(float a, float b) 340{ 341 // Handle comparisons of +0 and -0. 342 if (!std::signbit(a) && std::signbit(b)) 343 return a; 344 return fmaxf(a, b); 345} 346 347static inline float 348fpMinS(float a, float b) 349{ 350 // Handle comparisons of +0 and -0. 351 if (std::signbit(a) && !std::signbit(b)) 352 return a; 353 return fminf(a, b); 354} 355 356static inline float 357fpRSqrtsS(float a, float b) 358{ 359 int fpClassA = std::fpclassify(a); 360 int fpClassB = std::fpclassify(b); 361 float aXb; 362 int fpClassAxB; 363 364 if ((fpClassA == FP_ZERO && fpClassB == FP_INFINITE) || 365 (fpClassA == FP_INFINITE && fpClassB == FP_ZERO)) { 366 return 1.5; 367 } 368 aXb = a*b; 369 fpClassAxB = std::fpclassify(aXb); 370 if(fpClassAxB == FP_SUBNORMAL) { 371 feraiseexcept(FeUnderflow); 372 return 1.5; 373 } 374 return (3.0 - (a * b)) / 2.0; 375} 376 377static inline float 378fpRecpsS(float a, float b) 379{ 380 int fpClassA = std::fpclassify(a); 381 int fpClassB = std::fpclassify(b); 382 float aXb; 383 int fpClassAxB; 384 385 if ((fpClassA == FP_ZERO && fpClassB == FP_INFINITE) || 386 (fpClassA == FP_INFINITE && fpClassB == FP_ZERO)) { 387 return 2.0; 388 } 389 aXb = a*b; 390 fpClassAxB = std::fpclassify(aXb); 391 if(fpClassAxB == FP_SUBNORMAL) { 392 feraiseexcept(FeUnderflow); 393 return 2.0; 394 } 395 return 2.0 - (a * b); 396} 397 398class FpOp : public PredOp 399{ 400 protected: 401 FpOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) : 402 PredOp(mnem, _machInst, __opClass) 403 {} 404 405 virtual float 406 doOp(float op1, float op2) const 407 { 408 panic("Unimplemented version of doOp called.\n"); 409 } 410 411 virtual float 412 doOp(float op1) const 413 { 414 panic("Unimplemented version of doOp called.\n"); 415 } 416 417 virtual double 418 doOp(double op1, double op2) const 419 { 420 panic("Unimplemented version of doOp called.\n"); 421 } 422 423 virtual double 424 doOp(double op1) const 425 { 426 panic("Unimplemented version of doOp called.\n"); 427 } 428 429 double 430 dbl(uint32_t low, uint32_t high) const 431 { 432 double junk = 0.0; 433 return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk); 434 } 435 436 uint32_t 437 dblLow(double val) const 438 { 439 return fpToBits(val); 440 } 441 442 uint32_t 443 dblHi(double val) const 444 { 445 return fpToBits(val) >> 32; 446 } 447 448 template <class fpType> 449 fpType 450 processNans(FPSCR &fpscr, bool &done, bool defaultNan, 451 fpType op1, fpType op2) const; 452 453 template <class fpType> 454 fpType 455 binaryOp(FPSCR &fpscr, fpType op1, fpType op2, 456 fpType (*func)(fpType, fpType), 457 bool flush, bool defaultNan, uint32_t rMode) const; 458 459 template <class fpType> 460 fpType 461 unaryOp(FPSCR &fpscr, fpType op1, 462 fpType (*func)(fpType), 463 bool flush, uint32_t rMode) const; 464 465 void 466 advancePC(PCState &pcState) const 467 { 468 if (flags[IsLastMicroop]) { 469 pcState.uEnd(); 470 } else if (flags[IsMicroop]) { 471 pcState.uAdvance(); 472 } else { 473 pcState.advance(); 474 } 475 } 476}; 477 478class FpRegRegOp : public FpOp 479{ 480 protected: 481 IntRegIndex dest; 482 IntRegIndex op1; 483 484 FpRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, 485 IntRegIndex _dest, IntRegIndex _op1, 486 VfpMicroMode mode = VfpNotAMicroop) : 487 FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1) 488 { 489 setVfpMicroFlags(mode, flags); 490 } 491 492 std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; 493}; 494 495class FpRegImmOp : public FpOp 496{ 497 protected: 498 IntRegIndex dest; 499 uint64_t imm; 500 501 FpRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, 502 IntRegIndex _dest, uint64_t _imm, 503 VfpMicroMode mode = VfpNotAMicroop) : 504 FpOp(mnem, _machInst, __opClass), dest(_dest), imm(_imm) 505 { 506 setVfpMicroFlags(mode, flags); 507 } 508 509 std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; 510}; 511 512class FpRegRegImmOp : public FpOp 513{ 514 protected: 515 IntRegIndex dest; 516 IntRegIndex op1; 517 uint64_t imm; 518 519 FpRegRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, 520 IntRegIndex _dest, IntRegIndex _op1, 521 uint64_t _imm, VfpMicroMode mode = VfpNotAMicroop) : 522 FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), imm(_imm) 523 { 524 setVfpMicroFlags(mode, flags); 525 } 526 527 std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; 528}; 529 530class FpRegRegRegOp : public FpOp 531{ 532 protected: 533 IntRegIndex dest; 534 IntRegIndex op1; 535 IntRegIndex op2; 536 537 FpRegRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, 538 IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2, 539 VfpMicroMode mode = VfpNotAMicroop) : 540 FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), op2(_op2) 541 { 542 setVfpMicroFlags(mode, flags); 543 } 544 545 std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; 546}; 547 548class FpRegRegRegImmOp : public FpOp 549{ 550 protected: 551 IntRegIndex dest; 552 IntRegIndex op1; 553 IntRegIndex op2; 554 uint64_t imm; 555 556 FpRegRegRegImmOp(const char *mnem, ExtMachInst _machInst, 557 OpClass __opClass, IntRegIndex _dest, 558 IntRegIndex _op1, IntRegIndex _op2, 559 uint64_t _imm, VfpMicroMode mode = VfpNotAMicroop) : 560 FpOp(mnem, _machInst, __opClass), 561 dest(_dest), op1(_op1), op2(_op2), imm(_imm) 562 { 563 setVfpMicroFlags(mode, flags); 564 } 565 566 std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; 567}; 568 569} 570 571#endif //__ARCH_ARM_INSTS_VFP_HH__ 572