diff options
Diffstat (limited to 'src/systemc/dt/fx/sc_fxnum.cc')
-rw-r--r-- | src/systemc/dt/fx/sc_fxnum.cc | 867 |
1 files changed, 867 insertions, 0 deletions
diff --git a/src/systemc/dt/fx/sc_fxnum.cc b/src/systemc/dt/fx/sc_fxnum.cc new file mode 100644 index 000000000..f47b4d342 --- /dev/null +++ b/src/systemc/dt/fx/sc_fxnum.cc @@ -0,0 +1,867 @@ +/***************************************************************************** + + 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_fxnum.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_fxnum.cpp,v $ +// Revision 1.3 2011/01/19 18:57:40 acg +// Andy Goodrich: changes for IEEE_1666_2011. +// +// Revision 1.2 2010/12/07 20:09:08 acg +// Andy Goodrich: Philipp Hartmann's constructor disambiguation fix +// +// Revision 1.1.1.1 2006/12/15 20:20:04 acg +// SystemC 2.3 +// +// Revision 1.3 2006/01/13 18:53:57 acg +// Andy Goodrich: added $Log command so that CVS comments are reproduced in +// the source. +// + +#include <cmath> + +#include "systemc/ext/dt/fx/sc_fxnum.hh" + +namespace sc_dt +{ + +// ---------------------------------------------------------------------------- +// CLASS : sc_fxnum_bitref +// +// Proxy class for bit-selection in class sc_fxnum, behaves like sc_bit. +// ---------------------------------------------------------------------------- + +bool sc_fxnum_bitref::get() const { return m_num.get_bit(m_idx); } +void sc_fxnum_bitref::set(bool high) { m_num.set_bit(m_idx, high); } + +// print or dump content +void sc_fxnum_bitref::print(::std::ostream &os) const { os << get(); } + +void +sc_fxnum_bitref::scan(::std::istream &is) +{ + bool b; + is >> b; + *this = b; +} + +void +sc_fxnum_bitref::dump(::std::ostream &os) const +{ + os << "sc_fxnum_bitref" << ::std::endl; + os << "(" << ::std::endl; + os << "num = "; + m_num.dump(os); + os << "idx = " << m_idx << ::std::endl; + os << ")" << ::std::endl; +} + + +// ---------------------------------------------------------------------------- +// CLASS : sc_fxnum_fast_bitref +// +// Proxy class for bit-selection in class sc_fxnum_fast, behaves like sc_bit. +// ---------------------------------------------------------------------------- + +bool sc_fxnum_fast_bitref::get() const { return m_num.get_bit(m_idx); } +void sc_fxnum_fast_bitref::set(bool high) { m_num.set_bit(m_idx, high); } + +// print or dump content +void sc_fxnum_fast_bitref::print(::std::ostream &os) const { os << get(); } + +void +sc_fxnum_fast_bitref::scan(::std::istream &is) +{ + bool b; + is >> b; + *this = b; +} + +void +sc_fxnum_fast_bitref::dump(::std::ostream &os) const +{ + os << "sc_fxnum_fast_bitref" << ::std::endl; + os << "(" << ::std::endl; + os << "num = "; + m_num.dump(os); + os << "idx = " << m_idx << ::std::endl; + os << ")" << ::std::endl; +} + +// ---------------------------------------------------------------------------- +// CLASS : sc_fxnum_subref +// +// Proxy class for part-selection in class sc_fxnum, +// behaves like sc_bv_base. +// ---------------------------------------------------------------------------- + +bool +sc_fxnum_subref::get() const +{ + return m_num.get_slice(m_from, m_to, m_bv); +} + +bool +sc_fxnum_subref::set() +{ + return m_num.set_slice(m_from, m_to, m_bv); +} + +// print or dump content +void +sc_fxnum_subref::print(::std::ostream &os) const +{ + get(); + m_bv.print(os); +} + +void +sc_fxnum_subref::scan(::std::istream &is) +{ + m_bv.scan(is); + set(); +} + +void +sc_fxnum_subref::dump(::std::ostream &os) const +{ + os << "sc_fxnum_subref" << ::std::endl; + os << "(" << ::std::endl; + os << "num = "; + m_num.dump(os); + os << "from = " << m_from << ::std::endl; + os << "to = " << m_to << ::std::endl; + os << ")" << ::std::endl; +} + + +// ---------------------------------------------------------------------------- +// CLASS : sc_fxnum_fast_subref +// +// Proxy class for part-selection in class sc_fxnum_fast, +// behaves like sc_bv_base. +// ---------------------------------------------------------------------------- + +bool +sc_fxnum_fast_subref::get() const +{ + return m_num.get_slice(m_from, m_to, m_bv); +} + +bool +sc_fxnum_fast_subref::set() +{ + return m_num.set_slice(m_from, m_to, m_bv); +} + +// print or dump content +void +sc_fxnum_fast_subref::print(::std::ostream &os) const +{ + get(); + m_bv.print(os); +} + +void +sc_fxnum_fast_subref::scan(::std::istream &is) +{ + m_bv.scan(is); + set(); +} + +void +sc_fxnum_fast_subref::dump(::std::ostream &os) const +{ + os << "sc_fxnum_fast_subref" << ::std::endl; + os << "(" << ::std::endl; + os << "num = "; + m_num.dump(os); + os << "from = " << m_from << ::std::endl; + os << "to = " << m_to << ::std::endl; + os << ")" << ::std::endl; +} + + +// ---------------------------------------------------------------------------- +// CLASS : sc_fxnum +// +// Base class for the fixed-point types; arbitrary precision. +// ---------------------------------------------------------------------------- + +// explicit conversion to character string + +const std::string +sc_fxnum::to_string() const +{ + return std::string(m_rep->to_string(SC_DEC, -1, SC_F, &m_params)); +} + +const std::string +sc_fxnum::to_string(sc_numrep numrep) const +{ + return std::string(m_rep->to_string(numrep, -1, SC_F, &m_params)); +} + +const std::string +sc_fxnum::to_string(sc_numrep numrep, bool w_prefix) const +{ + return std::string(m_rep->to_string(numrep, (w_prefix ? 1 : 0), + SC_F, &m_params)); +} + +const std::string +sc_fxnum::to_string(sc_fmt fmt) const +{ + return std::string(m_rep->to_string(SC_DEC, -1, fmt, &m_params)); +} + +const std::string +sc_fxnum::to_string(sc_numrep numrep, sc_fmt fmt) const +{ + return std::string(m_rep->to_string(numrep, -1, fmt, &m_params)); +} + +const std::string +sc_fxnum::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, &m_params)); +} + + +const std::string +sc_fxnum::to_dec() const +{ + return std::string(m_rep->to_string(SC_DEC, -1, SC_F, &m_params)); +} + +const std::string +sc_fxnum::to_bin() const +{ + return std::string(m_rep->to_string(SC_BIN, -1, SC_F, &m_params)); +} + +const std::string +sc_fxnum::to_oct() const +{ + return std::string(m_rep->to_string(SC_OCT, -1, SC_F, &m_params)); +} + +const std::string +sc_fxnum::to_hex() const +{ + return std::string(m_rep->to_string(SC_HEX, -1, SC_F, &m_params)); +} + + +// print or dump content +void +sc_fxnum::print(::std::ostream &os) const +{ + os << m_rep->to_string(SC_DEC, -1, SC_F, &m_params); +} + +void +sc_fxnum::scan(::std::istream &is) +{ + std::string s; + is >> s; + *this = s.c_str(); +} + +void +sc_fxnum::dump(::std::ostream &os) const +{ + os << "sc_fxnum" << ::std::endl; + os << "(" << ::std::endl; + os << "rep = "; + m_rep->dump(os); + os << "params = "; + m_params.dump(os); + os << "q_flag = " << m_q_flag << ::std::endl; + os << "o_flag = " << m_o_flag << ::std::endl; + // TO BE COMPLETED + // os << "observer = "; + // if (m_observer != 0) + // m_observer->dump(os); + // else + // os << "0" << ::std::endl; + os << ")" << ::std::endl; +} + + +sc_fxnum_observer * +sc_fxnum::lock_observer() const +{ + SC_ASSERT_(m_observer != 0, "lock observer failed"); + sc_fxnum_observer * tmp = m_observer; + m_observer = 0; + return tmp; +} + +void +sc_fxnum::unlock_observer(sc_fxnum_observer *observer_) const +{ + SC_ASSERT_(observer_ != 0, "unlock observer failed"); + m_observer = observer_; +} + + +// ---------------------------------------------------------------------------- +// CLASS : sc_fxnum_fast +// +// Base class for the fixed-point types; limited precision. +// ---------------------------------------------------------------------------- + +static void +quantization(double &c, const scfx_params ¶ms, bool &q_flag) +{ + int fwl = params.wl() - params.iwl(); + double scale = scfx_pow2(fwl); + double val = scale * c; + double int_part; + double frac_part = modf(val, &int_part); + + q_flag = (frac_part != 0.0); + + if (q_flag) { + val = int_part; + + switch (params.q_mode()) { + case SC_TRN: // truncation + { + if (c < 0.0) + val -= 1.0; + break; + } + case SC_RND: // rounding to plus infinity + { + if (frac_part >= 0.5) + val += 1.0; + else if (frac_part < -0.5) + val -= 1.0; + break; + } + case SC_TRN_ZERO: // truncation to zero + { + break; + } + case SC_RND_INF: // rounding to infinity + { + if (frac_part >= 0.5) + val += 1.0; + else if (frac_part <= -0.5) + val -= 1.0; + break; + } + case SC_RND_CONV: // convergent rounding + { + if (frac_part > 0.5 || + (frac_part == 0.5 && fmod(int_part, 2.0) != 0.0)) { + val += 1.0; + } else if (frac_part < -0.5 || + (frac_part == -0.5 && fmod(int_part, 2.0) != 0.0)) { + val -= 1.0; + } + break; + } + case SC_RND_ZERO: // rounding to zero + { + if (frac_part > 0.5) + val += 1.0; + else if (frac_part < -0.5) + val -= 1.0; + break; + } + case SC_RND_MIN_INF: // rounding to minus infinity + { + if (frac_part > 0.5) + val += 1.0; + else if (frac_part <= -0.5) + val -= 1.0; + break; + } + default: + ; + } + } + + val /= scale; + c = val; +} + +static void +overflow(double &c, const scfx_params ¶ms, bool &o_flag) +{ + int iwl = params.iwl(); + int fwl = params.wl() - iwl; + double full_circle = scfx_pow2(iwl); + double resolution = scfx_pow2(-fwl); + double low, high; + if (params.enc() == SC_TC_) { + high = full_circle / 2.0 - resolution; + if (params.o_mode() == SC_SAT_SYM) + low = - high; + else + low = - full_circle / 2.0; + } else { + low = 0.0; + high = full_circle - resolution; + } + double val = c; + sc_fxval_fast c2(c); + + bool under = (val < low); + bool over = (val > high); + + o_flag = (under || over); + + if (o_flag) { + switch (params.o_mode()) { + case SC_WRAP: // wrap-around + { + int n_bits = params.n_bits(); + + if (n_bits == 0) { + // wrap-around all 'wl' bits + val -= floor(val / full_circle) * full_circle; + if (val > high) + val -= full_circle; + } else if (n_bits < params.wl()) { + double X = scfx_pow2(iwl - n_bits); + + // wrap-around least significant 'wl - n_bits' bits + val -= floor(val / X) * X; + if (val > (X - resolution)) + val -= X; + + // saturate most significant 'n_bits' bits + if (under) { + val += low; + } else { + if (params.enc() == SC_TC_) + val += full_circle / 2.0 - X; + else + val += full_circle - X; + } + } else { + // saturate all 'wl' bits + if (under) + val = low; + else + val = high; + } + break; + } + case SC_SAT: // saturation + case SC_SAT_SYM: // symmetrical saturation + { + if (under) + val = low; + else + val = high; + break; + } + case SC_SAT_ZERO: // saturation to zero + { + val = 0.0; + break; + } + case SC_WRAP_SM: // sign magnitude wrap-around + { + SC_ERROR_IF_(params.enc() == SC_US_, + "SC_WRAP_SM not defined for unsigned numbers"); + + int n_bits = params.n_bits(); + + if (n_bits == 0) { + // invert conditionally + if (c2.get_bit(iwl) != c2.get_bit(iwl - 1)) + val = -val - resolution; + + // wrap-around all 'wl' bits + val -= floor(val / full_circle) * full_circle; + if (val > high) + val -= full_circle; + } else if (n_bits == 1) { + // invert conditionally + if (c2.is_neg() != c2.get_bit(iwl - 1)) + val = -val - resolution; + + // wrap-around all 'wl' bits + val -= floor(val / full_circle) * full_circle; + if (val > high) + val -= full_circle; + } else if (n_bits < params.wl()) { + // invert conditionally + if (c2.is_neg() == c2.get_bit(iwl - n_bits)) + val = -val - resolution; + + double X = scfx_pow2(iwl - n_bits); + + // wrap-around least significant 'wl - n_bits' bits + val -= floor(val / X) * X; + if (val > (X - resolution)) + val -= X; + + // saturate most significant 'n_bits' bits + if (under) + val += low; + else + val += full_circle / 2.0 - X; + } else { + // saturate all 'wl' bits + if (under) + val = low; + else + val = high; + } + break; + } + default: + ; + } + + c = val; + } +} + + +void +sc_fxnum_fast::cast() +{ + scfx_ieee_double id(m_val); + SC_ERROR_IF_(id.is_nan() || id.is_inf(), "invalid fixed-point value"); + + if (m_params.cast_switch() == SC_ON) { + m_q_flag = false; + m_o_flag = false; + + // check for special cases + + if (id.is_zero()) { + if (id.negative() != 0) + m_val = -m_val; + return; + } + + // perform casting + sc_dt::quantization(m_val, m_params, m_q_flag); + sc_dt::overflow(m_val, m_params, m_o_flag); + + // check for special case: -0 + id = m_val; + if (id.is_zero() && id.negative() != 0) { + m_val = -m_val; + } + + // check for special case: NaN of Inf + if (id.is_nan() || id.is_inf()) { + m_val = 0.0; + } + } +} + + +// defined in sc_fxval.cpp; +extern const char* to_string(const scfx_ieee_double &, sc_numrep, int, sc_fmt, + const scfx_params * =0); + + +// explicit conversion to character string + +const std::string +sc_fxnum_fast::to_string() const +{ + return std::string(sc_dt::to_string(m_val, SC_DEC, -1, SC_F, &m_params)); +} + +const std::string +sc_fxnum_fast::to_string(sc_numrep numrep) const +{ + return std::string(sc_dt::to_string(m_val, numrep, -1, SC_F, &m_params)); +} + +const std::string +sc_fxnum_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_F, &m_params)); +} + +const std::string +sc_fxnum_fast::to_string(sc_fmt fmt) const +{ + return std::string(sc_dt::to_string(m_val, SC_DEC, -1, fmt, &m_params)); +} + +const std::string +sc_fxnum_fast::to_string(sc_numrep numrep, sc_fmt fmt) const +{ + return std::string(sc_dt::to_string(m_val, numrep, -1, fmt, &m_params)); +} + +const std::string +sc_fxnum_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, &m_params)); +} + + +const std::string +sc_fxnum_fast::to_dec() const +{ + return std::string(sc_dt::to_string(m_val, SC_DEC, -1, SC_F, &m_params)); +} + +const std::string +sc_fxnum_fast::to_bin() const +{ + return std::string(sc_dt::to_string(m_val, SC_BIN, -1, SC_F, &m_params)); +} + +const std::string +sc_fxnum_fast::to_oct() const +{ + return std::string(sc_dt::to_string(m_val, SC_OCT, -1, SC_F, &m_params)); +} + +const std::string +sc_fxnum_fast::to_hex() const +{ + return std::string(sc_dt::to_string(m_val, SC_HEX, -1, SC_F, &m_params)); +} + +// print or dump content +void +sc_fxnum_fast::print(::std::ostream &os) const +{ + os << sc_dt::to_string(m_val, SC_DEC, -1, SC_F, &m_params); +} + +void +sc_fxnum_fast::scan(::std::istream &is) +{ + std::string s; + is >> s; + *this = s.c_str(); +} + +void +sc_fxnum_fast::dump(::std::ostream &os) const +{ + os << "sc_fxnum_fast" << ::std::endl; + os << "(" << ::std::endl; + os << "val = " << m_val << ::std::endl; + os << "params = "; + m_params.dump(os); + os << "q_flag = " << m_q_flag << ::std::endl; + os << "o_flag = " << m_o_flag << ::std::endl; + // TO BE COMPLETED + // os << "observer = "; + // if (m_observer != 0) + // m_observer->dump(os); + // else + // os << "0" << ::std::endl; + os << ")" << ::std::endl; +} + +// internal use only; +bool +sc_fxnum_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; +} + + +bool +sc_fxnum_fast::set_bit(int i, bool high) +{ + scfx_ieee_double id(m_val); + if (id.is_nan() || id.is_inf()) + return false; + + if (high) { + if (get_bit(i)) + return true; + + if (m_params.enc() == SC_TC_ && i == m_params.iwl() - 1) + m_val -= scfx_pow2(i); + else + m_val += scfx_pow2(i); + } else { + if (!get_bit(i)) + return true; + + if (m_params.enc() == SC_TC_ && i == m_params.iwl() - 1) + m_val += scfx_pow2(i); + else + m_val -= scfx_pow2(i); + } + + return true; +} + + +bool +sc_fxnum_fast::get_slice(int i, int j, sc_bv_base &bv) const +{ + scfx_ieee_double id(m_val); + if (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 bits + int l = j; + for (int k = 0; k < bv.length(); ++ k) { + bool b = false; + + int n = l - id.exponent(); + if ((n += 20) >= 32) + b = ((m0 & 1U << 31) != 0); + else if (n >= 0) + b = ((m0 & 1U << n) != 0); + else if ((n += 32) >= 0) + b = ((m1 & 1U << n) != 0); + + bv[k] = b; + + if (i >= j) + ++l; + else + --l; + } + + return true; +} + +bool +sc_fxnum_fast::set_slice(int i, int j, const sc_bv_base &bv) +{ + scfx_ieee_double id(m_val); + if (id.is_nan() || id.is_inf()) + return false; + + // set the bits + int l = j; + for (int k = 0; k < bv.length(); ++k) { + if (bv[k].to_bool()) { + if (!get_bit(l)) { + if (m_params.enc() == SC_TC_ && l == m_params.iwl() - 1) + m_val -= scfx_pow2(l); + else + m_val += scfx_pow2(l); + } + } else { + if (get_bit(l)) { + if (m_params.enc() == SC_TC_ && l == m_params.iwl() - 1) + m_val += scfx_pow2(l); + else + m_val -= scfx_pow2(l); + } + } + + if (i >= j) + ++l; + else + --l; + } + + return true; +} + +sc_fxnum_fast_observer * +sc_fxnum_fast::lock_observer() const +{ + SC_ASSERT_(m_observer != 0, "lock observer failed"); + sc_fxnum_fast_observer *tmp = m_observer; + m_observer = 0; + return tmp; +} + +void +sc_fxnum_fast::unlock_observer(sc_fxnum_fast_observer *observer_) const +{ + SC_ASSERT_(observer_ != 0, "unlock observer failed"); + m_observer = observer_; +} + +} // namespace sc_dt |