diff options
Diffstat (limited to 'ext/systemc/src/sysc/datatypes/fx/sc_fxnum.cpp')
-rw-r--r-- | ext/systemc/src/sysc/datatypes/fx/sc_fxnum.cpp | 958 |
1 files changed, 958 insertions, 0 deletions
diff --git a/ext/systemc/src/sysc/datatypes/fx/sc_fxnum.cpp b/ext/systemc/src/sysc/datatypes/fx/sc_fxnum.cpp new file mode 100644 index 000000000..520c41854 --- /dev/null +++ b/ext/systemc/src/sysc/datatypes/fx/sc_fxnum.cpp @@ -0,0 +1,958 @@ +/***************************************************************************** + + 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 <math.h> + +#include "sysc/datatypes/fx/sc_fxnum.h" + + +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& params, 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& params, 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_core::SC_ID_WRAP_SM_NOT_DEFINED_ ); + + 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(), sc_core::SC_ID_INVALID_FX_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 + + +// Taf! |