1/* 2 * Copyright (c) 2010-2013, 2019 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 VfpRoundAway = 4 109}; 110 111static inline float bitsToFp(uint64_t, float); 112static inline double bitsToFp(uint64_t, double); 113static inline uint32_t fpToBits(float); 114static inline uint64_t fpToBits(double); 115 116template <class fpType> 117static inline bool 118flushToZero(fpType &op) 119{ 120 fpType junk = 0.0; 121 if (std::fpclassify(op) == FP_SUBNORMAL) { 122 uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1); 123 op = bitsToFp(fpToBits(op) & bitMask, junk); 124 return true; 125 } 126 return false; 127} 128 129template <class fpType> 130static inline bool 131flushToZero(fpType &op1, fpType &op2) 132{ 133 bool flush1 = flushToZero(op1); 134 bool flush2 = flushToZero(op2); 135 return flush1 || flush2; 136} 137 138template <class fpType> 139static inline void 140vfpFlushToZero(FPSCR &fpscr, fpType &op) 141{ 142 if (fpscr.fz == 1 && flushToZero(op)) { 143 fpscr.idc = 1; 144 } 145} 146 147template <class fpType> 148static inline void 149vfpFlushToZero(FPSCR &fpscr, fpType &op1, fpType &op2) 150{ 151 vfpFlushToZero(fpscr, op1); 152 vfpFlushToZero(fpscr, op2); 153} 154 155static inline uint32_t 156fpToBits(float fp) 157{ 158 union 159 { 160 float fp; 161 uint32_t bits; 162 } val; 163 val.fp = fp; 164 return val.bits; 165} 166 167static inline uint64_t 168fpToBits(double fp) 169{ 170 union 171 { 172 double fp; 173 uint64_t bits; 174 } val; 175 val.fp = fp; 176 return val.bits; 177} 178 179static inline float 180bitsToFp(uint64_t bits, float junk) 181{ 182 union 183 { 184 float fp; 185 uint32_t bits; 186 } val; 187 val.bits = bits; 188 return val.fp; 189} 190 191static inline double 192bitsToFp(uint64_t bits, double junk) 193{ 194 union 195 { 196 double fp; 197 uint64_t bits; 198 } val; 199 val.bits = bits; 200 return val.fp; 201} 202 203template <class fpType> 204static inline bool 205isSnan(fpType val) 206{ 207 const bool single = (sizeof(fpType) == sizeof(float)); 208 const uint64_t qnan = 209 single ? 0x7fc00000 : ULL(0x7ff8000000000000); 210 return std::isnan(val) && ((fpToBits(val) & qnan) != qnan); 211} 212 213typedef int VfpSavedState; 214 215VfpSavedState prepFpState(uint32_t rMode); 216void finishVfp(FPSCR &fpscr, VfpSavedState state, bool flush, FPSCR mask = FpscrExcMask); 217 218template <class fpType> 219fpType fixDest(FPSCR fpscr, fpType val, fpType op1); 220 221template <class fpType> 222fpType fixDest(FPSCR fpscr, fpType val, fpType op1, fpType op2); 223 224template <class fpType> 225fpType fixDivDest(FPSCR fpscr, fpType val, fpType op1, fpType op2); 226 227float fixFpDFpSDest(FPSCR fpscr, double val); 228double fixFpSFpDDest(FPSCR fpscr, float val); 229 230uint16_t vcvtFpSFpH(FPSCR &fpscr, bool flush, bool defaultNan, 231 uint32_t rMode, bool ahp, float op); 232uint16_t vcvtFpDFpH(FPSCR &fpscr, bool flush, bool defaultNan, 233 uint32_t rMode, bool ahp, double op); 234 235float vcvtFpHFpS(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op); 236double vcvtFpHFpD(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op); 237 238static inline double 239makeDouble(uint32_t low, uint32_t high) 240{ 241 double junk = 0.0; 242 return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk); 243} 244 245static inline uint32_t 246lowFromDouble(double val) 247{ 248 return fpToBits(val); 249} 250 251static inline uint32_t 252highFromDouble(double val) 253{ 254 return fpToBits(val) >> 32; 255} 256 257static inline void 258setFPExceptions(int exceptions) { 259 feclearexcept(FeAllExceptions); 260 feraiseexcept(exceptions); 261} 262 263template <typename T> 264uint64_t 265vfpFpToFixed(T val, bool isSigned, uint8_t width, uint8_t imm, bool 266 useRmode = true, VfpRoundingMode roundMode = VfpRoundZero, 267 bool aarch64 = false) 268{ 269 int rmode; 270 bool roundAwayFix = false; 271 272 if (!useRmode) { 273 rmode = fegetround(); 274 } else { 275 switch (roundMode) 276 { 277 case VfpRoundNearest: 278 rmode = FeRoundNearest; 279 break; 280 case VfpRoundUpward: 281 rmode = FeRoundUpward; 282 break; 283 case VfpRoundDown: 284 rmode = FeRoundDown; 285 break; 286 case VfpRoundZero: 287 rmode = FeRoundZero; 288 break; 289 case VfpRoundAway: 290 // There is no equivalent rounding mode, use round down and we'll 291 // fix it later 292 rmode = FeRoundDown; 293 roundAwayFix = true; 294 break; 295 default: 296 panic("Unsupported roundMode %d\n", roundMode); 297 } 298 } 299 __asm__ __volatile__("" : "=m" (rmode) : "m" (rmode)); 300 fesetround(FeRoundNearest); 301 val = val * pow(2.0, imm); 302 __asm__ __volatile__("" : "=m" (val) : "m" (val)); 303 fesetround(rmode); 304 feclearexcept(FeAllExceptions); 305 __asm__ __volatile__("" : "=m" (val) : "m" (val)); 306 T origVal = val; 307 val = rint(val); 308 __asm__ __volatile__("" : "=m" (val) : "m" (val)); 309 310 int exceptions = fetestexcept(FeAllExceptions); 311 312 int fpType = std::fpclassify(val); 313 if (fpType == FP_SUBNORMAL || fpType == FP_NAN) { 314 if (fpType == FP_NAN) { 315 exceptions |= FeInvalid; 316 } 317 val = 0.0; 318 } else if (origVal != val) { 319 switch (rmode) { 320 case FeRoundNearest: 321 if (origVal - val > 0.5) 322 val += 1.0; 323 else if (val - origVal > 0.5) 324 val -= 1.0; 325 break; 326 case FeRoundDown: 327 if (roundAwayFix) { 328 // The ordering on the subtraction looks a bit odd in that we 329 // don't do the obvious origVal - val, instead we do 330 // -(val - origVal). This is required to get the corruct bit 331 // exact behaviour when very close to the 0.5 threshold. 332 volatile T error = val; 333 error -= origVal; 334 error = -error; 335 if ( (error > 0.5) || 336 ((error == 0.5) && (val >= 0)) ) 337 val += 1.0; 338 } else { 339 if (origVal < val) 340 val -= 1.0; 341 } 342 break; 343 case FeRoundUpward: 344 if (origVal > val) 345 val += 1.0; 346 break; 347 } 348 exceptions |= FeInexact; 349 } 350 351 __asm__ __volatile__("" : "=m" (val) : "m" (val)); 352 353 if (isSigned) { 354 bool outOfRange = false; 355 int64_t result = (int64_t) val; 356 uint64_t finalVal; 357 358 if (!aarch64) { 359 if (width == 16) { 360 finalVal = (int16_t)val; 361 } else if (width == 32) { 362 finalVal =(int32_t)val; 363 } else if (width == 64) { 364 finalVal = result; 365 } else { 366 panic("Unsupported width %d\n", width); 367 } 368 369 // check if value is in range 370 int64_t minVal = ~mask(width-1); 371 if ((double)val < minVal) { 372 outOfRange = true; 373 finalVal = minVal; 374 } 375 int64_t maxVal = mask(width-1); 376 if ((double)val > maxVal) { 377 outOfRange = true; 378 finalVal = maxVal; 379 } 380 } else { 381 bool isNeg = val < 0; 382 finalVal = result & mask(width); 383 // If the result is supposed to be less than 64 bits check that the 384 // upper bits that got thrown away are just sign extension bits 385 if (width != 64) { 386 outOfRange = ((uint64_t) result >> (width - 1)) != 387 (isNeg ? mask(64-width+1) : 0); 388 } 389 // Check if the original floating point value doesn't matches the 390 // integer version we are also out of range. So create a saturated 391 // result. 392 if (isNeg) { 393 outOfRange |= val < result; 394 if (outOfRange) { 395 finalVal = 1LL << (width-1); 396 } 397 } else { 398 outOfRange |= val > result; 399 if (outOfRange) { 400 finalVal = mask(width-1); 401 } 402 } 403 } 404 405 // Raise an exception if the value was out of range 406 if (outOfRange) { 407 exceptions |= FeInvalid; 408 exceptions &= ~FeInexact; 409 } 410 setFPExceptions(exceptions); 411 return finalVal; 412 } else { 413 if ((double)val < 0) { 414 exceptions |= FeInvalid; 415 exceptions &= ~FeInexact; 416 setFPExceptions(exceptions); 417 return 0; 418 } 419 420 uint64_t result = ((uint64_t) val) & mask(width); 421 if (val > result) { 422 exceptions |= FeInvalid; 423 exceptions &= ~FeInexact; 424 setFPExceptions(exceptions); 425 return mask(width); 426 } 427 428 setFPExceptions(exceptions); 429 return result; 430 } 431}; 432 433 434float vfpUFixedToFpS(bool flush, bool defaultNan, 435 uint64_t val, uint8_t width, uint8_t imm); 436float vfpSFixedToFpS(bool flush, bool defaultNan, 437 int64_t val, uint8_t width, uint8_t imm); 438 439double vfpUFixedToFpD(bool flush, bool defaultNan, 440 uint64_t val, uint8_t width, uint8_t imm); 441double vfpSFixedToFpD(bool flush, bool defaultNan, 442 int64_t val, uint8_t width, uint8_t imm); 443 444float fprSqrtEstimate(FPSCR &fpscr, float op); 445uint32_t unsignedRSqrtEstimate(uint32_t op); 446 447float fpRecipEstimate(FPSCR &fpscr, float op); 448uint32_t unsignedRecipEstimate(uint32_t op); 449 450FPSCR 451fpStandardFPSCRValue(const FPSCR &fpscr); 452 453class VfpMacroOp : public PredMacroOp 454{ 455 public: 456 static bool 457 inScalarBank(IntRegIndex idx) 458 { 459 return (idx % 32) < 8; 460 } 461 462 protected: 463 bool wide; 464 465 VfpMacroOp(const char *mnem, ExtMachInst _machInst, 466 OpClass __opClass, bool _wide) : 467 PredMacroOp(mnem, _machInst, __opClass), wide(_wide) 468 {} 469 470 IntRegIndex addStride(IntRegIndex idx, unsigned stride); 471 void nextIdxs(IntRegIndex &dest, IntRegIndex &op1, IntRegIndex &op2); 472 void nextIdxs(IntRegIndex &dest, IntRegIndex &op1); 473 void nextIdxs(IntRegIndex &dest); 474}; 475 476template <typename T> 477static inline T 478fpAdd(T a, T b) 479{ 480 return a + b; 481}; 482 483template <typename T> 484static inline T 485fpSub(T a, T b) 486{ 487 return a - b; 488}; 489 490static inline float 491fpAddS(float a, float b) 492{ 493 return a + b; 494} 495 496static inline double 497fpAddD(double a, double b) 498{ 499 return a + b; 500} 501 502static inline float 503fpSubS(float a, float b) 504{ 505 return a - b; 506} 507 508static inline double 509fpSubD(double a, double b) 510{ 511 return a - b; 512} 513 514static inline float 515fpDivS(float a, float b) 516{ 517 return a / b; 518} 519 520static inline double 521fpDivD(double a, double b) 522{ 523 return a / b; 524} 525 526template <typename T> 527static inline T 528fpDiv(T a, T b) 529{ 530 return a / b; 531}; 532 533template <typename T> 534static inline T 535fpMulX(T a, T b) 536{ 537 uint64_t opData; 538 uint32_t sign1; 539 uint32_t sign2; 540 const bool single = (sizeof(T) == sizeof(float)); 541 if (single) { 542 opData = (fpToBits(a)); 543 sign1 = opData>>31; 544 opData = (fpToBits(b)); 545 sign2 = opData>>31; 546 } else { 547 opData = (fpToBits(a)); 548 sign1 = opData>>63; 549 opData = (fpToBits(b)); 550 sign2 = opData>>63; 551 } 552 bool inf1 = (std::fpclassify(a) == FP_INFINITE); 553 bool inf2 = (std::fpclassify(b) == FP_INFINITE); 554 bool zero1 = (std::fpclassify(a) == FP_ZERO); 555 bool zero2 = (std::fpclassify(b) == FP_ZERO); 556 if ((inf1 && zero2) || (zero1 && inf2)) { 557 if (sign1 ^ sign2) 558 return (T)(-2.0); 559 else 560 return (T)(2.0); 561 } else { 562 return (a * b); 563 } 564}; 565 566 567template <typename T> 568static inline T 569fpMul(T a, T b) 570{ 571 return a * b; 572}; 573 574static inline float 575fpMulS(float a, float b) 576{ 577 return a * b; 578} 579 580static inline double 581fpMulD(double a, double b) 582{ 583 return a * b; 584} 585 586template <typename T> 587static inline T 588// @todo remove this when all calls to it have been replaced with the new fplib implementation 589fpMulAdd(T op1, T op2, T addend) 590{ 591 T result; 592 593 if (sizeof(T) == sizeof(float)) 594 result = fmaf(op1, op2, addend); 595 else 596 result = fma(op1, op2, addend); 597 598 // ARM doesn't generate signed nan's from this opperation, so fix up the result 599 if (std::isnan(result) && !std::isnan(op1) && 600 !std::isnan(op2) && !std::isnan(addend)) 601 { 602 uint64_t bitMask = ULL(0x1) << ((sizeof(T) * 8) - 1); 603 result = bitsToFp(fpToBits(result) & ~bitMask, op1); 604 } 605 return result; 606} 607 608template <typename T> 609static inline T 610fpRIntX(T a, FPSCR &fpscr) 611{ 612 T rVal; 613 614 rVal = rint(a); 615 if (rVal != a && !std::isnan(a)) 616 fpscr.ixc = 1; 617 return (rVal); 618}; 619 620template <typename T> 621static inline T 622fpMaxNum(T a, T b) 623{ 624 const bool single = (sizeof(T) == sizeof(float)); 625 const uint64_t qnan = single ? 0x7fc00000 : ULL(0x7ff8000000000000); 626 627 if (std::isnan(a)) 628 return ((fpToBits(a) & qnan) == qnan) ? b : a; 629 if (std::isnan(b)) 630 return ((fpToBits(b) & qnan) == qnan) ? a : b; 631 // Handle comparisons of +0 and -0. 632 if (!std::signbit(a) && std::signbit(b)) 633 return a; 634 return fmax(a, b); 635}; 636 637template <typename T> 638static inline T 639fpMax(T a, T b) 640{ 641 if (std::isnan(a)) 642 return a; 643 if (std::isnan(b)) 644 return b; 645 return fpMaxNum<T>(a, b); 646}; 647 648template <typename T> 649static inline T 650fpMinNum(T a, T b) 651{ 652 const bool single = (sizeof(T) == sizeof(float)); 653 const uint64_t qnan = single ? 0x7fc00000 : ULL(0x7ff8000000000000); 654 655 if (std::isnan(a)) 656 return ((fpToBits(a) & qnan) == qnan) ? b : a; 657 if (std::isnan(b)) 658 return ((fpToBits(b) & qnan) == qnan) ? a : b; 659 // Handle comparisons of +0 and -0. 660 if (std::signbit(a) && !std::signbit(b)) 661 return a; 662 return fmin(a, b); 663}; 664 665template <typename T> 666static inline T 667fpMin(T a, T b) 668{ 669 if (std::isnan(a)) 670 return a; 671 if (std::isnan(b)) 672 return b; 673 return fpMinNum<T>(a, b); 674}; 675 676template <typename T> 677static inline T 678fpRSqrts(T a, T b) 679{ 680 int fpClassA = std::fpclassify(a); 681 int fpClassB = std::fpclassify(b); 682 T aXb; 683 int fpClassAxB; 684 685 if ((fpClassA == FP_ZERO && fpClassB == FP_INFINITE) || 686 (fpClassA == FP_INFINITE && fpClassB == FP_ZERO)) { 687 return 1.5; 688 } 689 aXb = a*b; 690 fpClassAxB = std::fpclassify(aXb); 691 if (fpClassAxB == FP_SUBNORMAL) { 692 feraiseexcept(FeUnderflow); 693 return 1.5; 694 } 695 return (3.0 - (a * b)) / 2.0; 696}; 697 698template <typename T> 699static inline T 700fpRecps(T a, T b) 701{ 702 int fpClassA = std::fpclassify(a); 703 int fpClassB = std::fpclassify(b); 704 T aXb; 705 int fpClassAxB; 706 707 if ((fpClassA == FP_ZERO && fpClassB == FP_INFINITE) || 708 (fpClassA == FP_INFINITE && fpClassB == FP_ZERO)) { 709 return 2.0; 710 } 711 aXb = a*b; 712 fpClassAxB = std::fpclassify(aXb); 713 if (fpClassAxB == FP_SUBNORMAL) { 714 feraiseexcept(FeUnderflow); 715 return 2.0; 716 } 717 return 2.0 - (a * b); 718}; 719 720 721static inline float 722fpRSqrtsS(float a, float b) 723{ 724 int fpClassA = std::fpclassify(a); 725 int fpClassB = std::fpclassify(b); 726 float aXb; 727 int fpClassAxB; 728 729 if ((fpClassA == FP_ZERO && fpClassB == FP_INFINITE) || 730 (fpClassA == FP_INFINITE && fpClassB == FP_ZERO)) { 731 return 1.5; 732 } 733 aXb = a*b; 734 fpClassAxB = std::fpclassify(aXb); 735 if (fpClassAxB == FP_SUBNORMAL) { 736 feraiseexcept(FeUnderflow); 737 return 1.5; 738 } 739 return (3.0 - (a * b)) / 2.0; 740} 741 742static inline float 743fpRecpsS(float a, float b) 744{ 745 int fpClassA = std::fpclassify(a); 746 int fpClassB = std::fpclassify(b); 747 float aXb; 748 int fpClassAxB; 749 750 if ((fpClassA == FP_ZERO && fpClassB == FP_INFINITE) || 751 (fpClassA == FP_INFINITE && fpClassB == FP_ZERO)) { 752 return 2.0; 753 } 754 aXb = a*b; 755 fpClassAxB = std::fpclassify(aXb); 756 if (fpClassAxB == FP_SUBNORMAL) { 757 feraiseexcept(FeUnderflow); 758 return 2.0; 759 } 760 return 2.0 - (a * b); 761} 762 763template <typename T> 764static inline T 765roundNEven(T a) { 766 T val; 767 768 val = round(a); 769 if (a - val == 0.5) { 770 if ( (((int) a) & 1) == 0 ) val += 1.0; 771 } 772 else if (a - val == -0.5) { 773 if ( (((int) a) & 1) == 0 ) val -= 1.0; 774 } 775 return val; 776} 777 778 779 780class FpOp : public PredOp 781{ 782 protected: 783 FpOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) : 784 PredOp(mnem, _machInst, __opClass) 785 {} 786 787 virtual float 788 doOp(float op1, float op2) const 789 { 790 panic("Unimplemented version of doOp called.\n"); 791 } 792 793 virtual float 794 doOp(float op1) const 795 { 796 panic("Unimplemented version of doOp called.\n"); 797 } 798 799 virtual double 800 doOp(double op1, double op2) const 801 { 802 panic("Unimplemented version of doOp called.\n"); 803 } 804 805 virtual double 806 doOp(double op1) const 807 { 808 panic("Unimplemented version of doOp called.\n"); 809 } 810 811 double 812 dbl(uint32_t low, uint32_t high) const 813 { 814 double junk = 0.0; 815 return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk); 816 } 817 818 uint32_t 819 dblLow(double val) const 820 { 821 return fpToBits(val); 822 } 823 824 uint32_t 825 dblHi(double val) const 826 { 827 return fpToBits(val) >> 32; 828 } 829 830 template <class fpType> 831 fpType 832 processNans(FPSCR &fpscr, bool &done, bool defaultNan, 833 fpType op1, fpType op2) const; 834 835 template <class fpType> 836 fpType 837 ternaryOp(FPSCR &fpscr, fpType op1, fpType op2, fpType op3, 838 fpType (*func)(fpType, fpType, fpType), 839 bool flush, bool defaultNan, uint32_t rMode) const; 840 841 template <class fpType> 842 fpType 843 binaryOp(FPSCR &fpscr, fpType op1, fpType op2, 844 fpType (*func)(fpType, fpType), 845 bool flush, bool defaultNan, uint32_t rMode) const; 846 847 template <class fpType> 848 fpType 849 unaryOp(FPSCR &fpscr, fpType op1, 850 fpType (*func)(fpType), 851 bool flush, uint32_t rMode) const; 852 853 void 854 advancePC(PCState &pcState) const 855 { 856 if (flags[IsLastMicroop]) { 857 pcState.uEnd(); 858 } else if (flags[IsMicroop]) { 859 pcState.uAdvance(); 860 } else { 861 pcState.advance(); 862 } 863 } 864 865 float 866 fpSqrt (FPSCR fpscr,float x) const 867 { 868 869 return unaryOp(fpscr,x,sqrtf,fpscr.fz,fpscr.rMode); 870 871 } 872 873 double 874 fpSqrt (FPSCR fpscr,double x) const 875 { 876 877 return unaryOp(fpscr,x,sqrt,fpscr.fz,fpscr.rMode); 878 879 } 880}; 881 882class FpCondCompRegOp : public FpOp 883{ 884 protected: 885 IntRegIndex op1, op2; 886 ConditionCode condCode; 887 uint8_t defCc; 888 889 FpCondCompRegOp(const char *mnem, ExtMachInst _machInst, 890 OpClass __opClass, IntRegIndex _op1, IntRegIndex _op2, 891 ConditionCode _condCode, uint8_t _defCc) : 892 FpOp(mnem, _machInst, __opClass), 893 op1(_op1), op2(_op2), condCode(_condCode), defCc(_defCc) 894 {} 895 896 std::string generateDisassembly( 897 Addr pc, const SymbolTable *symtab) const override; 898}; 899 900class FpCondSelOp : public FpOp 901{ 902 protected: 903 IntRegIndex dest, op1, op2; 904 ConditionCode condCode; 905 906 FpCondSelOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, 907 IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2, 908 ConditionCode _condCode) : 909 FpOp(mnem, _machInst, __opClass), 910 dest(_dest), op1(_op1), op2(_op2), condCode(_condCode) 911 {} 912 913 std::string generateDisassembly( 914 Addr pc, const SymbolTable *symtab) const override; 915}; 916 917class FpRegRegOp : public FpOp 918{ 919 protected: 920 IntRegIndex dest; 921 IntRegIndex op1; 922 923 FpRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, 924 IntRegIndex _dest, IntRegIndex _op1, 925 VfpMicroMode mode = VfpNotAMicroop) : 926 FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1) 927 { 928 setVfpMicroFlags(mode, flags); 929 } 930 931 std::string generateDisassembly( 932 Addr pc, const SymbolTable *symtab) const override; 933}; 934 935class FpRegImmOp : public FpOp 936{ 937 protected: 938 IntRegIndex dest; 939 uint64_t imm; 940 941 FpRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, 942 IntRegIndex _dest, uint64_t _imm, 943 VfpMicroMode mode = VfpNotAMicroop) : 944 FpOp(mnem, _machInst, __opClass), dest(_dest), imm(_imm) 945 { 946 setVfpMicroFlags(mode, flags); 947 } 948 949 std::string generateDisassembly( 950 Addr pc, const SymbolTable *symtab) const override; 951}; 952 953class FpRegRegImmOp : public FpOp 954{ 955 protected: 956 IntRegIndex dest; 957 IntRegIndex op1; 958 uint64_t imm; 959 960 FpRegRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, 961 IntRegIndex _dest, IntRegIndex _op1, 962 uint64_t _imm, VfpMicroMode mode = VfpNotAMicroop) : 963 FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), imm(_imm) 964 { 965 setVfpMicroFlags(mode, flags); 966 } 967 968 std::string generateDisassembly( 969 Addr pc, const SymbolTable *symtab) const override; 970}; 971 972class FpRegRegRegOp : public FpOp 973{ 974 protected: 975 IntRegIndex dest; 976 IntRegIndex op1; 977 IntRegIndex op2; 978 979 FpRegRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, 980 IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2, 981 VfpMicroMode mode = VfpNotAMicroop) : 982 FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), op2(_op2) 983 { 984 setVfpMicroFlags(mode, flags); 985 } 986 987 std::string generateDisassembly( 988 Addr pc, const SymbolTable *symtab) const override; 989}; 990 991class FpRegRegRegCondOp : public FpOp 992{ 993 protected: 994 IntRegIndex dest; 995 IntRegIndex op1; 996 IntRegIndex op2; 997 ConditionCode cond; 998 999 FpRegRegRegCondOp(const char *mnem, ExtMachInst _machInst, 1000 OpClass __opClass, IntRegIndex _dest, IntRegIndex _op1, 1001 IntRegIndex _op2, ConditionCode _cond, 1002 VfpMicroMode mode = VfpNotAMicroop) : 1003 FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), op2(_op2), 1004 cond(_cond) 1005 { 1006 setVfpMicroFlags(mode, flags); 1007 } 1008 1009 std::string generateDisassembly( 1010 Addr pc, const SymbolTable *symtab) const override; 1011}; 1012 1013class FpRegRegRegRegOp : public FpOp 1014{ 1015 protected: 1016 IntRegIndex dest; 1017 IntRegIndex op1; 1018 IntRegIndex op2; 1019 IntRegIndex op3; 1020 1021 FpRegRegRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, 1022 IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2, 1023 IntRegIndex _op3, VfpMicroMode mode = VfpNotAMicroop) : 1024 FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), op2(_op2), 1025 op3(_op3) 1026 { 1027 setVfpMicroFlags(mode, flags); 1028 } 1029 1030 std::string generateDisassembly( 1031 Addr pc, const SymbolTable *symtab) const override; 1032}; 1033 1034class FpRegRegRegImmOp : public FpOp 1035{ 1036 protected: 1037 IntRegIndex dest; 1038 IntRegIndex op1; 1039 IntRegIndex op2; 1040 uint64_t imm; 1041 1042 FpRegRegRegImmOp(const char *mnem, ExtMachInst _machInst, 1043 OpClass __opClass, IntRegIndex _dest, 1044 IntRegIndex _op1, IntRegIndex _op2, 1045 uint64_t _imm, VfpMicroMode mode = VfpNotAMicroop) : 1046 FpOp(mnem, _machInst, __opClass), 1047 dest(_dest), op1(_op1), op2(_op2), imm(_imm) 1048 { 1049 setVfpMicroFlags(mode, flags); 1050 } 1051 1052 std::string generateDisassembly( 1053 Addr pc, const SymbolTable *symtab) const override; 1054}; 1055 1056} 1057 1058#endif //__ARCH_ARM_INSTS_VFP_HH__ 1059