| /***************************************************************************** | |
| Licensed to Accellera Systems Initiative Inc. (Accellera) under one or | |
| more contributor license agreements. See the NOTICE file distributed | |
| with this work for additional information regarding copyright ownership. | |
| Accellera licenses this file to you under the Apache License, Version 2.0 | |
| (the "License"); you may not use this file except in compliance with the | |
| License. You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |
| implied. See the License for the specific language governing | |
| permissions and limitations under the License. | |
| *****************************************************************************/ | |
| /***************************************************************************** | |
| sc_fxval.cpp - | |
| Original Author: Martin Janssen, Synopsys, Inc. | |
| *****************************************************************************/ | |
| /***************************************************************************** | |
| MODIFICATION LOG - modifiers, enter your name, affiliation, date and | |
| changes you are making here. | |
| Name, Affiliation, Date: | |
| Description of Modification: | |
| *****************************************************************************/ | |
| // $Log: sc_fxval.cpp,v $ | |
| // Revision 1.1.1.1 2006/12/15 20:20:04 acg | |
| // SystemC 2.3 | |
| // | |
| // Revision 1.3 2006/01/13 18:53:58 acg | |
| // Andy Goodrich: added $Log command so that CVS comments are reproduced in | |
| // the source. | |
| // | |
| #include <cctype> | |
| #include <cfloat> | |
| #include <cmath> | |
| #include <cstdlib> | |
| #include "systemc/ext/dt/fx/sc_fxval.hh" | |
| namespace sc_dt | |
| { | |
| // ---------------------------------------------------------------------------- | |
| // CLASS : sc_fxval | |
| // | |
| // Fixed-point value type; arbitrary precision. | |
| // ---------------------------------------------------------------------------- | |
| // explicit conversion to character string | |
| const std::string | |
| sc_fxval::to_string() const | |
| { | |
| return std::string(m_rep->to_string(SC_DEC, -1, SC_E)); | |
| } | |
| const std::string | |
| sc_fxval::to_string(sc_numrep numrep) const | |
| { | |
| return std::string(m_rep->to_string(numrep, -1, SC_E)); | |
| } | |
| const std::string | |
| sc_fxval::to_string(sc_numrep numrep, bool w_prefix) const | |
| { | |
| return std::string(m_rep->to_string(numrep, (w_prefix ? 1 : 0), SC_E)); | |
| } | |
| const std::string | |
| sc_fxval::to_string(sc_fmt fmt) const | |
| { | |
| return std::string(m_rep->to_string(SC_DEC, -1, fmt)); | |
| } | |
| const std::string | |
| sc_fxval::to_string(sc_numrep numrep, sc_fmt fmt) const | |
| { | |
| return std::string(m_rep->to_string(numrep, -1, fmt)); | |
| } | |
| const std::string | |
| sc_fxval::to_string(sc_numrep numrep, bool w_prefix, sc_fmt fmt) const | |
| { | |
| return std::string(m_rep->to_string(numrep, (w_prefix ? 1 : 0), fmt)); | |
| } | |
| const std::string | |
| sc_fxval::to_dec() const | |
| { | |
| return std::string(m_rep->to_string(SC_DEC, -1, SC_E)); | |
| } | |
| const std::string | |
| sc_fxval::to_bin() const | |
| { | |
| return std::string(m_rep->to_string(SC_BIN, -1, SC_E)); | |
| } | |
| const std::string | |
| sc_fxval::to_oct() const | |
| { | |
| return std::string(m_rep->to_string(SC_OCT, -1, SC_E)); | |
| } | |
| const std::string | |
| sc_fxval::to_hex() const | |
| { | |
| return std::string(m_rep->to_string(SC_HEX, -1, SC_E)); | |
| } | |
| // print or dump content | |
| void sc_fxval::print(::std::ostream &os) const { m_rep->print(os); } | |
| void | |
| sc_fxval::scan(::std::istream &is) | |
| { | |
| std::string s; | |
| is >> s; | |
| *this = s.c_str(); | |
| } | |
| void | |
| sc_fxval::dump(::std::ostream &os) const | |
| { | |
| os << "sc_fxval" << ::std::endl; | |
| os << "(" << ::std::endl; | |
| os << "rep = "; | |
| m_rep->dump(os); | |
| // TO BE COMPLETED | |
| // os << "r_flag = " << m_r_flag << ::std::endl; | |
| // os << "observer = "; | |
| // if (m_observer != 0) | |
| // m_observer->dump(os); | |
| // else | |
| // os << "0" << ::std::endl; | |
| os << ")" << ::std::endl; | |
| } | |
| // protected methods and friend functions | |
| sc_fxval_observer * | |
| sc_fxval::lock_observer() const | |
| { | |
| SC_ASSERT_(m_observer != 0, "lock observer failed"); | |
| sc_fxval_observer *tmp = m_observer; | |
| m_observer = 0; | |
| return tmp; | |
| } | |
| void | |
| sc_fxval::unlock_observer(sc_fxval_observer *observer_) const | |
| { | |
| SC_ASSERT_(observer_ != 0, "unlock observer failed"); | |
| m_observer = observer_; | |
| } | |
| // ---------------------------------------------------------------------------- | |
| // CLASS : sc_fxval_fast | |
| // | |
| // Fixed-point value types; limited precision. | |
| // ---------------------------------------------------------------------------- | |
| static void | |
| print_dec(scfx_string &s, scfx_ieee_double id, int w_prefix, sc_fmt fmt) | |
| { | |
| if (id.negative() != 0) { | |
| id.negative(0); | |
| s += '-'; | |
| } | |
| if (w_prefix == 1) { | |
| scfx_print_prefix(s, SC_DEC); | |
| } | |
| if (id.is_zero()) { | |
| s += '0'; | |
| return; | |
| } | |
| // split 'id' into its integer and fractional part | |
| double int_part; | |
| double frac_part = std::modf(static_cast<double>(id), &int_part); | |
| int i; | |
| // print integer part | |
| int int_digits = 0; | |
| int int_zeros = 0; | |
| if (int_part != 0.0) { | |
| int_digits = (int)std::ceil(std::log10(int_part + 1.0)); | |
| int len = s.length(); | |
| s.append(int_digits); | |
| bool zero_digits = (frac_part == 0.0 && fmt != SC_F); | |
| for (i = int_digits + len - 1; i >= len; i--) { | |
| unsigned int remainder = (unsigned int)std::fmod(int_part, 10.0); | |
| s[i] = static_cast<char>('0' + remainder); | |
| if (zero_digits) { | |
| if (remainder == 0) | |
| int_zeros++; | |
| else | |
| zero_digits = false; | |
| } | |
| int_part /= 10.0; | |
| } | |
| // discard trailing zeros from int_part | |
| s.discard(int_zeros); | |
| if (s[len] == '0') { | |
| // int_digits was overestimated by one | |
| s.remove(len); | |
| --int_digits; | |
| } | |
| } | |
| // print fractional part | |
| int frac_digits = 0; | |
| int frac_zeros = 0; | |
| if (frac_part != 0.0) { | |
| s += '.'; | |
| bool zero_digits = (int_digits == 0 && fmt != SC_F); | |
| frac_zeros = (int)std::floor(-std::log10(frac_part + DBL_EPSILON)); | |
| frac_part *= std::pow(10.0, frac_zeros); | |
| frac_digits = frac_zeros; | |
| if (!zero_digits) { | |
| for (i = 0; i < frac_zeros; i++) | |
| s += '0'; | |
| frac_zeros = 0; | |
| } | |
| while (frac_part != 0.0) { | |
| frac_part *= 10.0; | |
| int n = static_cast<int>(frac_part); | |
| if (zero_digits) { | |
| if (n == 0) | |
| frac_zeros++; | |
| else | |
| zero_digits = false; | |
| } | |
| if (!zero_digits) | |
| s += static_cast<char>('0' + n); | |
| frac_part -= n; | |
| frac_digits++; | |
| } | |
| } | |
| // print exponent | |
| if (fmt != SC_F) { | |
| if (frac_digits == 0) | |
| scfx_print_exp(s, int_zeros); | |
| else if (int_digits == 0) | |
| scfx_print_exp(s, -frac_zeros); | |
| } | |
| } | |
| static void | |
| print_other(scfx_string &s, const scfx_ieee_double &id, sc_numrep numrep, | |
| int w_prefix, sc_fmt fmt, const scfx_params *params) | |
| { | |
| scfx_ieee_double id2 = id; | |
| sc_numrep numrep2 = numrep; | |
| bool numrep_is_sm = (numrep == SC_BIN_SM || | |
| numrep == SC_OCT_SM || | |
| numrep == SC_HEX_SM); | |
| if (numrep_is_sm) { | |
| if (id2.negative() != 0) { | |
| s += '-'; | |
| id2.negative(0); | |
| } | |
| switch (numrep) { | |
| case SC_BIN_SM: | |
| numrep2 = SC_BIN_US; | |
| break; | |
| case SC_OCT_SM: | |
| numrep2 = SC_OCT_US; | |
| break; | |
| case SC_HEX_SM: | |
| numrep2 = SC_HEX_US; | |
| break; | |
| default: | |
| ; | |
| } | |
| } | |
| if (w_prefix != 0) { | |
| scfx_print_prefix(s, numrep); | |
| } | |
| numrep = numrep2; | |
| sc_fxval_fast a(id2); | |
| int msb, lsb; | |
| if (params != 0) { | |
| msb = params->iwl() - 1; | |
| lsb = params->iwl() - params->wl(); | |
| if (params->enc() == SC_TC_ && | |
| (numrep == SC_BIN_US || | |
| numrep == SC_OCT_US || | |
| numrep == SC_HEX_US) && | |
| !numrep_is_sm && | |
| params->wl() > 1) { | |
| --msb; | |
| } else if (params->enc() == SC_US_ && | |
| (numrep == SC_BIN || | |
| numrep == SC_OCT || | |
| numrep == SC_HEX || | |
| numrep == SC_CSD)) { | |
| ++msb; | |
| } | |
| } else { | |
| if (a.is_zero()) { | |
| msb = 0; | |
| lsb = 0; | |
| } else { | |
| msb = id2.exponent() + 1; | |
| while (a.get_bit(msb) == a.get_bit(msb - 1)) | |
| --msb; | |
| if (numrep == SC_BIN_US || | |
| numrep == SC_OCT_US || | |
| numrep == SC_HEX_US) { | |
| --msb; | |
| } | |
| lsb = id2.exponent() - 52; | |
| while (!a.get_bit(lsb)) | |
| ++lsb; | |
| } | |
| } | |
| int step; | |
| switch (numrep) { | |
| case SC_BIN: | |
| case SC_BIN_US: | |
| case SC_CSD: | |
| step = 1; | |
| break; | |
| case SC_OCT: | |
| case SC_OCT_US: | |
| step = 3; | |
| break; | |
| case SC_HEX: | |
| case SC_HEX_US: | |
| step = 4; | |
| break; | |
| default: | |
| SC_REPORT_FATAL("assertion failed", "unexpected sc_numrep"); | |
| sc_core::sc_abort(); | |
| } | |
| msb = (int)std::ceil(double(msb + 1) / step) * step - 1; | |
| lsb = (int)std::floor(double(lsb) / step) * step; | |
| if (msb < 0) { | |
| s += '.'; | |
| if (fmt == SC_F) { | |
| int sign = (id2.negative() != 0) ? (1 << step) - 1 : 0; | |
| for (int i = (msb + 1) / step; i < 0; i++) { | |
| if (sign < 10) | |
| s += static_cast<char>(sign + '0'); | |
| else | |
| s += static_cast<char>(sign + 'a' - 10); | |
| } | |
| } | |
| } | |
| int i = msb; | |
| while (i >= lsb) { | |
| int value = 0; | |
| for (int j = step - 1; j >= 0; --j) { | |
| value += static_cast<int>(a.get_bit(i)) << j; | |
| --i; | |
| } | |
| if (value < 10) | |
| s += static_cast<char>(value + '0'); | |
| else | |
| s += static_cast<char>(value + 'a' - 10); | |
| if (i == -1) | |
| s += '.'; | |
| } | |
| if (lsb > 0 && fmt == SC_F) { | |
| for (int i = lsb / step; i > 0; i--) | |
| s += '0'; | |
| } | |
| if (s[s.length() - 1] == '.') | |
| s.discard(1); | |
| if (fmt != SC_F) { | |
| if (msb < 0) | |
| scfx_print_exp(s, (msb + 1) / step); | |
| else if (lsb > 0) | |
| scfx_print_exp(s, lsb / step); | |
| } | |
| if (numrep == SC_CSD) | |
| scfx_tc2csd(s, w_prefix); | |
| } | |
| const char * | |
| to_string(const scfx_ieee_double &id, sc_numrep numrep, int w_prefix, | |
| sc_fmt fmt, const scfx_params *params=0) | |
| { | |
| static scfx_string s; | |
| s.clear(); | |
| if (id.is_nan()) { | |
| scfx_print_nan(s); | |
| } else if (id.is_inf()) { | |
| scfx_print_inf(s, static_cast<bool>(id.negative())); | |
| } else if (id.negative() && !id.is_zero() && | |
| (numrep == SC_BIN_US || | |
| numrep == SC_OCT_US || | |
| numrep == SC_HEX_US)) { | |
| s += "negative"; | |
| } else if (numrep == SC_DEC) { | |
| sc_dt::print_dec(s, id, w_prefix, fmt); | |
| } else { | |
| sc_dt::print_other(s, id, numrep, w_prefix, fmt, params); | |
| } | |
| return s; | |
| } | |
| // explicit conversion to character string | |
| const std::string | |
| sc_fxval_fast::to_string() const | |
| { | |
| return std::string(sc_dt::to_string(m_val, SC_DEC, -1, SC_E)); | |
| } | |
| const std::string | |
| sc_fxval_fast::to_string(sc_numrep numrep) const | |
| { | |
| return std::string(sc_dt::to_string(m_val, numrep, -1, SC_E)); | |
| } | |
| const std::string | |
| sc_fxval_fast::to_string(sc_numrep numrep, bool w_prefix) const | |
| { | |
| return std::string(sc_dt::to_string(m_val, numrep, (w_prefix ? 1 : 0), | |
| SC_E)); | |
| } | |
| const std::string | |
| sc_fxval_fast::to_string(sc_fmt fmt) const | |
| { | |
| return std::string(sc_dt::to_string(m_val, SC_DEC, -1, fmt)); | |
| } | |
| const std::string | |
| sc_fxval_fast::to_string(sc_numrep numrep, sc_fmt fmt) const | |
| { | |
| return std::string(sc_dt::to_string(m_val, numrep, -1, fmt)); | |
| } | |
| const std::string | |
| sc_fxval_fast::to_string(sc_numrep numrep, bool w_prefix, sc_fmt fmt) const | |
| { | |
| return std::string(sc_dt::to_string(m_val, numrep, (w_prefix ? 1 : 0), | |
| fmt)); | |
| } | |
| const std::string | |
| sc_fxval_fast::to_dec() const | |
| { | |
| return std::string(sc_dt::to_string(m_val, SC_DEC, -1, SC_E)); | |
| } | |
| const std::string | |
| sc_fxval_fast::to_bin() const | |
| { | |
| return std::string(sc_dt::to_string(m_val, SC_BIN, -1, SC_E)); | |
| } | |
| const std::string | |
| sc_fxval_fast::to_oct() const | |
| { | |
| return std::string(sc_dt::to_string(m_val, SC_OCT, -1, SC_E)); | |
| } | |
| const std::string | |
| sc_fxval_fast::to_hex() const | |
| { | |
| return std::string(sc_dt::to_string(m_val, SC_HEX, -1, SC_E)); | |
| } | |
| // print or dump content | |
| void | |
| sc_fxval_fast::print(::std::ostream &os) const | |
| { | |
| os << sc_dt::to_string(m_val, SC_DEC, -1, SC_E); | |
| } | |
| void | |
| sc_fxval_fast::scan(::std::istream &is) | |
| { | |
| std::string s; | |
| is >> s; | |
| *this = s.c_str(); | |
| } | |
| void | |
| sc_fxval_fast::dump(::std::ostream &os) const | |
| { | |
| os << "sc_fxval_fast" << ::std::endl; | |
| os << "(" << ::std::endl; | |
| os << "val = " << m_val << ::std::endl; | |
| // TO BE COMPLETED | |
| // os << "r_flag = " << m_r_flag << ::std::endl; | |
| // os << "observer = "; | |
| // if (m_observer != 0) | |
| // m_observer->dump(os); | |
| // else | |
| // os << "0" << ::std::endl; | |
| os << ")" << ::std::endl; | |
| } | |
| // internal use only; | |
| bool | |
| sc_fxval_fast::get_bit(int i) const | |
| { | |
| scfx_ieee_double id(m_val); | |
| if (id.is_zero() || id.is_nan() || id.is_inf()) | |
| return false; | |
| // convert to two's complement | |
| unsigned int m0 = id.mantissa0(); | |
| unsigned int m1 = id.mantissa1(); | |
| if (id.is_normal()) | |
| m0 += 1U << 20; | |
| if (id.negative() != 0) { | |
| m0 = ~ m0; | |
| m1 = ~ m1; | |
| unsigned int tmp = m1; | |
| m1 += 1U; | |
| if (m1 <= tmp) | |
| m0 += 1U; | |
| } | |
| // get the right bit | |
| int j = i - id.exponent(); | |
| if ((j += 20) >= 32) | |
| return ((m0 & 1U << 31) != 0); | |
| else if (j >= 0) | |
| return ((m0 & 1U << j) != 0); | |
| else if ((j += 32) >= 0) | |
| return ((m1 & 1U << j) != 0); | |
| else | |
| return false; | |
| } | |
| // protected methods and friend functions | |
| sc_fxval_fast_observer * | |
| sc_fxval_fast::lock_observer() const | |
| { | |
| SC_ASSERT_(m_observer != 0, "lock observer failed"); | |
| sc_fxval_fast_observer *tmp = m_observer; | |
| m_observer = 0; | |
| return tmp; | |
| } | |
| void | |
| sc_fxval_fast::unlock_observer(sc_fxval_fast_observer *observer_) const | |
| { | |
| SC_ASSERT_(observer_ != 0, "unlock observer failed"); | |
| m_observer = observer_; | |
| } | |
| #define SCFX_FAIL_IF_(cnd) \ | |
| { \ | |
| if ((cnd)) \ | |
| return static_cast<double>(scfx_ieee_double::nan()); \ | |
| } | |
| double | |
| sc_fxval_fast::from_string(const char *s) | |
| { | |
| SCFX_FAIL_IF_(s == 0 || *s == 0); | |
| scfx_string s2; | |
| s2 += s; | |
| s2 += '\0'; | |
| bool sign_char; | |
| int sign = scfx_parse_sign(s, sign_char); | |
| sc_numrep numrep = scfx_parse_prefix(s); | |
| int base = 0; | |
| switch (numrep) { | |
| case SC_DEC: | |
| { | |
| base = 10; | |
| if (scfx_is_nan(s)) // special case: NaN | |
| return static_cast<double>(scfx_ieee_double::nan()); | |
| if (scfx_is_inf(s)) // special case: Infinity | |
| return static_cast<double>(scfx_ieee_double::inf(sign)); | |
| break; | |
| } | |
| case SC_BIN: | |
| case SC_BIN_US: | |
| { | |
| SCFX_FAIL_IF_(sign_char); | |
| base = 2; | |
| break; | |
| } | |
| case SC_BIN_SM: | |
| { | |
| base = 2; | |
| break; | |
| } | |
| case SC_OCT: | |
| case SC_OCT_US: | |
| { | |
| SCFX_FAIL_IF_(sign_char); | |
| base = 8; | |
| break; | |
| } | |
| case SC_OCT_SM: | |
| { | |
| base = 8; | |
| break; | |
| } | |
| case SC_HEX: | |
| case SC_HEX_US: | |
| { | |
| SCFX_FAIL_IF_(sign_char); | |
| base = 16; | |
| break; | |
| } | |
| case SC_HEX_SM: | |
| { | |
| base = 16; | |
| break; | |
| } | |
| case SC_CSD: | |
| { | |
| SCFX_FAIL_IF_(sign_char); | |
| base = 2; | |
| scfx_csd2tc(s2); | |
| s = (const char*) s2 + 4; | |
| numrep = SC_BIN; | |
| break; | |
| } | |
| default:;// Martin, what is default??? | |
| } | |
| // | |
| // find end of mantissa and count the digits and points | |
| // | |
| const char *end = s; | |
| bool based_point = false; | |
| int int_digits = 0; | |
| int frac_digits = 0; | |
| while (*end) { | |
| if (scfx_exp_start(end)) | |
| break; | |
| if (*end == '.') { | |
| SCFX_FAIL_IF_(based_point); | |
| based_point = true; | |
| } else { | |
| SCFX_FAIL_IF_(!scfx_is_digit(*end, numrep)); | |
| if (based_point) | |
| frac_digits++; | |
| else | |
| int_digits++; | |
| } | |
| end++; | |
| } | |
| SCFX_FAIL_IF_(int_digits == 0 && frac_digits == 0); | |
| // [ exponent ] | |
| int exponent = 0; | |
| if (*end) { | |
| for (const char *e = end + 2; *e; e++) | |
| SCFX_FAIL_IF_(!scfx_is_digit(*e, SC_DEC)); | |
| exponent = std::atoi(end + 1); | |
| } | |
| // | |
| // convert the mantissa | |
| // | |
| double integer = 0.0; | |
| if (int_digits != 0) { | |
| bool first_digit = true; | |
| for (; s < end; s++) { | |
| if (*s == '.') | |
| break; | |
| if (first_digit) { | |
| integer = scfx_to_digit(*s, numrep); | |
| switch (numrep) { | |
| case SC_BIN: | |
| case SC_OCT: | |
| case SC_HEX: | |
| { | |
| if (integer >= (base >> 1)) | |
| integer -= base; // two's complement | |
| break; | |
| } | |
| default: | |
| ; | |
| } | |
| first_digit = false; | |
| } else { | |
| integer *= base; | |
| integer += scfx_to_digit(*s, numrep); | |
| } | |
| } | |
| } | |
| // [ . fraction ] | |
| double fraction = 0.0; | |
| if (frac_digits != 0) { | |
| s++; // skip '.' | |
| bool first_digit = (int_digits == 0); | |
| double scale = 1.0; | |
| for (; s < end; s++) { | |
| scale /= base; | |
| if (first_digit) { | |
| fraction = scfx_to_digit(*s, numrep); | |
| switch (numrep) { | |
| case SC_BIN: | |
| case SC_OCT: | |
| case SC_HEX: | |
| { | |
| if (fraction >= (base >> 1)) | |
| fraction -= base; // two's complement | |
| break; | |
| } | |
| default: | |
| ; | |
| } | |
| fraction *= scale; | |
| first_digit = false; | |
| } else { | |
| fraction += scfx_to_digit(*s, numrep) * scale; | |
| } | |
| } | |
| } | |
| double exp = | |
| (exponent != 0) ? std::pow((double) base, (double) exponent) : 1; | |
| return (sign * (integer + fraction) * exp); | |
| } | |
| #undef SCFX_FAIL_IF_ | |
| } // namespace sc_dt |