| /***************************************************************************** | |
| 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.h - | |
| 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.h,v $ | |
| // Revision 1.6 2011/08/24 22:05:43 acg | |
| // Torsten Maehne: initialization changes to remove warnings. | |
| // | |
| // Revision 1.5 2011/07/25 10:20:29 acg | |
| // Andy Goodrich: check in aftermath of call to automake. | |
| // | |
| // Revision 1.4 2010/12/07 20:09:08 acg | |
| // Andy Goodrich: Philipp Hartmann's constructor disambiguation fix | |
| // | |
| // Revision 1.3 2010/08/03 15:54:52 acg | |
| // Andy Goodrich: formatting. | |
| // | |
| // Revision 1.2 2010/03/15 18:29:01 acg | |
| // Andy Goodrich: Moved default argument specifications from friend | |
| // declarations to the actual function signatures. | |
| // | |
| // Revision 1.1.1.1 2006/12/15 20:20:04 acg | |
| // SystemC 2.3 | |
| // | |
| // Revision 1.4 2006/03/13 20:24:27 acg | |
| // Andy Goodrich: Addition of function declarations, e.g., neg_scfx_rep(), | |
| // to keep gcc 4.x happy. | |
| // | |
| // Revision 1.3 2006/01/13 18:53:58 acg | |
| // Andy Goodrich: added $Log command so that CVS comments are reproduced in | |
| // the source. | |
| // | |
| #ifndef __SYSTEMC_EXT_DT_FX_SCFX_REP_HH__ | |
| #define __SYSTEMC_EXT_DT_FX_SCFX_REP_HH__ | |
| #include <climits> | |
| #include "scfx_mant.hh" | |
| #include "scfx_params.hh" | |
| #include "scfx_string.hh" | |
| namespace sc_dt | |
| { | |
| // classes defined in this module | |
| class scfx_index; | |
| class scfx_rep; | |
| // forward class declarations | |
| class sc_bv_base; | |
| class sc_signed; | |
| class sc_unsigned; | |
| // function declarations | |
| void multiply(scfx_rep &, const scfx_rep &, const scfx_rep &, | |
| int max_wl=SC_DEFAULT_MAX_WL_); | |
| scfx_rep *neg_scfx_rep(const scfx_rep &); | |
| scfx_rep *mult_scfx_rep(const scfx_rep &, const scfx_rep &, | |
| int max_wl=SC_DEFAULT_MAX_WL_); | |
| scfx_rep *div_scfx_rep(const scfx_rep &, const scfx_rep &, | |
| int max_wl=SC_DEFAULT_DIV_WL_); | |
| scfx_rep *add_scfx_rep(const scfx_rep &, const scfx_rep &, | |
| int max_wl=SC_DEFAULT_MAX_WL_); | |
| scfx_rep *sub_scfx_rep(const scfx_rep &, const scfx_rep &, | |
| int max_wl=SC_DEFAULT_MAX_WL_); | |
| scfx_rep *lsh_scfx_rep(const scfx_rep &, int); | |
| scfx_rep *rsh_scfx_rep(const scfx_rep &, int); | |
| int cmp_scfx_rep(const scfx_rep &, const scfx_rep &); | |
| const int min_mant = 4; | |
| const int bits_in_int = sizeof(int) * CHAR_BIT; | |
| const int bits_in_word = sizeof(word) * CHAR_BIT; | |
| // ---------------------------------------------------------------------------- | |
| // CLASS : scfx_index | |
| // ---------------------------------------------------------------------------- | |
| class scfx_index | |
| { | |
| public: | |
| scfx_index(int wi_, int bi_) : m_wi(wi_), m_bi(bi_) {} | |
| int wi() const { return m_wi; } | |
| int bi() const { return m_bi; } | |
| void wi(int wi_) { m_wi = wi_; } | |
| private: | |
| int m_wi; | |
| int m_bi; | |
| }; | |
| // ---------------------------------------------------------------------------- | |
| // CLASS : scfx_rep | |
| // | |
| // Arbitrary-precision fixed-point implementation class. | |
| // ---------------------------------------------------------------------------- | |
| class scfx_rep | |
| { | |
| enum state | |
| { | |
| normal, | |
| infinity, | |
| not_a_number | |
| }; | |
| public: | |
| // constructors | |
| scfx_rep(); | |
| explicit scfx_rep(int); | |
| explicit scfx_rep(unsigned int); | |
| explicit scfx_rep(long); | |
| explicit scfx_rep(unsigned long); | |
| explicit scfx_rep(double); | |
| explicit scfx_rep(const char *); | |
| explicit scfx_rep(int64); | |
| explicit scfx_rep(uint64); | |
| explicit scfx_rep(const sc_signed &); | |
| explicit scfx_rep(const sc_unsigned &); | |
| // copy constructor | |
| scfx_rep(const scfx_rep &); | |
| // destructor | |
| ~scfx_rep(); | |
| void *operator new (std::size_t); | |
| void operator delete (void *, std::size_t); | |
| void from_string(const char *, int); | |
| double to_double() const; | |
| uint64 to_uint64() const; | |
| const char *to_string(sc_numrep, int, sc_fmt, | |
| const scfx_params * =0) const; | |
| // assignment operator | |
| void operator = (const scfx_rep &); | |
| friend void multiply( scfx_rep&, const scfx_rep&, const scfx_rep&, int ); | |
| friend scfx_rep *neg_scfx_rep(const scfx_rep &); | |
| friend scfx_rep *mult_scfx_rep(const scfx_rep &, const scfx_rep &, int); | |
| friend scfx_rep *div_scfx_rep(const scfx_rep &, const scfx_rep &, int); | |
| friend scfx_rep *add_scfx_rep(const scfx_rep &, const scfx_rep &, int); | |
| friend scfx_rep *sub_scfx_rep(const scfx_rep &, const scfx_rep &, int); | |
| friend scfx_rep *lsh_scfx_rep(const scfx_rep &, int); | |
| friend scfx_rep *rsh_scfx_rep(const scfx_rep &, int); | |
| void lshift(int); | |
| void rshift(int); | |
| friend int cmp_scfx_rep(const scfx_rep &, const scfx_rep &); | |
| void cast(const scfx_params &, bool &, bool &); | |
| bool is_neg() const; | |
| bool is_zero() const; | |
| bool is_nan() const; | |
| bool is_inf() const; | |
| bool is_normal() const; | |
| void set_zero(int=1); | |
| void set_nan(); | |
| void set_inf(int); | |
| bool get_bit(int) const; | |
| bool set(int, const scfx_params &); | |
| bool clear(int, const scfx_params &); | |
| bool get_slice(int, int, const scfx_params &, sc_bv_base &) const; | |
| bool set_slice(int, int, const scfx_params &, const sc_bv_base &); | |
| void print(::std::ostream &) const; | |
| void dump(::std::ostream &) const; | |
| void get_type(int &, int &, sc_enc &) const; | |
| friend scfx_rep *quantization_scfx_rep( | |
| const scfx_rep &, const scfx_params &, bool &); | |
| friend scfx_rep *overflow_scfx_rep( | |
| const scfx_rep &, const scfx_params &, bool &); | |
| bool rounding_flag() const; | |
| private: | |
| friend void align(const scfx_rep &, const scfx_rep &, int &, int &, | |
| scfx_mant_ref &, scfx_mant_ref &); | |
| friend int compare_msw(const scfx_rep &, const scfx_rep &); | |
| friend int compare_msw_ff(const scfx_rep &lhs, const scfx_rep &rhs); | |
| unsigned int divide_by_ten(); | |
| int find_lsw() const; | |
| int find_msw() const; | |
| void find_sw(); | |
| void multiply_by_ten(); | |
| void normalize(int); | |
| scfx_mant *resize(int, int) const; | |
| void set_bin(int); | |
| void set_oct(int, int); | |
| void set_hex(int, int); | |
| void shift_left(int); | |
| void shift_right(int); | |
| const scfx_index calc_indices(int) const; | |
| void o_extend(const scfx_index &, sc_enc); | |
| bool o_bit_at(const scfx_index &) const; | |
| bool o_zero_left(const scfx_index &) const; | |
| bool o_zero_right(const scfx_index &) const; | |
| void o_set_low(const scfx_index &, sc_enc); | |
| void o_set_high(const scfx_index &, const scfx_index &, sc_enc, int=1); | |
| void o_set(const scfx_index &, const scfx_index &, sc_enc, bool); | |
| void o_invert(const scfx_index &); | |
| bool q_bit(const scfx_index &) const; | |
| void q_clear(const scfx_index &); | |
| void q_incr(const scfx_index &); | |
| bool q_odd(const scfx_index &) const; | |
| bool q_zero(const scfx_index &) const; | |
| void resize_to(int, int=0); | |
| int size() const; | |
| void toggle_tc(); | |
| friend void print_dec(scfx_string &, const scfx_rep &, int, sc_fmt); | |
| friend void print_other(scfx_string &, const scfx_rep &, sc_numrep, int, | |
| sc_fmt, const scfx_params *); | |
| void quantization(const scfx_params &, bool &); | |
| void overflow(const scfx_params &, bool &); | |
| friend int compare_abs(const scfx_rep &, const scfx_rep &); | |
| void round(int); | |
| private: | |
| scfx_mant m_mant; // mantissa (bits of the value). | |
| int m_wp; // index of highest order word in value. | |
| int m_sign; // sign of value. | |
| state m_state; // value state, e.g., normal, inf, etc. | |
| int m_msw; // index of most significant non-zero word. | |
| int m_lsw; // index of least significant non-zero word. | |
| bool m_r_flag; // true if rounding occurred. | |
| }; | |
| // IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII | |
| inline void | |
| scfx_rep::set_zero(int sign) | |
| { | |
| m_mant.clear(); | |
| m_wp = m_msw = m_lsw = 0; | |
| m_sign = sign; | |
| m_state = normal; | |
| } | |
| inline void | |
| scfx_rep::set_nan() | |
| { | |
| m_mant.resize_to(min_mant); | |
| m_state = not_a_number; | |
| } | |
| inline void | |
| scfx_rep::set_inf(int sign) | |
| { | |
| m_mant.resize_to(min_mant); | |
| m_state = infinity; | |
| m_sign = sign; | |
| } | |
| // constructors | |
| inline scfx_rep::scfx_rep(const char *s) : | |
| m_mant(min_mant), m_wp(2), m_sign(1), m_state(normal), | |
| m_msw(0), m_lsw(0), m_r_flag(false) | |
| { | |
| from_string(s, SC_DEFAULT_CTE_WL_); | |
| } | |
| // destructor | |
| inline scfx_rep::~scfx_rep() {} | |
| // assignment operator | |
| inline void | |
| scfx_rep::operator = (const scfx_rep &f) | |
| { | |
| if (&f != this) { | |
| m_mant = f.m_mant; | |
| m_wp = f.m_wp; | |
| m_sign = f.m_sign; | |
| m_state = f.m_state; | |
| m_msw = f.m_msw; | |
| m_lsw = f.m_lsw; | |
| round(SC_DEFAULT_MAX_WL_); | |
| } | |
| } | |
| inline scfx_rep * | |
| neg_scfx_rep(const scfx_rep &a) | |
| { | |
| scfx_rep &c = *new scfx_rep(a); | |
| c.m_sign = - c.m_sign; | |
| return &c; | |
| } | |
| inline scfx_rep * | |
| mult_scfx_rep(const scfx_rep &a, const scfx_rep &b, int max_wl) | |
| { | |
| scfx_rep &c = *new scfx_rep; | |
| sc_dt::multiply(c, a, b, max_wl); | |
| return &c; | |
| } | |
| inline scfx_rep * | |
| lsh_scfx_rep(const scfx_rep &a, int b) | |
| { | |
| scfx_rep &c = *new scfx_rep(a); | |
| c.lshift(b); | |
| return &c; | |
| } | |
| inline scfx_rep * | |
| rsh_scfx_rep(const scfx_rep &a, int b) | |
| { | |
| scfx_rep &c = *new scfx_rep(a); | |
| c.rshift(b); | |
| return &c; | |
| } | |
| inline int scfx_rep::size() const { return m_mant.size(); } | |
| inline bool scfx_rep::is_neg() const { return (m_sign == -1); } | |
| inline bool | |
| scfx_rep::is_zero() const | |
| { | |
| if (m_state != normal) | |
| return false; | |
| for (int i = 0; i < size(); i++) { | |
| if (m_mant[i]) | |
| return false; | |
| } | |
| return true; | |
| } | |
| inline bool scfx_rep::is_nan() const { return (m_state == not_a_number); } | |
| inline bool scfx_rep::is_inf() const { return (m_state == infinity); } | |
| inline bool scfx_rep::is_normal() const { return (m_state == normal); } | |
| inline scfx_rep * | |
| quantization_scfx_rep(const scfx_rep &a, const scfx_params ¶ms, | |
| bool &q_flag) | |
| { | |
| scfx_rep &c = *new scfx_rep(a); | |
| c.quantization(params, q_flag); | |
| return &c; | |
| } | |
| inline scfx_rep * | |
| overflow_scfx_rep(const scfx_rep &a, const scfx_params ¶ms, bool &o_flag) | |
| { | |
| scfx_rep& c = *new scfx_rep(a); | |
| c.overflow(params, o_flag); | |
| return &c; | |
| } | |
| inline bool scfx_rep::rounding_flag() const { return m_r_flag; } | |
| inline void | |
| scfx_rep::resize_to(int new_size, int restore) | |
| { | |
| if (restore == -1) { | |
| int size_incr = new_size - size(); | |
| m_wp += size_incr; | |
| m_msw += size_incr; | |
| m_lsw += size_incr; | |
| } | |
| m_mant.resize_to(new_size, restore); | |
| } | |
| inline const scfx_index | |
| scfx_rep::calc_indices(int n) const | |
| { | |
| int wi = n / bits_in_word + m_wp; | |
| int bi = n % bits_in_word; | |
| if (bi < 0) { | |
| bi += bits_in_word; | |
| -- wi; | |
| } | |
| return scfx_index(wi, bi); | |
| } | |
| inline void | |
| scfx_rep::o_extend(const scfx_index &x, sc_enc enc) | |
| { | |
| int wi = x.wi(); | |
| int bi = x.bi(); | |
| SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range"); | |
| if (enc == SC_US_ || (m_mant[wi] & (((word)1) << bi)) == 0) { | |
| if (bi != bits_in_word - 1) | |
| m_mant[wi] &= ~(((word)-1) << (bi + 1)); | |
| for (int i = wi + 1; i < size(); ++i) | |
| m_mant[i] = 0; | |
| m_sign = 1; | |
| } else { | |
| if (bi != bits_in_word - 1) | |
| m_mant[wi] |= (((word)-1) << (bi + 1)); | |
| for (int i = wi + 1; i < size(); ++i) | |
| m_mant[i] = static_cast<word>(-1); | |
| m_sign = -1; | |
| } | |
| } | |
| inline bool | |
| scfx_rep::o_bit_at(const scfx_index &x) const | |
| { | |
| int wi = x.wi(); | |
| int bi = x.bi(); | |
| SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range"); | |
| return (m_mant[wi] & (((word)1) << bi)) != 0; | |
| } | |
| inline bool | |
| scfx_rep::o_zero_left(const scfx_index &x) const | |
| { | |
| int wi = x.wi(); | |
| int bi = x.bi(); | |
| SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range"); | |
| bool zero = true; | |
| if (bi != bits_in_word - 1) | |
| zero = (m_mant[wi] & (((word)-1) << (bi + 1))) == 0; | |
| for (int i = wi + 1; i < size(); ++i) | |
| zero = zero && m_mant[i] == 0; | |
| return zero; | |
| } | |
| inline bool | |
| scfx_rep::o_zero_right(const scfx_index &x) const | |
| { | |
| int wi = x.wi(); | |
| int bi = x.bi(); | |
| SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range"); | |
| bool zero = (m_mant[wi] & ~(((word)-1) << bi)) == 0; | |
| for (int i = wi - 1; i >= 0; --i) | |
| zero = zero && m_mant[i] == 0; | |
| return zero; | |
| } | |
| inline void | |
| scfx_rep::o_set_low(const scfx_index &x, sc_enc enc) | |
| { | |
| int wi = x.wi(); | |
| int bi = x.bi(); | |
| SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range"); | |
| m_mant.clear(); | |
| if (enc == SC_TC_) { | |
| m_mant[wi] |= (((word)1) << bi); | |
| m_sign = -1; | |
| } else { | |
| m_sign = 1; | |
| } | |
| } | |
| inline void | |
| scfx_rep::o_set_high(const scfx_index &x, const scfx_index &x2, | |
| sc_enc enc, int sign) | |
| { | |
| int wi = x.wi(); | |
| int bi = x.bi(); | |
| int wi2 = x2.wi(); | |
| int bi2 = x2.bi(); | |
| SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range"); | |
| SC_ASSERT_(wi2 >= 0 && wi2 < size(), "word index out of range"); | |
| int i; | |
| for (i = 0; i < size(); ++i) | |
| m_mant[i] = static_cast<word>(-1); | |
| m_mant[wi] &= ~(((word)-1) << bi); | |
| for (i = wi + 1; i < size(); ++i) | |
| m_mant[i] = 0; | |
| m_mant[wi2] &= (((word)-1) << bi2); | |
| for (i = wi2 - 1; i >= 0; --i) | |
| m_mant[i] = 0; | |
| if (enc == SC_TC_) { | |
| m_sign = sign; | |
| } else { | |
| m_mant[wi] |= (((word)1) << bi); | |
| m_sign = 1; | |
| } | |
| } | |
| inline void | |
| scfx_rep::o_set(const scfx_index &x, const scfx_index &x3, sc_enc enc, | |
| bool under) | |
| { | |
| int wi = x.wi(); | |
| int bi = x.bi(); | |
| int wi3 = x3.wi(); | |
| int bi3 = x3.bi(); | |
| SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range"); | |
| SC_ASSERT_(wi3 >= 0 && wi3 < size(), "word index out of range"); | |
| if (bi3 != bits_in_word - 1) { | |
| if (under) | |
| m_mant[wi3] &= ~(((word)-1) << (bi3 + 1)); | |
| else | |
| m_mant[wi3] |= (((word)-1) << (bi3 + 1)); | |
| } | |
| for (int i = wi3 + 1; i < size(); ++i) { | |
| if (under) | |
| m_mant[i] = 0; | |
| else | |
| m_mant[i] = static_cast<word>(-1); | |
| } | |
| if (enc == SC_TC_) { | |
| if (under) | |
| m_mant[wi] |= (((word)1) << bi); | |
| else | |
| m_mant[wi] &= ~(((word)1) << bi); | |
| } | |
| } | |
| inline void | |
| scfx_rep::o_invert(const scfx_index &x2) | |
| { | |
| int wi2 = x2.wi(); | |
| int bi2 = x2.bi(); | |
| m_mant[wi2] ^= (((word)-1) << bi2); | |
| for (int i = wi2 + 1; i < size(); ++i) | |
| m_mant[i] = ~ m_mant[i]; | |
| } | |
| inline bool | |
| scfx_rep::q_bit(const scfx_index &x) const | |
| { | |
| int wi = x.wi(); | |
| int bi = x.bi(); | |
| SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range"); | |
| if (bi != 0) | |
| return (m_mant[wi] & (((word)1) << (bi - 1))) != 0; | |
| else if (wi != 0) | |
| return (m_mant[wi - 1] & (((word)1) << (bits_in_word - 1))) != 0; | |
| else | |
| return false; | |
| } | |
| inline void | |
| scfx_rep::q_clear(const scfx_index &x) | |
| { | |
| int wi = x.wi(); | |
| int bi = x.bi(); | |
| SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range"); | |
| m_mant[wi] &= (((word)-1) << bi); | |
| for (int i = wi - 1; i >= 0; --i) | |
| m_mant[i] = 0; | |
| } | |
| inline void | |
| scfx_rep::q_incr(const scfx_index &x) | |
| { | |
| int wi = x.wi(); | |
| int bi = x.bi(); | |
| SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range"); | |
| word old_val = m_mant[wi]; | |
| m_mant[wi] += (((word)1) << bi); | |
| if (m_mant[wi] <= old_val) { | |
| if (wi + 1 == size()) | |
| resize_to(size() + 1, 1); | |
| for (int i = wi + 1; i < size(); ++i) { | |
| if (++m_mant[i] != 0) | |
| break; | |
| } | |
| } | |
| } | |
| inline bool | |
| scfx_rep::q_odd(const scfx_index &x) const | |
| { | |
| int wi = x.wi(); | |
| int bi = x.bi(); | |
| SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range"); | |
| return (m_mant[wi] & (((word)1) << bi)) != 0; | |
| } | |
| inline bool | |
| scfx_rep::q_zero(const scfx_index &x) const | |
| { | |
| int wi = x.wi(); | |
| int bi = x.bi(); | |
| SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range"); | |
| bool zero; | |
| if (bi != 0) { | |
| zero = (m_mant[wi] & ~(((word)-1) << (bi - 1))) == 0; | |
| for (int i = wi - 1; i >= 0; --i) | |
| zero = zero && m_mant[i] == 0; | |
| } else if (wi != 0) { | |
| zero = (m_mant[wi - 1] & ~( ((word)-1) << (bits_in_word - 1))) == 0; | |
| for (int i = wi - 2; i >= 0; --i) | |
| zero = zero && m_mant[i] == 0; | |
| } else { | |
| zero = true; | |
| } | |
| return zero; | |
| } | |
| inline int | |
| scfx_rep::find_lsw() const | |
| { | |
| for (int i = 0; i < size(); i++) { | |
| if (m_mant[i]) | |
| return i; | |
| } | |
| return 0; | |
| } | |
| inline int | |
| scfx_rep::find_msw() const | |
| { | |
| for (int i = size() - 1; i >= 0; i--) { | |
| if (m_mant[i]) | |
| return i; | |
| } | |
| return 0; | |
| } | |
| inline void | |
| scfx_rep::find_sw() | |
| { | |
| m_lsw = find_lsw(); | |
| m_msw = find_msw(); | |
| } | |
| inline void | |
| scfx_rep::toggle_tc() | |
| { | |
| if (is_neg()) { | |
| complement(m_mant, m_mant, m_mant.size()); | |
| inc(m_mant); | |
| } | |
| } | |
| } // namespace sc_dt | |
| #endif // __SYSTEMC_EXT_DT_FX_SCFX_REP_HH__ |