sc_fxval.cc revision 13322
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_fxval.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_fxval.cpp,v $ 40// Revision 1.1.1.1 2006/12/15 20:20:04 acg 41// SystemC 2.3 42// 43// Revision 1.3 2006/01/13 18:53:58 acg 44// Andy Goodrich: added $Log command so that CVS comments are reproduced in 45// the source. 46// 47 48#include <cctype> 49#include <cfloat> 50#include <cmath> 51#include <cstdlib> 52 53#include "systemc/ext/dt/fx/sc_fxval.hh" 54#include "systemc/ext/utils/messages.hh" 55 56namespace sc_dt 57{ 58 59// ---------------------------------------------------------------------------- 60// CLASS : sc_fxval 61// 62// Fixed-point value type; arbitrary precision. 63// ---------------------------------------------------------------------------- 64 65// explicit conversion to character string 66 67const std::string 68sc_fxval::to_string() const 69{ 70 return std::string(m_rep->to_string(SC_DEC, -1, SC_E)); 71} 72 73const std::string 74sc_fxval::to_string(sc_numrep numrep) const 75{ 76 return std::string(m_rep->to_string(numrep, -1, SC_E)); 77} 78 79const std::string 80sc_fxval::to_string(sc_numrep numrep, bool w_prefix) const 81{ 82 return std::string(m_rep->to_string(numrep, (w_prefix ? 1 : 0), SC_E)); 83} 84 85const std::string 86sc_fxval::to_string(sc_fmt fmt) const 87{ 88 return std::string(m_rep->to_string(SC_DEC, -1, fmt)); 89} 90 91const std::string 92sc_fxval::to_string(sc_numrep numrep, sc_fmt fmt) const 93{ 94 return std::string(m_rep->to_string(numrep, -1, fmt)); 95} 96 97const std::string 98sc_fxval::to_string(sc_numrep numrep, bool w_prefix, sc_fmt fmt) const 99{ 100 return std::string(m_rep->to_string(numrep, (w_prefix ? 1 : 0), fmt)); 101} 102 103 104const std::string 105sc_fxval::to_dec() const 106{ 107 return std::string(m_rep->to_string(SC_DEC, -1, SC_E)); 108} 109 110const std::string 111sc_fxval::to_bin() const 112{ 113 return std::string(m_rep->to_string(SC_BIN, -1, SC_E)); 114} 115 116const std::string 117sc_fxval::to_oct() const 118{ 119 return std::string(m_rep->to_string(SC_OCT, -1, SC_E)); 120} 121 122const std::string 123sc_fxval::to_hex() const 124{ 125 return std::string(m_rep->to_string(SC_HEX, -1, SC_E)); 126} 127 128 129// print or dump content 130 131void sc_fxval::print(::std::ostream &os) const { m_rep->print(os); } 132 133void 134sc_fxval::scan(::std::istream &is) 135{ 136 std::string s; 137 is >> s; 138 *this = s.c_str(); 139} 140 141void 142sc_fxval::dump(::std::ostream &os) const 143{ 144 os << "sc_fxval" << ::std::endl; 145 os << "(" << ::std::endl; 146 os << "rep = "; 147 m_rep->dump(os); 148 // TO BE COMPLETED 149 // os << "r_flag = " << m_r_flag << ::std::endl; 150 // os << "observer = "; 151 // if (m_observer != 0) 152 // m_observer->dump(os); 153 // else 154 // os << "0" << ::std::endl; 155 os << ")" << ::std::endl; 156} 157 158// protected methods and friend functions 159sc_fxval_observer * 160sc_fxval::lock_observer() const 161{ 162 SC_ASSERT_(m_observer != 0, "lock observer failed"); 163 sc_fxval_observer *tmp = m_observer; 164 m_observer = 0; 165 return tmp; 166} 167 168void 169sc_fxval::unlock_observer(sc_fxval_observer *observer_) const 170{ 171 SC_ASSERT_(observer_ != 0, "unlock observer failed"); 172 m_observer = observer_; 173} 174 175 176// ---------------------------------------------------------------------------- 177// CLASS : sc_fxval_fast 178// 179// Fixed-point value types; limited precision. 180// ---------------------------------------------------------------------------- 181 182static void 183print_dec(scfx_string &s, scfx_ieee_double id, int w_prefix, sc_fmt fmt) 184{ 185 if (id.negative() != 0) { 186 id.negative(0); 187 s += '-'; 188 } 189 190 if (w_prefix == 1) { 191 scfx_print_prefix(s, SC_DEC); 192 } 193 194 if (id.is_zero()) { 195 s += '0'; 196 return; 197 } 198 199 // split 'id' into its integer and fractional part 200 double int_part; 201 double frac_part = std::modf(static_cast<double>(id), &int_part); 202 203 int i; 204 205 // print integer part 206 int int_digits = 0; 207 int int_zeros = 0; 208 209 if (int_part != 0.0) { 210 int_digits = (int)std::ceil(std::log10(int_part + 1.0)); 211 212 int len = s.length(); 213 s.append(int_digits); 214 215 bool zero_digits = (frac_part == 0.0 && fmt != SC_F); 216 217 for (i = int_digits + len - 1; i >= len; i--) { 218 unsigned int remainder = (unsigned int)std::fmod(int_part, 10.0); 219 s[i] = static_cast<char>('0' + remainder); 220 221 if (zero_digits) { 222 if (remainder == 0) 223 int_zeros++; 224 else 225 zero_digits = false; 226 } 227 228 int_part /= 10.0; 229 } 230 231 // discard trailing zeros from int_part 232 s.discard(int_zeros); 233 234 if (s[len] == '0') { 235 // int_digits was overestimated by one 236 s.remove(len); 237 --int_digits; 238 } 239 } 240 241 // print fractional part 242 int frac_digits = 0; 243 int frac_zeros = 0; 244 245 if (frac_part != 0.0) { 246 s += '.'; 247 248 bool zero_digits = (int_digits == 0 && fmt != SC_F); 249 250 frac_zeros = (int)std::floor(-std::log10(frac_part + DBL_EPSILON)); 251 252 frac_part *= std::pow(10.0, frac_zeros); 253 254 frac_digits = frac_zeros; 255 if (!zero_digits) { 256 for (i = 0; i < frac_zeros; i++) 257 s += '0'; 258 frac_zeros = 0; 259 } 260 261 while (frac_part != 0.0) { 262 frac_part *= 10.0; 263 int n = static_cast<int>(frac_part); 264 265 if (zero_digits) { 266 if (n == 0) 267 frac_zeros++; 268 else 269 zero_digits = false; 270 } 271 272 if (!zero_digits) 273 s += static_cast<char>('0' + n); 274 275 frac_part -= n; 276 frac_digits++; 277 } 278 } 279 280 // print exponent 281 if (fmt != SC_F) { 282 if (frac_digits == 0) 283 scfx_print_exp(s, int_zeros); 284 else if (int_digits == 0) 285 scfx_print_exp(s, -frac_zeros); 286 } 287} 288 289static void 290print_other(scfx_string &s, const scfx_ieee_double &id, sc_numrep numrep, 291 int w_prefix, sc_fmt fmt, const scfx_params *params) 292{ 293 scfx_ieee_double id2 = id; 294 295 sc_numrep numrep2 = numrep; 296 297 bool numrep_is_sm = (numrep == SC_BIN_SM || 298 numrep == SC_OCT_SM || 299 numrep == SC_HEX_SM); 300 301 if (numrep_is_sm) { 302 if (id2.negative() != 0) { 303 s += '-'; 304 id2.negative(0); 305 } 306 switch (numrep) { 307 case SC_BIN_SM: 308 numrep2 = SC_BIN_US; 309 break; 310 case SC_OCT_SM: 311 numrep2 = SC_OCT_US; 312 break; 313 case SC_HEX_SM: 314 numrep2 = SC_HEX_US; 315 break; 316 default: 317 ; 318 } 319 } 320 321 if (w_prefix != 0) { 322 scfx_print_prefix(s, numrep); 323 } 324 325 numrep = numrep2; 326 327 sc_fxval_fast a(id2); 328 329 int msb, lsb; 330 331 if (params != 0) { 332 msb = params->iwl() - 1; 333 lsb = params->iwl() - params->wl(); 334 335 if (params->enc() == SC_TC_ && 336 (numrep == SC_BIN_US || 337 numrep == SC_OCT_US || 338 numrep == SC_HEX_US) && 339 !numrep_is_sm && 340 params->wl() > 1) { 341 --msb; 342 } else if (params->enc() == SC_US_ && 343 (numrep == SC_BIN || 344 numrep == SC_OCT || 345 numrep == SC_HEX || 346 numrep == SC_CSD)) { 347 ++msb; 348 } 349 } else { 350 if (a.is_zero()) { 351 msb = 0; 352 lsb = 0; 353 } else { 354 msb = id2.exponent() + 1; 355 while (a.get_bit(msb) == a.get_bit(msb - 1)) 356 --msb; 357 358 if (numrep == SC_BIN_US || 359 numrep == SC_OCT_US || 360 numrep == SC_HEX_US) { 361 --msb; 362 } 363 364 lsb = id2.exponent() - 52; 365 while (!a.get_bit(lsb)) 366 ++lsb; 367 } 368 } 369 370 int step; 371 372 switch (numrep) { 373 case SC_BIN: 374 case SC_BIN_US: 375 case SC_CSD: 376 step = 1; 377 break; 378 case SC_OCT: 379 case SC_OCT_US: 380 step = 3; 381 break; 382 case SC_HEX: 383 case SC_HEX_US: 384 step = 4; 385 break; 386 default: 387 SC_REPORT_FATAL(sc_core::SC_ID_ASSERTION_FAILED_, 388 "unexpected sc_numrep"); 389 sc_core::sc_abort(); 390 } 391 392 msb = (int)std::ceil(double(msb + 1) / step) * step - 1; 393 394 lsb = (int)std::floor(double(lsb) / step) * step; 395 396 if (msb < 0) { 397 s += '.'; 398 if (fmt == SC_F) { 399 int sign = (id2.negative() != 0) ? (1 << step) - 1 : 0; 400 for (int i = (msb + 1) / step; i < 0; i++) { 401 if (sign < 10) 402 s += static_cast<char>(sign + '0'); 403 else 404 s += static_cast<char>(sign + 'a' - 10); 405 } 406 } 407 } 408 409 int i = msb; 410 while (i >= lsb) { 411 int value = 0; 412 for (int j = step - 1; j >= 0; --j) { 413 value += static_cast<int>(a.get_bit(i)) << j; 414 --i; 415 } 416 if (value < 10) 417 s += static_cast<char>(value + '0'); 418 else 419 s += static_cast<char>(value + 'a' - 10); 420 if (i == -1) 421 s += '.'; 422 } 423 424 if (lsb > 0 && fmt == SC_F) { 425 for (int i = lsb / step; i > 0; i--) 426 s += '0'; 427 } 428 429 if (s[s.length() - 1] == '.') 430 s.discard(1); 431 432 if (fmt != SC_F) { 433 if (msb < 0) 434 scfx_print_exp(s, (msb + 1) / step); 435 else if (lsb > 0) 436 scfx_print_exp(s, lsb / step); 437 } 438 439 if (numrep == SC_CSD) 440 scfx_tc2csd(s, w_prefix); 441} 442 443const char * 444to_string(const scfx_ieee_double &id, sc_numrep numrep, int w_prefix, 445 sc_fmt fmt, const scfx_params *params=0) 446{ 447 static scfx_string s; 448 449 s.clear(); 450 451 if (id.is_nan()) { 452 scfx_print_nan(s); 453 } else if (id.is_inf()) { 454 scfx_print_inf(s, static_cast<bool>(id.negative())); 455 } else if (id.negative() && !id.is_zero() && 456 (numrep == SC_BIN_US || 457 numrep == SC_OCT_US || 458 numrep == SC_HEX_US)) { 459 s += "negative"; 460 } else if (numrep == SC_DEC) { 461 sc_dt::print_dec(s, id, w_prefix, fmt); 462 } else { 463 sc_dt::print_other(s, id, numrep, w_prefix, fmt, params); 464 } 465 466 return s; 467} 468 469 470// explicit conversion to character string 471const std::string 472sc_fxval_fast::to_string() const 473{ 474 return std::string(sc_dt::to_string(m_val, SC_DEC, -1, SC_E)); 475} 476 477const std::string 478sc_fxval_fast::to_string(sc_numrep numrep) const 479{ 480 return std::string(sc_dt::to_string(m_val, numrep, -1, SC_E)); 481} 482 483const std::string 484sc_fxval_fast::to_string(sc_numrep numrep, bool w_prefix) const 485{ 486 return std::string(sc_dt::to_string(m_val, numrep, (w_prefix ? 1 : 0), 487 SC_E)); 488} 489 490const std::string 491sc_fxval_fast::to_string(sc_fmt fmt) const 492{ 493 return std::string(sc_dt::to_string(m_val, SC_DEC, -1, fmt)); 494} 495 496const std::string 497sc_fxval_fast::to_string(sc_numrep numrep, sc_fmt fmt) const 498{ 499 return std::string(sc_dt::to_string(m_val, numrep, -1, fmt)); 500} 501 502const std::string 503sc_fxval_fast::to_string(sc_numrep numrep, bool w_prefix, sc_fmt fmt) const 504{ 505 return std::string(sc_dt::to_string(m_val, numrep, (w_prefix ? 1 : 0), 506 fmt)); 507} 508 509const std::string 510sc_fxval_fast::to_dec() const 511{ 512 return std::string(sc_dt::to_string(m_val, SC_DEC, -1, SC_E)); 513} 514 515const std::string 516sc_fxval_fast::to_bin() const 517{ 518 return std::string(sc_dt::to_string(m_val, SC_BIN, -1, SC_E)); 519} 520 521const std::string 522sc_fxval_fast::to_oct() const 523{ 524 return std::string(sc_dt::to_string(m_val, SC_OCT, -1, SC_E)); 525} 526 527const std::string 528sc_fxval_fast::to_hex() const 529{ 530 return std::string(sc_dt::to_string(m_val, SC_HEX, -1, SC_E)); 531} 532 533 534// print or dump content 535 536void 537sc_fxval_fast::print(::std::ostream &os) const 538{ 539 os << sc_dt::to_string(m_val, SC_DEC, -1, SC_E); 540} 541 542void 543sc_fxval_fast::scan(::std::istream &is) 544{ 545 std::string s; 546 is >> s; 547 *this = s.c_str(); 548} 549 550void 551sc_fxval_fast::dump(::std::ostream &os) const 552{ 553 os << "sc_fxval_fast" << ::std::endl; 554 os << "(" << ::std::endl; 555 os << "val = " << m_val << ::std::endl; 556 // TO BE COMPLETED 557 // os << "r_flag = " << m_r_flag << ::std::endl; 558 // os << "observer = "; 559 // if (m_observer != 0) 560 // m_observer->dump(os); 561 // else 562 // os << "0" << ::std::endl; 563 os << ")" << ::std::endl; 564} 565 566 567// internal use only; 568bool 569sc_fxval_fast::get_bit(int i) const 570{ 571 scfx_ieee_double id(m_val); 572 if (id.is_zero() || id.is_nan() || id.is_inf()) 573 return false; 574 575 // convert to two's complement 576 unsigned int m0 = id.mantissa0(); 577 unsigned int m1 = id.mantissa1(); 578 579 if (id.is_normal()) 580 m0 += 1U << 20; 581 582 if (id.negative() != 0) { 583 m0 = ~ m0; 584 m1 = ~ m1; 585 unsigned int tmp = m1; 586 m1 += 1U; 587 if (m1 <= tmp) 588 m0 += 1U; 589 } 590 591 // get the right bit 592 int j = i - id.exponent(); 593 if ((j += 20) >= 32) 594 return ((m0 & 1U << 31) != 0); 595 else if (j >= 0) 596 return ((m0 & 1U << j) != 0); 597 else if ((j += 32) >= 0) 598 return ((m1 & 1U << j) != 0); 599 else 600 return false; 601} 602 603 604// protected methods and friend functions 605sc_fxval_fast_observer * 606sc_fxval_fast::lock_observer() const 607{ 608 SC_ASSERT_(m_observer != 0, "lock observer failed"); 609 sc_fxval_fast_observer *tmp = m_observer; 610 m_observer = 0; 611 return tmp; 612} 613 614void 615sc_fxval_fast::unlock_observer(sc_fxval_fast_observer *observer_) const 616{ 617 SC_ASSERT_(observer_ != 0, "unlock observer failed"); 618 m_observer = observer_; 619} 620 621#define SCFX_FAIL_IF_(cnd) \ 622{ \ 623 if ((cnd)) \ 624 return static_cast<double>(scfx_ieee_double::nan()); \ 625} 626 627double 628sc_fxval_fast::from_string(const char *s) 629{ 630 SCFX_FAIL_IF_(s == 0 || *s == 0); 631 632 scfx_string s2; 633 s2 += s; 634 s2 += '\0'; 635 636 bool sign_char; 637 int sign = scfx_parse_sign(s, sign_char); 638 639 sc_numrep numrep = scfx_parse_prefix(s); 640 641 int base = 0; 642 643 switch (numrep) { 644 case SC_DEC: 645 { 646 base = 10; 647 if (scfx_is_nan(s)) // special case: NaN 648 return static_cast<double>(scfx_ieee_double::nan()); 649 if (scfx_is_inf(s)) // special case: Infinity 650 return static_cast<double>(scfx_ieee_double::inf(sign)); 651 break; 652 } 653 case SC_BIN: 654 case SC_BIN_US: 655 { 656 SCFX_FAIL_IF_(sign_char); 657 base = 2; 658 break; 659 } 660 661 case SC_BIN_SM: 662 { 663 base = 2; 664 break; 665 } 666 case SC_OCT: 667 case SC_OCT_US: 668 { 669 SCFX_FAIL_IF_(sign_char); 670 base = 8; 671 break; 672 } 673 case SC_OCT_SM: 674 { 675 base = 8; 676 break; 677 } 678 case SC_HEX: 679 case SC_HEX_US: 680 { 681 SCFX_FAIL_IF_(sign_char); 682 base = 16; 683 break; 684 } 685 case SC_HEX_SM: 686 { 687 base = 16; 688 break; 689 } 690 case SC_CSD: 691 { 692 SCFX_FAIL_IF_(sign_char); 693 base = 2; 694 scfx_csd2tc(s2); 695 s = (const char*) s2 + 4; 696 numrep = SC_BIN; 697 break; 698 } 699 default:;// Martin, what is default??? 700 } 701 702 // 703 // find end of mantissa and count the digits and points 704 // 705 706 const char *end = s; 707 bool based_point = false; 708 int int_digits = 0; 709 int frac_digits = 0; 710 711 while (*end) { 712 if (scfx_exp_start(end)) 713 break; 714 715 if (*end == '.') { 716 SCFX_FAIL_IF_(based_point); 717 based_point = true; 718 } else { 719 SCFX_FAIL_IF_(!scfx_is_digit(*end, numrep)); 720 if (based_point) 721 frac_digits++; 722 else 723 int_digits++; 724 } 725 726 end++; 727 } 728 729 SCFX_FAIL_IF_(int_digits == 0 && frac_digits == 0); 730 731 // [ exponent ] 732 int exponent = 0; 733 if (*end) { 734 for (const char *e = end + 2; *e; e++) 735 SCFX_FAIL_IF_(!scfx_is_digit(*e, SC_DEC)); 736 exponent = std::atoi(end + 1); 737 } 738 739 // 740 // convert the mantissa 741 // 742 double integer = 0.0; 743 if (int_digits != 0) { 744 bool first_digit = true; 745 746 for (; s < end; s++) { 747 if (*s == '.') 748 break; 749 750 if (first_digit) { 751 integer = scfx_to_digit(*s, numrep); 752 switch (numrep) { 753 case SC_BIN: 754 case SC_OCT: 755 case SC_HEX: 756 { 757 if (integer >= (base >> 1)) 758 integer -= base; // two's complement 759 break; 760 } 761 default: 762 ; 763 } 764 first_digit = false; 765 } else { 766 integer *= base; 767 integer += scfx_to_digit(*s, numrep); 768 } 769 } 770 } 771 772 // [ . fraction ] 773 double fraction = 0.0; 774 if (frac_digits != 0) { 775 s++; // skip '.' 776 777 bool first_digit = (int_digits == 0); 778 double scale = 1.0; 779 for (; s < end; s++) { 780 scale /= base; 781 782 if (first_digit) { 783 fraction = scfx_to_digit(*s, numrep); 784 switch (numrep) { 785 case SC_BIN: 786 case SC_OCT: 787 case SC_HEX: 788 { 789 if (fraction >= (base >> 1)) 790 fraction -= base; // two's complement 791 break; 792 } 793 default: 794 ; 795 } 796 fraction *= scale; 797 first_digit = false; 798 } else { 799 fraction += scfx_to_digit(*s, numrep) * scale; 800 } 801 } 802 } 803 804 double exp = 805 (exponent != 0) ? std::pow((double) base, (double) exponent) : 1; 806 807 return (sign * (integer + fraction) * exp); 808} 809 810#undef SCFX_FAIL_IF_ 811 812} // namespace sc_dt 813