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
43namespace sc_core
44{
45
46class sc_port_base;
47
48} // namespace sc_core
49
50namespace sc_gem5
51{
52
53class Process;
54class Reset;
55
56class ScSignalBase : public sc_core::sc_prim_channel
57{
58  public:
59    virtual const char *kind() const { return "sc_signal"; }
60
61  protected:
62    ScSignalBase(const char *_name);
63    virtual ~ScSignalBase();
64
65    const sc_core::sc_event &defaultEvent() const;
66    const sc_core::sc_event &valueChangedEvent() const;
67
68    bool event() const;
69
70    void _signalChange();
71
72    virtual sc_core::sc_writer_policy get_writer_policy() const = 0;
73
74    InternalScEvent _valueChangedEvent;
75    uint64_t _changeStamp;
76    sc_core::sc_port_base *_gem5WriterPort;
77};
78
79class ScSignalBaseBinary : public ScSignalBase
80{
81  protected:
82    ScSignalBaseBinary(const char *_name);
83
84    mutable std::vector<sc_gem5::Reset *> _resets;
85    void _signalReset(sc_gem5::Reset *reset);
86    void _signalReset();
87
88    const sc_core::sc_event &posedgeEvent() const;
89    const sc_core::sc_event &negedgeEvent() const;
90
91    bool posedge() const;
92    bool negedge() const;
93
94    InternalScEvent _posedgeEvent;
95    InternalScEvent _negedgeEvent;
96
97    uint64_t _posStamp;
98    uint64_t _negStamp;
99
100    void _signalPosedge();
101    void _signalNegedge();
102};
103
104template <class T>
105class ScSignalBasePicker : public ScSignalBase
106{
107  protected:
108    ScSignalBasePicker(const char *_name) : ScSignalBase(_name) {}
109};
110
111template <>
112class ScSignalBasePicker<bool> : public ScSignalBaseBinary
113{
114  protected:
115    ScSignalBasePicker(const char *_name) : ScSignalBaseBinary(_name) {}
116};
117
118template <>
119class ScSignalBasePicker<sc_dt::sc_logic> : public ScSignalBaseBinary
120{
121  protected:
122    ScSignalBasePicker(const char *_name) : ScSignalBaseBinary(_name) {}
123};
124
125template <sc_core::sc_writer_policy WRITER_POLICY>
126class WriteChecker;
127
128template <>
129class WriteChecker<sc_core::SC_ONE_WRITER>
130{
131  public:
132    WriteChecker(ScSignalBase *_sig);
133
134    void checkPort(sc_core::sc_port_base &port,
135            std::string iface_type_name, std::string out_name);
136    void checkWriter();
137
138  private:
139    ScSignalBase *sig;
140    sc_core::sc_port_base *firstPort;
141    Process *proc;
142    uint64_t writeStamp;
143};
144
145template <>
146class WriteChecker<sc_core::SC_MANY_WRITERS>
147{
148  public:
149    WriteChecker(ScSignalBase *_sig);
150
151    void checkPort(sc_core::sc_port_base &port,
152            std::string iface_type_name, std::string out_name);
153    void checkWriter();
154
155  private:
156    ScSignalBase *sig;
157    Process *proc;
158    uint64_t writeStamp;
159};
160
161template <class T, sc_core::sc_writer_policy WRITER_POLICY>
162class ScSignalBaseT :
163    public ScSignalBasePicker<T>, public sc_core::sc_signal_inout_if<T>
164{
165  public:
166    ScSignalBaseT(const char *_name) :
167        ScSignalBasePicker<T>(_name), m_cur_val(T()), m_new_val(T()),
168        _checker(this)
169    {}
170    ScSignalBaseT(const char *_name, const T &initial_value) :
171        ScSignalBasePicker<T>(_name), m_cur_val(initial_value),
172        m_new_val(initial_value), _checker(this)
173    {}
174    virtual ~ScSignalBaseT() {}
175
176    virtual void
177    register_port(sc_core::sc_port_base &port, const char *iface_type_name)
178    {
179#       if !defined(SC_NO_WRITE_CHECK)
180        {
181            _checker.checkPort(port, iface_type_name,
182                typeid(sc_core::sc_signal_inout_if<T>).name());
183        }
184#       endif
185    }
186
187    virtual const T &read() const { return m_cur_val; }
188    operator const T&() const { return read(); }
189
190    virtual void
191    write(const T &t)
192    {
193#       if !defined(SC_NO_WRITE_CHECK)
194        {
195            _checker.checkWriter();
196        }
197#       endif
198        m_new_val = t;
199        bool changed = !(m_cur_val == m_new_val);
200        if (changed)
201            this->request_update();
202    }
203
204    virtual const sc_core::sc_event &
205    default_event() const
206    {
207        return ScSignalBase::defaultEvent();
208    }
209
210    virtual const sc_core::sc_event &
211    value_changed_event() const
212    {
213        return ScSignalBase::valueChangedEvent();
214    }
215
216    virtual void print(std::ostream &os=std::cout) const { os << m_cur_val; }
217    virtual void
218    dump(std::ostream &os=std::cout) const
219    {
220        os << "     name = " << this->name() << ::std::endl;
221        os << "    value = " << m_cur_val << ::std::endl;
222        os << "new value = " << m_new_val << ::std::endl;
223    }
224
225    virtual bool event() const { return ScSignalBase::event(); }
226
227    virtual sc_core::sc_writer_policy
228    get_writer_policy() const
229    {
230        return WRITER_POLICY;
231    }
232
233  protected:
234    // These members which store the current and future value of the signal
235    // are not specified in the standard but are referred to directly by one
236    // of the tests.
237    T m_cur_val;
238    T m_new_val;
239
240    WriteChecker<WRITER_POLICY> _checker;
241};
242
243template <typename T, sc_core::sc_writer_policy WRITER_POLICY>
244class ScSignalBinary : public ScSignalBaseT<T, WRITER_POLICY>
245{
246  public:
247    ScSignalBinary(const char *_name) : ScSignalBaseT<T, WRITER_POLICY>(_name)
248    {}
249    ScSignalBinary(const char *_name, const T& initial_value) :
250        ScSignalBaseT<T, WRITER_POLICY>(_name, initial_value)
251    {}
252
253    const sc_core::sc_event &
254    posedge_event() const
255    {
256        return ScSignalBaseBinary::posedgeEvent();
257    }
258    const sc_core::sc_event &
259    negedge_event() const
260    {
261        return ScSignalBaseBinary::negedgeEvent();
262    }
263
264    bool posedge() const { return ScSignalBaseBinary::posedge(); }
265    bool negedge() const { return ScSignalBaseBinary::negedge(); }
266};
267
268} // namespace sc_gem5
269
270namespace sc_core
271{
272
273template <class T, sc_writer_policy WRITER_POLICY=SC_ONE_WRITER>
274class sc_signal : public sc_gem5::ScSignalBaseT<T, WRITER_POLICY>
275{
276  public:
277    sc_signal() : sc_gem5::ScSignalBaseT<T, WRITER_POLICY>(
278            sc_gen_unique_name("signal"))
279    {}
280    explicit sc_signal(const char *name) :
281        sc_gem5::ScSignalBaseT<T, WRITER_POLICY>(name)
282    {}
283    explicit sc_signal(const char *name, const T &initial_value) :
284        sc_gem5::ScSignalBaseT<T, WRITER_POLICY>(name, initial_value)
285    {}
286    virtual ~sc_signal() {}
287
288    sc_signal<T, WRITER_POLICY> &
289    operator = (const T &t)
290    {
291        this->write(t);
292        return *this;
293    }
294    sc_signal<T, WRITER_POLICY> &
295    operator = (const sc_signal<T, WRITER_POLICY> &s)
296    {
297        this->write(s.read());
298        return *this;
299    }
300
301  protected:
302    virtual void
303    update()
304    {
305        if (this->m_new_val == this->m_cur_val)
306            return;
307
308        this->m_cur_val = this->m_new_val;
309        this->_signalChange();
310    }
311
312  private:
313    // Disabled
314    sc_signal(const sc_signal<T, WRITER_POLICY> &);
315};
316
317template <class T, sc_writer_policy WRITER_POLICY>
318inline std::ostream &
319operator << (std::ostream &os, const sc_signal<T, WRITER_POLICY> &s)
320{
321    os << s.read();
322    return os;
323}
324
325template <sc_writer_policy WRITER_POLICY>
326class sc_signal<bool, WRITER_POLICY> :
327    public sc_gem5::ScSignalBinary<bool, WRITER_POLICY>
328{
329  public:
330    sc_signal() :
331        sc_gem5::ScSignalBinary<bool, WRITER_POLICY>(
332                sc_gen_unique_name("signal"))
333    {}
334    explicit sc_signal(const char *name) :
335        sc_gem5::ScSignalBinary<bool, WRITER_POLICY>(name)
336    {}
337    explicit sc_signal(const char *name, const bool &initial_value) :
338        sc_gem5::ScSignalBinary<bool, WRITER_POLICY>(name, initial_value)
339    {}
340    virtual ~sc_signal() {}
341
342    sc_signal<bool, WRITER_POLICY> &
343    operator = (const bool &b)
344    {
345        this->write(b);
346        return *this;
347    }
348    sc_signal<bool, WRITER_POLICY> &
349    operator = (const sc_signal<bool, WRITER_POLICY> &s)
350    {
351        this->write(s.read());
352        return *this;
353    }
354
355  protected:
356    virtual void
357    update()
358    {
359        if (this->m_new_val == this->m_cur_val)
360            return;
361
362        this->m_cur_val = this->m_new_val;
363        this->_signalChange();
364    }
365
366    void
367    _signalChange()
368    {
369        sc_gem5::ScSignalBinary<bool, WRITER_POLICY>::_signalChange();
370        this->_signalReset();
371        if (this->m_cur_val)
372            this->_signalPosedge();
373        else
374            this->_signalNegedge();
375    }
376
377  private:
378    bool
379    _addReset(sc_gem5::Reset *reset) const
380    {
381        this->_resets.push_back(reset);
382        return true;
383    }
384
385    // Disabled
386    sc_signal(const sc_signal<bool, WRITER_POLICY> &);
387};
388
389template <sc_writer_policy WRITER_POLICY>
390class sc_signal<sc_dt::sc_logic, WRITER_POLICY> :
391    public sc_gem5::ScSignalBinary<sc_dt::sc_logic, WRITER_POLICY>
392{
393  public:
394    sc_signal() :
395        sc_gem5::ScSignalBinary<sc_dt::sc_logic, WRITER_POLICY>(
396                sc_gen_unique_name("signal"))
397    {}
398    explicit sc_signal(const char *name) :
399        sc_gem5::ScSignalBinary<sc_dt::sc_logic, WRITER_POLICY>(name)
400    {}
401    explicit sc_signal(const char *name,
402            const sc_dt::sc_logic &initial_value) :
403        sc_gem5::ScSignalBinary<sc_dt::sc_logic, WRITER_POLICY>(
404                name, initial_value)
405    {}
406    virtual ~sc_signal() {}
407
408    sc_signal<sc_dt::sc_logic, WRITER_POLICY> &
409    operator = (const sc_dt::sc_logic &l)
410    {
411        this->write(l);
412        return *this;
413    }
414    sc_signal<sc_dt::sc_logic, WRITER_POLICY> &
415    operator = (const sc_signal<sc_dt::sc_logic, WRITER_POLICY> &s)
416    {
417        this->write(s.read());
418        return *this;
419    }
420
421  protected:
422    virtual void
423    update()
424    {
425        if (this->m_new_val == this->m_cur_val)
426            return;
427
428        this->m_cur_val = this->m_new_val;
429        this->_signalChange();
430    }
431
432    void
433    _signalChange()
434    {
435        sc_gem5::ScSignalBinary<sc_dt::sc_logic, WRITER_POLICY>::
436            _signalChange();
437        if (this->m_cur_val == sc_dt::SC_LOGIC_1)
438            this->_signalPosedge();
439        else if (this->m_cur_val == sc_dt::SC_LOGIC_0)
440            this->_signalNegedge();
441    }
442
443  private:
444    // Disabled
445    sc_signal(const sc_signal<sc_dt::sc_logic, WRITER_POLICY> &);
446};
447
448} // namespace sc_core
449
450#endif  //__SYSTEMC_EXT_CHANNEL_SC_SIGNAL_HH__
451