diff options
Diffstat (limited to 'ext/systemc/src/sysc/datatypes/fx/sc_fxval.cpp')
-rw-r--r-- | ext/systemc/src/sysc/datatypes/fx/sc_fxval.cpp | 884 |
1 files changed, 884 insertions, 0 deletions
diff --git a/ext/systemc/src/sysc/datatypes/fx/sc_fxval.cpp b/ext/systemc/src/sysc/datatypes/fx/sc_fxval.cpp new file mode 100644 index 000000000..3ba5fbacd --- /dev/null +++ b/ext/systemc/src/sysc/datatypes/fx/sc_fxval.cpp @@ -0,0 +1,884 @@ +/***************************************************************************** + + 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 <ctype.h> +#include <stdlib.h> +#include <math.h> +#include <float.h> + +#include "sysc/datatypes/fx/sc_fxval.h" + + +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 = 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) ceil( 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) 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) floor( - log10( frac_part + DBL_EPSILON ) ); + + frac_part *= 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: + step = 0; + } + + msb = (int) ceil( double( msb + 1 ) / step ) * step - 1; + + lsb = (int) 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 = 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 ) ? pow( (double) base, (double) exponent ) + : 1; + + return ( sign * ( integer + fraction ) * exp ); +} + +#undef SCFX_FAIL_IF_ + +} // namespace sc_dt + + +// Taf! |