sc_signal.hh revision 13274
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 <sstream>
35#include <string>
36#include <vector>
37
38#include "../core/sc_event.hh"
39#include "../core/sc_module.hh" // for sc_gen_unique_name
40#include "../core/sc_prim.hh"
41#include "../dt/bit/sc_logic.hh"
42#include "sc_signal_inout_if.hh"
43
44namespace sc_core
45{
46
47class sc_port_base;
48
49template <class T, sc_writer_policy WRITER_POLICY=SC_ONE_WRITER>
50class sc_signal : public sc_signal_inout_if<T>,
51                  public sc_prim_channel
52{
53  public:
54    sc_signal() : sc_signal_inout_if<T>(),
55                  sc_prim_channel(sc_gen_unique_name("signal")),
56                  m_cur_val(T()), m_new_val(T()), _changeStamp(~0ULL),
57                  _gem5Writer(NULL)
58    {}
59    explicit sc_signal(const char *name) :
60        sc_signal_inout_if<T>(), sc_prim_channel(name),
61        m_cur_val(T()), m_new_val(T()), _changeStamp(~0ULL),
62        _gem5Writer(NULL)
63    {}
64    explicit sc_signal(const char *name, const T &initial_value) :
65        sc_signal_inout_if<T>(), sc_prim_channel(name),
66        m_cur_val(initial_value), m_new_val(initial_value),
67        _changeStamp(~0ULL), _gem5Writer(NULL)
68    {}
69    virtual ~sc_signal() {}
70
71    virtual void
72    register_port(sc_port_base &port, const char *iface_type_name)
73    {
74        if (WRITER_POLICY == SC_ONE_WRITER &&
75                std::string(iface_type_name) ==
76                typeid(sc_signal_inout_if<T>).name()) {
77            if (_gem5Writer) {
78                std::ostringstream ss;
79                ss << "\n signal " << "`" << name() << "' (" <<
80                    kind() << ")";
81                ss << "\n first driver `" << _gem5Writer->name() << "'  (" <<
82                    _gem5Writer->kind() << ")";
83                ss << "\n second driver `" << port.name() << "' (" <<
84                    port.kind() << ")";
85                SC_REPORT_ERROR(
86                        "(E115) sc_signal<T> cannot have more than one driver",
87                        ss.str().c_str());
88            }
89            _gem5Writer = &port;
90        }
91    }
92
93    virtual const T &read() const { return m_cur_val; }
94    operator const T&() const { return read(); }
95
96    virtual sc_writer_policy
97    get_writer_policy() const
98    {
99        return WRITER_POLICY;
100    }
101    virtual void
102    write(const T &t)
103    {
104        m_new_val = t;
105        bool changed = !(m_cur_val == m_new_val);
106        //TODO check whether this write follows the write policy.
107        if (changed)
108            request_update();
109    }
110    sc_signal<T, WRITER_POLICY> &
111    operator = (const T &t)
112    {
113        write(t);
114        return *this;
115    }
116    sc_signal<T, WRITER_POLICY> &
117    operator = (const sc_signal<T, WRITER_POLICY> &s)
118    {
119        write(s.read());
120        return *this;
121    }
122
123    virtual const sc_event &
124    default_event() const
125    {
126        return value_changed_event();
127    }
128    virtual const sc_event &
129    value_changed_event() const
130    {
131        return _valueChangedEvent;
132    }
133    virtual bool
134    event() const
135    {
136        return _changeStamp == ::sc_gem5::getChangeStamp();
137    }
138
139    virtual void print(std::ostream &os=std::cout) const { os << m_cur_val; }
140    virtual void
141    dump(std::ostream &os=std::cout) const
142    {
143        os << "     name = " << name() << ::std::endl;
144        os << "    value = " << m_cur_val << ::std::endl;
145        os << "new value = " << m_new_val << ::std::endl;
146    }
147    virtual const char *kind() const { return "sc_signal"; }
148
149  protected:
150    virtual void
151    update()
152    {
153        if (m_new_val == m_cur_val)
154            return;
155
156        m_cur_val = m_new_val;
157        _signalChange();
158        _changeStamp = ::sc_gem5::getChangeStamp();
159        _valueChangedEvent.notify(SC_ZERO_TIME);
160    }
161
162    void
163    _signalChange()
164    {
165        _changeStamp = ::sc_gem5::getChangeStamp();
166        _valueChangedEvent.notify(SC_ZERO_TIME);
167    }
168
169    // These members which store the current and future value of the signal
170    // are not specified in the standard but are referred to directly by one
171    // of the tests.
172    T m_cur_val;
173    T m_new_val;
174
175  private:
176    sc_event _valueChangedEvent;
177    uint64_t _changeStamp;
178    sc_port_base *_gem5Writer;
179
180    // Disabled
181    sc_signal(const sc_signal<T, WRITER_POLICY> &) :
182            sc_signal_inout_if<T>(), sc_prim_channel("")
183    {}
184};
185
186template <class T, sc_writer_policy WRITER_POLICY>
187inline std::ostream &
188operator << (std::ostream &os, const sc_signal<T, WRITER_POLICY> &s)
189{
190    os << s.read();
191    return os;
192}
193
194template <sc_writer_policy WRITER_POLICY>
195class sc_signal<bool, WRITER_POLICY> :
196    public sc_signal_inout_if<bool>, public sc_prim_channel
197{
198  public:
199    sc_signal() : sc_signal_inout_if<bool>(),
200                  sc_prim_channel(sc_gen_unique_name("signal")),
201                  m_cur_val(bool()), m_new_val(bool()),
202                  _changeStamp(~0ULL), _posStamp(~0ULL), _negStamp(~0ULL),
203                  _gem5Writer(NULL)
204    {}
205    explicit sc_signal(const char *name) :
206        sc_signal_inout_if<bool>(), sc_prim_channel(name),
207        m_cur_val(bool()), m_new_val(bool()),
208        _changeStamp(~0ULL), _posStamp(~0ULL), _negStamp(~0ULL),
209        _gem5Writer(NULL)
210    {}
211    explicit sc_signal(const char *name, const bool &initial_value) :
212        sc_signal_inout_if<bool>(), sc_prim_channel(name),
213        m_cur_val(initial_value), m_new_val(initial_value),
214        _changeStamp(~0ULL), _posStamp(~0ULL), _negStamp(~0ULL),
215        _gem5Writer(NULL)
216    {}
217    virtual ~sc_signal() {}
218
219    virtual void
220    register_port(sc_port_base &port, const char *iface_type_name)
221    {
222        if (WRITER_POLICY == SC_ONE_WRITER &&
223                std::string(iface_type_name) ==
224                typeid(sc_signal_inout_if<bool>).name()) {
225            if (_gem5Writer) {
226                std::ostringstream ss;
227                ss << "\n signal " << "`" << name() << "' (" <<
228                    kind() << ")";
229                ss << "\n first driver `" << _gem5Writer->name() << "'  (" <<
230                    _gem5Writer->kind() << ")";
231                ss << "\n second driver `" << port.name() << "' (" <<
232                    port.kind() << ")";
233                SC_REPORT_ERROR(
234                        "(E115) sc_signal<T> cannot have more than one driver",
235                        ss.str().c_str());
236            }
237            _gem5Writer = &port;
238        }
239    }
240
241    virtual const bool &read() const { return m_cur_val; }
242    operator const bool &() const { return read(); }
243
244    virtual sc_writer_policy
245    get_writer_policy() const
246    {
247        return WRITER_POLICY;
248    }
249    virtual void
250    write(const bool &b)
251    {
252        m_new_val = b;
253        bool changed = !(m_cur_val == m_new_val);
254        //TODO check whether this write follows the write policy.
255        if (changed)
256            request_update();
257    }
258    sc_signal<bool, WRITER_POLICY> &
259    operator = (const bool &b)
260    {
261        write(b);
262        return *this;
263    }
264    sc_signal<bool, WRITER_POLICY> &
265    operator = (const sc_signal<bool, WRITER_POLICY> &s)
266    {
267        write(s.read());
268        return *this;
269    }
270
271    virtual const sc_event &
272    default_event() const
273    {
274        return value_changed_event();
275    }
276
277    virtual const sc_event &
278    value_changed_event() const
279    {
280        return _valueChangedEvent;
281    }
282    virtual const sc_event &
283    posedge_event() const
284    {
285        return _posedgeEvent;
286    }
287    virtual const sc_event &
288    negedge_event() const
289    {
290        return _negedgeEvent;
291    }
292
293    virtual bool
294    event() const
295    {
296        return _changeStamp == ::sc_gem5::getChangeStamp();
297    }
298    virtual bool
299    posedge() const
300    {
301        return _posStamp == ::sc_gem5::getChangeStamp();
302    }
303    virtual bool
304    negedge() const
305    {
306        return _negStamp == ::sc_gem5::getChangeStamp();
307    }
308
309    virtual void print(std::ostream &os=std::cout) const { os << m_cur_val; }
310    virtual void
311    dump(std::ostream &os=std::cout) const
312    {
313        os << "     name = " << name() << ::std::endl;
314        os << "    value = " << m_cur_val << ::std::endl;
315        os << "new value = " << m_new_val << ::std::endl;
316    }
317    virtual const char *kind() const { return "sc_signal"; }
318
319  protected:
320    virtual void
321    update()
322    {
323        if (m_new_val == m_cur_val)
324            return;
325
326        m_cur_val = m_new_val;
327        _signalChange();
328        if (m_cur_val) {
329            _posStamp = ::sc_gem5::getChangeStamp();
330            _posedgeEvent.notify(SC_ZERO_TIME);
331        } else {
332            _negStamp = ::sc_gem5::getChangeStamp();
333            _negedgeEvent.notify(SC_ZERO_TIME);
334        }
335    }
336
337    void
338    _signalChange()
339    {
340        _changeStamp = ::sc_gem5::getChangeStamp();
341        _valueChangedEvent.notify(SC_ZERO_TIME);
342    }
343
344    bool m_cur_val;
345    bool m_new_val;
346
347  private:
348    sc_event _valueChangedEvent;
349    sc_event _posedgeEvent;
350    sc_event _negedgeEvent;
351
352    uint64_t _changeStamp;
353    uint64_t _posStamp;
354    uint64_t _negStamp;
355
356    sc_port_base *_gem5Writer;
357
358    // Disabled
359    sc_signal(const sc_signal<bool, WRITER_POLICY> &) :
360            sc_signal_inout_if<bool>(), sc_prim_channel("")
361    {}
362};
363
364template <sc_writer_policy WRITER_POLICY>
365class sc_signal<sc_dt::sc_logic, WRITER_POLICY> :
366    public sc_signal_inout_if<sc_dt::sc_logic>, public sc_prim_channel
367{
368  public:
369    sc_signal() : sc_signal_inout_if<sc_dt::sc_logic>(),
370                  sc_prim_channel(sc_gen_unique_name("signal")),
371                  m_cur_val(sc_dt::sc_logic()), m_new_val(sc_dt::sc_logic()),
372                  _changeStamp(~0ULL), _posStamp(~0ULL), _negStamp(~0ULL),
373                  _gem5Writer(NULL)
374    {}
375    explicit sc_signal(const char *name) :
376        sc_signal_inout_if<sc_dt::sc_logic>(), sc_prim_channel(name),
377        m_cur_val(sc_dt::sc_logic()), m_new_val(sc_dt::sc_logic()),
378        _changeStamp(~0ULL), _posStamp(~0ULL), _negStamp(~0ULL),
379        _gem5Writer(NULL)
380    {}
381    explicit sc_signal(const char *name,
382            const sc_dt::sc_logic &initial_value) :
383        sc_signal_inout_if<sc_dt::sc_logic>(), sc_prim_channel(name),
384        m_cur_val(initial_value), m_new_val(initial_value),
385        _changeStamp(~0ULL), _posStamp(~0ULL), _negStamp(~0ULL),
386        _gem5Writer(NULL)
387    {}
388    virtual ~sc_signal() {}
389
390    virtual void
391    register_port(sc_port_base &port, const char *iface_type_name)
392    {
393        if (WRITER_POLICY == SC_ONE_WRITER &&
394                std::string(iface_type_name) ==
395                typeid(sc_signal_inout_if<sc_dt::sc_logic>).name()) {
396            if (_gem5Writer) {
397                std::ostringstream ss;
398                ss << "\n signal " << "`" << name() << "' (" <<
399                    kind() << ")";
400                ss << "\n first driver `" << _gem5Writer->name() << "'  (" <<
401                    _gem5Writer->kind() << ")";
402                ss << "\n second driver `" << port.name() << "' (" <<
403                    port.kind() << ")";
404                SC_REPORT_ERROR(
405                        "(E115) sc_signal<T> cannot have more than one driver",
406                        ss.str().c_str());
407            }
408            _gem5Writer = &port;
409        }
410    }
411
412    virtual const sc_dt::sc_logic &read() const { return m_cur_val; }
413    operator const sc_dt::sc_logic &() const { return read(); }
414
415    virtual sc_writer_policy
416    get_writer_policy() const
417    {
418        return WRITER_POLICY;
419    }
420    virtual void
421    write(const sc_dt::sc_logic &l)
422    {
423        m_new_val = l;
424        bool changed = !(m_cur_val == m_new_val);
425        //TODO check whether this write follows the write policy.
426        if (changed)
427            request_update();
428    }
429    sc_signal<sc_dt::sc_logic, WRITER_POLICY> &
430    operator = (const sc_dt::sc_logic &l)
431    {
432        write(l);
433        return *this;
434    }
435    sc_signal<sc_dt::sc_logic, WRITER_POLICY> &
436    operator = (const sc_signal<sc_dt::sc_logic, WRITER_POLICY> &s)
437    {
438        write(s.read());
439        return *this;
440    }
441
442    virtual const sc_event &
443    default_event() const
444    {
445        return value_changed_event();
446    }
447
448    virtual const sc_event &
449    value_changed_event() const
450    {
451        return _valueChangedEvent;
452    }
453    virtual const sc_event &
454    posedge_event() const
455    {
456        return _posedgeEvent;
457    }
458    virtual const sc_event &
459    negedge_event() const
460    {
461        return _negedgeEvent;
462    }
463
464    virtual bool
465    event() const
466    {
467        return _changeStamp == ::sc_gem5::getChangeStamp();
468    }
469    virtual bool
470    posedge() const
471    {
472        return _posStamp == ::sc_gem5::getChangeStamp();
473    }
474    virtual bool
475    negedge() const
476    {
477        return _negStamp == ::sc_gem5::getChangeStamp();
478    }
479
480    virtual void print(std::ostream &os=std::cout) const { os << m_cur_val; }
481    virtual void
482    dump(std::ostream &os=std::cout) const
483    {
484        os << "     name = " << name() << ::std::endl;
485        os << "    value = " << m_cur_val << ::std::endl;
486        os << "new value = " << m_new_val << ::std::endl;
487    }
488    virtual const char *kind() const { return "sc_signal"; }
489
490  protected:
491    virtual void
492    update()
493    {
494        if (m_new_val == m_cur_val)
495            return;
496
497        m_cur_val = m_new_val;
498        _signalChange();
499        if (m_cur_val == sc_dt::SC_LOGIC_1) {
500            _posStamp = ::sc_gem5::getChangeStamp();
501            _posedgeEvent.notify(SC_ZERO_TIME);
502        } else if (m_cur_val == sc_dt::SC_LOGIC_0) {
503            _negStamp = ::sc_gem5::getChangeStamp();
504            _negedgeEvent.notify(SC_ZERO_TIME);
505        }
506    }
507
508    void
509    _signalChange()
510    {
511        _changeStamp = ::sc_gem5::getChangeStamp();
512        _valueChangedEvent.notify(SC_ZERO_TIME);
513    }
514
515    sc_dt::sc_logic m_cur_val;
516    sc_dt::sc_logic m_new_val;
517
518  private:
519    sc_event _valueChangedEvent;
520    sc_event _posedgeEvent;
521    sc_event _negedgeEvent;
522
523    uint64_t _changeStamp;
524    uint64_t _posStamp;
525    uint64_t _negStamp;
526
527    sc_port_base *_gem5Writer;
528
529    // Disabled
530    sc_signal(const sc_signal<sc_dt::sc_logic, WRITER_POLICY> &) :
531            sc_signal_inout_if<sc_dt::sc_logic>(), sc_prim_channel("")
532    {}
533};
534
535} // namespace sc_core
536
537#endif  //__SYSTEMC_EXT_CHANNEL_SC_SIGNAL_HH__
538