| /***************************************************************************** |
| |
| 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! |