1/*****************************************************************************
2
3  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
4  more contributor license agreements.  See the NOTICE file distributed
5  with this work for additional information regarding copyright ownership.
6  Accellera licenses this file to you under the Apache License, Version 2.0
7  (the "License"); you may not use this file except in compliance with the
8  License.  You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15  implied.  See the License for the specific language governing
16  permissions and limitations under the License.
17
18 *****************************************************************************/
19
20/*****************************************************************************
21
22  scfx_rep.h -
23
24  Original Author: Robert Graulich, Synopsys, Inc.
25                   Martin Janssen,  Synopsys, Inc.
26
27 *****************************************************************************/
28
29/*****************************************************************************
30
31  MODIFICATION LOG - modifiers, enter your name, affiliation, date and
32  changes you are making here.
33
34      Name, Affiliation, Date:
35  Description of Modification:
36
37 *****************************************************************************/
38
39// $Log: scfx_rep.h,v $
40// Revision 1.6  2011/08/24 22:05:43  acg
41//  Torsten Maehne: initialization changes to remove warnings.
42//
43// Revision 1.5  2011/07/25 10:20:29  acg
44//  Andy Goodrich: check in aftermath of call to automake.
45//
46// Revision 1.4  2010/12/07 20:09:08  acg
47// Andy Goodrich: Philipp Hartmann's constructor disambiguation fix
48//
49// Revision 1.3  2010/08/03 15:54:52  acg
50//  Andy Goodrich: formatting.
51//
52// Revision 1.2  2010/03/15 18:29:01  acg
53//  Andy Goodrich: Moved default argument specifications from friend
54//  declarations to the actual function signatures.
55//
56// Revision 1.1.1.1  2006/12/15 20:20:04  acg
57// SystemC 2.3
58//
59// Revision 1.4  2006/03/13 20:24:27  acg
60//  Andy Goodrich: Addition of function declarations, e.g., neg_scfx_rep(),
61//  to keep gcc 4.x happy.
62//
63// Revision 1.3  2006/01/13 18:53:58  acg
64// Andy Goodrich: added $Log command so that CVS comments are reproduced in
65// the source.
66//
67
68#ifndef __SYSTEMC_EXT_DT_FX_SCFX_REP_HH__
69#define __SYSTEMC_EXT_DT_FX_SCFX_REP_HH__
70
71#include <climits>
72
73#include "scfx_mant.hh"
74#include "scfx_params.hh"
75#include "scfx_string.hh"
76
77namespace sc_dt
78{
79
80// classes defined in this module
81class scfx_index;
82class scfx_rep;
83
84// forward class declarations
85class sc_bv_base;
86class sc_signed;
87class sc_unsigned;
88
89// function declarations
90void multiply(scfx_rep &, const scfx_rep &, const scfx_rep &,
91              int max_wl=SC_DEFAULT_MAX_WL_);
92scfx_rep *neg_scfx_rep(const scfx_rep &);
93scfx_rep *mult_scfx_rep(const scfx_rep &, const scfx_rep &,
94                        int max_wl=SC_DEFAULT_MAX_WL_);
95scfx_rep *div_scfx_rep(const scfx_rep &, const scfx_rep &,
96                       int max_wl=SC_DEFAULT_DIV_WL_);
97scfx_rep *add_scfx_rep(const scfx_rep &, const scfx_rep &,
98                       int max_wl=SC_DEFAULT_MAX_WL_);
99scfx_rep *sub_scfx_rep(const scfx_rep &, const scfx_rep &,
100                       int max_wl=SC_DEFAULT_MAX_WL_);
101scfx_rep *lsh_scfx_rep(const scfx_rep &, int);
102scfx_rep *rsh_scfx_rep(const scfx_rep &, int);
103int cmp_scfx_rep(const scfx_rep &, const scfx_rep &);
104
105const int min_mant = 4;
106
107const int bits_in_int = sizeof(int) * CHAR_BIT;
108const int bits_in_word = sizeof(word) * CHAR_BIT;
109
110
111// ----------------------------------------------------------------------------
112//  CLASS : scfx_index
113// ----------------------------------------------------------------------------
114
115class scfx_index
116{
117  public:
118    scfx_index(int wi_, int bi_) : m_wi(wi_), m_bi(bi_) {}
119
120    int wi() const { return m_wi; }
121    int bi() const { return m_bi; }
122
123    void wi(int wi_) { m_wi = wi_; }
124
125  private:
126    int m_wi;
127    int m_bi;
128};
129
130
131// ----------------------------------------------------------------------------
132//  CLASS : scfx_rep
133//
134//  Arbitrary-precision fixed-point implementation class.
135// ----------------------------------------------------------------------------
136
137class scfx_rep
138{
139    enum state
140    {
141        normal,
142        infinity,
143        not_a_number
144    };
145
146  public:
147    // constructors
148    scfx_rep();
149    explicit scfx_rep(int);
150    explicit scfx_rep(unsigned int);
151    explicit scfx_rep(long);
152    explicit scfx_rep(unsigned long);
153    explicit scfx_rep(double);
154    explicit scfx_rep(const char *);
155    explicit scfx_rep(int64);
156    explicit scfx_rep(uint64);
157    explicit scfx_rep(const sc_signed &);
158    explicit scfx_rep(const sc_unsigned &);
159
160    // copy constructor
161    scfx_rep(const scfx_rep &);
162
163    // destructor
164    ~scfx_rep();
165
166    void *operator new (std::size_t);
167    void operator delete (void *, std::size_t);
168
169    void from_string(const char *, int);
170
171    double to_double() const;
172    uint64 to_uint64() const;
173
174    const char *to_string(sc_numrep, int, sc_fmt,
175                          const scfx_params * =0) const;
176
177    // assignment operator
178    void operator = (const scfx_rep &);
179
180    friend void multiply( scfx_rep&, const scfx_rep&, const scfx_rep&, int );
181
182    friend scfx_rep *neg_scfx_rep(const scfx_rep &);
183    friend scfx_rep *mult_scfx_rep(const scfx_rep &, const scfx_rep &, int);
184    friend scfx_rep *div_scfx_rep(const scfx_rep &, const scfx_rep &, int);
185    friend scfx_rep *add_scfx_rep(const scfx_rep &, const scfx_rep &, int);
186    friend scfx_rep *sub_scfx_rep(const scfx_rep &, const scfx_rep &, int);
187    friend scfx_rep *lsh_scfx_rep(const scfx_rep &, int);
188    friend scfx_rep *rsh_scfx_rep(const scfx_rep &, int);
189
190    void lshift(int);
191    void rshift(int);
192
193    friend int cmp_scfx_rep(const scfx_rep &, const scfx_rep &);
194
195    void cast(const scfx_params &, bool &, bool &);
196
197    bool is_neg() const;
198    bool is_zero() const;
199    bool is_nan() const;
200    bool is_inf() const;
201    bool is_normal() const;
202
203    void set_zero(int=1);
204    void set_nan();
205    void set_inf(int);
206
207    bool get_bit(int) const;
208    bool set(int, const scfx_params &);
209    bool clear(int, const scfx_params &);
210
211    bool get_slice(int, int, const scfx_params &, sc_bv_base &) const;
212    bool set_slice(int, int, const scfx_params &, const sc_bv_base &);
213
214    void print(::std::ostream &) const;
215    void dump(::std::ostream &) const;
216
217    void get_type(int &, int &, sc_enc &) const;
218
219    friend scfx_rep *quantization_scfx_rep(
220            const scfx_rep &, const scfx_params &, bool &);
221    friend scfx_rep *overflow_scfx_rep(
222            const scfx_rep &, const scfx_params &, bool &);
223
224    bool rounding_flag() const;
225
226  private:
227    friend void align(const scfx_rep &, const scfx_rep &, int &, int &,
228                      scfx_mant_ref &, scfx_mant_ref &);
229    friend int compare_msw(const scfx_rep &, const scfx_rep &);
230    friend int compare_msw_ff(const scfx_rep &lhs, const scfx_rep &rhs);
231    unsigned int divide_by_ten();
232    int find_lsw() const;
233    int find_msw() const;
234    void find_sw();
235    void multiply_by_ten();
236    void normalize(int);
237    scfx_mant *resize(int, int) const;
238    void set_bin(int);
239    void set_oct(int, int);
240    void set_hex(int, int);
241    void shift_left(int);
242    void shift_right(int);
243
244    const scfx_index calc_indices(int) const;
245
246    void o_extend(const scfx_index &, sc_enc);
247    bool o_bit_at(const scfx_index &) const;
248    bool o_zero_left(const scfx_index &) const;
249    bool o_zero_right(const scfx_index &) const;
250    void o_set_low(const scfx_index &, sc_enc);
251    void o_set_high(const scfx_index &, const scfx_index &, sc_enc, int=1);
252    void o_set(const scfx_index &, const scfx_index &, sc_enc, bool);
253    void o_invert(const scfx_index &);
254    bool q_bit(const scfx_index &) const;
255    void q_clear(const scfx_index &);
256    void q_incr(const scfx_index &);
257    bool q_odd(const scfx_index &) const;
258    bool q_zero(const scfx_index &) const;
259
260    void resize_to(int, int=0);
261    int  size() const;
262    void toggle_tc();
263
264    friend void print_dec(scfx_string &, const scfx_rep &, int, sc_fmt);
265    friend void print_other(scfx_string &, const scfx_rep &, sc_numrep, int,
266                            sc_fmt, const scfx_params *);
267
268    void quantization(const scfx_params &, bool &);
269    void overflow(const scfx_params &, bool &);
270
271    friend int compare_abs(const scfx_rep &, const scfx_rep &);
272
273    void round(int);
274
275  private:
276    scfx_mant m_mant; // mantissa (bits of the value).
277    int m_wp; // index of highest order word in value.
278    int m_sign; // sign of value.
279    state m_state; // value state, e.g., normal, inf, etc.
280    int m_msw; // index of most significant non-zero word.
281    int m_lsw; // index of least significant non-zero word.
282    bool m_r_flag; // true if rounding occurred.
283};
284
285
286// IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
287
288inline void
289scfx_rep::set_zero(int sign)
290{
291    m_mant.clear();
292    m_wp = m_msw = m_lsw = 0;
293    m_sign = sign;
294    m_state = normal;
295}
296
297inline void
298scfx_rep::set_nan()
299{
300    m_mant.resize_to(min_mant);
301    m_state = not_a_number;
302}
303
304inline void
305scfx_rep::set_inf(int sign)
306{
307    m_mant.resize_to(min_mant);
308    m_state = infinity;
309    m_sign = sign;
310}
311
312// constructors
313inline scfx_rep::scfx_rep(const char *s) :
314    m_mant(min_mant), m_wp(2), m_sign(1), m_state(normal),
315    m_msw(0), m_lsw(0), m_r_flag(false)
316{
317    from_string(s, SC_DEFAULT_CTE_WL_);
318}
319
320// destructor
321inline scfx_rep::~scfx_rep() {}
322
323// assignment operator
324inline void
325scfx_rep::operator = (const scfx_rep &f)
326{
327    if (&f != this) {
328        m_mant = f.m_mant;
329        m_wp = f.m_wp;
330        m_sign = f.m_sign;
331        m_state = f.m_state;
332        m_msw = f.m_msw;
333        m_lsw = f.m_lsw;
334        round(SC_DEFAULT_MAX_WL_);
335    }
336}
337
338inline scfx_rep *
339neg_scfx_rep(const scfx_rep &a)
340{
341    scfx_rep &c = *new scfx_rep(a);
342    c.m_sign = - c.m_sign;
343    return &c;
344}
345
346inline scfx_rep *
347mult_scfx_rep(const scfx_rep &a, const scfx_rep &b, int max_wl)
348{
349    scfx_rep &c = *new scfx_rep;
350    sc_dt::multiply(c, a, b, max_wl);
351    return &c;
352}
353
354inline scfx_rep *
355lsh_scfx_rep(const scfx_rep &a, int b)
356{
357    scfx_rep &c = *new scfx_rep(a);
358    c.lshift(b);
359    return &c;
360}
361
362inline scfx_rep *
363rsh_scfx_rep(const scfx_rep &a, int b)
364{
365    scfx_rep &c = *new scfx_rep(a);
366    c.rshift(b);
367    return &c;
368}
369
370inline int scfx_rep::size() const { return m_mant.size(); }
371
372inline bool scfx_rep::is_neg() const { return (m_sign == -1); }
373
374inline bool
375scfx_rep::is_zero() const
376{
377    if (m_state != normal)
378        return false;
379
380    for (int i = 0; i < size(); i++) {
381        if (m_mant[i])
382            return false;
383    }
384
385    return true;
386}
387
388inline bool scfx_rep::is_nan() const { return (m_state == not_a_number); }
389
390inline bool scfx_rep::is_inf() const { return (m_state == infinity); }
391
392inline bool scfx_rep::is_normal() const { return (m_state == normal); }
393
394inline scfx_rep *
395quantization_scfx_rep(const scfx_rep &a, const scfx_params &params,
396                      bool &q_flag)
397{
398    scfx_rep &c = *new scfx_rep(a);
399    c.quantization(params, q_flag);
400    return &c;
401}
402
403inline scfx_rep *
404overflow_scfx_rep(const scfx_rep &a, const scfx_params &params, bool &o_flag)
405{
406    scfx_rep& c = *new scfx_rep(a);
407    c.overflow(params, o_flag);
408    return &c;
409}
410
411inline bool scfx_rep::rounding_flag() const { return m_r_flag; }
412
413inline void
414scfx_rep::resize_to(int new_size, int restore)
415{
416    if (restore == -1) {
417        int size_incr = new_size - size();
418        m_wp += size_incr;
419        m_msw += size_incr;
420        m_lsw += size_incr;
421    }
422    m_mant.resize_to(new_size, restore);
423}
424
425inline const scfx_index
426scfx_rep::calc_indices(int n) const
427{
428    int wi = n / bits_in_word + m_wp;
429    int bi = n % bits_in_word;
430
431    if (bi < 0) {
432        bi += bits_in_word;
433        -- wi;
434    }
435
436    return scfx_index(wi, bi);
437}
438
439inline void
440scfx_rep::o_extend(const scfx_index &x, sc_enc enc)
441{
442    int wi = x.wi();
443    int bi = x.bi();
444
445    SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range");
446
447    if (enc == SC_US_ || (m_mant[wi] & (((word)1) << bi)) == 0) {
448        if (bi != bits_in_word - 1)
449            m_mant[wi] &= ~(((word)-1) << (bi + 1));
450        for (int i = wi + 1; i < size(); ++i)
451            m_mant[i] = 0;
452        m_sign = 1;
453    } else {
454        if (bi != bits_in_word - 1)
455            m_mant[wi] |= (((word)-1) << (bi + 1));
456        for (int i = wi + 1; i < size(); ++i)
457            m_mant[i] = static_cast<word>(-1);
458        m_sign = -1;
459    }
460}
461
462inline bool
463scfx_rep::o_bit_at(const scfx_index &x) const
464{
465    int wi = x.wi();
466    int bi = x.bi();
467
468    SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range");
469
470    return (m_mant[wi] & (((word)1) << bi)) != 0;
471}
472
473inline bool
474scfx_rep::o_zero_left(const scfx_index &x) const
475{
476    int wi = x.wi();
477    int bi = x.bi();
478
479    SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range");
480
481    bool zero = true;
482    if (bi != bits_in_word - 1)
483        zero = (m_mant[wi] & (((word)-1) << (bi + 1))) == 0;
484    for (int i = wi + 1; i < size(); ++i)
485        zero = zero && m_mant[i] == 0;
486
487    return zero;
488}
489
490inline bool
491scfx_rep::o_zero_right(const scfx_index &x) const
492{
493    int wi = x.wi();
494    int bi = x.bi();
495
496    SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range");
497
498    bool zero = (m_mant[wi] & ~(((word)-1) << bi)) == 0;
499    for (int i = wi - 1; i >= 0; --i)
500        zero = zero && m_mant[i] == 0;
501
502    return zero;
503}
504
505inline void
506scfx_rep::o_set_low(const scfx_index &x, sc_enc enc)
507{
508    int wi = x.wi();
509    int bi = x.bi();
510
511    SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range");
512
513    m_mant.clear();
514
515    if (enc == SC_TC_) {
516        m_mant[wi] |= (((word)1) << bi);
517        m_sign = -1;
518    } else {
519        m_sign = 1;
520    }
521}
522
523inline void
524scfx_rep::o_set_high(const scfx_index &x, const scfx_index &x2,
525                     sc_enc enc, int sign)
526{
527    int wi = x.wi();
528    int bi = x.bi();
529    int wi2 = x2.wi();
530    int bi2 = x2.bi();
531
532    SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range");
533    SC_ASSERT_(wi2 >= 0 && wi2 < size(), "word index out of range");
534
535    int i;
536
537    for (i = 0; i < size(); ++i)
538        m_mant[i] = static_cast<word>(-1);
539
540    m_mant[wi] &= ~(((word)-1) << bi);
541    for (i = wi + 1; i < size(); ++i)
542        m_mant[i] = 0;
543
544    m_mant[wi2] &= (((word)-1) << bi2);
545    for (i = wi2 - 1; i >= 0; --i)
546        m_mant[i] = 0;
547
548    if (enc == SC_TC_) {
549        m_sign = sign;
550    } else {
551        m_mant[wi] |= (((word)1) << bi);
552        m_sign = 1;
553    }
554}
555
556inline void
557scfx_rep::o_set(const scfx_index &x, const scfx_index &x3, sc_enc enc,
558                bool under)
559{
560    int wi = x.wi();
561    int bi = x.bi();
562    int wi3 = x3.wi();
563    int bi3 = x3.bi();
564
565    SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range");
566    SC_ASSERT_(wi3 >= 0 && wi3 < size(), "word index out of range");
567
568    if (bi3 != bits_in_word - 1) {
569        if (under)
570            m_mant[wi3] &= ~(((word)-1) << (bi3 + 1));
571        else
572            m_mant[wi3] |= (((word)-1) << (bi3 + 1));
573    }
574    for (int i = wi3 + 1; i < size(); ++i) {
575        if (under)
576            m_mant[i] = 0;
577        else
578            m_mant[i] = static_cast<word>(-1);
579    }
580
581    if (enc == SC_TC_) {
582        if (under)
583            m_mant[wi] |= (((word)1) << bi);
584        else
585            m_mant[wi] &= ~(((word)1) << bi);
586    }
587}
588
589inline void
590scfx_rep::o_invert(const scfx_index &x2)
591{
592    int wi2 = x2.wi();
593    int bi2 = x2.bi();
594
595    m_mant[wi2] ^= (((word)-1) << bi2);
596    for (int i = wi2 + 1; i < size(); ++i)
597        m_mant[i] = ~ m_mant[i];
598}
599
600inline bool
601scfx_rep::q_bit(const scfx_index &x) const
602{
603    int wi = x.wi();
604    int bi = x.bi();
605
606    SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range");
607
608    if (bi != 0)
609        return (m_mant[wi] & (((word)1) << (bi - 1))) != 0;
610    else if (wi != 0)
611        return (m_mant[wi - 1] & (((word)1) << (bits_in_word - 1))) != 0;
612    else
613        return false;
614}
615
616inline void
617scfx_rep::q_clear(const scfx_index &x)
618{
619    int wi = x.wi();
620    int bi = x.bi();
621
622    SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range");
623
624    m_mant[wi] &= (((word)-1) << bi);
625    for (int i = wi - 1; i >= 0; --i)
626        m_mant[i] = 0;
627}
628
629inline void
630scfx_rep::q_incr(const scfx_index &x)
631{
632    int wi = x.wi();
633    int bi = x.bi();
634
635    SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range");
636
637    word old_val = m_mant[wi];
638    m_mant[wi] += (((word)1) << bi);
639    if (m_mant[wi] <= old_val) {
640        if (wi + 1 == size())
641            resize_to(size() + 1, 1);
642
643        for (int i = wi + 1; i < size(); ++i) {
644            if (++m_mant[i] != 0)
645                break;
646        }
647    }
648}
649
650inline bool
651scfx_rep::q_odd(const scfx_index &x) const
652{
653    int wi = x.wi();
654    int bi = x.bi();
655
656    SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range");
657
658    return (m_mant[wi] & (((word)1) << bi)) != 0;
659}
660
661inline bool
662scfx_rep::q_zero(const scfx_index &x) const
663{
664    int wi = x.wi();
665    int bi = x.bi();
666
667    SC_ASSERT_(wi >= 0 && wi < size(), "word index out of range");
668
669    bool zero;
670
671    if (bi != 0) {
672        zero = (m_mant[wi] & ~(((word)-1) << (bi - 1))) == 0;
673        for (int i = wi - 1; i >= 0; --i)
674            zero = zero && m_mant[i] == 0;
675    } else if (wi != 0) {
676        zero = (m_mant[wi - 1] & ~( ((word)-1) << (bits_in_word - 1))) == 0;
677        for (int i = wi - 2; i >= 0; --i)
678            zero = zero && m_mant[i] == 0;
679    } else {
680        zero = true;
681    }
682
683    return zero;
684}
685
686inline int
687scfx_rep::find_lsw() const
688{
689    for (int i = 0; i < size(); i++) {
690        if (m_mant[i])
691            return i;
692    }
693    return 0;
694}
695
696inline int
697scfx_rep::find_msw() const
698{
699    for (int i = size() - 1; i >= 0; i--) {
700        if (m_mant[i])
701            return i;
702    }
703    return 0;
704}
705
706inline void
707scfx_rep::find_sw()
708{
709    m_lsw = find_lsw();
710    m_msw = find_msw();
711}
712
713inline void
714scfx_rep::toggle_tc()
715{
716    if (is_neg()) {
717        complement(m_mant, m_mant, m_mant.size());
718        inc(m_mant);
719    }
720}
721
722} // namespace sc_dt
723
724#endif // __SYSTEMC_EXT_DT_FX_SCFX_REP_HH__
725