1/***************************************************************************** 2 3 Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 4 more contributor license agreements. See the NOTICE file distributed 5 with this work for additional information regarding copyright ownership. 6 Accellera licenses this file to you under the Apache License, Version 2.0 7 (the "License"); you may not use this file except in compliance with the 8 License. You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 implied. See the License for the specific language governing 16 permissions and limitations under the License. 17 18 *****************************************************************************/ 19 20/***************************************************************************** 21 22 sc_fxnum.cpp - 23 24 Original Author: Martin Janssen, Synopsys, Inc. 25 26 *****************************************************************************/ 27 28/***************************************************************************** 29 30 MODIFICATION LOG - modifiers, enter your name, affiliation, date and 31 changes you are making here. 32 33 Name, Affiliation, Date: 34 Description of Modification: 35 36 *****************************************************************************/ 37 38 39// $Log: sc_fxnum.cpp,v $ 40// Revision 1.3 2011/01/19 18:57:40 acg 41// Andy Goodrich: changes for IEEE_1666_2011. 42// 43// Revision 1.2 2010/12/07 20:09:08 acg 44// Andy Goodrich: Philipp Hartmann's constructor disambiguation fix 45// 46// Revision 1.1.1.1 2006/12/15 20:20:04 acg 47// SystemC 2.3 48// 49// Revision 1.3 2006/01/13 18:53:57 acg 50// Andy Goodrich: added $Log command so that CVS comments are reproduced in 51// the source. 52// 53 54#include <cmath> 55 56#include "systemc/ext/dt/fx/messages.hh" 57#include "systemc/ext/dt/fx/sc_fxnum.hh" 58 59namespace sc_dt 60{ 61 62// ---------------------------------------------------------------------------- 63// CLASS : sc_fxnum_bitref 64// 65// Proxy class for bit-selection in class sc_fxnum, behaves like sc_bit. 66// ---------------------------------------------------------------------------- 67 68bool sc_fxnum_bitref::get() const { return m_num.get_bit(m_idx); } 69void sc_fxnum_bitref::set(bool high) { m_num.set_bit(m_idx, high); } 70 71// print or dump content 72void sc_fxnum_bitref::print(::std::ostream &os) const { os << get(); } 73 74void 75sc_fxnum_bitref::scan(::std::istream &is) 76{ 77 bool b; 78 is >> b; 79 *this = b; 80} 81 82void 83sc_fxnum_bitref::dump(::std::ostream &os) const 84{ 85 os << "sc_fxnum_bitref" << ::std::endl; 86 os << "(" << ::std::endl; 87 os << "num = "; 88 m_num.dump(os); 89 os << "idx = " << m_idx << ::std::endl; 90 os << ")" << ::std::endl; 91} 92 93 94// ---------------------------------------------------------------------------- 95// CLASS : sc_fxnum_fast_bitref 96// 97// Proxy class for bit-selection in class sc_fxnum_fast, behaves like sc_bit. 98// ---------------------------------------------------------------------------- 99 100bool sc_fxnum_fast_bitref::get() const { return m_num.get_bit(m_idx); } 101void sc_fxnum_fast_bitref::set(bool high) { m_num.set_bit(m_idx, high); } 102 103// print or dump content 104void sc_fxnum_fast_bitref::print(::std::ostream &os) const { os << get(); } 105 106void 107sc_fxnum_fast_bitref::scan(::std::istream &is) 108{ 109 bool b; 110 is >> b; 111 *this = b; 112} 113 114void 115sc_fxnum_fast_bitref::dump(::std::ostream &os) const 116{ 117 os << "sc_fxnum_fast_bitref" << ::std::endl; 118 os << "(" << ::std::endl; 119 os << "num = "; 120 m_num.dump(os); 121 os << "idx = " << m_idx << ::std::endl; 122 os << ")" << ::std::endl; 123} 124 125// ---------------------------------------------------------------------------- 126// CLASS : sc_fxnum_subref 127// 128// Proxy class for part-selection in class sc_fxnum, 129// behaves like sc_bv_base. 130// ---------------------------------------------------------------------------- 131 132bool 133sc_fxnum_subref::get() const 134{ 135 return m_num.get_slice(m_from, m_to, m_bv); 136} 137 138bool 139sc_fxnum_subref::set() 140{ 141 return m_num.set_slice(m_from, m_to, m_bv); 142} 143 144// print or dump content 145void 146sc_fxnum_subref::print(::std::ostream &os) const 147{ 148 get(); 149 m_bv.print(os); 150} 151 152void 153sc_fxnum_subref::scan(::std::istream &is) 154{ 155 m_bv.scan(is); 156 set(); 157} 158 159void 160sc_fxnum_subref::dump(::std::ostream &os) const 161{ 162 os << "sc_fxnum_subref" << ::std::endl; 163 os << "(" << ::std::endl; 164 os << "num = "; 165 m_num.dump(os); 166 os << "from = " << m_from << ::std::endl; 167 os << "to = " << m_to << ::std::endl; 168 os << ")" << ::std::endl; 169} 170 171 172// ---------------------------------------------------------------------------- 173// CLASS : sc_fxnum_fast_subref 174// 175// Proxy class for part-selection in class sc_fxnum_fast, 176// behaves like sc_bv_base. 177// ---------------------------------------------------------------------------- 178 179bool 180sc_fxnum_fast_subref::get() const 181{ 182 return m_num.get_slice(m_from, m_to, m_bv); 183} 184 185bool 186sc_fxnum_fast_subref::set() 187{ 188 return m_num.set_slice(m_from, m_to, m_bv); 189} 190 191// print or dump content 192void 193sc_fxnum_fast_subref::print(::std::ostream &os) const 194{ 195 get(); 196 m_bv.print(os); 197} 198 199void 200sc_fxnum_fast_subref::scan(::std::istream &is) 201{ 202 m_bv.scan(is); 203 set(); 204} 205 206void 207sc_fxnum_fast_subref::dump(::std::ostream &os) const 208{ 209 os << "sc_fxnum_fast_subref" << ::std::endl; 210 os << "(" << ::std::endl; 211 os << "num = "; 212 m_num.dump(os); 213 os << "from = " << m_from << ::std::endl; 214 os << "to = " << m_to << ::std::endl; 215 os << ")" << ::std::endl; 216} 217 218 219// ---------------------------------------------------------------------------- 220// CLASS : sc_fxnum 221// 222// Base class for the fixed-point types; arbitrary precision. 223// ---------------------------------------------------------------------------- 224 225// explicit conversion to character string 226 227const std::string 228sc_fxnum::to_string() const 229{ 230 return std::string(m_rep->to_string(SC_DEC, -1, SC_F, &m_params)); 231} 232 233const std::string 234sc_fxnum::to_string(sc_numrep numrep) const 235{ 236 return std::string(m_rep->to_string(numrep, -1, SC_F, &m_params)); 237} 238 239const std::string 240sc_fxnum::to_string(sc_numrep numrep, bool w_prefix) const 241{ 242 return std::string(m_rep->to_string(numrep, (w_prefix ? 1 : 0), 243 SC_F, &m_params)); 244} 245 246const std::string 247sc_fxnum::to_string(sc_fmt fmt) const 248{ 249 return std::string(m_rep->to_string(SC_DEC, -1, fmt, &m_params)); 250} 251 252const std::string 253sc_fxnum::to_string(sc_numrep numrep, sc_fmt fmt) const 254{ 255 return std::string(m_rep->to_string(numrep, -1, fmt, &m_params)); 256} 257 258const std::string 259sc_fxnum::to_string(sc_numrep numrep, bool w_prefix, sc_fmt fmt) const 260{ 261 return std::string(m_rep->to_string(numrep, (w_prefix ? 1 : 0), 262 fmt, &m_params)); 263} 264 265 266const std::string 267sc_fxnum::to_dec() const 268{ 269 return std::string(m_rep->to_string(SC_DEC, -1, SC_F, &m_params)); 270} 271 272const std::string 273sc_fxnum::to_bin() const 274{ 275 return std::string(m_rep->to_string(SC_BIN, -1, SC_F, &m_params)); 276} 277 278const std::string 279sc_fxnum::to_oct() const 280{ 281 return std::string(m_rep->to_string(SC_OCT, -1, SC_F, &m_params)); 282} 283 284const std::string 285sc_fxnum::to_hex() const 286{ 287 return std::string(m_rep->to_string(SC_HEX, -1, SC_F, &m_params)); 288} 289 290 291// print or dump content 292void 293sc_fxnum::print(::std::ostream &os) const 294{ 295 os << m_rep->to_string(SC_DEC, -1, SC_F, &m_params); 296} 297 298void 299sc_fxnum::scan(::std::istream &is) 300{ 301 std::string s; 302 is >> s; 303 *this = s.c_str(); 304} 305 306void 307sc_fxnum::dump(::std::ostream &os) const 308{ 309 os << "sc_fxnum" << ::std::endl; 310 os << "(" << ::std::endl; 311 os << "rep = "; 312 m_rep->dump(os); 313 os << "params = "; 314 m_params.dump(os); 315 os << "q_flag = " << m_q_flag << ::std::endl; 316 os << "o_flag = " << m_o_flag << ::std::endl; 317 // TO BE COMPLETED 318 // os << "observer = "; 319 // if (m_observer != 0) 320 // m_observer->dump(os); 321 // else 322 // os << "0" << ::std::endl; 323 os << ")" << ::std::endl; 324} 325 326 327sc_fxnum_observer * 328sc_fxnum::lock_observer() const 329{ 330 SC_ASSERT_(m_observer != 0, "lock observer failed"); 331 sc_fxnum_observer * tmp = m_observer; 332 m_observer = 0; 333 return tmp; 334} 335 336void 337sc_fxnum::unlock_observer(sc_fxnum_observer *observer_) const 338{ 339 SC_ASSERT_(observer_ != 0, "unlock observer failed"); 340 m_observer = observer_; 341} 342 343 344// ---------------------------------------------------------------------------- 345// CLASS : sc_fxnum_fast 346// 347// Base class for the fixed-point types; limited precision. 348// ---------------------------------------------------------------------------- 349 350static void 351quantization(double &c, const scfx_params ¶ms, bool &q_flag) 352{ 353 int fwl = params.wl() - params.iwl(); 354 double scale = scfx_pow2(fwl); 355 double val = scale * c; 356 double int_part; 357 double frac_part = modf(val, &int_part); 358 359 q_flag = (frac_part != 0.0); 360 361 if (q_flag) { 362 val = int_part; 363 364 switch (params.q_mode()) { 365 case SC_TRN: // truncation 366 { 367 if (c < 0.0) 368 val -= 1.0; 369 break; 370 } 371 case SC_RND: // rounding to plus infinity 372 { 373 if (frac_part >= 0.5) 374 val += 1.0; 375 else if (frac_part < -0.5) 376 val -= 1.0; 377 break; 378 } 379 case SC_TRN_ZERO: // truncation to zero 380 { 381 break; 382 } 383 case SC_RND_INF: // rounding to infinity 384 { 385 if (frac_part >= 0.5) 386 val += 1.0; 387 else if (frac_part <= -0.5) 388 val -= 1.0; 389 break; 390 } 391 case SC_RND_CONV: // convergent rounding 392 { 393 if (frac_part > 0.5 || 394 (frac_part == 0.5 && fmod(int_part, 2.0) != 0.0)) { 395 val += 1.0; 396 } else if (frac_part < -0.5 || 397 (frac_part == -0.5 && fmod(int_part, 2.0) != 0.0)) { 398 val -= 1.0; 399 } 400 break; 401 } 402 case SC_RND_ZERO: // rounding to zero 403 { 404 if (frac_part > 0.5) 405 val += 1.0; 406 else if (frac_part < -0.5) 407 val -= 1.0; 408 break; 409 } 410 case SC_RND_MIN_INF: // rounding to minus infinity 411 { 412 if (frac_part > 0.5) 413 val += 1.0; 414 else if (frac_part <= -0.5) 415 val -= 1.0; 416 break; 417 } 418 default: 419 ; 420 } 421 } 422 423 val /= scale; 424 c = val; 425} 426 427static void 428overflow(double &c, const scfx_params ¶ms, bool &o_flag) 429{ 430 int iwl = params.iwl(); 431 int fwl = params.wl() - iwl; 432 double full_circle = scfx_pow2(iwl); 433 double resolution = scfx_pow2(-fwl); 434 double low, high; 435 if (params.enc() == SC_TC_) { 436 high = full_circle / 2.0 - resolution; 437 if (params.o_mode() == SC_SAT_SYM) 438 low = - high; 439 else 440 low = - full_circle / 2.0; 441 } else { 442 low = 0.0; 443 high = full_circle - resolution; 444 } 445 double val = c; 446 sc_fxval_fast c2(c); 447 448 bool under = (val < low); 449 bool over = (val > high); 450 451 o_flag = (under || over); 452 453 if (o_flag) { 454 switch (params.o_mode()) { 455 case SC_WRAP: // wrap-around 456 { 457 int n_bits = params.n_bits(); 458 459 if (n_bits == 0) { 460 // wrap-around all 'wl' bits 461 val -= floor(val / full_circle) * full_circle; 462 if (val > high) 463 val -= full_circle; 464 } else if (n_bits < params.wl()) { 465 double X = scfx_pow2(iwl - n_bits); 466 467 // wrap-around least significant 'wl - n_bits' bits 468 val -= floor(val / X) * X; 469 if (val > (X - resolution)) 470 val -= X; 471 472 // saturate most significant 'n_bits' bits 473 if (under) { 474 val += low; 475 } else { 476 if (params.enc() == SC_TC_) 477 val += full_circle / 2.0 - X; 478 else 479 val += full_circle - X; 480 } 481 } else { 482 // saturate all 'wl' bits 483 if (under) 484 val = low; 485 else 486 val = high; 487 } 488 break; 489 } 490 case SC_SAT: // saturation 491 case SC_SAT_SYM: // symmetrical saturation 492 { 493 if (under) 494 val = low; 495 else 496 val = high; 497 break; 498 } 499 case SC_SAT_ZERO: // saturation to zero 500 { 501 val = 0.0; 502 break; 503 } 504 case SC_WRAP_SM: // sign magnitude wrap-around 505 { 506 SC_ERROR_IF_(params.enc() == SC_US_, 507 sc_core::SC_ID_WRAP_SM_NOT_DEFINED_); 508 509 int n_bits = params.n_bits(); 510 511 if (n_bits == 0) { 512 // invert conditionally 513 if (c2.get_bit(iwl) != c2.get_bit(iwl - 1)) 514 val = -val - resolution; 515 516 // wrap-around all 'wl' bits 517 val -= floor(val / full_circle) * full_circle; 518 if (val > high) 519 val -= full_circle; 520 } else if (n_bits == 1) { 521 // invert conditionally 522 if (c2.is_neg() != c2.get_bit(iwl - 1)) 523 val = -val - resolution; 524 525 // wrap-around all 'wl' bits 526 val -= floor(val / full_circle) * full_circle; 527 if (val > high) 528 val -= full_circle; 529 } else if (n_bits < params.wl()) { 530 // invert conditionally 531 if (c2.is_neg() == c2.get_bit(iwl - n_bits)) 532 val = -val - resolution; 533 534 double X = scfx_pow2(iwl - n_bits); 535 536 // wrap-around least significant 'wl - n_bits' bits 537 val -= floor(val / X) * X; 538 if (val > (X - resolution)) 539 val -= X; 540 541 // saturate most significant 'n_bits' bits 542 if (under) 543 val += low; 544 else 545 val += full_circle / 2.0 - X; 546 } else { 547 // saturate all 'wl' bits 548 if (under) 549 val = low; 550 else 551 val = high; 552 } 553 break; 554 } 555 default: 556 ; 557 } 558 559 c = val; 560 } 561} 562 563 564void 565sc_fxnum_fast::cast() 566{ 567 scfx_ieee_double id(m_val); 568 SC_ERROR_IF_(id.is_nan() || id.is_inf(), sc_core::SC_ID_INVALID_FX_VALUE_); 569 570 if (m_params.cast_switch() == SC_ON) { 571 m_q_flag = false; 572 m_o_flag = false; 573 574 // check for special cases 575 576 if (id.is_zero()) { 577 if (id.negative() != 0) 578 m_val = -m_val; 579 return; 580 } 581 582 // perform casting 583 sc_dt::quantization(m_val, m_params, m_q_flag); 584 sc_dt::overflow(m_val, m_params, m_o_flag); 585 586 // check for special case: -0 587 id = m_val; 588 if (id.is_zero() && id.negative() != 0) { 589 m_val = -m_val; 590 } 591 592 // check for special case: NaN of Inf 593 if (id.is_nan() || id.is_inf()) { 594 m_val = 0.0; 595 } 596 } 597} 598 599 600// defined in sc_fxval.cpp; 601extern const char* to_string(const scfx_ieee_double &, sc_numrep, int, sc_fmt, 602 const scfx_params * =0); 603 604 605// explicit conversion to character string 606 607const std::string 608sc_fxnum_fast::to_string() const 609{ 610 return std::string(sc_dt::to_string(m_val, SC_DEC, -1, SC_F, &m_params)); 611} 612 613const std::string 614sc_fxnum_fast::to_string(sc_numrep numrep) const 615{ 616 return std::string(sc_dt::to_string(m_val, numrep, -1, SC_F, &m_params)); 617} 618 619const std::string 620sc_fxnum_fast::to_string(sc_numrep numrep, bool w_prefix) const 621{ 622 return std::string(sc_dt::to_string(m_val, numrep, (w_prefix ? 1 : 0), 623 SC_F, &m_params)); 624} 625 626const std::string 627sc_fxnum_fast::to_string(sc_fmt fmt) const 628{ 629 return std::string(sc_dt::to_string(m_val, SC_DEC, -1, fmt, &m_params)); 630} 631 632const std::string 633sc_fxnum_fast::to_string(sc_numrep numrep, sc_fmt fmt) const 634{ 635 return std::string(sc_dt::to_string(m_val, numrep, -1, fmt, &m_params)); 636} 637 638const std::string 639sc_fxnum_fast::to_string(sc_numrep numrep, bool w_prefix, sc_fmt fmt) const 640{ 641 return std::string(sc_dt::to_string(m_val, numrep, (w_prefix ? 1 : 0), 642 fmt, &m_params)); 643} 644 645 646const std::string 647sc_fxnum_fast::to_dec() const 648{ 649 return std::string(sc_dt::to_string(m_val, SC_DEC, -1, SC_F, &m_params)); 650} 651 652const std::string 653sc_fxnum_fast::to_bin() const 654{ 655 return std::string(sc_dt::to_string(m_val, SC_BIN, -1, SC_F, &m_params)); 656} 657 658const std::string 659sc_fxnum_fast::to_oct() const 660{ 661 return std::string(sc_dt::to_string(m_val, SC_OCT, -1, SC_F, &m_params)); 662} 663 664const std::string 665sc_fxnum_fast::to_hex() const 666{ 667 return std::string(sc_dt::to_string(m_val, SC_HEX, -1, SC_F, &m_params)); 668} 669 670// print or dump content 671void 672sc_fxnum_fast::print(::std::ostream &os) const 673{ 674 os << sc_dt::to_string(m_val, SC_DEC, -1, SC_F, &m_params); 675} 676 677void 678sc_fxnum_fast::scan(::std::istream &is) 679{ 680 std::string s; 681 is >> s; 682 *this = s.c_str(); 683} 684 685void 686sc_fxnum_fast::dump(::std::ostream &os) const 687{ 688 os << "sc_fxnum_fast" << ::std::endl; 689 os << "(" << ::std::endl; 690 os << "val = " << m_val << ::std::endl; 691 os << "params = "; 692 m_params.dump(os); 693 os << "q_flag = " << m_q_flag << ::std::endl; 694 os << "o_flag = " << m_o_flag << ::std::endl; 695 // TO BE COMPLETED 696 // os << "observer = "; 697 // if (m_observer != 0) 698 // m_observer->dump(os); 699 // else 700 // os << "0" << ::std::endl; 701 os << ")" << ::std::endl; 702} 703 704// internal use only; 705bool 706sc_fxnum_fast::get_bit(int i) const 707{ 708 scfx_ieee_double id(m_val); 709 if (id.is_zero() || id.is_nan() || id.is_inf()) 710 return false; 711 712 // convert to two's complement 713 unsigned int m0 = id.mantissa0(); 714 unsigned int m1 = id.mantissa1(); 715 716 if (id.is_normal()) 717 m0 += 1U << 20; 718 719 if (id.negative() != 0) { 720 m0 = ~ m0; 721 m1 = ~ m1; 722 unsigned int tmp = m1; 723 m1 += 1U; 724 if (m1 <= tmp) 725 m0 += 1U; 726 } 727 728 // get the right bit 729 int j = i - id.exponent(); 730 if ((j += 20) >= 32) 731 return ((m0 & 1U << 31) != 0); 732 else if (j >= 0) 733 return ((m0 & 1U << j) != 0); 734 else if ((j += 32) >= 0) 735 return ((m1 & 1U << j) != 0); 736 else 737 return false; 738} 739 740 741bool 742sc_fxnum_fast::set_bit(int i, bool high) 743{ 744 scfx_ieee_double id(m_val); 745 if (id.is_nan() || id.is_inf()) 746 return false; 747 748 if (high) { 749 if (get_bit(i)) 750 return true; 751 752 if (m_params.enc() == SC_TC_ && i == m_params.iwl() - 1) 753 m_val -= scfx_pow2(i); 754 else 755 m_val += scfx_pow2(i); 756 } else { 757 if (!get_bit(i)) 758 return true; 759 760 if (m_params.enc() == SC_TC_ && i == m_params.iwl() - 1) 761 m_val += scfx_pow2(i); 762 else 763 m_val -= scfx_pow2(i); 764 } 765 766 return true; 767} 768 769 770bool 771sc_fxnum_fast::get_slice(int i, int j, sc_bv_base &bv) const 772{ 773 scfx_ieee_double id(m_val); 774 if (id.is_nan() || id.is_inf()) 775 return false; 776 777 // convert to two's complement 778 unsigned int m0 = id.mantissa0(); 779 unsigned int m1 = id.mantissa1(); 780 781 if (id.is_normal()) 782 m0 += 1U << 20; 783 784 if (id.negative() != 0) { 785 m0 = ~ m0; 786 m1 = ~ m1; 787 unsigned int tmp = m1; 788 m1 += 1U; 789 if (m1 <= tmp) 790 m0 += 1U; 791 } 792 793 // get the bits 794 int l = j; 795 for (int k = 0; k < bv.length(); ++ k) { 796 bool b = false; 797 798 int n = l - id.exponent(); 799 if ((n += 20) >= 32) 800 b = ((m0 & 1U << 31) != 0); 801 else if (n >= 0) 802 b = ((m0 & 1U << n) != 0); 803 else if ((n += 32) >= 0) 804 b = ((m1 & 1U << n) != 0); 805 806 bv[k] = b; 807 808 if (i >= j) 809 ++l; 810 else 811 --l; 812 } 813 814 return true; 815} 816 817bool 818sc_fxnum_fast::set_slice(int i, int j, const sc_bv_base &bv) 819{ 820 scfx_ieee_double id(m_val); 821 if (id.is_nan() || id.is_inf()) 822 return false; 823 824 // set the bits 825 int l = j; 826 for (int k = 0; k < bv.length(); ++k) { 827 if (bv[k].to_bool()) { 828 if (!get_bit(l)) { 829 if (m_params.enc() == SC_TC_ && l == m_params.iwl() - 1) 830 m_val -= scfx_pow2(l); 831 else 832 m_val += scfx_pow2(l); 833 } 834 } else { 835 if (get_bit(l)) { 836 if (m_params.enc() == SC_TC_ && l == m_params.iwl() - 1) 837 m_val += scfx_pow2(l); 838 else 839 m_val -= scfx_pow2(l); 840 } 841 } 842 843 if (i >= j) 844 ++l; 845 else 846 --l; 847 } 848 849 return true; 850} 851 852sc_fxnum_fast_observer * 853sc_fxnum_fast::lock_observer() const 854{ 855 SC_ASSERT_(m_observer != 0, "lock observer failed"); 856 sc_fxnum_fast_observer *tmp = m_observer; 857 m_observer = 0; 858 return tmp; 859} 860 861void 862sc_fxnum_fast::unlock_observer(sc_fxnum_fast_observer *observer_) const 863{ 864 SC_ASSERT_(observer_ != 0, "unlock observer failed"); 865 m_observer = observer_; 866} 867 868} // namespace sc_dt 869