| /***************************************************************************** | |
| Licensed to Accellera Systems Initiative Inc. (Accellera) under one or | |
| more contributor license agreements. See the NOTICE file distributed | |
| with this work for additional information regarding copyright ownership. | |
| Accellera licenses this file to you under the Apache License, Version 2.0 | |
| (the "License"); you may not use this file except in compliance with the | |
| License. You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |
| implied. See the License for the specific language governing | |
| permissions and limitations under the License. | |
| *****************************************************************************/ | |
| /***************************************************************************** | |
| sc_uint_base.cpp -- contains interface definitions between sc_uint and | |
| sc_signed, sc_unsigned, and definitions for sc_uint_subref. | |
| Original Author: Ali Dasdan, Synopsys, Inc. | |
| *****************************************************************************/ | |
| /***************************************************************************** | |
| MODIFICATION LOG - modifiers, enter your name, affiliation, date and | |
| changes you are making here. | |
| Name, Affiliation, Date: | |
| Description of Modification: | |
| *****************************************************************************/ | |
| // $Log: sc_uint_base.cpp,v $ | |
| // Revision 1.5 2011/02/18 20:19:15 acg | |
| // Andy Goodrich: updating Copyright notice. | |
| // | |
| // Revision 1.4 2010/02/04 22:23:29 acg | |
| // Andy Goodrich: fixed bug in concatenation reads for part selections, | |
| // the mask being used was 32 bits and should have been 64 bits. | |
| // | |
| // Revision 1.3 2008/06/19 17:47:57 acg | |
| // Andy Goodrich: fixes for bugs. See 2.2.1 RELEASENOTES. | |
| // | |
| // Revision 1.2 2007/11/04 21:27:00 acg | |
| // Andy Goodrich: changes to make sure the proper value is returned from | |
| // concat_get_data(). | |
| // | |
| // Revision 1.1.1.1 2006/12/15 20:20:05 acg | |
| // SystemC 2.3 | |
| // | |
| // Revision 1.3 2006/01/13 18:49:32 acg | |
| // Added $Log command so that CVS check in comments are reproduced in the | |
| // source. | |
| // | |
| #include <sstream> | |
| #include "systemc/ext/dt/bit/sc_bv_base.hh" | |
| #include "systemc/ext/dt/bit/sc_lv_base.hh" | |
| #include "systemc/ext/dt/fx/sc_ufix.hh" | |
| #include "systemc/ext/dt/fx/scfx_other_defs.hh" | |
| #include "systemc/ext/dt/int/sc_signed.hh" | |
| #include "systemc/ext/dt/int/sc_uint_base.hh" | |
| #include "systemc/ext/dt/int/sc_unsigned.hh" | |
| #include "systemc/ext/dt/misc/sc_concatref.hh" | |
| // explicit template instantiations | |
| namespace sc_core | |
| { | |
| template class sc_vpool<sc_dt::sc_uint_bitref>; | |
| template class sc_vpool<sc_dt::sc_uint_subref>; | |
| } // namespace sc_core | |
| namespace sc_dt | |
| { | |
| // to avoid code bloat in sc_uint_concat<T1,T2> | |
| void | |
| sc_uint_concref_invalid_length(int length) | |
| { | |
| std::stringstream msg; | |
| msg << "sc_uint_concref<T1,T2> initialization: length = " << length << | |
| "violates 1 <= length <= " << SC_INTWIDTH; | |
| SC_REPORT_ERROR(sc_core::SC_ID_OUT_OF_BOUNDS_, msg.str().c_str()); | |
| sc_core::sc_abort(); // can't recover from here | |
| } | |
| // ---------------------------------------------------------------------------- | |
| // CLASS : sc_uint_bitref | |
| // | |
| // Proxy class for sc_uint bit selection (r-value and l-value). | |
| // ---------------------------------------------------------------------------- | |
| sc_core::sc_vpool<sc_uint_bitref> sc_uint_bitref::m_pool(9); | |
| // concatenation methods: | |
| // #### OPTIMIZE | |
| void | |
| sc_uint_bitref::concat_set(int64 src, int low_i) | |
| { | |
| sc_uint_base aa(1); | |
| *this = aa = (low_i < 64) ? src >> low_i : src >> 63; | |
| } | |
| void | |
| sc_uint_bitref::concat_set(const sc_signed &src, int low_i) | |
| { | |
| sc_uint_base aa(1); | |
| if (low_i < src.length()) | |
| *this = aa = 1 & (src >> low_i); | |
| else | |
| *this = aa = (src < 0) ? (int_type)-1 : 0; | |
| } | |
| void | |
| sc_uint_bitref::concat_set(const sc_unsigned &src, int low_i) | |
| { | |
| sc_uint_base aa(1); | |
| if (low_i < src.length()) | |
| *this = aa = 1 & (src >> low_i); | |
| else | |
| *this = aa = 0; | |
| } | |
| void | |
| sc_uint_bitref::concat_set(uint64 src, int low_i) | |
| { | |
| sc_uint_base aa(1); | |
| *this = aa = (low_i < 64) ? src >> low_i : 0; | |
| } | |
| // other methods | |
| void | |
| sc_uint_bitref::scan(::std::istream &is) | |
| { | |
| bool b; | |
| is >> b; | |
| *this = b; | |
| } | |
| // ---------------------------------------------------------------------------- | |
| // CLASS : sc_uint_subref_r | |
| // | |
| // Proxy class for sc_uint part selection (l-value). | |
| // ---------------------------------------------------------------------------- | |
| bool | |
| sc_uint_subref_r::concat_get_ctrl(sc_digit *dst_p, int low_i) const | |
| { | |
| int dst_i; // Word in dst_p now processing. | |
| int end_i; // Highest order word in dst_p to process. | |
| int left_shift; // Left shift for val. | |
| uint_type mask; // Mask for bits to extract or keep. | |
| dst_i = low_i / BITS_PER_DIGIT; | |
| left_shift = low_i % BITS_PER_DIGIT; | |
| end_i = (low_i + (m_left-m_right)) / BITS_PER_DIGIT; | |
| mask = ~(~UINT_ZERO << left_shift); | |
| dst_p[dst_i] = (sc_digit)((dst_p[dst_i] & mask)); | |
| dst_i++; | |
| for (; dst_i <= end_i; dst_i++) | |
| dst_p[dst_i] = 0; | |
| return false; | |
| } | |
| bool | |
| sc_uint_subref_r::concat_get_data(sc_digit *dst_p, int low_i) const | |
| { | |
| int dst_i; // Word in dst_p now processing. | |
| int end_i; // Highest order word in dst_p to process. | |
| int high_i; // Index of high order bit in dst_p to set. | |
| int left_shift; // Left shift for val. | |
| uint_type mask; // Mask for bits to extract or keep. | |
| bool result; // True if inserting non-zero value. | |
| uint_type val; // Selection value extracted from m_obj_p. | |
| dst_i = low_i / BITS_PER_DIGIT; | |
| left_shift = low_i % BITS_PER_DIGIT; | |
| high_i = low_i + (m_left-m_right); | |
| end_i = high_i / BITS_PER_DIGIT; | |
| mask = ~mask_int[m_left][m_right]; | |
| val = (m_obj_p->m_val & mask) >> m_right; | |
| result = val != 0; | |
| // PROCESS THE FIRST WORD: | |
| mask = ~(~UINT_ZERO << left_shift); | |
| dst_p[dst_i] = (sc_digit)(((dst_p[dst_i] & mask)) | | |
| ((val << left_shift) & DIGIT_MASK)); | |
| switch (end_i - dst_i) { | |
| // BITS ARE ACROSS TWO WORDS: | |
| case 1: | |
| dst_i++; | |
| val >>= (BITS_PER_DIGIT-left_shift); | |
| dst_p[dst_i] = (sc_digit)val; | |
| break; | |
| // BITS ARE ACROSS THREE WORDS: | |
| case 2: | |
| dst_i++; | |
| val >>= (BITS_PER_DIGIT-left_shift); | |
| dst_p[dst_i++] = (sc_digit)(val & DIGIT_MASK); | |
| val >>= BITS_PER_DIGIT; | |
| dst_p[dst_i] = (sc_digit)val; | |
| break; | |
| // BITS ARE ACROSS THREE WORDS: | |
| case 3: | |
| dst_i++; | |
| val >>= (BITS_PER_DIGIT-left_shift); | |
| dst_p[dst_i++] = (sc_digit)(val & DIGIT_MASK); | |
| val >>= BITS_PER_DIGIT; | |
| dst_p[dst_i++] = (sc_digit)(val & DIGIT_MASK); | |
| val >>= BITS_PER_DIGIT; | |
| dst_p[dst_i] = (sc_digit)val; | |
| break; | |
| } | |
| return result; | |
| } | |
| // ---------------------------------------------------------------------------- | |
| // CLASS : sc_uint_subref | |
| // | |
| // Proxy class for sc_uint part selection (r-value and l-value). | |
| // ---------------------------------------------------------------------------- | |
| sc_core::sc_vpool<sc_uint_subref> sc_uint_subref::m_pool(9); | |
| // assignment operators | |
| sc_uint_subref & | |
| sc_uint_subref::operator = (uint_type v) | |
| { | |
| uint_type val = m_obj_p->m_val; | |
| uint_type mask = mask_int[m_left][m_right]; | |
| val &= mask; | |
| val |= (v << m_right) & ~mask; | |
| m_obj_p->m_val = val; | |
| m_obj_p->extend_sign(); | |
| return *this; | |
| } | |
| sc_uint_subref & | |
| sc_uint_subref::operator = (const sc_signed &a) | |
| { | |
| sc_uint_base aa(length()); | |
| return (*this = aa = a); | |
| } | |
| sc_uint_subref & | |
| sc_uint_subref::operator = (const sc_unsigned &a) | |
| { | |
| sc_uint_base aa(length()); | |
| return (*this = aa = a); | |
| } | |
| sc_uint_subref & | |
| sc_uint_subref::operator = (const sc_bv_base &a) | |
| { | |
| sc_uint_base aa(length()); | |
| return (*this = aa = a); | |
| } | |
| sc_uint_subref & | |
| sc_uint_subref::operator = (const sc_lv_base &a) | |
| { | |
| sc_uint_base aa(length()); | |
| return (*this = aa = a); | |
| } | |
| // concatenation methods: | |
| // #### OPTIMIZE | |
| void | |
| sc_uint_subref::concat_set(int64 src, int low_i) | |
| { | |
| sc_uint_base aa(length()); | |
| *this = aa = (low_i < 64) ? src >> low_i : src >> 63; | |
| } | |
| void | |
| sc_uint_subref::concat_set(const sc_signed &src, int low_i) | |
| { | |
| sc_uint_base aa(length()); | |
| if (low_i < src.length()) | |
| *this = aa = src >> low_i; | |
| else | |
| *this = aa = (src < 0) ? (int_type)-1 : 0; | |
| } | |
| void | |
| sc_uint_subref::concat_set(const sc_unsigned &src, int low_i) | |
| { | |
| sc_uint_base aa(length()); | |
| if (low_i < src.length()) | |
| *this = aa = src >> low_i; | |
| else | |
| *this = aa = 0; | |
| } | |
| void | |
| sc_uint_subref::concat_set(uint64 src, int low_i) | |
| { | |
| sc_uint_base aa(length()); | |
| *this = aa = (low_i < 64) ? src >> low_i : 0; | |
| } | |
| // other methods | |
| void | |
| sc_uint_subref::scan(::std::istream &is) | |
| { | |
| std::string s; | |
| is >> s; | |
| *this = s.c_str(); | |
| } | |
| // ---------------------------------------------------------------------------- | |
| // CLASS : sc_uint_base | |
| // | |
| // Base class for sc_uint. | |
| // ---------------------------------------------------------------------------- | |
| // support methods | |
| void | |
| sc_uint_base::invalid_length() const | |
| { | |
| std::stringstream msg; | |
| msg << "sc_uint[_base] initialization: length = " << m_len << | |
| " violates 1 <= length <= " << SC_INTWIDTH; | |
| SC_REPORT_ERROR(sc_core::SC_ID_OUT_OF_BOUNDS_, msg.str().c_str()); | |
| sc_core::sc_abort(); // can't recover from here} | |
| } | |
| void | |
| sc_uint_base::invalid_index(int i) const | |
| { | |
| std::stringstream msg; | |
| msg << "sc_uint[_base] bit selection: index = " << i << | |
| " violates 0 <= index <= " << (m_len - 1); | |
| SC_REPORT_ERROR(sc_core::SC_ID_OUT_OF_BOUNDS_, msg.str().c_str()); | |
| sc_core::sc_abort(); // can't recover from here | |
| } | |
| void | |
| sc_uint_base::invalid_range(int l, int r) const | |
| { | |
| std::stringstream msg; | |
| msg << "sc_uint[_base] part selection: " << | |
| "left = " << l << ", right = " << r << " violates " << | |
| (m_len - 1) << " >= left >= right >= 0"; | |
| SC_REPORT_ERROR(sc_core::SC_ID_OUT_OF_BOUNDS_, msg.str().c_str()); | |
| sc_core::sc_abort(); // can't recover from here | |
| } | |
| void | |
| sc_uint_base::check_value() const | |
| { | |
| uint_type limit = (~UINT_ZERO >> m_ulen); | |
| if (m_val > limit) { | |
| std::stringstream msg; | |
| msg << "sc_uint[_base]: value does not fit into a length of " << m_len; | |
| SC_REPORT_WARNING(sc_core::SC_ID_OUT_OF_BOUNDS_, msg.str().c_str()); | |
| } | |
| } | |
| // constructors | |
| sc_uint_base::sc_uint_base(const sc_bv_base &v) : | |
| m_val(0), m_len(v.length()), m_ulen(SC_INTWIDTH - m_len) | |
| { | |
| check_length(); | |
| *this = v; | |
| } | |
| sc_uint_base::sc_uint_base(const sc_lv_base &v) : | |
| m_val(0), m_len(v.length()), m_ulen(SC_INTWIDTH - m_len) | |
| { | |
| check_length(); | |
| *this = v; | |
| } | |
| sc_uint_base::sc_uint_base(const sc_int_subref_r &v) : | |
| m_val(0), m_len(v.length()), m_ulen(SC_INTWIDTH - m_len) | |
| { | |
| check_length(); | |
| *this = v.to_uint64(); | |
| } | |
| sc_uint_base::sc_uint_base(const sc_signed_subref_r &v) : | |
| m_val(0), m_len(v.length()), m_ulen(SC_INTWIDTH - m_len) | |
| { | |
| check_length(); | |
| *this = v.to_uint64(); | |
| } | |
| sc_uint_base::sc_uint_base(const sc_unsigned_subref_r &v) : | |
| m_val(0), m_len(v.length()), m_ulen(SC_INTWIDTH - m_len) | |
| { | |
| check_length(); | |
| *this = v.to_uint64(); | |
| } | |
| sc_uint_base::sc_uint_base(const sc_signed &a) : | |
| m_val(0), m_len(a.length()), m_ulen(SC_INTWIDTH - m_len) | |
| { | |
| check_length(); | |
| *this = a.to_uint64(); | |
| } | |
| sc_uint_base::sc_uint_base(const sc_unsigned &a) : | |
| m_val(0), m_len(a.length()), m_ulen(SC_INTWIDTH - m_len) | |
| { | |
| check_length(); | |
| *this = a.to_uint64(); | |
| } | |
| // assignment operators | |
| sc_uint_base & | |
| sc_uint_base::operator = (const sc_signed &a) | |
| { | |
| int minlen = sc_min(m_len, a.length()); | |
| int i = 0; | |
| for (; i < minlen; ++i) { | |
| set(i, a.test(i)); | |
| } | |
| bool sgn = a.sign(); | |
| for (; i < m_len; ++i) { | |
| // sign extension | |
| set(i, sgn); | |
| } | |
| extend_sign(); | |
| return *this; | |
| } | |
| sc_uint_base & | |
| sc_uint_base::operator = (const sc_unsigned &a) | |
| { | |
| int minlen = sc_min(m_len, a.length()); | |
| int i = 0; | |
| for (; i < minlen; ++i) { | |
| set(i, a.test(i)); | |
| } | |
| for (; i < m_len; ++i) { | |
| // zero extension | |
| set(i, 0); | |
| } | |
| extend_sign(); | |
| return *this; | |
| } | |
| sc_uint_base & | |
| sc_uint_base::operator = (const sc_bv_base &a) | |
| { | |
| int minlen = sc_min(m_len, a.length()); | |
| int i = 0; | |
| for (; i < minlen; ++i) { | |
| set(i, a.get_bit(i)); | |
| } | |
| for (; i < m_len; ++i) { | |
| // zero extension | |
| set(i, 0); | |
| } | |
| extend_sign(); | |
| return *this; | |
| } | |
| sc_uint_base & | |
| sc_uint_base::operator = (const sc_lv_base &a) | |
| { | |
| int minlen = sc_min(m_len, a.length()); | |
| int i = 0; | |
| for (; i < minlen; ++i) { | |
| set(i, sc_logic(a.get_bit(i)).to_bool()); | |
| } | |
| for (; i < m_len; ++i) { | |
| // zero extension | |
| set(i, 0); | |
| } | |
| extend_sign(); | |
| return *this; | |
| } | |
| sc_uint_base & | |
| sc_uint_base::operator = (const char *a) | |
| { | |
| if (a == 0) { | |
| SC_REPORT_ERROR(sc_core::SC_ID_CONVERSION_FAILED_, | |
| "character string is zero"); | |
| } else if (*a == 0) { | |
| SC_REPORT_ERROR(sc_core::SC_ID_CONVERSION_FAILED_, | |
| "character string is empty"); | |
| } else try { | |
| int len = m_len; | |
| sc_ufix aa(a, len, len, SC_TRN, SC_WRAP, 0, SC_ON); | |
| return this->operator = (aa); | |
| } catch(const sc_core::sc_report &) { | |
| std::stringstream msg; | |
| msg << "character string '" << a << "' is not valid"; | |
| SC_REPORT_ERROR(sc_core::SC_ID_CONVERSION_FAILED_, msg.str().c_str()); | |
| } | |
| return *this; | |
| } | |
| // explicit conversion to character string | |
| const std::string | |
| sc_uint_base::to_string(sc_numrep numrep) const | |
| { | |
| int len = m_len; | |
| sc_ufix aa(*this, len, len, SC_TRN, SC_WRAP, 0, SC_ON); | |
| return aa.to_string(numrep); | |
| } | |
| const std::string | |
| sc_uint_base::to_string(sc_numrep numrep, bool w_prefix) const | |
| { | |
| int len = m_len; | |
| sc_ufix aa(*this, len, len, SC_TRN, SC_WRAP, 0, SC_ON); | |
| return aa.to_string(numrep, w_prefix); | |
| } | |
| // reduce methods | |
| bool | |
| sc_uint_base::and_reduce() const | |
| { | |
| return (m_val == (~UINT_ZERO >> m_ulen)); | |
| } | |
| bool | |
| sc_uint_base::or_reduce() const | |
| { | |
| return (m_val != uint_type(0)); | |
| } | |
| bool | |
| sc_uint_base::xor_reduce() const | |
| { | |
| uint_type mask = ~UINT_ZERO; | |
| uint_type val = m_val; | |
| int n = SC_INTWIDTH; | |
| do { | |
| n >>= 1; | |
| mask >>= n; | |
| val = ((val & (mask << n)) >> n) ^ (val & mask); | |
| } while (n != 1); | |
| return (val != uint_type(0)); | |
| } | |
| bool | |
| sc_uint_base::concat_get_ctrl(sc_digit *dst_p, int low_i) const | |
| { | |
| int dst_i; // Word in dst_p now processing. | |
| int end_i; // Highest order word in dst_p to process. | |
| int left_shift; // Left shift for val. | |
| uint_type mask; // Mask for bits to extract or keep. | |
| dst_i = low_i / BITS_PER_DIGIT; | |
| left_shift = low_i % BITS_PER_DIGIT; | |
| end_i = (low_i + (m_len - 1)) / BITS_PER_DIGIT; | |
| // PROCESS THE FIRST WORD: | |
| mask = ~(~UINT_ZERO << left_shift); | |
| dst_p[dst_i] = (sc_digit)((dst_p[dst_i] & mask)); | |
| dst_i++; | |
| for (; dst_i <= end_i; dst_i++) | |
| dst_p[dst_i] = 0; | |
| return false; | |
| } | |
| //----------------------------------------------------------------------------- | |
| //"sc_uint_base::concat_get_data" | |
| // | |
| // This method transfers the value of this object instance to the supplied | |
| // array of sc_unsigned digits starting with the bit specified by low_i within | |
| // the array of digits. | |
| // | |
| // Notes: | |
| // (1) we don't worry about masking the high order data we transfer since | |
| // concat_get_data() is called from low order bit to high order bit. So | |
| // the bits above where we place ours will be filled in by someone else. | |
| // | |
| // dst_p -> array of sc_unsigned digits to be filled in. | |
| // low_i = first bit within dst_p to be set. | |
| //----------------------------------------------------------------------------- | |
| bool | |
| sc_uint_base::concat_get_data(sc_digit *dst_p, int low_i) const | |
| { | |
| int dst_i; // Word in dst_p now processing. | |
| int end_i; // Highest order word in dst_p to process. | |
| int high_i; // Index of high order bit in dst_p to set. | |
| int left_shift; // Left shift for val. | |
| uint_type mask; // Mask for bits to extract or keep. | |
| bool result; // True if inserting non-zero value. | |
| uint_type val; // Value for this object. | |
| dst_i = low_i / BITS_PER_DIGIT; | |
| left_shift = low_i % BITS_PER_DIGIT; | |
| high_i = low_i + (m_len - 1); | |
| end_i = high_i / BITS_PER_DIGIT; | |
| val = m_val; | |
| result = val != 0; | |
| // MASK OFF DATA TO BE TRANSFERRED BASE ON WIDTH: | |
| if (m_len < 64) { | |
| mask = ~(~UINT_ZERO << m_len); | |
| val &= mask; | |
| } | |
| // PROCESS THE FIRST WORD: | |
| mask = ~(~UINT_ZERO << left_shift); | |
| dst_p[dst_i] = (sc_digit)(((dst_p[dst_i] & mask)) | | |
| ((val << left_shift) & DIGIT_MASK)); | |
| switch (end_i - dst_i) { | |
| // BITS ARE ACROSS TWO WORDS: | |
| case 1: | |
| dst_i++; | |
| val >>= (BITS_PER_DIGIT - left_shift); | |
| dst_p[dst_i] = (sc_digit)val; | |
| break; | |
| // BITS ARE ACROSS THREE WORDS: | |
| case 2: | |
| dst_i++; | |
| val >>= (BITS_PER_DIGIT - left_shift); | |
| dst_p[dst_i++] = (sc_digit)(val & DIGIT_MASK); | |
| val >>= BITS_PER_DIGIT; | |
| dst_p[dst_i] = (sc_digit)val; | |
| break; | |
| // BITS ARE ACROSS FOUR WORDS: | |
| case 3: | |
| dst_i++; | |
| val >>= (BITS_PER_DIGIT - left_shift); | |
| dst_p[dst_i++] = (sc_digit)(val & DIGIT_MASK); | |
| val >>= BITS_PER_DIGIT; | |
| dst_p[dst_i++] = (sc_digit)(val & DIGIT_MASK); | |
| val >>= BITS_PER_DIGIT; | |
| dst_p[dst_i] = (sc_digit)val; | |
| break; | |
| } | |
| return result; | |
| } | |
| // #### OPTIMIZE | |
| void | |
| sc_uint_base::concat_set(int64 src, int low_i) | |
| { | |
| *this = (low_i < 64) ? src >> low_i : src >> 63; | |
| } | |
| void | |
| sc_uint_base::concat_set(const sc_signed &src, int low_i) | |
| { | |
| if (low_i < src.length()) | |
| *this = src >> low_i; | |
| else | |
| *this = (src < 0) ? (int_type)-1 : 0; | |
| } | |
| void | |
| sc_uint_base::concat_set(const sc_unsigned &src, int low_i) | |
| { | |
| if (low_i < src.length()) | |
| *this = src >> low_i; | |
| else | |
| *this = 0; | |
| } | |
| void | |
| sc_uint_base::concat_set(uint64 src, int low_i) | |
| { | |
| *this = (low_i < 64) ? src >> low_i : 0; | |
| } | |
| // other methods | |
| void | |
| sc_uint_base::scan(::std::istream &is) | |
| { | |
| std::string s; | |
| is >> s; | |
| *this = s.c_str(); | |
| } | |
| } // namespace sc_dt |