diff options
Diffstat (limited to 'ext/systemc/src/sysc/datatypes/fx/scfx_rep.cpp')
-rw-r--r-- | ext/systemc/src/sysc/datatypes/fx/scfx_rep.cpp | 2926 |
1 files changed, 2926 insertions, 0 deletions
diff --git a/ext/systemc/src/sysc/datatypes/fx/scfx_rep.cpp b/ext/systemc/src/sysc/datatypes/fx/scfx_rep.cpp new file mode 100644 index 000000000..772835e6d --- /dev/null +++ b/ext/systemc/src/sysc/datatypes/fx/scfx_rep.cpp @@ -0,0 +1,2926 @@ +/***************************************************************************** + + 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 "sysc/utils/sc_machine.h" +#include "sysc/datatypes/fx/scfx_rep.h" + +#include "sysc/datatypes/fx/scfx_ieee.h" +#include "sysc/datatypes/fx/scfx_pow10.h" +#include "sysc/datatypes/fx/scfx_utils.h" + +#include "sysc/datatypes/bit/sc_bv_base.h" + +#include <ctype.h> +#include <cstdio> +#include <stdlib.h> +#include <math.h> + + +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 = 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 ); + case '0': + j --; + 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' ); + case '0': + j -= 3; + 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' ); + case '0': + j -= 4; + 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] |= -1 << 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_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) ceil( int_wl * 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) floor( frac_wl * 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: + 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 = ( 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_BIG_ENDIAN ) + half_word u; + half_word l; +#elif defined( SC_LITTLE_ENDIAN ) + half_word l; + half_word u; +#endif + } s; +}; + + +#if defined( SC_BIG_ENDIAN ) +static const int half_word_incr = -1; +#elif defined( SC_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 == true + + 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() ) + { +#if 0 + if( a.is_nan() && b.is_nan() ) + { + return 0; + } +#endif + 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& params, 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& params, 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_core::SC_ID_WRAP_SM_NOT_DEFINED_ ); + + 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& params, 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_BIG_ENDIAN ) + half_word* hw = (half_word*) &m_mant[m_msw]; +#elif defined( SC_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_BIG_ENDIAN ) + for( int i = 0, end = ( m_msw - m_wp + 1 ) * 2; i < end; i ++ ) +#elif defined( SC_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 ); + +#if 0 + for( int i = size() - 1; i > 0; i -- ) + { + m_mant[i] = ( m_mant[i] << 3 ) | + ( m_mant[i-1] >> ( bits_in_word - 3 ) ) + + ( m_mant[i] << 1 ) | + ( m_mant[i-1] >> ( bits_in_word - 1 ) ); + } + m_mant[0] = ( m_mant[0] << 3 ) + ( m_mant[0] << 1 ); +#endif +} + + +// ---------------------------------------------------------------------------- +// 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& params ) +{ + 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& params ) +{ + 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& params, + 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 + + +// Taf! |