/***************************************************************************** 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 #include #include #include #include "base/compiler.hh" #include "systemc/ext/dt/bit/sc_bv_base.hh" #include "systemc/ext/dt/bit/sc_lv_base.hh" #include "systemc/ext/dt/fx/messages.hh" #include "systemc/ext/dt/fx/scfx_ieee.hh" #include "systemc/ext/dt/fx/scfx_pow10.hh" #include "systemc/ext/dt/fx/scfx_rep.hh" #include "systemc/ext/dt/fx/scfx_utils.hh" #include "systemc/ext/utils/endian.hh" #include "systemc/ext/utils/messages.hh" namespace sc_dt { // ---------------------------------------------------------------------------- // some utilities // ---------------------------------------------------------------------------- static scfx_pow10 pow10_fx; static const int mantissa0_size = SCFX_IEEE_DOUBLE_M_SIZE - bits_in_int; static inline int n_word(int x) { return (x + bits_in_word - 1) / bits_in_word; } // ---------------------------------------------------------------------------- // CONSTRUCTORS // ---------------------------------------------------------------------------- scfx_rep::scfx_rep() : m_mant(min_mant), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(), m_r_flag(false) { set_zero(); } scfx_rep::scfx_rep(int a) : m_mant(min_mant), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(), m_r_flag(false) { if (a != 0) { m_mant.clear(); m_wp = m_msw = m_lsw = 2; m_state = normal; if (a > 0) { m_mant[2] = a; m_sign = 1; } else { m_mant[2] = -a; m_sign = -1; } } else { set_zero(); } } scfx_rep::scfx_rep(unsigned int a) : m_mant(min_mant), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(), m_r_flag(false) { if (a != 0) { m_mant.clear(); m_wp = m_msw = m_lsw = 2; m_state = normal; m_mant[2] = a; m_sign = 1; } else { set_zero(); } } scfx_rep::scfx_rep(long a) : m_mant(min_mant), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(), m_r_flag(false) { if (a != 0) { m_mant.clear(); m_state = normal; if (a > 0) { m_sign = 1; } else { a = -a; m_sign = -1; } # if SC_LONG_64 m_wp = 1; m_mant[1] = static_cast(a); m_mant[2] = static_cast(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 SC_LONG_64 m_wp = 1; m_mant[1] = static_cast(a); m_mant[2] = static_cast(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(a); m_mant[2] = static_cast(a >> bits_in_word); m_sign = 1; } else { m_mant[1] = static_cast(-a); m_mant[2] = static_cast((-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(a); m_mant[2] = static_cast(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(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(ptr); node->next = list; list = node; } // ---------------------------------------------------------------------------- // METHOD : from_string // // Convert from character string to sc_fxrep. // ---------------------------------------------------------------------------- #define SCFX_FAIL_IF_(cnd) \ { \ if ((cnd)) { \ m_state = not_a_number; \ m_mant.clear(); /* to avoid Purify UMRs during assignment */ \ return; \ } \ } void scfx_rep::from_string(const char *s, int cte_wl) { SCFX_FAIL_IF_(s == 0 || *s == 0); scfx_string s2; s2 += s; s2 += '\0'; bool sign_char; m_sign = scfx_parse_sign(s, sign_char); sc_numrep numrep = scfx_parse_prefix(s); int base = 0; switch (numrep) { case SC_DEC: { base = 10; if (scfx_is_nan(s)) { // special case: NaN m_state = not_a_number; m_mant.clear(); /* to avoid Purify UMRs during assignment */ return; } if (scfx_is_inf(s)) { // special case: Infinity m_state = infinity; m_mant.clear(); /* to avoid Purify UMRs during assignment */ return; } break; } case SC_BIN: case SC_BIN_US: { SCFX_FAIL_IF_(sign_char); base = 2; break; } case SC_BIN_SM: { base = 2; break; } case SC_OCT: case SC_OCT_US: { SCFX_FAIL_IF_(sign_char); base = 8; break; } case SC_OCT_SM: { base = 8; break; } case SC_HEX: case SC_HEX_US: { SCFX_FAIL_IF_(sign_char); base = 16; break; } case SC_HEX_SM: { base = 16; break; } case SC_CSD: { SCFX_FAIL_IF_(sign_char); base = 2; scfx_csd2tc(s2); s = (const char *)s2 + 4; numrep = SC_BIN; break; } default: ; } // // find end of mantissa and count the digits and points // const char *end = s; bool based_point = false; int int_digits = 0; int frac_digits = 0; while (*end) { if (scfx_exp_start(end)) break; if (*end == '.') { SCFX_FAIL_IF_(based_point); based_point = true; } else { SCFX_FAIL_IF_(!scfx_is_digit(*end, numrep)); if (based_point) frac_digits++; else int_digits++; } ++end; } SCFX_FAIL_IF_(int_digits == 0 && frac_digits == 0); // [ exponent ] int exponent = 0; if (*end) { for (const char *e = end + 2; *e; ++e) SCFX_FAIL_IF_(!scfx_is_digit(*e, SC_DEC)); exponent = std::atoi(end + 1); } // // check if the mantissa is negative // bool mant_is_neg = false; switch (numrep) { case SC_BIN: case SC_OCT: case SC_HEX: { const char *p = s; if (*p == '.') ++p; mant_is_neg = (scfx_to_digit(* p, numrep) >= (base >> 1)); break; } default: ; } // // convert the mantissa // switch (base) { case 2: { int bit_offset = exponent % bits_in_word; int word_offset = exponent / bits_in_word; int_digits += bit_offset; frac_digits -= bit_offset; int words = n_word(int_digits) + n_word(frac_digits); if (words > size()) resize_to(words); m_mant.clear(); int j = n_word(frac_digits) * bits_in_word + int_digits - 1; for (; s < end; s++) { switch (*s) { case '1': set_bin(j); M5_FALLTHROUGH; case '0': j--; M5_FALLTHROUGH; case '.': break; default: SCFX_FAIL_IF_(true); // should not happen } } m_wp = n_word(frac_digits) - word_offset; break; } case 8: { exponent *= 3; int_digits *= 3; frac_digits *= 3; int bit_offset = exponent % bits_in_word; int word_offset = exponent / bits_in_word; int_digits += bit_offset; frac_digits -= bit_offset; int words = n_word(int_digits) + n_word(frac_digits); if (words > size()) resize_to(words); m_mant.clear(); int j = n_word(frac_digits) * bits_in_word + int_digits - 3; for (; s < end; s++) { switch (*s) { case '7': case '6': case '5': case '4': case '3': case '2': case '1': set_oct(j, *s - '0'); M5_FALLTHROUGH; case '0': j -= 3; M5_FALLTHROUGH; case '.': break; default: SCFX_FAIL_IF_(true); // should not happen } } m_wp = n_word(frac_digits) - word_offset; break; } case 10: { word carry, temp; int length = int_digits + frac_digits; resize_to(sc_max(min_mant, n_word(4 * length))); m_mant.clear(); m_msw = m_lsw = 0; for (; s < end; s++) { switch (*s) { case '9': case '8': case '7': case '6': case '5': case '4': case '3': case '2': case '1': case '0': multiply_by_ten(); carry = *s - '0'; for (int i = 0; carry && i < m_mant.size(); i++) { temp = m_mant[i]; temp += carry; carry = temp < m_mant[i]; m_mant[i] = temp; } case '.': break; default: SCFX_FAIL_IF_(true); // should not happen } } m_wp = 0; find_sw(); int denominator = frac_digits - exponent; if (denominator) { scfx_rep frac_num = pow10_fx(denominator); scfx_rep *temp_num = div_scfx_rep(const_cast(*this), frac_num, cte_wl); *this = *temp_num; delete temp_num; } break; } case 16: { exponent *= 4; int_digits *= 4; frac_digits *= 4; int bit_offset = exponent % bits_in_word; int word_offset = exponent / bits_in_word; int_digits += bit_offset; frac_digits -= bit_offset; int words = n_word(int_digits) + n_word(frac_digits); if (words > size()) resize_to(words); m_mant.clear(); int j = n_word(frac_digits) * bits_in_word + int_digits - 4; for (; s < end; s ++) { switch (*s) { case 'f': case 'e': case 'd': case 'c': case 'b': case 'a': set_hex(j, *s - 'a' + 10); j -= 4; break; case 'F': case 'E': case 'D': case 'C': case 'B': case 'A': set_hex(j, *s - 'A' + 10); j -= 4; break; case '9': case '8': case '7': case '6': case '5': case '4': case '3': case '2': case '1': set_hex(j, *s - '0'); M5_FALLTHROUGH; case '0': j -= 4; M5_FALLTHROUGH; case '.': break; default: SCFX_FAIL_IF_(true); // should not happen } } m_wp = n_word(frac_digits) - word_offset; break; } } m_state = normal; find_sw(); // // two's complement of mantissa if it is negative // if (mant_is_neg) { m_mant[m_msw] |= ~0U << scfx_find_msb(m_mant[m_msw]); for (int i = m_msw + 1; i < m_mant.size(); ++i) m_mant[i] = static_cast(-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(SCFX_IEEE_DOUBLE_M_SIZE)) { id = 0.; return id; } int shift = mantissa0_size - msb; unsigned int m0; unsigned int m1 = 0; unsigned int guard = 0; if (shift == 0) { m0 = m_mant[m_msw] & ~(1 << mantissa0_size); if (m_msw > m_lsw) { m1 = m_mant[m_msw - 1]; if (m_msw - 1 > m_lsw) guard = m_mant[m_msw - 2] >> (bits_in_word - 1); } } else if (shift < 0) { m0 = (m_mant[m_msw] >> -shift) & ~(1 << mantissa0_size); m1 = m_mant[m_msw] << (bits_in_word + shift); if (m_msw > m_lsw) { m1 |= m_mant[m_msw - 1] >> -shift; guard = (m_mant[m_msw - 1] >> (-shift - 1)) & 1; } } else { m0 = (m_mant[m_msw] << shift) & ~(1 << mantissa0_size); if (m_msw > m_lsw) { m0 |= m_mant[m_msw - 1] >> (bits_in_word - shift); m1 = m_mant[m_msw - 1] << shift; if (m_msw - 1 > m_lsw) { m1 |= m_mant[m_msw - 2] >> (bits_in_word - shift); guard = (m_mant[m_msw - 2] >> (bits_in_word - shift - 1)) & 1; } } } if (exp < SCFX_IEEE_DOUBLE_E_MIN) { m0 |= (1 << mantissa0_size); int subnormal_shift = SCFX_IEEE_DOUBLE_E_MIN - exp; if (subnormal_shift < bits_in_word) { m1 = m1 >> subnormal_shift | m0 << (bits_in_word - subnormal_shift); m0 = m0 >> subnormal_shift; } else { m1 = m0 >> (subnormal_shift - bits_in_word); m0 = 0; } guard = 0; exp = SCFX_IEEE_DOUBLE_E_MIN - 1; } id.mantissa0(m0); id.mantissa1(m1); id.exponent(exp); id.negative(m_sign < 0); double result = id; if (guard != 0) result += m_sign * scfx_pow2(exp - SCFX_IEEE_DOUBLE_M_SIZE); return result; } // ---------------------------------------------------------------------------- // METHOD : to_uint64 // // Convert from scfx_rep to uint64. // Truncates towards 0 _then_ wraps; infinities and NaN go to zero. // ---------------------------------------------------------------------------- uint64 scfx_rep::to_uint64() const { if (!is_normal() || is_zero()) { return 0; } uint64 result = 0; int shift = 0; int idx = m_wp; // Ignore bits off the top; they modulo out. // Ignore bits off the bottom; we're truncating. while (shift < 64 && m_msw >= idx && idx >= m_lsw) { result += static_cast(m_mant[idx]) << shift; shift += bits_in_word; idx += 1; } return m_sign > 0 ? result : -result; } // ---------------------------------------------------------------------------- // METHOD : to_string // // Convert from scfx_rep to character string. // ---------------------------------------------------------------------------- void print_dec(scfx_string &s, const scfx_rep &num, int w_prefix, sc_fmt fmt) { if (num.is_neg()) s += '-'; if (w_prefix == 1) { scfx_print_prefix(s, SC_DEC); } if (num.is_zero()) { s += '0'; return; } // split 'num' into its integer and fractional part scfx_rep int_part = num; scfx_rep frac_part = num; int i; for (i = int_part.m_lsw; i <= int_part.m_msw && i < int_part.m_wp; i++) int_part.m_mant[i] = 0; int_part.find_sw(); if (int_part.m_wp < int_part.m_lsw) int_part.resize_to(int_part.size() - int_part.m_wp, -1); for (i = frac_part.m_msw; i >= frac_part.m_lsw && i >= frac_part.m_wp; i--) frac_part.m_mant[i] = 0; frac_part.find_sw(); if (frac_part.m_msw == frac_part.size() - 1) frac_part.resize_to(frac_part.size() + 1, 1); // print integer part int int_digits = 0; int int_zeros = 0; if (!int_part.is_zero()) { double int_wl = (int_part.m_msw - int_part.m_wp) * bits_in_word + scfx_find_msb(int_part.m_mant[int_part.m_msw]) + 1; int_digits = (int)std::ceil(int_wl * std::log10(2.)); int len = s.length(); s.append(int_digits); bool zero_digits = (frac_part.is_zero() && fmt != SC_F); for (i = int_digits + len - 1; i >= len; i--) { unsigned int remainder = int_part.divide_by_ten(); s[i] = static_cast('0' + remainder); if (zero_digits) { if (remainder == 0) int_zeros++; else zero_digits = false; } } // discard trailing zeros from int_part s.discard(int_zeros); if (s[len] == '0') { // int_digits was overestimated by one s.remove(len); --int_digits; } } // print fractional part int frac_digits = 0; int frac_zeros = 0; if (!frac_part.is_zero()) { s += '.'; bool zero_digits = (int_digits == 0 && fmt != SC_F); double frac_wl = (frac_part.m_wp - frac_part.m_msw) * bits_in_word - scfx_find_msb(frac_part.m_mant[frac_part.m_msw]) - 1; frac_zeros = (int)std::floor(frac_wl * std::log10(2.)); scfx_rep temp; sc_dt::multiply(temp, frac_part, pow10_fx(frac_zeros)); frac_part = temp; if (frac_part.m_msw == frac_part.size() - 1) frac_part.resize_to(frac_part.size() + 1, 1); frac_digits = frac_zeros; if (!zero_digits) { for (i = 0; i < frac_zeros; i++) s += '0'; frac_zeros = 0; } while (!frac_part.is_zero()) { frac_part.multiply_by_ten(); int n = frac_part.m_mant[frac_part.m_msw + 1]; if (zero_digits) { if (n == 0) frac_zeros++; else zero_digits = false; } if (! zero_digits) s += static_cast('0' + n); frac_part.m_mant[frac_part.m_msw + 1] = 0; frac_digits++; } } // print exponent if (fmt != SC_F) { if (frac_digits == 0) scfx_print_exp(s, int_zeros); else if (int_digits == 0) scfx_print_exp(s, -frac_zeros); } } void print_other(scfx_string &s, const scfx_rep &a, sc_numrep numrep, int w_prefix, sc_fmt fmt, const scfx_params *params) { scfx_rep b = a; sc_numrep numrep2 = numrep; bool numrep_is_sm = (numrep == SC_BIN_SM || numrep == SC_OCT_SM || numrep == SC_HEX_SM); if (numrep_is_sm) { if (b.is_neg()) { s += '-'; b = *neg_scfx_rep(a); } switch (numrep) { case SC_BIN_SM: numrep2 = SC_BIN_US; break; case SC_OCT_SM: numrep2 = SC_OCT_US; break; case SC_HEX_SM: numrep2 = SC_HEX_US; break; default: ; } } if (w_prefix != 0) { scfx_print_prefix(s, numrep); } numrep = numrep2; int msb, lsb; if (params != 0) { msb = params->iwl() - 1; lsb = params->iwl() - params->wl(); if (params->enc() == SC_TC_ && (numrep == SC_BIN_US || numrep == SC_OCT_US || numrep == SC_HEX_US) && !numrep_is_sm && params->wl() > 1) { --msb; } else if (params->enc() == SC_US_ && (numrep == SC_BIN || numrep == SC_OCT || numrep == SC_HEX || numrep == SC_CSD)) { ++msb; } } else { if (b.is_zero()) { msb = 0; lsb = 0; } else { msb = (b.m_msw - b.m_wp) * bits_in_word + scfx_find_msb(b.m_mant[ b.m_msw ]) + 1; while (b.get_bit(msb) == b.get_bit(msb - 1)) --msb; if (numrep == SC_BIN_US || numrep == SC_OCT_US || numrep == SC_HEX_US) { --msb; } lsb = (b.m_lsw - b.m_wp) * bits_in_word + scfx_find_lsb(b.m_mant[b.m_lsw]); } } int step; switch (numrep) { case SC_BIN: case SC_BIN_US: case SC_CSD: step = 1; break; case SC_OCT: case SC_OCT_US: step = 3; break; case SC_HEX: case SC_HEX_US: step = 4; break; default: SC_REPORT_FATAL(sc_core::SC_ID_ASSERTION_FAILED_, "unexpected sc_numrep"); sc_core::sc_abort(); } msb = (int)std::ceil(double(msb + 1) / step) * step - 1; lsb = (int)std::floor(double(lsb) / step) * step; if (msb < 0) { s += '.'; if (fmt == SC_F) { int sign = (b.is_neg()) ? (1 << step) - 1 : 0; for (int i = (msb + 1) / step; i < 0; i++) { if (sign < 10) s += static_cast(sign + '0'); else s += static_cast(sign + 'a' - 10); } } } int i = msb; while (i >= lsb) { int value = 0; for (int j = step - 1; j >= 0; --j) { value += static_cast(b.get_bit(i)) << j; --i; } if (value < 10) s += static_cast(value + '0'); else s += static_cast(value + 'a' - 10); if (i == -1) s += '.'; } if (lsb > 0 && fmt == SC_F) { for (int i = lsb / step; i > 0; i--) s += '0'; } if (s[s.length() - 1] == '.') s.discard(1); if (fmt != SC_F) { if (msb < 0) scfx_print_exp(s, (msb + 1) / step); else if (lsb > 0) scfx_print_exp(s, lsb / step); } if (numrep == SC_CSD) scfx_tc2csd(s, w_prefix); } const char * scfx_rep::to_string(sc_numrep numrep, int w_prefix, sc_fmt fmt, const scfx_params *params) const { static scfx_string s; s.clear(); if (is_nan()) { scfx_print_nan(s); } else if (is_inf()) { scfx_print_inf(s, is_neg()); } else if (is_neg() && !is_zero() && (numrep == SC_BIN_US || numrep == SC_OCT_US || numrep == SC_HEX_US)) { s += "negative"; } else if (numrep == SC_DEC || numrep == SC_NOBASE) { sc_dt::print_dec(s, *this, w_prefix, fmt); } else { sc_dt::print_other(s, *this, numrep, w_prefix, fmt, params); } return s; } // ---------------------------------------------------------------------------- // ADD // // add two mantissas of the same size // result has the same size // returns carry of operation // ---------------------------------------------------------------------------- static inline int add_mants(int size, scfx_mant &result, const scfx_mant &a, const scfx_mant &b) { unsigned int carry = 0; int index = 0; do { word x = a[index]; word y = b[index]; y += carry; carry = y < carry; y += x; carry += y < x; result[index] = y; } while (++index < size); return (carry ? 1 : 0); } static inline int sub_mants(int size, scfx_mant &result, const scfx_mant &a, const scfx_mant &b) { unsigned carry = 0; int index = 0; do { word x = a[index]; word y = b[index]; y += carry; carry = y < carry; y = x - y; carry += y > x; result[index] = y; } while (++index < size); return (carry ? 1 : 0); } scfx_rep * add_scfx_rep(const scfx_rep &lhs, const scfx_rep &rhs, int max_wl) { scfx_rep &result = *new scfx_rep; // // check for special cases // if (lhs.is_nan() || rhs.is_nan() || (lhs.is_inf() && rhs.is_inf() && lhs.m_sign != rhs.m_sign)) { result.set_nan(); return &result; } if (lhs.is_inf()) { result.set_inf(lhs.m_sign); return &result; } if (rhs.is_inf()) { result.set_inf(rhs.m_sign); return &result; } // // align operands if needed // scfx_mant_ref lhs_mant; scfx_mant_ref rhs_mant; int len_mant = lhs.size(); int new_wp = lhs.m_wp; align(lhs, rhs, new_wp, len_mant, lhs_mant, rhs_mant); // // size the result mantissa // result.resize_to(len_mant); result.m_wp = new_wp; // // do it // if (lhs.m_sign == rhs.m_sign) { add_mants(len_mant, result.m_mant, lhs_mant, rhs_mant); result.m_sign = lhs.m_sign; } else { int cmp = compare_abs(lhs, rhs); if (cmp == 1) { sub_mants(len_mant, result.m_mant, lhs_mant, rhs_mant); result.m_sign = lhs.m_sign; } else if (cmp == -1) { sub_mants(len_mant, result.m_mant, rhs_mant, lhs_mant); result.m_sign = rhs.m_sign; } else { result.m_mant.clear(); result.m_sign = 1; } } result.find_sw(); result.round(max_wl); return &result; } // ---------------------------------------------------------------------------- // SUB // // sub two word's of the same size // result has the same size // returns carry of operation // ---------------------------------------------------------------------------- static inline int sub_with_index(scfx_mant &a, int a_msw, int /*a_lsw*/, const scfx_mant &b, int b_msw, int b_lsw) { unsigned carry = 0; int size = b_msw - b_lsw; int a_index = a_msw - size; int b_index = b_msw - size; do { word x = a[a_index]; word y = b[b_index]; y += carry; carry = y < carry; y = x - y; carry += y > x; a[a_index] = y; a_index++; b_index++; } while (size--); if (carry) { // special case: a[a_msw + 1] == 1 a[a_msw + 1] = 0; } return (carry ? 1 : 0); } scfx_rep * sub_scfx_rep(const scfx_rep &lhs, const scfx_rep &rhs, int max_wl) { scfx_rep &result = *new scfx_rep; // // check for special cases // if (lhs.is_nan() || rhs.is_nan() || (lhs.is_inf() && rhs.is_inf() && lhs.m_sign == rhs.m_sign)) { result.set_nan(); return &result; } if (lhs.is_inf()) { result.set_inf(lhs.m_sign); return &result; } if (rhs.is_inf()) { result.set_inf(-1 * rhs.m_sign); return &result; } // // align operands if needed // scfx_mant_ref lhs_mant; scfx_mant_ref rhs_mant; int len_mant = lhs.size(); int new_wp = lhs.m_wp; align(lhs, rhs, new_wp, len_mant, lhs_mant, rhs_mant); // // size the result mantissa // result.resize_to(len_mant); result.m_wp = new_wp; // // do it // if (lhs.m_sign != rhs.m_sign) { add_mants(len_mant, result.m_mant, lhs_mant, rhs_mant); result.m_sign = lhs.m_sign; } else { int cmp = compare_abs(lhs, rhs); if (cmp == 1) { sub_mants(len_mant, result.m_mant, lhs_mant, rhs_mant); result.m_sign = lhs.m_sign; } else if (cmp == -1) { sub_mants(len_mant, result.m_mant, rhs_mant, lhs_mant); result.m_sign = -rhs.m_sign; } else { result.m_mant.clear(); result.m_sign = 1; } } result.find_sw(); result.round(max_wl); return &result; } // ---------------------------------------------------------------------------- // MUL // ---------------------------------------------------------------------------- union word_short { word l; struct { #if defined(SC_BOOST_BIG_ENDIAN) half_word u; half_word l; #elif defined(SC_BOOST_LITTLE_ENDIAN) half_word l; half_word u; #endif } s; }; #if defined(SC_BOOST_BIG_ENDIAN) static const int half_word_incr = -1; #elif defined(SC_BOOST_LITTLE_ENDIAN) static const int half_word_incr = 1; #endif void multiply(scfx_rep &result, const scfx_rep &lhs, const scfx_rep &rhs, int max_wl) { // // check for special cases // if (lhs.is_nan() || rhs.is_nan() || (lhs.is_inf() && rhs.is_zero()) || (lhs.is_zero() && rhs.is_inf())) { result.set_nan(); return; } if (lhs.is_inf() || rhs.is_inf()) { result.set_inf(lhs.m_sign * rhs.m_sign); return; } if (lhs.is_zero() || rhs.is_zero()) { result.set_zero(lhs.m_sign * rhs.m_sign); return; } // // do it // int len_lhs = lhs.m_msw - lhs.m_lsw + 1; int len_rhs = rhs.m_msw - rhs.m_lsw + 1; int new_size = sc_max(min_mant, len_lhs + len_rhs); int new_wp = (lhs.m_wp - lhs.m_lsw) + (rhs.m_wp - rhs.m_lsw); int new_sign = lhs.m_sign * rhs.m_sign; result.resize_to(new_size); result.m_mant.clear(); result.m_wp = new_wp; result.m_sign = new_sign; result.m_state = scfx_rep::normal; half_word *s1 = lhs.m_mant.half_addr(lhs.m_lsw); half_word *s2 = rhs.m_mant.half_addr(rhs.m_lsw); half_word *t = result.m_mant.half_addr(); len_lhs <<= 1; len_rhs <<= 1; int i1, i2; for (i1 = 0; i1 * half_word_incr < len_lhs; i1 += half_word_incr) { word_short ls; ls.l = 0; half_word v1 = s1[i1]; for (i2 = 0; i2 * half_word_incr < len_rhs; i2 += half_word_incr) { ls.l += v1 * s2[i2]; ls.s.l = ls.s.u + ((t[i2] += ls.s.l) < ls.s.l); ls.s.u = 0; } t[i2] = ls.s.l; t += half_word_incr; } result.find_sw(); result.round(max_wl); } // ---------------------------------------------------------------------------- // DIV // ---------------------------------------------------------------------------- scfx_rep * div_scfx_rep(const scfx_rep &lhs, const scfx_rep &rhs, int div_wl) { scfx_rep &result = *new scfx_rep; // // check for special cases // if (lhs.is_nan() || rhs.is_nan() || (lhs.is_inf() && rhs.is_inf()) || (lhs.is_zero() && rhs.is_zero())) { result.set_nan(); return &result; } if (lhs.is_inf() || rhs.is_zero()) { result.set_inf(lhs.m_sign * rhs.m_sign); return &result; } if (lhs.is_zero() || rhs.is_inf()) { result.set_zero(lhs.m_sign * rhs.m_sign); return &result; } // // do it // // compute one bit more for rounding div_wl++; result.resize_to(sc_max(n_word(div_wl) + 1, min_mant)); result.m_mant.clear(); result.m_sign = lhs.m_sign * rhs.m_sign; int msb_lhs = scfx_find_msb(lhs.m_mant[lhs.m_msw]) + (lhs.m_msw - lhs.m_wp) * bits_in_word; int msb_rhs = scfx_find_msb(rhs.m_mant[rhs.m_msw]) + (rhs.m_msw - rhs.m_wp) * bits_in_word; int msb_res = msb_lhs - msb_rhs; int to_shift = -msb_res % bits_in_word; int result_index; int c = (msb_res % bits_in_word >= 0) ? 1 : 0; result_index = (result.size() - c) * bits_in_word + msb_res % bits_in_word; result.m_wp = (result.size() - c) - msb_res / bits_in_word; scfx_rep remainder = lhs; // align msb from remainder to msb from rhs remainder.lshift(to_shift); // make sure msw(remainder) < size - 1 if (remainder.m_msw == remainder.size() - 1) remainder.resize_to(remainder.size() + 1, 1); // make sure msw(remainder) >= msw(rhs)! int msw_diff = rhs.m_msw - remainder.m_msw; if (msw_diff > 0) remainder.resize_to(remainder.size() + msw_diff, -1); int counter; for (counter = div_wl; counter && !remainder.is_zero(); counter--) { if (compare_msw_ff(rhs, remainder) <= 0) { result.set_bin(result_index); sub_with_index(remainder.m_mant, remainder.m_msw, remainder.m_lsw, rhs.m_mant, rhs.m_msw, rhs.m_lsw); } result_index--; remainder.shift_left(1); remainder.m_lsw = remainder.find_lsw(); } // perform convergent rounding, if needed if (counter == 0) { int index = result_index + 1 - result.m_wp * bits_in_word; scfx_index x = result.calc_indices(index); scfx_index x1 = result.calc_indices(index + 1); if (result.o_bit_at(x) && result.o_bit_at(x1)) result.q_incr(x); result.m_r_flag = true; } result.find_sw(); return &result; } // ---------------------------------------------------------------------------- // destructive shift mantissa to the left // ---------------------------------------------------------------------------- void scfx_rep::lshift(int n) { if (n == 0) return; if (n < 0) { rshift(-n); return; } if (is_normal()) { int shift_bits = n % bits_in_word; int shift_words = n / bits_in_word; // resize if needed if (m_msw == size() - 1 && scfx_find_msb(m_mant[m_msw]) >= bits_in_word - shift_bits) resize_to(size() + 1, 1); // do it m_wp -= shift_words; shift_left(shift_bits); find_sw(); } } // ---------------------------------------------------------------------------- // destructive shift mantissa to the right // ---------------------------------------------------------------------------- void scfx_rep::rshift(int n) { if (n == 0) return; if (n < 0) { lshift(-n); return; } if (is_normal()) { int shift_bits = n % bits_in_word; int shift_words = n / bits_in_word; // resize if needed if (m_lsw == 0 && scfx_find_lsb(m_mant[m_lsw]) < shift_bits) resize_to(size() + 1, -1); // do it m_wp += shift_words; shift_right(shift_bits); find_sw(); } } // ---------------------------------------------------------------------------- // FRIEND FUNCTION : compare_abs // // Compares the absolute values of two scfx_reps, excluding the special cases. // ---------------------------------------------------------------------------- int compare_abs(const scfx_rep &a, const scfx_rep &b) { // check for zero word a_word = a.m_mant[a.m_msw]; word b_word = b.m_mant[b.m_msw]; if (a_word == 0 || b_word == 0) { if (a_word != 0) return 1; if (b_word != 0) return -1; return 0; } // compare msw index int a_msw = a.m_msw - a.m_wp; int b_msw = b.m_msw - b.m_wp; if (a_msw > b_msw) return 1; if (a_msw < b_msw) return -1; // compare content int a_i = a.m_msw; int b_i = b.m_msw; while (a_i >= a.m_lsw && b_i >= b.m_lsw) { a_word = a.m_mant[a_i]; b_word = b.m_mant[b_i]; if (a_word > b_word) return 1; if (a_word < b_word) return -1; --a_i; --b_i; } bool a_zero = true; while (a_i >= a.m_lsw) { a_zero = a_zero && (a.m_mant[a_i] == 0); --a_i; } bool b_zero = true; while (b_i >= b.m_lsw) { b_zero = b_zero && (b.m_mant[b_i] == 0); --b_i; } // assertion: a_zero || b_zero if (!a_zero && b_zero) return 1; if (a_zero && !b_zero) return -1; return 0; } // ---------------------------------------------------------------------------- // FRIEND FUNCTION : cmp_scfx_rep // // Compares the values of two scfx_reps, including the special cases. // ---------------------------------------------------------------------------- int cmp_scfx_rep(const scfx_rep &a, const scfx_rep &b) { // handle special cases if (a.is_nan() || b.is_nan()) { return 2; } if (a.is_inf() || b.is_inf()) { if (a.is_inf()) { if (!a.is_neg()) { if (b.is_inf() && !b.is_neg()) { return 0; } else { return 1; } } else { if (b.is_inf() && b.is_neg()) { return 0; } else { return -1; } } } if (b.is_inf()) { if (!b.is_neg()) { return -1; } else { return 1; } } } if (a.is_zero() && b.is_zero()) { return 0; } // compare sign if (a.m_sign != b.m_sign) { return a.m_sign; } return (a.m_sign * compare_abs(a, b)); } // ---------------------------------------------------------------------------- // PRIVATE METHOD : quantization // // Performs destructive quantization. // ---------------------------------------------------------------------------- void scfx_rep::quantization(const scfx_params ¶ms, bool &q_flag) { scfx_index x = calc_indices(params.iwl() - params.wl()); if (x.wi() < 0) return; if (x.wi() >= size()) resize_to(x.wi() + 1, 1); bool qb = q_bit(x); bool qz = q_zero(x); q_flag = (qb || ! qz); if (q_flag) { switch (params.q_mode()) { case SC_TRN: // truncation { if (is_neg()) q_incr(x); break; } case SC_RND: // rounding to plus infinity { if (!is_neg()) { if (qb) q_incr(x); } else { if (qb && !qz) q_incr(x); } break; } case SC_TRN_ZERO: // truncation to zero { break; } case SC_RND_INF: // rounding to infinity { if (qb) q_incr(x); break; } case SC_RND_CONV: // convergent rounding { if ((qb && !qz) || (qb && qz && q_odd(x))) q_incr(x); break; } case SC_RND_ZERO: // rounding to zero { if (qb && !qz) q_incr(x); break; } case SC_RND_MIN_INF: // rounding to minus infinity { if (!is_neg()) { if (qb && !qz) q_incr(x); } else { if (qb) q_incr(x); } break; } default: ; } q_clear(x); find_sw(); } } // ---------------------------------------------------------------------------- // PRIVATE METHOD : overflow // // Performs destructive overflow handling. // ---------------------------------------------------------------------------- void scfx_rep::overflow(const scfx_params ¶ms, bool &o_flag) { scfx_index x = calc_indices(params.iwl() - 1); if (x.wi() >= size()) resize_to(x.wi() + 1, 1); if (x.wi() < 0) { resize_to(size() - x.wi(), -1); x.wi(0); } bool zero_left = o_zero_left(x); bool bit_at = o_bit_at(x); bool zero_right = o_zero_right(x); bool under = false; bool over = false; sc_enc enc = params.enc(); if (enc == SC_TC_) { if (is_neg()) { if (params.o_mode() == SC_SAT_SYM) under = (!zero_left || bit_at); else under = (!zero_left || (zero_left && bit_at && ! zero_right)); } else { over = (! zero_left || bit_at); } } else { if (is_neg()) under = (!is_zero()); else over = (!zero_left); } o_flag = (under || over); if (o_flag) { scfx_index x2 = calc_indices(params.iwl() - params.wl()); if (x2.wi() < 0) { resize_to(size() - x2.wi(), -1); x.wi(x.wi() - x2.wi()); x2.wi(0); } switch (params.o_mode()) { case SC_WRAP: // wrap-around { int n_bits = params.n_bits(); if (n_bits == 0) { // wrap-around all 'wl' bits toggle_tc(); o_extend(x, enc); toggle_tc(); } else if (n_bits < params.wl()) { scfx_index x3 = calc_indices(params.iwl() - 1 - n_bits); // wrap-around least significant 'wl - n_bits' bits; // saturate most significant 'n_bits' bits toggle_tc(); o_set(x, x3, enc, under); o_extend(x, enc); toggle_tc(); } else { // saturate all 'wl' bits if (under) o_set_low(x, enc); else o_set_high(x, x2, enc); } break; } case SC_SAT: // saturation { if (under) o_set_low(x, enc); else o_set_high(x, x2, enc); break; } case SC_SAT_SYM: // symmetrical saturation { if (under) { if (enc == SC_TC_) o_set_high(x, x2, SC_TC_, -1); else o_set_low(x, SC_US_); } else { o_set_high(x, x2, enc); } break; } case SC_SAT_ZERO: // saturation to zero { set_zero(); break; } case SC_WRAP_SM: // sign magnitude wrap-around { SC_ERROR_IF_(enc == SC_US_, sc_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 ¶ms, bool &q_flag, bool &o_flag) { q_flag = false; o_flag = false; // check for special cases if (is_zero()) { if (is_neg()) m_sign = 1; return; } // perform casting quantization(params, q_flag); overflow(params, o_flag); // check for special case: -0 if (is_zero() && is_neg()) m_sign = 1; } // ---------------------------------------------------------------------------- // make sure, the two mantissas are aligned // ---------------------------------------------------------------------------- void align(const scfx_rep &lhs, const scfx_rep &rhs, int &new_wp, int &len_mant, scfx_mant_ref &lhs_mant, scfx_mant_ref &rhs_mant) { bool need_lhs = true; bool need_rhs = true; if (lhs.m_wp != rhs.m_wp || lhs.size() != rhs.size()) { int lower_bound_lhs = lhs.m_lsw - lhs.m_wp; int upper_bound_lhs = lhs.m_msw - lhs.m_wp; int lower_bound_rhs = rhs.m_lsw - rhs.m_wp; int upper_bound_rhs = rhs.m_msw - rhs.m_wp; int lower_bound = sc_min(lower_bound_lhs, lower_bound_rhs); int upper_bound = sc_max(upper_bound_lhs, upper_bound_rhs); new_wp = -lower_bound; len_mant = sc_max(min_mant, upper_bound - lower_bound + 1); if (new_wp != lhs.m_wp || len_mant != lhs.size()) { lhs_mant = lhs.resize(len_mant, new_wp); need_lhs = false; } if (new_wp != rhs.m_wp || len_mant != rhs.size()) { rhs_mant = rhs.resize(len_mant, new_wp); need_rhs = false; } } if (need_lhs) { lhs_mant = lhs.m_mant; } if (need_rhs) { rhs_mant = rhs.m_mant; } } // ---------------------------------------------------------------------------- // compare two mantissas // ---------------------------------------------------------------------------- int compare_msw_ff(const scfx_rep &lhs, const scfx_rep &rhs) { // special case: rhs.m_mant[rhs.m_msw + 1] == 1 if (rhs.m_msw < rhs.size() - 1 && rhs.m_mant[rhs.m_msw + 1 ] != 0) { return -1; } int lhs_size = lhs.m_msw - lhs.m_lsw + 1; int rhs_size = rhs.m_msw - rhs.m_lsw + 1; int size = sc_min(lhs_size, rhs_size); int lhs_index = lhs.m_msw; int rhs_index = rhs.m_msw; int i; for (i = 0; i < size && lhs.m_mant[lhs_index] == rhs.m_mant[rhs_index]; i++) { lhs_index--; rhs_index--; } if (i == size) { if (lhs_size == rhs_size) { return 0; } if (lhs_size < rhs_size) { return -1; } else { return 1; } } if (lhs.m_mant[lhs_index] < rhs.m_mant[rhs_index]) { return -1; } else { return 1; } } // ---------------------------------------------------------------------------- // divide the mantissa by ten // ---------------------------------------------------------------------------- unsigned int scfx_rep::divide_by_ten() { #if defined(SC_BOOST_BIG_ENDIAN) half_word *hw = (half_word *)&m_mant[m_msw]; #elif defined(SC_BOOST_LITTLE_ENDIAN) half_word *hw = ((half_word *)&m_mant[m_msw]) + 1; #endif unsigned int remainder = 0; word_short ls; ls.l = 0; #if defined(SC_BOOST_BIG_ENDIAN) for (int i = 0, end = (m_msw - m_wp + 1) * 2; i < end; i++) { #elif defined(SC_BOOST_LITTLE_ENDIAN) for (int i = 0, end = -(m_msw - m_wp + 1) * 2; i > end; i--) { #endif ls.s.u = static_cast(remainder); ls.s.l = hw[i]; remainder = ls.l % 10; ls.l /= 10; hw[i] = ls.s.l; } return remainder; } // ---------------------------------------------------------------------------- // multiply the mantissa by ten // ---------------------------------------------------------------------------- void scfx_rep::multiply_by_ten() { int size = m_mant.size() + 1; scfx_mant mant8(size); scfx_mant mant2(size); size--; mant8[size] = (m_mant[size - 1] >> (bits_in_word - 3)); mant2[size] = (m_mant[size - 1] >> (bits_in_word - 1)); while (--size) { mant8[size] = (m_mant[size] << 3) | (m_mant[size - 1] >> (bits_in_word - 3)); mant2[size] = (m_mant[size] << 1) | (m_mant[size - 1] >> (bits_in_word - 1)); } mant8[0] = (m_mant[0] << 3); mant2[0] = (m_mant[0] << 1); add_mants(m_mant.size(), m_mant, mant8, mant2); } // ---------------------------------------------------------------------------- // normalize // ---------------------------------------------------------------------------- void scfx_rep::normalize(int exponent) { int shift = exponent % bits_in_word; if (shift < 0) { shift += bits_in_word; } if (shift) { shift_left(shift); } find_sw(); m_wp = (shift - exponent) / bits_in_word; } // ---------------------------------------------------------------------------- // return a new mantissa that is aligned and resized // ---------------------------------------------------------------------------- scfx_mant * scfx_rep::resize(int new_size, int new_wp) const { scfx_mant *result = new scfx_mant(new_size); result->clear(); int shift = new_wp - m_wp; for (int j = m_lsw; j <= m_msw; j++) { (*result)[j + shift] = m_mant[j]; } return result; } // ---------------------------------------------------------------------------- // set a single bit // ---------------------------------------------------------------------------- void scfx_rep::set_bin(int i) { m_mant[i >> 5] |= 1 << (i & 31); } // ---------------------------------------------------------------------------- // set three bits // ---------------------------------------------------------------------------- void scfx_rep::set_oct(int i, int n) { if (n & 1) { m_mant[i >> 5] |= 1 << (i & 31); } i++; if (n & 2) { m_mant[i >> 5] |= 1 << (i & 31); } i++; if (n & 4) { m_mant[i >> 5] |= 1 << (i & 31); } } // ---------------------------------------------------------------------------- // set four bits // ---------------------------------------------------------------------------- void scfx_rep::set_hex(int i, int n) { if (n & 1) { m_mant[i >> 5] |= 1 << (i & 31); } i++; if (n & 2) { m_mant[i >> 5] |= 1 << (i & 31); } i++; if (n & 4) { m_mant[i >> 5] |= 1 << (i & 31); } i++; if (n & 8) { m_mant[i >> 5] |= 1 << (i & 31); } } // ---------------------------------------------------------------------------- // PRIVATE METHOD : shift_left // // Shifts a scfx_rep to the left by a MAXIMUM of bits_in_word - 1 bits. // ---------------------------------------------------------------------------- void scfx_rep::shift_left(int n) { if (n != 0) { int shift_left = n; int shift_right = bits_in_word - n; SC_ASSERT_(!(m_mant[size() - 1] >> shift_right), "shift_left overflow"); for (int i = size() - 1; i > 0; i--) { m_mant[i] = (m_mant[i] << shift_left) | (m_mant[i - 1] >> shift_right); } m_mant[0] <<= shift_left; } } // ---------------------------------------------------------------------------- // PRIVATE METHOD : shift_right // // Shifts a scfx_rep to the right by a MAXIMUM of bits_in_word - 1 bits. // ---------------------------------------------------------------------------- void scfx_rep::shift_right(int n) { if (n != 0) { int shift_left = bits_in_word - n; int shift_right = n; SC_ASSERT_(!(m_mant[0] << shift_left), "shift_right overflow"); for (int i = 0; i < size() - 1; i++) { m_mant[i] = (m_mant[i] >> shift_right) | (m_mant[i + 1] << shift_left); } m_mant[size() - 1] >>= shift_right; } } // ---------------------------------------------------------------------------- // METHOD : get_bit // // Tests a bit, in two's complement. // ---------------------------------------------------------------------------- bool scfx_rep::get_bit(int i) const { if (!is_normal()) return false; scfx_index x = calc_indices(i); if (x.wi() >= size()) return is_neg(); if (x.wi() < 0) return false; const_cast(this)->toggle_tc(); bool result = (m_mant[x.wi()] & (1 << x.bi())) != 0; const_cast(this)->toggle_tc(); return result; } // ---------------------------------------------------------------------------- // METHOD : set // // Sets a bit, in two's complement, between iwl-1 and -fwl. // ---------------------------------------------------------------------------- bool scfx_rep::set(int i, const scfx_params ¶ms) { if (!is_normal()) return false; scfx_index x = calc_indices(i); if (x.wi() >= size()) { if (is_neg()) return true; else resize_to(x.wi() + 1, 1); } else if (x.wi() < 0) { resize_to(size() - x.wi(), -1); x.wi(0); } toggle_tc(); m_mant[x.wi()] |= 1 << x.bi(); if (i == params.iwl() - 1) o_extend(x, params.enc()); // sign extension toggle_tc(); find_sw(); return true; } // ---------------------------------------------------------------------------- // METHOD : clear // // Clears a bit, in two's complement, between iwl-1 and -fwl. // ---------------------------------------------------------------------------- bool scfx_rep::clear(int i, const scfx_params ¶ms) { if (!is_normal()) return false; scfx_index x = calc_indices(i); if (x.wi() >= size()) { if (!is_neg()) return true; else resize_to(x.wi() + 1, 1); } else if (x.wi() < 0) { return true; } toggle_tc(); m_mant[x.wi()] &= ~(1 << x.bi()); if (i == params.iwl() - 1) o_extend(x, params.enc()); // sign extension toggle_tc(); find_sw(); return true; } // ---------------------------------------------------------------------------- // METHOD : get_slice // ---------------------------------------------------------------------------- bool scfx_rep::get_slice(int i, int j, const scfx_params &, sc_bv_base &bv) const { if (is_nan() || is_inf()) return false; // get the bits int l = j; for (int k = 0; k < bv.length(); ++k) { bv[k] = get_bit(l); if (i >= j) ++l; else --l; } return true; } bool scfx_rep::set_slice(int i, int j, const scfx_params ¶ms, const sc_bv_base &bv) { if (is_nan() || is_inf()) return false; // set the bits int l = j; for (int k = 0; k < bv.length(); ++k) { if (bv[k].to_bool()) set(l, params); else clear(l, params); if (i >= j) ++l; else --l; } return true; } // ---------------------------------------------------------------------------- // METHOD : print // ---------------------------------------------------------------------------- void scfx_rep::print(::std::ostream &os) const { os << to_string(SC_DEC, -1, SC_E); } // ---------------------------------------------------------------------------- // METHOD : dump // ---------------------------------------------------------------------------- void scfx_rep::dump(::std::ostream &os) const { os << "scfx_rep" << ::std::endl; os << "(" << ::std::endl; os << "mant =" << ::std::endl; for (int i = size() - 1; i >= 0; i--) { char buf[BUFSIZ]; std::sprintf(buf, " %d: %10u (%8x)", i, (int)m_mant[i], (int)m_mant[i]); os << buf << ::std::endl; } os << "wp = " << m_wp << ::std::endl; os << "sign = " << m_sign << ::std::endl; os << "state = "; switch (m_state) { case normal: os << "normal"; break; case infinity: os << "infinity"; break; case not_a_number: os << "not_a_number"; break; default: os << "unknown"; } os << ::std::endl; os << "msw = " << m_msw << ::std::endl; os << "lsw = " << m_lsw << ::std::endl; os << ")" << ::std::endl; } // ---------------------------------------------------------------------------- // METHOD : get_type // ---------------------------------------------------------------------------- void scfx_rep::get_type(int &wl, int &iwl, sc_enc &enc) const { if (is_nan() || is_inf()) { wl = 0; iwl = 0; enc = SC_TC_; return; } if (is_zero()) { wl = 1; iwl = 1; enc = SC_US_; return; } int msb = (m_msw - m_wp) * bits_in_word + scfx_find_msb(m_mant[ m_msw ]) + 1; while (get_bit(msb) == get_bit(msb - 1)) { --msb; } int lsb = (m_lsw - m_wp) * bits_in_word + scfx_find_lsb(m_mant[m_lsw]); if (is_neg()) { wl = msb - lsb + 1; iwl = msb + 1; enc = SC_TC_; } else { wl = msb - lsb; iwl = msb; enc = SC_US_; } } // ---------------------------------------------------------------------------- // PRIVATE METHOD : round // // Performs convergent rounding (rounding to even) as in floating-point. // ---------------------------------------------------------------------------- void scfx_rep::round(int wl) { // check for special cases if (is_nan() || is_inf() || is_zero()) return; // estimate effective wordlength and compare int wl_effective; wl_effective = (m_msw - m_lsw + 1) * bits_in_word; if (wl_effective <= wl) return; // calculate effective wordlength and compare int msb = scfx_find_msb(m_mant[m_msw]); int lsb = scfx_find_lsb(m_mant[m_lsw]); wl_effective = (m_msw * bits_in_word + msb) - (m_lsw * bits_in_word + lsb) + 1; if (wl_effective <= wl) return; // perform rounding int wi = m_msw - (wl - 1) / bits_in_word; int bi = msb - (wl - 1) % bits_in_word; if (bi < 0) { --wi; bi += bits_in_word; } scfx_index x(wi, bi); if ((q_bit(x) && ! q_zero(x)) || (q_bit(x) && q_zero(x) && q_odd(x))) { q_incr(x); } q_clear(x); find_sw(); m_r_flag = true; } } // namespace sc_dt