| /***************************************************************************** | |
| 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 <cctype> | |
| #include <cmath> | |
| #include <cstdio> | |
| #include <cstdlib> | |
| #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<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 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 = 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<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'); | |
| 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<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_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<uint64>(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<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)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<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: | |
| 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<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_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<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); | |
| } | |
| // ---------------------------------------------------------------------------- | |
| // 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 ¶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 |