diff options
Diffstat (limited to 'src/systemc/dt/fx')
-rw-r--r-- | src/systemc/dt/fx/SConscript | 41 | ||||
-rw-r--r-- | src/systemc/dt/fx/sc_fxcast_switch.cc | 86 | ||||
-rw-r--r-- | src/systemc/dt/fx/sc_fxdefs.cc | 166 | ||||
-rw-r--r-- | src/systemc/dt/fx/sc_fxnum.cc | 867 | ||||
-rw-r--r-- | src/systemc/dt/fx/sc_fxnum_observer.cc | 70 | ||||
-rw-r--r-- | src/systemc/dt/fx/sc_fxtype_params.cc | 97 | ||||
-rw-r--r-- | src/systemc/dt/fx/sc_fxval.cc | 810 | ||||
-rw-r--r-- | src/systemc/dt/fx/sc_fxval_observer.cc | 72 | ||||
-rw-r--r-- | src/systemc/dt/fx/scfx_mant.cc | 117 | ||||
-rw-r--r-- | src/systemc/dt/fx/scfx_pow10.cc | 129 | ||||
-rw-r--r-- | src/systemc/dt/fx/scfx_rep.cc | 2651 | ||||
-rw-r--r-- | src/systemc/dt/fx/scfx_utils.cc | 162 |
12 files changed, 5268 insertions, 0 deletions
diff --git a/src/systemc/dt/fx/SConscript b/src/systemc/dt/fx/SConscript new file mode 100644 index 000000000..698496cf4 --- /dev/null +++ b/src/systemc/dt/fx/SConscript @@ -0,0 +1,41 @@ +# Copyright 2018 Google, Inc. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +Import('*') + +if env['USE_SYSTEMC']: + Source('sc_fxcast_switch.cc') + Source('sc_fxdefs.cc') + Source('scfx_mant.cc') + Source('sc_fxnum.cc') + Source('sc_fxnum_observer.cc') + Source('scfx_pow10.cc') + Source('scfx_rep.cc') + Source('sc_fxtype_params.cc') + Source('scfx_utils.cc') + Source('sc_fxval.cc') + Source('sc_fxval_observer.cc') diff --git a/src/systemc/dt/fx/sc_fxcast_switch.cc b/src/systemc/dt/fx/sc_fxcast_switch.cc new file mode 100644 index 000000000..9aabe14ae --- /dev/null +++ b/src/systemc/dt/fx/sc_fxcast_switch.cc @@ -0,0 +1,86 @@ +/***************************************************************************** + + 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_fxcast_switch.cpp - + + Original Author: Martin Janssen, Synopsys, Inc. + + *****************************************************************************/ + +/***************************************************************************** + + MODIFICATION LOG - modifiers, enter your name, affiliation, date and + changes you are making here. + + Name, Affiliation, Date: Gene Bushuyev, Synopsys, Inc. + Description of Modification: - fix explicit instantiation syntax. + + Name, Affiliation, Date: + Description of Modification: + + *****************************************************************************/ + + +// $Log: sc_fxcast_switch.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:57 acg +// Andy Goodrich: added $Log command so that CVS comments are reproduced in +// the source. +// + +#include "systemc/ext/dt/fx/sc_fxcast_switch.hh" + +namespace sc_dt +{ + +template class sc_global<sc_fxcast_switch>; +template class sc_context<sc_fxcast_switch>; + +// ---------------------------------------------------------------------------- +// CLASS : sc_fxcast_switch +// +// Fixed-point cast switch class. +// ---------------------------------------------------------------------------- + +const std::string +sc_fxcast_switch::to_string() const +{ + return sc_dt::to_string(m_sw); +} + +void +sc_fxcast_switch::print(::std::ostream &os) const +{ + os << sc_dt::to_string(m_sw); +} + +void +sc_fxcast_switch::dump(::std::ostream &os) const +{ + os << "sc_fxcast_switch" << ::std::endl; + os << "(" << ::std::endl; + os << "sw = " << sc_dt::to_string(m_sw) << ::std::endl; + os << ")" << ::std::endl; +} + +} // namespace sc_dt diff --git a/src/systemc/dt/fx/sc_fxdefs.cc b/src/systemc/dt/fx/sc_fxdefs.cc new file mode 100644 index 000000000..4a9e7458f --- /dev/null +++ b/src/systemc/dt/fx/sc_fxdefs.cc @@ -0,0 +1,166 @@ +/***************************************************************************** + + 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_fxdefs.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_fxdefs.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:57 acg +// Andy Goodrich: added $Log command so that CVS comments are reproduced in +// the source. +// + +#include "systemc/ext/dt/fx/sc_fxdefs.hh" + +namespace sc_dt +{ + +// ---------------------------------------------------------------------------- +// ENUM : sc_enc +// +// Enumeration of sign encodings. +// ---------------------------------------------------------------------------- + +const std::string +to_string(sc_enc enc) +{ + switch (enc) { + case SC_TC_: + return std::string("SC_TC_"); + case SC_US_: + return std::string("SC_US_"); + default: + return std::string("unknown"); + } +} + +// ---------------------------------------------------------------------------- +// ENUM : sc_q_mode +// +// Enumeration of quantization modes. +// ---------------------------------------------------------------------------- + +const std::string +to_string(sc_q_mode q_mode) +{ + switch (q_mode) { + case SC_RND: + return std::string("SC_RND"); + case SC_RND_ZERO: + return std::string("SC_RND_ZERO"); + case SC_RND_MIN_INF: + return std::string("SC_RND_MIN_INF"); + case SC_RND_INF: + return std::string("SC_RND_INF"); + case SC_RND_CONV: + return std::string("SC_RND_CONV"); + case SC_TRN: + return std::string("SC_TRN"); + case SC_TRN_ZERO: + return std::string("SC_TRN_ZERO"); + default: + return std::string("unknown"); + } +} + +// ---------------------------------------------------------------------------- +// ENUM : sc_o_mode +// +// Enumeration of overflow modes. +// ---------------------------------------------------------------------------- + +const std::string +to_string(sc_o_mode o_mode) +{ + switch (o_mode) { + case SC_SAT: + return std::string("SC_SAT"); + case SC_SAT_ZERO: + return std::string("SC_SAT_ZERO"); + case SC_SAT_SYM: + return std::string("SC_SAT_SYM"); + case SC_WRAP: + return std::string("SC_WRAP"); + case SC_WRAP_SM: + return std::string("SC_WRAP_SM"); + default: + return std::string("unknown"); + } +} + + +// ---------------------------------------------------------------------------- +// ENUM : sc_switch +// +// Enumeration of switch states. +// ---------------------------------------------------------------------------- + +const std::string +to_string(sc_switch sw) +{ + switch (sw) { + case SC_OFF: + return std::string("SC_OFF"); + case SC_ON: + return std::string("SC_ON"); + default: + return std::string("unknown"); + } +} + + +// ---------------------------------------------------------------------------- +// ENUM : sc_fmt +// +// Enumeration of formats for character string conversion. +// ---------------------------------------------------------------------------- + +const std::string +to_string(sc_fmt fmt) +{ + switch (fmt) { + case SC_F: + return std::string("SC_F"); + case SC_E: + return std::string("SC_E"); + default: + return std::string("unknown"); + } +} + +} // namespace sc_dt 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 diff --git a/src/systemc/dt/fx/sc_fxnum_observer.cc b/src/systemc/dt/fx/sc_fxnum_observer.cc new file mode 100644 index 000000000..1ee3c9b8b --- /dev/null +++ b/src/systemc/dt/fx/sc_fxnum_observer.cc @@ -0,0 +1,70 @@ +/***************************************************************************** + + 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_observer.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_observer.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 "systemc/ext/dt/fx/sc_fxnum_observer.hh" + +namespace sc_dt +{ + +// ---------------------------------------------------------------------------- +// CLASS : sc_fxnum_observer +// +// Abstract base class for fixed-point types observers; arbitrary precision. +// ---------------------------------------------------------------------------- + +sc_fxnum_observer *(* sc_fxnum_observer::default_observer) () = 0; + + +// ---------------------------------------------------------------------------- +// CLASS : sc_fxnum_fast_observer +// +// Abstract base class for fixed-point types observers; limited precision. +// ---------------------------------------------------------------------------- + +sc_fxnum_fast_observer *(* sc_fxnum_fast_observer::default_observer) () = 0; + +} // namespace sc_dt diff --git a/src/systemc/dt/fx/sc_fxtype_params.cc b/src/systemc/dt/fx/sc_fxtype_params.cc new file mode 100644 index 000000000..54af8a7ee --- /dev/null +++ b/src/systemc/dt/fx/sc_fxtype_params.cc @@ -0,0 +1,97 @@ +/***************************************************************************** + + 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_fxtype_params.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_fxtype_params.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 <sstream> + +#include "systemc/ext/dt/fx/sc_fxtype_params.hh" + +namespace sc_dt +{ + +template class sc_global<sc_fxtype_params>; +template class sc_context<sc_fxtype_params>; + +// ---------------------------------------------------------------------------- +// CLASS : sc_fxtype_params +// +// Fixed-point type parameters class. +// ---------------------------------------------------------------------------- + +const std::string +sc_fxtype_params::to_string() const +{ + std::stringstream ss; + print(ss); + return ss.str(); +} + +void +sc_fxtype_params::print(::std::ostream &os) const +{ + os << "(" + << m_wl << "," + << m_iwl << "," + << m_q_mode << "," + << m_o_mode << "," + << m_n_bits + << ")"; +} + +void +sc_fxtype_params::dump(::std::ostream &os) const +{ + os << "sc_fxtype_params" << ::std::endl; + os << "(" << ::std::endl; + os << "wl = " << m_wl << ::std::endl; + os << "iwl = " << m_iwl << ::std::endl; + os << "q_mode = " << m_q_mode << ::std::endl; + os << "o_mode = " << m_o_mode << ::std::endl; + os << "n_bits = " << m_n_bits << ::std::endl; + os << ")" << ::std::endl; +} + +} // namespace sc_dt 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 diff --git a/src/systemc/dt/fx/sc_fxval_observer.cc b/src/systemc/dt/fx/sc_fxval_observer.cc new file mode 100644 index 000000000..7b143ad04 --- /dev/null +++ b/src/systemc/dt/fx/sc_fxval_observer.cc @@ -0,0 +1,72 @@ +/***************************************************************************** + + 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_observer.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_observer.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 "systemc/ext/dt/fx/sc_fxval_observer.hh" + +namespace sc_dt +{ + +// ---------------------------------------------------------------------------- +// CLASS : sc_fxval_observer +// +// Abstract base class for fixed-point value type observers; +// arbitrary precision. +// ---------------------------------------------------------------------------- + +sc_fxval_observer *(* sc_fxval_observer::default_observer)() = 0; + + +// ---------------------------------------------------------------------------- +// CLASS : sc_fxval_fast_observer +// +// Abstract base class for fixed-point value type observers; +// limited precision. +// ---------------------------------------------------------------------------- + +sc_fxval_fast_observer *(* sc_fxval_fast_observer::default_observer)() = 0; + +} // namespace sc_dt diff --git a/src/systemc/dt/fx/scfx_mant.cc b/src/systemc/dt/fx/scfx_mant.cc new file mode 100644 index 000000000..41f3aedcb --- /dev/null +++ b/src/systemc/dt/fx/scfx_mant.cc @@ -0,0 +1,117 @@ +/***************************************************************************** + + 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. + + *****************************************************************************/ + +/***************************************************************************** + + scfx_mant.cpp - + + Original Author: Robert Graulich, Synopsys, Inc. + 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: scfx_mant.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 "systemc/ext/dt/fx/scfx_mant.hh" + +namespace sc_dt +{ + +// ---------------------------------------------------------------------------- +// word memory management +// ---------------------------------------------------------------------------- + +class word_list // Entry in free_words bucket. +{ + public: + word_list *m_next_p; +}; + +static inline unsigned +next_pow2_index(std::size_t size) +{ + unsigned index = scfx_find_msb(size); + // If this was a power of 2 we are one bucket too low. + if (~(UINT64_ONE << index) & size) + index++; + // If this is a 64-bit machine and we are using 32-bit words go down + // one slot size, as all the slots are 2x in size. + if (index != 0 && (sizeof(word_list) != sizeof(word))) { + index -= 1; + } + return index; +} + +static word_list *free_words[32] = { 0 }; + +word * +scfx_mant::alloc_word(std::size_t size) +{ + const int ALLOC_SIZE = 128; + + unsigned slot_index = next_pow2_index(size); + unsigned alloc_size = (UINT64_ONE << slot_index); + + word_list*& slot = free_words[slot_index]; + + if (!slot) { + slot = new word_list[ALLOC_SIZE * alloc_size]; + unsigned i; + for (i = 0; i < alloc_size * (ALLOC_SIZE - 1) ; i += alloc_size) { + slot[i].m_next_p = &slot[i + alloc_size]; + } + slot[i].m_next_p = 0; + } + + word *result = (word *)slot; + free_words[slot_index] = slot[0].m_next_p; + return result; +} + +void +scfx_mant::free_word(word *array, std::size_t size) +{ + if (array && size) { + int slot_index = next_pow2_index(size); + word_list *wl_p = (word_list *)array; + + wl_p->m_next_p = free_words[slot_index]; + free_words[slot_index] = wl_p; + } +} + +} // namespace sc_dt diff --git a/src/systemc/dt/fx/scfx_pow10.cc b/src/systemc/dt/fx/scfx_pow10.cc new file mode 100644 index 000000000..fd940f94e --- /dev/null +++ b/src/systemc/dt/fx/scfx_pow10.cc @@ -0,0 +1,129 @@ +/***************************************************************************** + + 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. + + *****************************************************************************/ + +/***************************************************************************** + + scfx_pow10.cpp - + + Original Author: Robert Graulich, Synopsys, Inc. + 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: scfx_pow10.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 "systemc/ext/dt/fx/scfx_pow10.hh" + +namespace sc_dt +{ + +// ---------------------------------------------------------------------------- +// CLASS : scfx_pow10 +// +// Class to compute (and cache) powers of 10 in arbitrary precision. +// ---------------------------------------------------------------------------- + +scfx_pow10::scfx_pow10() +{ + m_pos[0] = scfx_rep(10.0); + m_neg[0] = scfx_rep(0.1); + + for (int i = 1; i < SCFX_POW10_TABLE_SIZE; i++) { + m_pos[i].set_nan(); + m_neg[i].set_nan(); + } +} + +scfx_pow10::~scfx_pow10() {} + +const scfx_rep +scfx_pow10::operator() (int i) +{ + if (i == 0) { + return scfx_rep(1.0); + } + + if (i > 0) { + int bit = scfx_find_msb(i); + scfx_rep result = *pos(bit); + if (bit) { + while (--bit >= 0) { + if ((1 << bit) & i) { + scfx_rep *tmp = mult_scfx_rep(result, *pos(bit)); + result = *tmp; + delete tmp; + } + } + } + return result; + } else { + i = -i; + int bit = scfx_find_msb(i); + scfx_rep result = *neg(bit); + if (bit) { + while (--bit >= 0) { + if ((1 << bit) & i) { + scfx_rep *tmp = mult_scfx_rep(result, *neg(bit)); + result = *tmp; + delete tmp; + } + } + } + return result; + } +} + + +scfx_rep * +scfx_pow10::pos(int i) +{ + if (!m_pos[i].is_normal()) { + multiply(m_pos[i], *pos(i - 1), *pos(i - 1)); + } + return &m_pos[i]; +} + +scfx_rep * +scfx_pow10::neg(int i) +{ + if (!m_neg[i].is_normal()) { + multiply(m_neg[i], *neg(i - 1), *neg(i - 1)); + } + return &m_neg[i]; +} + +} // namespace sc_dt diff --git a/src/systemc/dt/fx/scfx_rep.cc b/src/systemc/dt/fx/scfx_rep.cc new file mode 100644 index 000000000..3d10fb3f6 --- /dev/null +++ b/src/systemc/dt/fx/scfx_rep.cc @@ -0,0 +1,2651 @@ +/***************************************************************************** + + 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. + + *****************************************************************************/ + +/***************************************************************************** + + scfx_rep.cpp - + + Original Author: Robert Graulich, Synopsys, Inc. + 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: scfx_rep.cpp,v $ +// Revision 1.4 2011/08/24 22:05:43 acg +// Torsten Maehne: initialization changes to remove warnings. +// +// Revision 1.3 2011/08/15 16:43:24 acg +// Torsten Maehne: changes to remove unused argument warnings. +// +// Revision 1.2 2009/02/28 00:26:20 acg +// Andy Goodrich: bug fixes. +// +// Revision 1.2 2008/11/06 17:22:47 acg +// Andy Goodrich: bug fixes for 2.2.1. +// +// Revision 1.1.1.1 2006/12/15 20:31:36 acg +// SystemC 2.2 +// +// 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 <cmath> +#include <cstdio> +#include <cstdlib> + +#include "base/compiler.hh" +#include "systemc/ext/dt/bit/sc_bv_base.hh" +#include "systemc/ext/dt/bit/sc_lv_base.hh" +#include "systemc/ext/dt/fx/scfx_ieee.hh" +#include "systemc/ext/dt/fx/scfx_pow10.hh" +#include "systemc/ext/dt/fx/scfx_rep.hh" +#include "systemc/ext/dt/fx/scfx_utils.hh" +#include "systemc/ext/utils/endian.hh" + +namespace sc_dt +{ + +// ---------------------------------------------------------------------------- +// some utilities +// ---------------------------------------------------------------------------- + +static scfx_pow10 pow10_fx; + +static const int mantissa0_size = SCFX_IEEE_DOUBLE_M_SIZE - bits_in_int; + +static inline int +n_word(int x) +{ + return (x + bits_in_word - 1) / bits_in_word; +} + + +// ---------------------------------------------------------------------------- +// CONSTRUCTORS +// ---------------------------------------------------------------------------- + +scfx_rep::scfx_rep() : + m_mant(min_mant), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(), + m_r_flag(false) +{ + set_zero(); +} + +scfx_rep::scfx_rep(int a) : m_mant(min_mant), m_wp(), m_sign(), m_state(), + m_msw(), m_lsw(), m_r_flag(false) +{ + if (a != 0) { + m_mant.clear(); + m_wp = m_msw = m_lsw = 2; + m_state = normal; + if (a > 0) { + m_mant[2] = a; + m_sign = 1; + } else { + m_mant[2] = -a; + m_sign = -1; + } + } else { + set_zero(); + } +} + +scfx_rep::scfx_rep(unsigned int a) : m_mant(min_mant), m_wp(), m_sign(), + m_state(), m_msw(), m_lsw(), m_r_flag(false) +{ + if (a != 0) { + m_mant.clear(); + m_wp = m_msw = m_lsw = 2; + m_state = normal; + m_mant[2] = a; + m_sign = 1; + } else { + set_zero(); + } +} + +scfx_rep::scfx_rep(long a) : + m_mant(min_mant), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(), + m_r_flag(false) +{ + if (a != 0) { + m_mant.clear(); + m_state = normal; + if (a > 0) { + m_sign = 1; + } else { + a = -a; + m_sign = -1; + } +# if defined(SC_LONG_64) + m_wp = 1; + m_mant[1] = static_cast<word>(a); + m_mant[2] = static_cast<word>(a >> bits_in_word); + find_sw(); +# else + m_wp = 2; + m_msw = 2; + m_lsw = 2; + m_mant[2] = a; +# endif + } else { + set_zero(); + } +} + +scfx_rep::scfx_rep(unsigned long a) : + m_mant(min_mant), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(), + m_r_flag(false) +{ + if (a != 0) { + m_mant.clear(); + m_wp = m_msw = m_lsw = 2; + m_state = normal; +# if defined(SC_LONG_64) + m_wp = 1; + m_mant[1] = static_cast<word>(a); + m_mant[2] = static_cast<word>(a >> bits_in_word); + find_sw(); +# else + m_wp = 2; + m_msw = 2; + m_lsw = 2; + m_mant[2] = a; +# endif + m_sign = 1; + } + else + set_zero(); +} + +scfx_rep::scfx_rep(double a) : + m_mant(min_mant), m_wp(0), m_sign(), m_state(normal), m_msw(0), + m_lsw(0), m_r_flag(false) +{ + m_mant.clear(); + + scfx_ieee_double id(a); + + m_sign = id.negative() ? -1 : 1; + + if (id.is_nan()) { + m_state = not_a_number; + } else if (id.is_inf()) { + m_state = infinity; + } else if (id.is_subnormal()) { + m_mant[0] = id.mantissa1(); + m_mant[1] = id.mantissa0(); + normalize(id.exponent() + 1 - SCFX_IEEE_DOUBLE_M_SIZE); + } else if (id.is_normal()) { + m_mant[0] = id.mantissa1(); + m_mant[1] = id.mantissa0() | (1 << mantissa0_size); + normalize(id.exponent() - SCFX_IEEE_DOUBLE_M_SIZE); + } +} + +scfx_rep::scfx_rep(int64 a) : + m_mant(min_mant), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(), + m_r_flag(false) +{ + if (a != 0) { + m_mant.clear(); + m_wp = 1; + m_state = normal; + if (a > 0) { + m_mant[1] = static_cast<word>(a); + m_mant[2] = static_cast<word>(a >> bits_in_word); + m_sign = 1; + } else { + m_mant[1] = static_cast<word>(-a); + m_mant[2] = static_cast<word>((-a) >> bits_in_word); + m_sign = -1; + } + find_sw(); + } else { + set_zero(); + } +} + +scfx_rep::scfx_rep(uint64 a) : + m_mant(min_mant), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(), + m_r_flag(false) +{ + if (a != 0) { + m_mant.clear(); + m_wp = 1; + m_state = normal; + m_mant[1] = static_cast<word>(a); + m_mant[2] = static_cast<word>(a >> bits_in_word); + m_sign = 1; + find_sw(); + } else { + set_zero(); + } +} + +scfx_rep::scfx_rep(const sc_signed &a) : + m_mant(min_mant), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(), + m_r_flag(false) +{ + if (a.iszero()) { + set_zero(); + } else { + int words = n_word(a.length()); + if (words > size()) + resize_to(words); + m_mant.clear(); + m_wp = 0; + m_state = normal; + if (a.sign()) { + sc_signed a2 = -a; + for (int i = 0; i < a2.length(); ++i) { + if (a2[i]) { + scfx_index x = calc_indices(i); + m_mant[x.wi()] |= 1 << x.bi(); + } + } + m_sign = -1; + } else { + for (int i = 0; i < a.length(); ++i) { + if (a[i]) { + scfx_index x = calc_indices(i); + m_mant[x.wi()] |= 1 << x.bi(); + } + } + m_sign = 1; + } + find_sw(); + } +} + +scfx_rep::scfx_rep(const sc_unsigned &a) : + m_mant(min_mant), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(), + m_r_flag(false) +{ + if (a.iszero()) { + set_zero(); + } else { + int words = n_word(a.length()); + if (words > size()) + resize_to(words); + m_mant.clear(); + m_wp = 0; + m_state = normal; + for (int i = 0; i < a.length(); ++i) { + if (a[i]) { + scfx_index x = calc_indices(i); + m_mant[x.wi()] |= 1 << x.bi(); + } + } + m_sign = 1; + find_sw(); + } +} + +// copy constructor +scfx_rep::scfx_rep(const scfx_rep &a) : + m_mant(a.m_mant), m_wp(a.m_wp), m_sign(a.m_sign), m_state(a.m_state), + m_msw(a.m_msw), m_lsw(a.m_lsw), m_r_flag(false) +{} + + +// ---------------------------------------------------------------------------- +// OPERATORS : new, delete +// +// Memory management for class scfx_rep. +// ---------------------------------------------------------------------------- + +union scfx_rep_node +{ + char data[sizeof(scfx_rep)]; + scfx_rep_node *next; +}; + +static scfx_rep_node *list = 0; + +void * +scfx_rep::operator new(std::size_t size) +{ + const int ALLOC_SIZE = 1024; + + if (size != sizeof(scfx_rep)) + return ::operator new(size); + + if (!list) { + list = new scfx_rep_node[ALLOC_SIZE]; + for (int i = 0; i < ALLOC_SIZE - 1; i++) + list[i].next = list + i + 1; + list[ALLOC_SIZE - 1].next = 0; + } + + scfx_rep *ptr = reinterpret_cast<scfx_rep *>(list->data); + list = list->next; + + return ptr; +} + +void +scfx_rep::operator delete(void *ptr, std::size_t size) +{ + if (size != sizeof(scfx_rep)) { + ::operator delete(ptr); + return; + } + + scfx_rep_node *node = static_cast<scfx_rep_node *>(ptr); + node->next = list; + list = node; +} + + +// ---------------------------------------------------------------------------- +// METHOD : from_string +// +// Convert from character string to sc_fxrep. +// ---------------------------------------------------------------------------- + +#define SCFX_FAIL_IF_(cnd) \ +{ \ + if ((cnd)) { \ + m_state = not_a_number; \ + m_mant.clear(); /* to avoid Purify UMRs during assignment */ \ + return; \ + } \ +} + +void +scfx_rep::from_string(const char *s, int cte_wl) +{ + SCFX_FAIL_IF_(s == 0 || *s == 0); + + scfx_string s2; + s2 += s; + s2 += '\0'; + + bool sign_char; + m_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 + m_state = not_a_number; + m_mant.clear(); /* to avoid Purify UMRs during assignment */ + return; + } + if (scfx_is_inf(s)) { // special case: Infinity + m_state = infinity; + m_mant.clear(); /* to avoid Purify UMRs during assignment */ + return; + } + 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: + ; + } + + // + // 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); + } + + // + // check if the mantissa is negative + // + bool mant_is_neg = false; + switch (numrep) { + case SC_BIN: + case SC_OCT: + case SC_HEX: + { + const char *p = s; + if (*p == '.') + ++p; + + mant_is_neg = (scfx_to_digit(* p, numrep) >= (base >> 1)); + break; + } + default: + ; + } + + // + // convert the mantissa + // + + switch (base) { + case 2: + { + int bit_offset = exponent % bits_in_word; + int word_offset = exponent / bits_in_word; + + int_digits += bit_offset; + frac_digits -= bit_offset; + + int words = n_word(int_digits) + n_word(frac_digits); + if (words > size()) + resize_to(words); + m_mant.clear(); + + int j = n_word(frac_digits) * bits_in_word + int_digits - 1; + + for (; s < end; s++) { + switch (*s) { + case '1': + set_bin(j); + M5_FALLTHROUGH; + case '0': + j--; + M5_FALLTHROUGH; + case '.': + break; + default: + SCFX_FAIL_IF_(true); // should not happen + } + } + + m_wp = n_word(frac_digits) - word_offset; + break; + } + case 8: + { + exponent *= 3; + int_digits *= 3; + frac_digits *= 3; + + int bit_offset = exponent % bits_in_word; + int word_offset = exponent / bits_in_word; + + int_digits += bit_offset; + frac_digits -= bit_offset; + + int words = n_word(int_digits) + n_word(frac_digits); + if (words > size()) + resize_to(words); + m_mant.clear(); + + int j = n_word(frac_digits) * bits_in_word + int_digits - 3; + + for (; s < end; s++) { + switch (*s) { + case '7': case '6': case '5': case '4': + case '3': case '2': case '1': + set_oct(j, *s - '0'); + M5_FALLTHROUGH; + case '0': + j -= 3; + M5_FALLTHROUGH; + case '.': + break; + default: + SCFX_FAIL_IF_(true); // should not happen + } + } + + m_wp = n_word(frac_digits) - word_offset; + break; + } + case 10: + { + word carry, temp; + int length = int_digits + frac_digits; + resize_to(sc_max(min_mant, n_word(4 * length))); + + m_mant.clear(); + m_msw = m_lsw = 0; + + for (; s < end; s++) { + switch (*s) { + case '9': case '8': case '7': case '6': case '5': + case '4': case '3': case '2': case '1': case '0': + multiply_by_ten(); + carry = *s - '0'; + for (int i = 0; carry && i < m_mant.size(); i++) { + temp = m_mant[i]; + temp += carry; + carry = temp < m_mant[i]; + m_mant[i] = temp; + } + case '.': + break; + default: + SCFX_FAIL_IF_(true); // should not happen + } + } + + m_wp = 0; + find_sw(); + + int denominator = frac_digits - exponent; + + if (denominator) { + scfx_rep frac_num = pow10_fx(denominator); + scfx_rep *temp_num = + div_scfx_rep(const_cast<const scfx_rep &>(*this), + frac_num, cte_wl); + *this = *temp_num; + delete temp_num; + } + + break; + } + case 16: + { + exponent *= 4; + int_digits *= 4; + frac_digits *= 4; + + int bit_offset = exponent % bits_in_word; + int word_offset = exponent / bits_in_word; + + int_digits += bit_offset; + frac_digits -= bit_offset; + + int words = n_word(int_digits) + n_word(frac_digits); + if (words > size()) + resize_to(words); + m_mant.clear(); + + int j = n_word(frac_digits) * bits_in_word + int_digits - 4; + + for (; s < end; s ++) { + switch (*s) { + case 'f': case 'e': case 'd': case 'c': case 'b': case 'a': + set_hex(j, *s - 'a' + 10); + j -= 4; + break; + case 'F': case 'E': case 'D': case 'C': case 'B': case 'A': + set_hex(j, *s - 'A' + 10); + j -= 4; + break; + case '9': case '8': case '7': case '6': case '5': + case '4': case '3': case '2': case '1': + set_hex(j, *s - '0'); + M5_FALLTHROUGH; + case '0': + j -= 4; + M5_FALLTHROUGH; + case '.': + break; + default: + SCFX_FAIL_IF_(true); // should not happen + } + } + + m_wp = n_word(frac_digits) - word_offset; + break; + } + } + + m_state = normal; + find_sw(); + + // + // two's complement of mantissa if it is negative + // + if (mant_is_neg) { + m_mant[m_msw] |= ~0U << scfx_find_msb(m_mant[m_msw]); + for (int i = m_msw + 1; i < m_mant.size(); ++i) + m_mant[i] = static_cast<word>(-1); + complement(m_mant, m_mant, m_mant.size()); + inc(m_mant); + m_sign *= -1; + find_sw(); + } +} + +#undef SCFX_FAIL_IF_ + +// ---------------------------------------------------------------------------- +// METHOD : to_double +// +// Convert from scfx_rep to double. +// ---------------------------------------------------------------------------- + +double +scfx_rep::to_double() const +{ + scfx_ieee_double id; + + // handle special cases + if (is_nan()) { + id.set_nan(); + return id; + } + + if (is_inf()) { + id.set_inf(); + id.negative(m_sign < 0); + return id; + } + + if (is_zero()) { + id = 0.; + id.negative(m_sign < 0); + return id; + } + + int msb = scfx_find_msb(m_mant[m_msw]); + + int exp = (m_msw - m_wp) * bits_in_word + msb; + + if (exp > SCFX_IEEE_DOUBLE_E_MAX) { + id.set_inf(); + id.negative(m_sign < 0); + return id; + } + + if (exp < SCFX_IEEE_DOUBLE_E_MIN - + static_cast<int>(SCFX_IEEE_DOUBLE_M_SIZE)) + { + id = 0.; + return id; + } + + int shift = mantissa0_size - msb; + + unsigned int m0; + unsigned int m1 = 0; + unsigned int guard = 0; + + if (shift == 0) { + m0 = m_mant[m_msw] & ~(1 << mantissa0_size); + if (m_msw > m_lsw) { + m1 = m_mant[m_msw - 1]; + if (m_msw - 1 > m_lsw) + guard = m_mant[m_msw - 2] >> (bits_in_word - 1); + } + } else if (shift < 0) { + m0 = (m_mant[m_msw] >> -shift) & ~(1 << mantissa0_size); + m1 = m_mant[m_msw] << (bits_in_word + shift); + if (m_msw > m_lsw) { + m1 |= m_mant[m_msw - 1] >> -shift; + guard = (m_mant[m_msw - 1] >> (-shift - 1)) & 1; + } + } else { + m0 = (m_mant[m_msw] << shift) & ~(1 << mantissa0_size); + if (m_msw > m_lsw) { + m0 |= m_mant[m_msw - 1] >> (bits_in_word - shift); + m1 = m_mant[m_msw - 1] << shift; + if (m_msw - 1 > m_lsw) { + m1 |= m_mant[m_msw - 2] >> (bits_in_word - shift); + guard = (m_mant[m_msw - 2] >> (bits_in_word - shift - 1)) & 1; + } + } + } + + if (exp < SCFX_IEEE_DOUBLE_E_MIN) { + m0 |= (1 << mantissa0_size); + + int subnormal_shift = SCFX_IEEE_DOUBLE_E_MIN - exp; + + if (subnormal_shift < bits_in_word) { + m1 = m1 >> subnormal_shift | + m0 << (bits_in_word - subnormal_shift); + m0 = m0 >> subnormal_shift; + } else { + m1 = m0 >> (subnormal_shift - bits_in_word); + m0 = 0; + } + + guard = 0; + + exp = SCFX_IEEE_DOUBLE_E_MIN - 1; + } + + id.mantissa0(m0); + id.mantissa1(m1); + id.exponent(exp); + id.negative(m_sign < 0); + + double result = id; + + if (guard != 0) + result += m_sign * scfx_pow2(exp - SCFX_IEEE_DOUBLE_M_SIZE); + + return result; +} + + +// ---------------------------------------------------------------------------- +// METHOD : to_uint64 +// +// Convert from scfx_rep to uint64. +// Truncates towards 0 _then_ wraps; infinities and NaN go to zero. +// ---------------------------------------------------------------------------- + +uint64 +scfx_rep::to_uint64() const +{ + if (!is_normal() || is_zero()) { + return 0; + } + + uint64 result = 0; + int shift = 0; + int idx = m_wp; + + // Ignore bits off the top; they modulo out. + // Ignore bits off the bottom; we're truncating. + while (shift < 64 && m_msw >= idx && idx >= m_lsw) { + result += static_cast<uint64>(m_mant[idx]) << shift; + shift += bits_in_word; + idx += 1; + } + + return m_sign > 0 ? result : -result; +} + + +// ---------------------------------------------------------------------------- +// METHOD : to_string +// +// Convert from scfx_rep to character string. +// ---------------------------------------------------------------------------- + +void +print_dec(scfx_string &s, const scfx_rep &num, int w_prefix, sc_fmt fmt) +{ + if (num.is_neg()) + s += '-'; + + if (w_prefix == 1) { + scfx_print_prefix(s, SC_DEC); + } + + if (num.is_zero()) { + s += '0'; + return; + } + + // split 'num' into its integer and fractional part + scfx_rep int_part = num; + scfx_rep frac_part = num; + + int i; + + for (i = int_part.m_lsw; i <= int_part.m_msw && i < int_part.m_wp; i++) + int_part.m_mant[i] = 0; + int_part.find_sw(); + if (int_part.m_wp < int_part.m_lsw) + int_part.resize_to(int_part.size() - int_part.m_wp, -1); + + for (i = frac_part.m_msw; + i >= frac_part.m_lsw && i >= frac_part.m_wp; i--) + frac_part.m_mant[i] = 0; + frac_part.find_sw(); + if (frac_part.m_msw == frac_part.size() - 1) + frac_part.resize_to(frac_part.size() + 1, 1); + + // print integer part + int int_digits = 0; + int int_zeros = 0; + + if (!int_part.is_zero()) { + double int_wl = (int_part.m_msw - int_part.m_wp) * bits_in_word + + scfx_find_msb(int_part.m_mant[int_part.m_msw]) + 1; + int_digits = (int)std::ceil(int_wl * std::log10(2.)); + + int len = s.length(); + s.append(int_digits); + + bool zero_digits = (frac_part.is_zero() && fmt != SC_F); + + for (i = int_digits + len - 1; i >= len; i--) { + unsigned int remainder = int_part.divide_by_ten(); + s[i] = static_cast<char>('0' + remainder); + + if (zero_digits) { + if (remainder == 0) + int_zeros++; + else + zero_digits = false; + } + } + + // 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.is_zero()) { + s += '.'; + + bool zero_digits = (int_digits == 0 && fmt != SC_F); + + double frac_wl = (frac_part.m_wp - frac_part.m_msw) * bits_in_word - + scfx_find_msb(frac_part.m_mant[frac_part.m_msw]) - 1; + frac_zeros = (int)std::floor(frac_wl * std::log10(2.)); + + scfx_rep temp; + sc_dt::multiply(temp, frac_part, pow10_fx(frac_zeros)); + frac_part = temp; + if (frac_part.m_msw == frac_part.size() - 1) + frac_part.resize_to(frac_part.size() + 1, 1); + + frac_digits = frac_zeros; + if (!zero_digits) { + for (i = 0; i < frac_zeros; i++) + s += '0'; + frac_zeros = 0; + } + + while (!frac_part.is_zero()) { + frac_part.multiply_by_ten(); + int n = frac_part.m_mant[frac_part.m_msw + 1]; + + if (zero_digits) { + if (n == 0) + frac_zeros++; + else + zero_digits = false; + } + + if (! zero_digits) + s += static_cast<char>('0' + n); + + frac_part.m_mant[frac_part.m_msw + 1] = 0; + 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); + } +} + +void +print_other(scfx_string &s, const scfx_rep &a, sc_numrep numrep, int w_prefix, + sc_fmt fmt, const scfx_params *params) +{ + scfx_rep b = a; + + 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 (b.is_neg()) { + s += '-'; + b = *neg_scfx_rep(a); + } + 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; + + 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 (b.is_zero()) { + msb = 0; + lsb = 0; + } else { + msb = (b.m_msw - b.m_wp) * bits_in_word + + scfx_find_msb(b.m_mant[ b.m_msw ]) + 1; + while (b.get_bit(msb) == b.get_bit(msb - 1)) + --msb; + + if (numrep == SC_BIN_US || + numrep == SC_OCT_US || + numrep == SC_HEX_US) { + --msb; + } + + lsb = (b.m_lsw - b.m_wp) * bits_in_word + + scfx_find_lsb(b.m_mant[b.m_lsw]); + } + } + + 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 = (b.is_neg()) ? (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>(b.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 * +scfx_rep::to_string(sc_numrep numrep, int w_prefix, + sc_fmt fmt, const scfx_params *params) const +{ + static scfx_string s; + + s.clear(); + + if (is_nan()) { + scfx_print_nan(s); + } else if (is_inf()) { + scfx_print_inf(s, is_neg()); + } else if (is_neg() && !is_zero() && + (numrep == SC_BIN_US || + numrep == SC_OCT_US || + numrep == SC_HEX_US)) { + s += "negative"; + } else if (numrep == SC_DEC || numrep == SC_NOBASE) { + sc_dt::print_dec(s, *this, w_prefix, fmt); + } else { + sc_dt::print_other(s, *this, numrep, w_prefix, fmt, params); + } + + return s; +} + + +// ---------------------------------------------------------------------------- +// ADD +// +// add two mantissas of the same size +// result has the same size +// returns carry of operation +// ---------------------------------------------------------------------------- + +static inline int +add_mants(int size, scfx_mant &result, const scfx_mant &a, const scfx_mant &b) +{ + unsigned int carry = 0; + + int index = 0; + + do { + word x = a[index]; + word y = b[index]; + + y += carry; + carry = y < carry; + y += x; + carry += y < x; + result[index] = y; + } while (++index < size); + + return (carry ? 1 : 0); +} + +static inline int +sub_mants(int size, scfx_mant &result, const scfx_mant &a, const scfx_mant &b) +{ + unsigned carry = 0; + + int index = 0; + + do { + word x = a[index]; + word y = b[index]; + + y += carry; + carry = y < carry; + y = x - y; + carry += y > x; + result[index] = y; + } while (++index < size); + + return (carry ? 1 : 0); +} + +scfx_rep * +add_scfx_rep(const scfx_rep &lhs, const scfx_rep &rhs, int max_wl) +{ + scfx_rep &result = *new scfx_rep; + + // + // check for special cases + // + if (lhs.is_nan() || rhs.is_nan() || + (lhs.is_inf() && rhs.is_inf() && lhs.m_sign != rhs.m_sign)) { + result.set_nan(); + return &result; + } + + if (lhs.is_inf()) { + result.set_inf(lhs.m_sign); + return &result; + } + + if (rhs.is_inf()) { + result.set_inf(rhs.m_sign); + return &result; + } + + // + // align operands if needed + // + scfx_mant_ref lhs_mant; + scfx_mant_ref rhs_mant; + + int len_mant = lhs.size(); + int new_wp = lhs.m_wp; + + align(lhs, rhs, new_wp, len_mant, lhs_mant, rhs_mant); + + // + // size the result mantissa + // + result.resize_to(len_mant); + result.m_wp = new_wp; + + // + // do it + // + if (lhs.m_sign == rhs.m_sign) { + add_mants(len_mant, result.m_mant, lhs_mant, rhs_mant); + result.m_sign = lhs.m_sign; + } else { + int cmp = compare_abs(lhs, rhs); + + if (cmp == 1) { + sub_mants(len_mant, result.m_mant, lhs_mant, rhs_mant); + result.m_sign = lhs.m_sign; + } else if (cmp == -1) { + sub_mants(len_mant, result.m_mant, rhs_mant, lhs_mant); + result.m_sign = rhs.m_sign; + } else { + result.m_mant.clear(); + result.m_sign = 1; + } + } + + result.find_sw(); + result.round(max_wl); + + return &result; +} + + +// ---------------------------------------------------------------------------- +// SUB +// +// sub two word's of the same size +// result has the same size +// returns carry of operation +// ---------------------------------------------------------------------------- + +static inline int +sub_with_index(scfx_mant &a, int a_msw, int /*a_lsw*/, + const scfx_mant &b, int b_msw, int b_lsw) +{ + unsigned carry = 0; + + int size = b_msw - b_lsw; + int a_index = a_msw - size; + int b_index = b_msw - size; + + do { + word x = a[a_index]; + word y = b[b_index]; + + y += carry; + carry = y < carry; + y = x - y; + carry += y > x; + a[a_index] = y; + + a_index++; + b_index++; + } while (size--); + + if (carry) { + // special case: a[a_msw + 1] == 1 + a[a_msw + 1] = 0; + } + + return (carry ? 1 : 0); +} + +scfx_rep * +sub_scfx_rep(const scfx_rep &lhs, const scfx_rep &rhs, int max_wl) +{ + scfx_rep &result = *new scfx_rep; + + // + // check for special cases + // + if (lhs.is_nan() || rhs.is_nan() || + (lhs.is_inf() && rhs.is_inf() && lhs.m_sign == rhs.m_sign)) { + result.set_nan(); + return &result; + } + + if (lhs.is_inf()) { + result.set_inf(lhs.m_sign); + return &result; + } + + if (rhs.is_inf()) { + result.set_inf(-1 * rhs.m_sign); + return &result; + } + + // + // align operands if needed + // + scfx_mant_ref lhs_mant; + scfx_mant_ref rhs_mant; + + int len_mant = lhs.size(); + int new_wp = lhs.m_wp; + + align(lhs, rhs, new_wp, len_mant, lhs_mant, rhs_mant); + + // + // size the result mantissa + // + result.resize_to(len_mant); + result.m_wp = new_wp; + + // + // do it + // + if (lhs.m_sign != rhs.m_sign) { + add_mants(len_mant, result.m_mant, lhs_mant, rhs_mant); + result.m_sign = lhs.m_sign; + } else { + int cmp = compare_abs(lhs, rhs); + + if (cmp == 1) { + sub_mants(len_mant, result.m_mant, lhs_mant, rhs_mant); + result.m_sign = lhs.m_sign; + } else if (cmp == -1) { + sub_mants(len_mant, result.m_mant, rhs_mant, lhs_mant); + result.m_sign = -rhs.m_sign; + } else { + result.m_mant.clear(); + result.m_sign = 1; + } + } + + result.find_sw(); + result.round(max_wl); + + return &result; +} + + +// ---------------------------------------------------------------------------- +// MUL +// ---------------------------------------------------------------------------- + +union word_short +{ + word l; + struct + { +#if defined(SC_BOOST_BIG_ENDIAN) + half_word u; + half_word l; +#elif defined(SC_BOOST_LITTLE_ENDIAN) + half_word l; + half_word u; +#endif + } s; +}; + +#if defined(SC_BOOST_BIG_ENDIAN) +static const int half_word_incr = -1; +#elif defined(SC_BOOST_LITTLE_ENDIAN) +static const int half_word_incr = 1; +#endif + +void +multiply(scfx_rep &result, const scfx_rep &lhs, const scfx_rep &rhs, + int max_wl) +{ + // + // check for special cases + // + if (lhs.is_nan() || rhs.is_nan() || + (lhs.is_inf() && rhs.is_zero()) || + (lhs.is_zero() && rhs.is_inf())) { + result.set_nan(); + return; + } + + if (lhs.is_inf() || rhs.is_inf()) { + result.set_inf(lhs.m_sign * rhs.m_sign); + return; + } + + if (lhs.is_zero() || rhs.is_zero()) { + result.set_zero(lhs.m_sign * rhs.m_sign); + return; + } + + // + // do it + // + int len_lhs = lhs.m_msw - lhs.m_lsw + 1; + int len_rhs = rhs.m_msw - rhs.m_lsw + 1; + + int new_size = sc_max(min_mant, len_lhs + len_rhs); + int new_wp = (lhs.m_wp - lhs.m_lsw) + (rhs.m_wp - rhs.m_lsw); + int new_sign = lhs.m_sign * rhs.m_sign; + + result.resize_to(new_size); + result.m_mant.clear(); + result.m_wp = new_wp; + result.m_sign = new_sign; + result.m_state = scfx_rep::normal; + + half_word *s1 = lhs.m_mant.half_addr(lhs.m_lsw); + half_word *s2 = rhs.m_mant.half_addr(rhs.m_lsw); + + half_word *t = result.m_mant.half_addr(); + + len_lhs <<= 1; + len_rhs <<= 1; + + int i1, i2; + + for (i1 = 0; i1 * half_word_incr < len_lhs; i1 += half_word_incr) { + word_short ls; + ls.l = 0; + + half_word v1 = s1[i1]; + + for (i2 = 0; i2 * half_word_incr < len_rhs; i2 += half_word_incr) { + ls.l += v1 * s2[i2]; + ls.s.l = ls.s.u + ((t[i2] += ls.s.l) < ls.s.l); + ls.s.u = 0; + } + + t[i2] = ls.s.l; + t += half_word_incr; + } + + result.find_sw(); + result.round(max_wl); +} + + +// ---------------------------------------------------------------------------- +// DIV +// ---------------------------------------------------------------------------- + +scfx_rep * +div_scfx_rep(const scfx_rep &lhs, const scfx_rep &rhs, int div_wl) +{ + scfx_rep &result = *new scfx_rep; + + // + // check for special cases + // + if (lhs.is_nan() || rhs.is_nan() || (lhs.is_inf() && rhs.is_inf()) || + (lhs.is_zero() && rhs.is_zero())) { + result.set_nan(); + return &result; + } + + if (lhs.is_inf() || rhs.is_zero()) { + result.set_inf(lhs.m_sign * rhs.m_sign); + return &result; + } + + if (lhs.is_zero() || rhs.is_inf()) { + result.set_zero(lhs.m_sign * rhs.m_sign); + return &result; + } + + // + // do it + // + + // compute one bit more for rounding + div_wl++; + + result.resize_to(sc_max(n_word(div_wl) + 1, min_mant)); + result.m_mant.clear(); + result.m_sign = lhs.m_sign * rhs.m_sign; + + int msb_lhs = scfx_find_msb(lhs.m_mant[lhs.m_msw]) + + (lhs.m_msw - lhs.m_wp) * bits_in_word; + int msb_rhs = scfx_find_msb(rhs.m_mant[rhs.m_msw]) + + (rhs.m_msw - rhs.m_wp) * bits_in_word; + + int msb_res = msb_lhs - msb_rhs; + int to_shift = -msb_res % bits_in_word; + int result_index; + + int c = (msb_res % bits_in_word >= 0) ? 1 : 0; + + result_index = (result.size() - c) * bits_in_word + msb_res % bits_in_word; + result.m_wp = (result.size() - c) - msb_res / bits_in_word; + + scfx_rep remainder = lhs; + + // align msb from remainder to msb from rhs + remainder.lshift(to_shift); + + // make sure msw(remainder) < size - 1 + if (remainder.m_msw == remainder.size() - 1) + remainder.resize_to(remainder.size() + 1, 1); + + // make sure msw(remainder) >= msw(rhs)! + int msw_diff = rhs.m_msw - remainder.m_msw; + if (msw_diff > 0) + remainder.resize_to(remainder.size() + msw_diff, -1); + + int counter; + + for (counter = div_wl; counter && !remainder.is_zero(); counter--) { + if (compare_msw_ff(rhs, remainder) <= 0) { + result.set_bin(result_index); + sub_with_index(remainder.m_mant, remainder.m_msw, remainder.m_lsw, + rhs.m_mant, rhs.m_msw, rhs.m_lsw); + } + result_index--; + remainder.shift_left(1); + remainder.m_lsw = remainder.find_lsw(); + } + + // perform convergent rounding, if needed + if (counter == 0) { + int index = result_index + 1 - result.m_wp * bits_in_word; + + scfx_index x = result.calc_indices(index); + scfx_index x1 = result.calc_indices(index + 1); + + if (result.o_bit_at(x) && result.o_bit_at(x1)) + result.q_incr(x); + + result.m_r_flag = true; + } + + result.find_sw(); + + return &result; +} + +// ---------------------------------------------------------------------------- +// destructive shift mantissa to the left +// ---------------------------------------------------------------------------- + +void +scfx_rep::lshift(int n) +{ + if (n == 0) + return; + + if (n < 0) { + rshift(-n); + return; + } + + if (is_normal()) { + int shift_bits = n % bits_in_word; + int shift_words = n / bits_in_word; + + // resize if needed + if (m_msw == size() - 1 && + scfx_find_msb(m_mant[m_msw]) >= bits_in_word - shift_bits) + resize_to(size() + 1, 1); + + // do it + m_wp -= shift_words; + shift_left(shift_bits); + find_sw(); + } +} + +// ---------------------------------------------------------------------------- +// destructive shift mantissa to the right +// ---------------------------------------------------------------------------- + +void +scfx_rep::rshift(int n) +{ + if (n == 0) + return; + + if (n < 0) { + lshift(-n); + return; + } + + if (is_normal()) { + int shift_bits = n % bits_in_word; + int shift_words = n / bits_in_word; + + // resize if needed + if (m_lsw == 0 && scfx_find_lsb(m_mant[m_lsw]) < shift_bits) + resize_to(size() + 1, -1); + + // do it + m_wp += shift_words; + shift_right(shift_bits); + find_sw(); + } +} + + +// ---------------------------------------------------------------------------- +// FRIEND FUNCTION : compare_abs +// +// Compares the absolute values of two scfx_reps, excluding the special cases. +// ---------------------------------------------------------------------------- + +int +compare_abs(const scfx_rep &a, const scfx_rep &b) +{ + // check for zero + word a_word = a.m_mant[a.m_msw]; + word b_word = b.m_mant[b.m_msw]; + + if (a_word == 0 || b_word == 0) { + if (a_word != 0) + return 1; + if (b_word != 0) + return -1; + return 0; + } + + // compare msw index + int a_msw = a.m_msw - a.m_wp; + int b_msw = b.m_msw - b.m_wp; + + if (a_msw > b_msw) + return 1; + + if (a_msw < b_msw) + return -1; + + // compare content + int a_i = a.m_msw; + int b_i = b.m_msw; + + while (a_i >= a.m_lsw && b_i >= b.m_lsw) { + a_word = a.m_mant[a_i]; + b_word = b.m_mant[b_i]; + if (a_word > b_word) + return 1; + if (a_word < b_word) + return -1; + --a_i; + --b_i; + } + + bool a_zero = true; + while (a_i >= a.m_lsw) { + a_zero = a_zero && (a.m_mant[a_i] == 0); + --a_i; + } + + bool b_zero = true; + while (b_i >= b.m_lsw) { + b_zero = b_zero && (b.m_mant[b_i] == 0); + --b_i; + } + + // assertion: a_zero || b_zero + + if (!a_zero && b_zero) + return 1; + + if (a_zero && !b_zero) + return -1; + + return 0; +} + +// ---------------------------------------------------------------------------- +// FRIEND FUNCTION : cmp_scfx_rep +// +// Compares the values of two scfx_reps, including the special cases. +// ---------------------------------------------------------------------------- + +int +cmp_scfx_rep(const scfx_rep &a, const scfx_rep &b) +{ + // handle special cases + + if (a.is_nan() || b.is_nan()) { + return 2; + } + + if (a.is_inf() || b.is_inf()) { + if (a.is_inf()) { + if (!a.is_neg()) { + if (b.is_inf() && !b.is_neg()) { + return 0; + } else { + return 1; + } + } else { + if (b.is_inf() && b.is_neg()) { + return 0; + } else { + return -1; + } + } + } + if (b.is_inf()) { + if (!b.is_neg()) { + return -1; + } else { + return 1; + } + } + } + + if (a.is_zero() && b.is_zero()) { + return 0; + } + + // compare sign + if (a.m_sign != b.m_sign) { + return a.m_sign; + } + + return (a.m_sign * compare_abs(a, b)); +} + + +// ---------------------------------------------------------------------------- +// PRIVATE METHOD : quantization +// +// Performs destructive quantization. +// ---------------------------------------------------------------------------- + +void +scfx_rep::quantization(const scfx_params ¶ms, bool &q_flag) +{ + scfx_index x = calc_indices(params.iwl() - params.wl()); + + if (x.wi() < 0) + return; + + if (x.wi() >= size()) + resize_to(x.wi() + 1, 1); + + bool qb = q_bit(x); + bool qz = q_zero(x); + + q_flag = (qb || ! qz); + + if (q_flag) { + switch (params.q_mode()) { + case SC_TRN: // truncation + { + if (is_neg()) + q_incr(x); + break; + } + case SC_RND: // rounding to plus infinity + { + if (!is_neg()) { + if (qb) + q_incr(x); + } else { + if (qb && !qz) + q_incr(x); + } + break; + } + case SC_TRN_ZERO: // truncation to zero + { + break; + } + case SC_RND_INF: // rounding to infinity + { + if (qb) + q_incr(x); + break; + } + case SC_RND_CONV: // convergent rounding + { + if ((qb && !qz) || (qb && qz && q_odd(x))) + q_incr(x); + break; + } + case SC_RND_ZERO: // rounding to zero + { + if (qb && !qz) + q_incr(x); + break; + } + case SC_RND_MIN_INF: // rounding to minus infinity + { + if (!is_neg()) { + if (qb && !qz) + q_incr(x); + } else { + if (qb) + q_incr(x); + } + break; + } + default: + ; + } + q_clear(x); + + find_sw(); + } +} + + +// ---------------------------------------------------------------------------- +// PRIVATE METHOD : overflow +// +// Performs destructive overflow handling. +// ---------------------------------------------------------------------------- + +void +scfx_rep::overflow(const scfx_params ¶ms, bool &o_flag) +{ + scfx_index x = calc_indices(params.iwl() - 1); + + if (x.wi() >= size()) + resize_to(x.wi() + 1, 1); + + if (x.wi() < 0) { + resize_to(size() - x.wi(), -1); + x.wi(0); + } + + bool zero_left = o_zero_left(x); + bool bit_at = o_bit_at(x); + bool zero_right = o_zero_right(x); + + bool under = false; + bool over = false; + + sc_enc enc = params.enc(); + + if (enc == SC_TC_) { + if (is_neg()) { + if (params.o_mode() == SC_SAT_SYM) + under = (!zero_left || bit_at); + else + under = (!zero_left || (zero_left && bit_at && ! zero_right)); + } else { + over = (! zero_left || bit_at); + } + } else { + if (is_neg()) + under = (!is_zero()); + else + over = (!zero_left); + } + + o_flag = (under || over); + + if (o_flag) { + scfx_index x2 = calc_indices(params.iwl() - params.wl()); + + if (x2.wi() < 0) { + resize_to(size() - x2.wi(), -1); + x.wi(x.wi() - x2.wi()); + x2.wi(0); + } + + switch (params.o_mode()) { + case SC_WRAP: // wrap-around + { + int n_bits = params.n_bits(); + + if (n_bits == 0) { + // wrap-around all 'wl' bits + toggle_tc(); + o_extend(x, enc); + toggle_tc(); + } else if (n_bits < params.wl()) { + scfx_index x3 = calc_indices(params.iwl() - 1 - n_bits); + + // wrap-around least significant 'wl - n_bits' bits; + // saturate most significant 'n_bits' bits + toggle_tc(); + o_set(x, x3, enc, under); + o_extend(x, enc); + toggle_tc(); + } else { + // saturate all 'wl' bits + if (under) + o_set_low(x, enc); + else + o_set_high(x, x2, enc); + } + break; + } + case SC_SAT: // saturation + { + if (under) + o_set_low(x, enc); + else + o_set_high(x, x2, enc); + break; + } + case SC_SAT_SYM: // symmetrical saturation + { + if (under) { + if (enc == SC_TC_) + o_set_high(x, x2, SC_TC_, -1); + else + o_set_low(x, SC_US_); + } else { + o_set_high(x, x2, enc); + } + break; + } + case SC_SAT_ZERO: // saturation to zero + { + set_zero(); + break; + } + case SC_WRAP_SM: // sign magnitude wrap-around + { + SC_ERROR_IF_(enc == SC_US_, + "SC_WRAP_SM not defined for unsigned numbers"); + + int n_bits = params.n_bits(); + + if (n_bits == 0) { + scfx_index x4 = calc_indices(params.iwl()); + + if (x4.wi() >= size()) + resize_to(x4.wi() + 1, 1); + + toggle_tc(); + if (o_bit_at(x4) != o_bit_at(x)) + o_invert(x2); + o_extend(x, SC_TC_); + toggle_tc(); + } else if (n_bits == 1) { + toggle_tc(); + if (is_neg() != o_bit_at(x)) + o_invert(x2); + o_extend(x, SC_TC_); + toggle_tc(); + } else if (n_bits < params.wl()) { + scfx_index x3 = calc_indices(params.iwl() - 1 - n_bits); + scfx_index x4 = calc_indices(params.iwl() - n_bits); + + // wrap-around least significant 'wl - n_bits' bits; + // saturate most significant 'n_bits' bits + toggle_tc(); + if (is_neg() == o_bit_at(x4)) + o_invert(x2); + o_set(x, x3, SC_TC_, under); + o_extend(x, SC_TC_); + toggle_tc(); + } else { + if (under) + o_set_low(x, SC_TC_); + else + o_set_high(x, x2, SC_TC_); + } + break; + } + default: + ; + } + + find_sw(); + } +} + + +// ---------------------------------------------------------------------------- +// PUBLIC METHOD : cast +// +// Performs a destructive cast operation on a scfx_rep. +// ---------------------------------------------------------------------------- + +void +scfx_rep::cast(const scfx_params ¶ms, bool &q_flag, bool &o_flag) +{ + q_flag = false; + o_flag = false; + + // check for special cases + if (is_zero()) { + if (is_neg()) + m_sign = 1; + return; + } + + // perform casting + quantization(params, q_flag); + overflow(params, o_flag); + + // check for special case: -0 + if (is_zero() && is_neg()) + m_sign = 1; +} + + +// ---------------------------------------------------------------------------- +// make sure, the two mantissas are aligned +// ---------------------------------------------------------------------------- + +void +align(const scfx_rep &lhs, const scfx_rep &rhs, int &new_wp, + int &len_mant, scfx_mant_ref &lhs_mant, scfx_mant_ref &rhs_mant) +{ + bool need_lhs = true; + bool need_rhs = true; + + if (lhs.m_wp != rhs.m_wp || lhs.size() != rhs.size()) { + int lower_bound_lhs = lhs.m_lsw - lhs.m_wp; + int upper_bound_lhs = lhs.m_msw - lhs.m_wp; + int lower_bound_rhs = rhs.m_lsw - rhs.m_wp; + int upper_bound_rhs = rhs.m_msw - rhs.m_wp; + + int lower_bound = sc_min(lower_bound_lhs, lower_bound_rhs); + int upper_bound = sc_max(upper_bound_lhs, upper_bound_rhs); + + new_wp = -lower_bound; + len_mant = sc_max(min_mant, upper_bound - lower_bound + 1); + + if (new_wp != lhs.m_wp || len_mant != lhs.size()) { + lhs_mant = lhs.resize(len_mant, new_wp); + need_lhs = false; + } + + if (new_wp != rhs.m_wp || len_mant != rhs.size()) { + rhs_mant = rhs.resize(len_mant, new_wp); + need_rhs = false; + } + } + + if (need_lhs) { + lhs_mant = lhs.m_mant; + } + + if (need_rhs) { + rhs_mant = rhs.m_mant; + } +} + + +// ---------------------------------------------------------------------------- +// compare two mantissas +// ---------------------------------------------------------------------------- + +int +compare_msw_ff(const scfx_rep &lhs, const scfx_rep &rhs) +{ + // special case: rhs.m_mant[rhs.m_msw + 1] == 1 + if (rhs.m_msw < rhs.size() - 1 && rhs.m_mant[rhs.m_msw + 1 ] != 0) { + return -1; + } + + int lhs_size = lhs.m_msw - lhs.m_lsw + 1; + int rhs_size = rhs.m_msw - rhs.m_lsw + 1; + + int size = sc_min(lhs_size, rhs_size); + + int lhs_index = lhs.m_msw; + int rhs_index = rhs.m_msw; + + int i; + + for (i = 0; + i < size && lhs.m_mant[lhs_index] == rhs.m_mant[rhs_index]; + i++) { + lhs_index--; + rhs_index--; + } + + if (i == size) { + if (lhs_size == rhs_size) { + return 0; + } + + if (lhs_size < rhs_size) { + return -1; + } else { + return 1; + } + } + + if (lhs.m_mant[lhs_index] < rhs.m_mant[rhs_index]) { + return -1; + } else { + return 1; + } +} + + +// ---------------------------------------------------------------------------- +// divide the mantissa by ten +// ---------------------------------------------------------------------------- + +unsigned int +scfx_rep::divide_by_ten() +{ +#if defined(SC_BOOST_BIG_ENDIAN) + half_word *hw = (half_word *)&m_mant[m_msw]; +#elif defined(SC_BOOST_LITTLE_ENDIAN) + half_word *hw = ((half_word *)&m_mant[m_msw]) + 1; +#endif + + unsigned int remainder = 0; + + word_short ls; + ls.l = 0; + +#if defined(SC_BOOST_BIG_ENDIAN) + for (int i = 0, end = (m_msw - m_wp + 1) * 2; i < end; i++) { +#elif defined(SC_BOOST_LITTLE_ENDIAN) + for (int i = 0, end = -(m_msw - m_wp + 1) * 2; i > end; i--) { +#endif + ls.s.u = static_cast<half_word>(remainder); + ls.s.l = hw[i]; + remainder = ls.l % 10; + ls.l /= 10; + hw[i] = ls.s.l; + } + + return remainder; +} + + +// ---------------------------------------------------------------------------- +// multiply the mantissa by ten +// ---------------------------------------------------------------------------- + +void +scfx_rep::multiply_by_ten() +{ + int size = m_mant.size() + 1; + + scfx_mant mant8(size); + scfx_mant mant2(size); + + size--; + + mant8[size] = (m_mant[size - 1] >> (bits_in_word - 3)); + mant2[size] = (m_mant[size - 1] >> (bits_in_word - 1)); + + while (--size) { + mant8[size] = (m_mant[size] << 3) | + (m_mant[size - 1] >> (bits_in_word - 3)); + mant2[size] = (m_mant[size] << 1) | + (m_mant[size - 1] >> (bits_in_word - 1)); + } + + mant8[0] = (m_mant[0] << 3); + mant2[0] = (m_mant[0] << 1); + + add_mants(m_mant.size(), m_mant, mant8, mant2); +} + + +// ---------------------------------------------------------------------------- +// normalize +// ---------------------------------------------------------------------------- + +void +scfx_rep::normalize(int exponent) +{ + int shift = exponent % bits_in_word; + if (shift < 0) { + shift += bits_in_word; + } + + if (shift) { + shift_left(shift); + } + + find_sw(); + + m_wp = (shift - exponent) / bits_in_word; +} + + +// ---------------------------------------------------------------------------- +// return a new mantissa that is aligned and resized +// ---------------------------------------------------------------------------- + +scfx_mant * +scfx_rep::resize(int new_size, int new_wp) const +{ + scfx_mant *result = new scfx_mant(new_size); + + result->clear(); + + int shift = new_wp - m_wp; + + for (int j = m_lsw; j <= m_msw; j++) { + (*result)[j + shift] = m_mant[j]; + } + + return result; +} + + +// ---------------------------------------------------------------------------- +// set a single bit +// ---------------------------------------------------------------------------- + +void +scfx_rep::set_bin(int i) +{ + m_mant[i >> 5] |= 1 << (i & 31); +} + + +// ---------------------------------------------------------------------------- +// set three bits +// ---------------------------------------------------------------------------- + +void +scfx_rep::set_oct(int i, int n) +{ + if (n & 1) { + m_mant[i >> 5] |= 1 << (i & 31); + } + i++; + if (n & 2) { + m_mant[i >> 5] |= 1 << (i & 31); + } + i++; + if (n & 4) { + m_mant[i >> 5] |= 1 << (i & 31); + } +} + + +// ---------------------------------------------------------------------------- +// set four bits +// ---------------------------------------------------------------------------- + +void +scfx_rep::set_hex(int i, int n) +{ + if (n & 1) { + m_mant[i >> 5] |= 1 << (i & 31); + } + i++; + if (n & 2) { + m_mant[i >> 5] |= 1 << (i & 31); + } + i++; + if (n & 4) { + m_mant[i >> 5] |= 1 << (i & 31); + } + i++; + if (n & 8) { + m_mant[i >> 5] |= 1 << (i & 31); + } +} + + +// ---------------------------------------------------------------------------- +// PRIVATE METHOD : shift_left +// +// Shifts a scfx_rep to the left by a MAXIMUM of bits_in_word - 1 bits. +// ---------------------------------------------------------------------------- + +void +scfx_rep::shift_left(int n) +{ + if (n != 0) { + int shift_left = n; + int shift_right = bits_in_word - n; + + SC_ASSERT_(!(m_mant[size() - 1] >> shift_right), + "shift_left overflow"); + + for (int i = size() - 1; i > 0; i--) { + m_mant[i] = (m_mant[i] << shift_left) | + (m_mant[i - 1] >> shift_right); + } + m_mant[0] <<= shift_left; + } +} + + +// ---------------------------------------------------------------------------- +// PRIVATE METHOD : shift_right +// +// Shifts a scfx_rep to the right by a MAXIMUM of bits_in_word - 1 bits. +// ---------------------------------------------------------------------------- + +void +scfx_rep::shift_right(int n) +{ + if (n != 0) { + int shift_left = bits_in_word - n; + int shift_right = n; + + SC_ASSERT_(!(m_mant[0] << shift_left), "shift_right overflow"); + + for (int i = 0; i < size() - 1; i++) { + m_mant[i] = (m_mant[i] >> shift_right) | + (m_mant[i + 1] << shift_left); + } + m_mant[size() - 1] >>= shift_right; + } +} + + +// ---------------------------------------------------------------------------- +// METHOD : get_bit +// +// Tests a bit, in two's complement. +// ---------------------------------------------------------------------------- + +bool +scfx_rep::get_bit(int i) const +{ + if (!is_normal()) + return false; + + scfx_index x = calc_indices(i); + + if (x.wi() >= size()) + return is_neg(); + + if (x.wi() < 0) + return false; + + const_cast<scfx_rep*>(this)->toggle_tc(); + + bool result = (m_mant[x.wi()] & (1 << x.bi())) != 0; + + const_cast<scfx_rep *>(this)->toggle_tc(); + + return result; +} + + +// ---------------------------------------------------------------------------- +// METHOD : set +// +// Sets a bit, in two's complement, between iwl-1 and -fwl. +// ---------------------------------------------------------------------------- + +bool +scfx_rep::set(int i, const scfx_params ¶ms) +{ + if (!is_normal()) + return false; + + scfx_index x = calc_indices(i); + + if (x.wi() >= size()) { + if (is_neg()) + return true; + else + resize_to(x.wi() + 1, 1); + } else if (x.wi() < 0) { + resize_to(size() - x.wi(), -1); + x.wi(0); + } + + toggle_tc(); + + m_mant[x.wi()] |= 1 << x.bi(); + + if (i == params.iwl() - 1) + o_extend(x, params.enc()); // sign extension + + toggle_tc(); + + find_sw(); + + return true; +} + + +// ---------------------------------------------------------------------------- +// METHOD : clear +// +// Clears a bit, in two's complement, between iwl-1 and -fwl. +// ---------------------------------------------------------------------------- + +bool +scfx_rep::clear(int i, const scfx_params ¶ms) +{ + if (!is_normal()) + return false; + + scfx_index x = calc_indices(i); + + if (x.wi() >= size()) { + if (!is_neg()) + return true; + else + resize_to(x.wi() + 1, 1); + } else if (x.wi() < 0) { + return true; + } + + toggle_tc(); + + m_mant[x.wi()] &= ~(1 << x.bi()); + + if (i == params.iwl() - 1) + o_extend(x, params.enc()); // sign extension + + toggle_tc(); + + find_sw(); + + return true; +} + + +// ---------------------------------------------------------------------------- +// METHOD : get_slice +// ---------------------------------------------------------------------------- + +bool +scfx_rep::get_slice(int i, int j, const scfx_params &, sc_bv_base &bv) const +{ + if (is_nan() || is_inf()) + return false; + + // get the bits + + int l = j; + for (int k = 0; k < bv.length(); ++k) { + bv[k] = get_bit(l); + + if (i >= j) + ++l; + else + --l; + } + + return true; +} + +bool +scfx_rep::set_slice(int i, int j, const scfx_params ¶ms, + const sc_bv_base &bv) +{ + if (is_nan() || is_inf()) + return false; + + // set the bits + int l = j; + for (int k = 0; k < bv.length(); ++k) { + if (bv[k].to_bool()) + set(l, params); + else + clear(l, params); + + if (i >= j) + ++l; + else + --l; + } + + return true; +} + + +// ---------------------------------------------------------------------------- +// METHOD : print +// ---------------------------------------------------------------------------- + +void +scfx_rep::print(::std::ostream &os) const +{ + os << to_string(SC_DEC, -1, SC_E); +} + + +// ---------------------------------------------------------------------------- +// METHOD : dump +// ---------------------------------------------------------------------------- + +void +scfx_rep::dump(::std::ostream &os) const +{ + os << "scfx_rep" << ::std::endl; + os << "(" << ::std::endl; + + os << "mant =" << ::std::endl; + for (int i = size() - 1; i >= 0; i--) { + char buf[BUFSIZ]; + std::sprintf(buf, " %d: %10u (%8x)", i, + (int)m_mant[i], (int)m_mant[i]); + os << buf << ::std::endl; + } + + os << "wp = " << m_wp << ::std::endl; + os << "sign = " << m_sign << ::std::endl; + + os << "state = "; + switch (m_state) { + case normal: + os << "normal"; + break; + case infinity: + os << "infinity"; + break; + case not_a_number: + os << "not_a_number"; + break; + default: + os << "unknown"; + } + os << ::std::endl; + + os << "msw = " << m_msw << ::std::endl; + os << "lsw = " << m_lsw << ::std::endl; + + os << ")" << ::std::endl; +} + + +// ---------------------------------------------------------------------------- +// METHOD : get_type +// ---------------------------------------------------------------------------- + +void +scfx_rep::get_type(int &wl, int &iwl, sc_enc &enc) const +{ + if (is_nan() || is_inf()) { + wl = 0; + iwl = 0; + enc = SC_TC_; + return; + } + + if (is_zero()) { + wl = 1; + iwl = 1; + enc = SC_US_; + return; + } + + int msb = (m_msw - m_wp) * bits_in_word + + scfx_find_msb(m_mant[ m_msw ]) + 1; + while (get_bit(msb) == get_bit(msb - 1)) { + --msb; + } + + int lsb = (m_lsw - m_wp) * bits_in_word + + scfx_find_lsb(m_mant[m_lsw]); + + if (is_neg()) { + wl = msb - lsb + 1; + iwl = msb + 1; + enc = SC_TC_; + } else { + wl = msb - lsb; + iwl = msb; + enc = SC_US_; + } +} + + +// ---------------------------------------------------------------------------- +// PRIVATE METHOD : round +// +// Performs convergent rounding (rounding to even) as in floating-point. +// ---------------------------------------------------------------------------- + +void +scfx_rep::round(int wl) +{ + // check for special cases + + if (is_nan() || is_inf() || is_zero()) + return; + + // estimate effective wordlength and compare + int wl_effective; + wl_effective = (m_msw - m_lsw + 1) * bits_in_word; + if (wl_effective <= wl) + return; + + // calculate effective wordlength and compare + int msb = scfx_find_msb(m_mant[m_msw]); + int lsb = scfx_find_lsb(m_mant[m_lsw]); + wl_effective = (m_msw * bits_in_word + msb) - + (m_lsw * bits_in_word + lsb) + 1; + if (wl_effective <= wl) + return; + + // perform rounding + int wi = m_msw - (wl - 1) / bits_in_word; + int bi = msb - (wl - 1) % bits_in_word; + if (bi < 0) { + --wi; + bi += bits_in_word; + } + + scfx_index x(wi, bi); + + if ((q_bit(x) && ! q_zero(x)) || (q_bit(x) && q_zero(x) && q_odd(x))) { + q_incr(x); + } + q_clear(x); + + find_sw(); + + m_r_flag = true; +} + +} // namespace sc_dt diff --git a/src/systemc/dt/fx/scfx_utils.cc b/src/systemc/dt/fx/scfx_utils.cc new file mode 100644 index 000000000..844e15df6 --- /dev/null +++ b/src/systemc/dt/fx/scfx_utils.cc @@ -0,0 +1,162 @@ +/***************************************************************************** + + 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. + + *****************************************************************************/ + +/***************************************************************************** + + scfx_utils.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: scfx_utils.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 "systemc/ext/dt/fx/scfx_utils.hh" + +namespace sc_dt +{ + +void +scfx_tc2csd(scfx_string &s, int w_prefix) +{ + if (w_prefix != 0) { + SC_ASSERT_(s[0] == '0' && s[1] == 'c' && + s[2] == 's' && s[3] == 'd', "invalid prefix"); + } + + scfx_string csd; + + // copy bits from 's' into 'csd'; skip prefix, point, and exponent + int i = 0; + int j = (w_prefix != 0 ? 4 : 0); + while (s[j]) { + if (s[j] == '0' || s[j] == '1') + csd[i ++] = s[j]; + else if (s[j] != '.') + break; + ++j; + } + csd[i] = '\0'; + + // convert 'csd' from two's complement to csd + --i; + while (i >= 0) { + if (csd[i] == '0') { + --i; + } else { + if (i > 0 && csd[i - 1] == '0') { + --i; + } else if (i == 0) { + csd[i--] = '-'; + } else { + csd[i--] = '-'; + while (i >= 0 && csd[i] == '1') + csd[i--] = '0'; + if (i > 0) + csd[i] = '1'; + else if (i == 0) + csd[i--] = '1'; + } + } + } + + // copy bits from 'csd' back into 's' + i = 0; + j = (w_prefix != 0 ? 4 : 0); + while (csd[i]) { + if (s[j] == '.') + ++j; + s[j++] = csd[i++]; + } +} + + +void +scfx_csd2tc(scfx_string &csd) +{ + SC_ASSERT_(csd[0] == '0' && csd[1] == 'c' && + csd[2] == 's' && csd[3] == 'd', "invalid prefix"); + + scfx_string s; + + // copy bits from 'csd' into 's'; skip prefix, point, and exponent + int i = 0; + s[i++] = '0'; + int j = 4; + while (csd[j]) { + if (csd[j] == '-' || csd[j] == '0' || csd[j] == '1') + s[i++] = csd[j]; + else if (csd[j] != '.') + break; + ++j; + } + s[i] = '\0'; + + // convert 's' from csd to two's complement + int len = i; + i = 1; + while (i < len) { + while (i < len && s[i] != '-') + i++; + if (i < len) { + j = i++; + s[j--] = '1'; + while (j >= 0 && s[j] == '0') + s[j--] = '1'; + if (j >= 0) + s[j] = '0'; + } + } + + // copy bits from 's' back into 'csd' + j = csd.length(); + csd[j + 1] = '\0'; + while (j > 4) { + csd[j] = csd[j - 1]; + --j; + } + + i = 0; + j = 4; + while (s[i]) { + if (csd[j] == '.') + ++j; + csd[j++] = s[i++]; + } +} + +} // namespace sc_dt |