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