summaryrefslogtreecommitdiff
path: root/src/systemc/dt/fx/sc_fxval.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/systemc/dt/fx/sc_fxval.cc')
-rw-r--r--src/systemc/dt/fx/sc_fxval.cc810
1 files changed, 810 insertions, 0 deletions
diff --git a/src/systemc/dt/fx/sc_fxval.cc b/src/systemc/dt/fx/sc_fxval.cc
new file mode 100644
index 000000000..45d7d5735
--- /dev/null
+++ b/src/systemc/dt/fx/sc_fxval.cc
@@ -0,0 +1,810 @@
+/*****************************************************************************
+
+ 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