sc_signal.hh revision 13205
1/*
2 * Copyright 2018 Google, Inc.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met: redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer;
8 * redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution;
11 * neither the name of the copyright holders nor the names of its
12 * contributors may be used to endorse or promote products derived from
13 * this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 * Authors: Gabe Black
28 */
29
30#ifndef __SYSTEMC_EXT_CHANNEL_SC_SIGNAL_HH__
31#define __SYSTEMC_EXT_CHANNEL_SC_SIGNAL_HH__
32
33#include <iostream>
34#include <string>
35#include <vector>
36
37#include "../core/sc_event.hh"
38#include "../core/sc_module.hh" // for sc_gen_unique_name
39#include "../core/sc_prim.hh"
40#include "../dt/bit/sc_logic.hh"
41#include "sc_signal_inout_if.hh"
42#include "warn_unimpl.hh" // for warn_unimpl
43
44namespace sc_core
45{
46
47class sc_port_base;
48class sc_trace_file;
49
50// Nonstandard
51// Despite having a warning "FOR INTERNAL USE ONLY!" in all caps above this
52// class definition in the Accellera implementation, it appears in their
53// examples and test programs, and so we need to have it here as well.
54struct sc_trace_params
55{
56    sc_trace_file *tf;
57    std::string name;
58
59    sc_trace_params(sc_trace_file *tf, const std::string &name) :
60        tf(tf), name(name)
61    {}
62};
63typedef std::vector<sc_trace_params *> sc_trace_params_vec;
64
65template <class T, sc_writer_policy WRITER_POLICY=SC_ONE_WRITER>
66class sc_signal : public sc_signal_inout_if<T>,
67                  public sc_prim_channel
68{
69  public:
70    sc_signal() : sc_signal_inout_if<T>(),
71                  sc_prim_channel(sc_gen_unique_name("signal")),
72                  m_cur_val(T()), m_new_val(T()), _changeStamp(~0ULL)
73    {}
74    explicit sc_signal(const char *name) :
75        sc_signal_inout_if<T>(), sc_prim_channel(name),
76        m_cur_val(T()), m_new_val(T()), _changeStamp(~0ULL)
77    {}
78    explicit sc_signal(const char *name, const T &initial_value) :
79        sc_signal_inout_if<T>(), sc_prim_channel(name),
80        m_cur_val(initial_value), m_new_val(initial_value), _changeStamp(~0ULL)
81    {}
82    virtual ~sc_signal() {}
83
84    virtual void
85    register_port(sc_port_base &, const char *)
86    {
87        sc_channel_warn_unimpl(__PRETTY_FUNCTION__);
88    }
89
90    virtual const T &read() const { return m_cur_val; }
91    operator const T&() const { return read(); }
92
93    virtual sc_writer_policy
94    get_writer_policy() const
95    {
96        return WRITER_POLICY;
97    }
98    virtual void
99    write(const T &t)
100    {
101        m_new_val = t;
102        bool changed = !(m_cur_val == m_new_val);
103        //TODO check whether this write follows the write policy.
104        if (changed)
105            request_update();
106    }
107    sc_signal<T, WRITER_POLICY> &
108    operator = (const T &t)
109    {
110        write(t);
111        return *this;
112    }
113    sc_signal<T, WRITER_POLICY> &
114    operator = (const sc_signal<T, WRITER_POLICY> &s)
115    {
116        write(s.read());
117        return *this;
118    }
119
120    virtual const sc_event &
121    default_event() const
122    {
123        return value_changed_event();
124    }
125    virtual const sc_event &
126    value_changed_event() const
127    {
128        return _valueChangedEvent;
129    }
130    virtual bool
131    event() const
132    {
133        return _changeStamp == ::sc_gem5::getChangeStamp();
134    }
135
136    virtual void print(std::ostream &os=std::cout) const { os << m_cur_val; }
137    virtual void
138    dump(std::ostream &os=std::cout) const
139    {
140        os << "     name = " << name() << ::std::endl;
141        os << "    value = " << m_cur_val << ::std::endl;
142        os << "new value = " << m_new_val << ::std::endl;
143    }
144    virtual const char *kind() const { return "sc_signal"; }
145
146  protected:
147    virtual void
148    update()
149    {
150        if (m_new_val == m_cur_val)
151            return;
152
153        m_cur_val = m_new_val;
154        _signalChange();
155        _changeStamp = ::sc_gem5::getChangeStamp();
156        _valueChangedEvent.notify(SC_ZERO_TIME);
157    }
158
159    void
160    _signalChange()
161    {
162        _changeStamp = ::sc_gem5::getChangeStamp();
163        _valueChangedEvent.notify(SC_ZERO_TIME);
164    }
165
166    // These members which store the current and future value of the signal
167    // are not specified in the standard but are referred to directly by one
168    // of the tests.
169    T m_cur_val;
170    T m_new_val;
171
172  private:
173    sc_event _valueChangedEvent;
174    uint64_t _changeStamp;
175
176    // Disabled
177    sc_signal(const sc_signal<T, WRITER_POLICY> &) :
178            sc_signal_inout_if<T>(), sc_prim_channel("")
179    {}
180};
181
182template <class T, sc_writer_policy WRITER_POLICY>
183inline std::ostream &
184operator << (std::ostream &os, const sc_signal<T, WRITER_POLICY> &s)
185{
186    os << s.read();
187    return os;
188}
189
190template <sc_writer_policy WRITER_POLICY>
191class sc_signal<bool, WRITER_POLICY> :
192    public sc_signal_inout_if<bool>, public sc_prim_channel
193{
194  public:
195    sc_signal() : sc_signal_inout_if<bool>(),
196                  sc_prim_channel(sc_gen_unique_name("signal")),
197                  m_cur_val(bool()), m_new_val(bool()),
198                  _changeStamp(~0ULL), _posStamp(~0ULL), _negStamp(~0ULL)
199    {}
200    explicit sc_signal(const char *name) :
201        sc_signal_inout_if<bool>(), sc_prim_channel(name),
202        m_cur_val(bool()), m_new_val(bool()),
203        _changeStamp(~0ULL), _posStamp(~0ULL), _negStamp(~0ULL)
204    {}
205    explicit sc_signal(const char *name, const bool &initial_value) :
206        sc_signal_inout_if<bool>(), sc_prim_channel(name),
207        m_cur_val(initial_value), m_new_val(initial_value),
208        _changeStamp(~0ULL), _posStamp(~0ULL), _negStamp(~0ULL)
209    {}
210    virtual ~sc_signal() {}
211
212    virtual void
213    register_port(sc_port_base &, const char *)
214    {
215        sc_channel_warn_unimpl(__PRETTY_FUNCTION__);
216    }
217
218    virtual const bool &read() const { return m_cur_val; }
219    operator const bool &() const { return read(); }
220
221    virtual sc_writer_policy
222    get_writer_policy() const
223    {
224        return WRITER_POLICY;
225    }
226    virtual void
227    write(const bool &b)
228    {
229        m_new_val = b;
230        bool changed = !(m_cur_val == m_new_val);
231        //TODO check whether this write follows the write policy.
232        if (changed)
233            request_update();
234    }
235    sc_signal<bool, WRITER_POLICY> &
236    operator = (const bool &b)
237    {
238        write(b);
239        return *this;
240    }
241    sc_signal<bool, WRITER_POLICY> &
242    operator = (const sc_signal<bool, WRITER_POLICY> &s)
243    {
244        write(s.read());
245        return *this;
246    }
247
248    virtual const sc_event &
249    default_event() const
250    {
251        return value_changed_event();
252    }
253
254    virtual const sc_event &
255    value_changed_event() const
256    {
257        return _valueChangedEvent;
258    }
259    virtual const sc_event &
260    posedge_event() const
261    {
262        return _posedgeEvent;
263    }
264    virtual const sc_event &
265    negedge_event() const
266    {
267        return _negedgeEvent;
268    }
269
270    virtual bool
271    event() const
272    {
273        return _changeStamp == ::sc_gem5::getChangeStamp();
274    }
275    virtual bool
276    posedge() const
277    {
278        return _posStamp == ::sc_gem5::getChangeStamp();
279    }
280    virtual bool
281    negedge() const
282    {
283        return _negStamp == ::sc_gem5::getChangeStamp();
284    }
285
286    virtual void print(std::ostream &os=std::cout) const { os << m_cur_val; }
287    virtual void
288    dump(std::ostream &os=std::cout) const
289    {
290        os << "     name = " << name() << ::std::endl;
291        os << "    value = " << m_cur_val << ::std::endl;
292        os << "new value = " << m_new_val << ::std::endl;
293    }
294    virtual const char *kind() const { return "sc_signal"; }
295
296  protected:
297    virtual void
298    update()
299    {
300        if (m_new_val == m_cur_val)
301            return;
302
303        m_cur_val = m_new_val;
304        _signalChange();
305        if (m_cur_val) {
306            _posStamp = ::sc_gem5::getChangeStamp();
307            _posedgeEvent.notify(SC_ZERO_TIME);
308        } else {
309            _negStamp = ::sc_gem5::getChangeStamp();
310            _negedgeEvent.notify(SC_ZERO_TIME);
311        }
312    }
313
314    void
315    _signalChange()
316    {
317        _changeStamp = ::sc_gem5::getChangeStamp();
318        _valueChangedEvent.notify(SC_ZERO_TIME);
319    }
320
321    bool m_cur_val;
322    bool m_new_val;
323
324  private:
325    sc_event _valueChangedEvent;
326    sc_event _posedgeEvent;
327    sc_event _negedgeEvent;
328
329    uint64_t _changeStamp;
330    uint64_t _posStamp;
331    uint64_t _negStamp;
332
333    // Disabled
334    sc_signal(const sc_signal<bool, WRITER_POLICY> &) :
335            sc_signal_inout_if<bool>(), sc_prim_channel("")
336    {}
337};
338
339template <sc_writer_policy WRITER_POLICY>
340class sc_signal<sc_dt::sc_logic, WRITER_POLICY> :
341    public sc_signal_inout_if<sc_dt::sc_logic>, public sc_prim_channel
342{
343  public:
344    sc_signal() : sc_signal_inout_if<sc_dt::sc_logic>(),
345                  sc_prim_channel(sc_gen_unique_name("signal")),
346                  m_cur_val(sc_dt::sc_logic()), m_new_val(sc_dt::sc_logic()),
347                  _changeStamp(~0ULL), _posStamp(~0ULL), _negStamp(~0ULL)
348    {}
349    explicit sc_signal(const char *name) :
350        sc_signal_inout_if<sc_dt::sc_logic>(), sc_prim_channel(name),
351        m_cur_val(sc_dt::sc_logic()), m_new_val(sc_dt::sc_logic()),
352        _changeStamp(~0ULL), _posStamp(~0ULL), _negStamp(~0ULL)
353    {}
354    explicit sc_signal(const char *name,
355            const sc_dt::sc_logic &initial_value) :
356        sc_signal_inout_if<sc_dt::sc_logic>(), sc_prim_channel(name),
357        m_cur_val(initial_value), m_new_val(initial_value),
358        _changeStamp(~0ULL), _posStamp(~0ULL), _negStamp(~0ULL)
359    {}
360    virtual ~sc_signal() {}
361
362    virtual void
363    register_port(sc_port_base &, const char *)
364    {
365        sc_channel_warn_unimpl(__PRETTY_FUNCTION__);
366    }
367
368    virtual const sc_dt::sc_logic &read() const { return m_cur_val; }
369    operator const sc_dt::sc_logic &() const { return read(); }
370
371    virtual sc_writer_policy
372    get_writer_policy() const
373    {
374        return WRITER_POLICY;
375    }
376    virtual void
377    write(const sc_dt::sc_logic &l)
378    {
379        m_new_val = l;
380        bool changed = !(m_cur_val == m_new_val);
381        //TODO check whether this write follows the write policy.
382        if (changed)
383            request_update();
384    }
385    sc_signal<sc_dt::sc_logic, WRITER_POLICY> &
386    operator = (const sc_dt::sc_logic &l)
387    {
388        write(l);
389        return *this;
390    }
391    sc_signal<sc_dt::sc_logic, WRITER_POLICY> &
392    operator = (const sc_signal<sc_dt::sc_logic, WRITER_POLICY> &s)
393    {
394        write(s.read());
395        return *this;
396    }
397
398    virtual const sc_event &
399    default_event() const
400    {
401        return value_changed_event();
402    }
403
404    virtual const sc_event &
405    value_changed_event() const
406    {
407        return _valueChangedEvent;
408    }
409    virtual const sc_event &
410    posedge_event() const
411    {
412        return _posedgeEvent;
413    }
414    virtual const sc_event &
415    negedge_event() const
416    {
417        return _negedgeEvent;
418    }
419
420    virtual bool
421    event() const
422    {
423        return _changeStamp == ::sc_gem5::getChangeStamp();
424    }
425    virtual bool
426    posedge() const
427    {
428        return _posStamp == ::sc_gem5::getChangeStamp();
429    }
430    virtual bool
431    negedge() const
432    {
433        return _negStamp == ::sc_gem5::getChangeStamp();
434    }
435
436    virtual void print(std::ostream &os=std::cout) const { os << m_cur_val; }
437    virtual void
438    dump(std::ostream &os=std::cout) const
439    {
440        os << "     name = " << name() << ::std::endl;
441        os << "    value = " << m_cur_val << ::std::endl;
442        os << "new value = " << m_new_val << ::std::endl;
443    }
444    virtual const char *kind() const { return "sc_signal"; }
445
446  protected:
447    virtual void
448    update()
449    {
450        if (m_new_val == m_cur_val)
451            return;
452
453        m_cur_val = m_new_val;
454        _signalChange();
455        if (m_cur_val == sc_dt::SC_LOGIC_1) {
456            _posStamp = ::sc_gem5::getChangeStamp();
457            _posedgeEvent.notify(SC_ZERO_TIME);
458        } else if (m_cur_val == sc_dt::SC_LOGIC_0) {
459            _negStamp = ::sc_gem5::getChangeStamp();
460            _negedgeEvent.notify(SC_ZERO_TIME);
461        }
462    }
463
464    void
465    _signalChange()
466    {
467        _changeStamp = ::sc_gem5::getChangeStamp();
468        _valueChangedEvent.notify(SC_ZERO_TIME);
469    }
470
471    sc_dt::sc_logic m_cur_val;
472    sc_dt::sc_logic m_new_val;
473
474  private:
475    sc_event _valueChangedEvent;
476    sc_event _posedgeEvent;
477    sc_event _negedgeEvent;
478
479    uint64_t _changeStamp;
480    uint64_t _posStamp;
481    uint64_t _negStamp;
482
483    // Disabled
484    sc_signal(const sc_signal<sc_dt::sc_logic, WRITER_POLICY> &) :
485            sc_signal_inout_if<sc_dt::sc_logic>(), sc_prim_channel("")
486    {}
487};
488
489} // namespace sc_core
490
491#endif  //__SYSTEMC_EXT_CHANNEL_SC_SIGNAL_HH__
492