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_INOUT_HH__
31#define __SYSTEMC_EXT_CHANNEL_SC_INOUT_HH__
32
33#include <string>
34
35#include "../core/sc_event.hh"
36#include "../core/sc_main.hh"
37#include "../core/sc_port.hh"
38#include "../dt/bit/sc_logic.hh"
39#include "../utils/sc_trace_file.hh"
40#include "sc_signal_inout_if.hh"
41
42namespace sc_dt
43{
44
45class sc_logic;
46
47} // namespace sc_dt
48
49namespace sc_core
50{
51
52class sc_event;
53class sc_trace_file;
54
55template <class T>
56class sc_inout : public sc_port<sc_signal_inout_if<T>, 1>
57{
58  public:
59    sc_inout() : sc_port<sc_signal_inout_if<T>, 1>(), initValue(nullptr),
60        _valueChangedFinder(*this, &sc_signal_inout_if<T>::value_changed_event)
61    {}
62    explicit sc_inout(const char *name) :
63        sc_port<sc_signal_inout_if<T>, 1>(name), initValue(nullptr),
64        _valueChangedFinder(*this, &sc_signal_inout_if<T>::value_changed_event)
65    {}
66    virtual ~sc_inout() { delete initValue; }
67
68    // Deprecated binding constructors.
69    explicit sc_inout(const sc_signal_inout_if<T> &interface) :
70        sc_port<sc_signal_inout_if<T>, 1>(interface), initValue(nullptr),
71        _valueChangedFinder(*this, &sc_signal_inout_if<T>::value_changed_event)
72    {}
73    sc_inout(const char *name, const sc_signal_inout_if<T> &interface) :
74        sc_port<sc_signal_inout_if<T>, 1>(name, interface), initValue(nullptr),
75        _valueChangedFinder(*this, &sc_signal_inout_if<T>::value_changed_event)
76    {}
77    explicit sc_inout(sc_port_b<sc_signal_inout_if<T> > &parent) :
78        sc_port<sc_signal_inout_if<T>, 1>(parent), initValue(nullptr),
79        _valueChangedFinder(*this, &sc_signal_inout_if<T>::value_changed_event)
80    {}
81    sc_inout(const char *name, sc_port_b<sc_signal_inout_if<T> > &parent) :
82        sc_port<sc_signal_inout_if<T>, 1>(name, parent), initValue(nullptr),
83        _valueChangedFinder(*this, &sc_signal_inout_if<T>::value_changed_event)
84    {}
85    explicit sc_inout(sc_port<sc_signal_inout_if<T>, 1> &parent) :
86        sc_port<sc_signal_inout_if<T>, 1>(parent), initValue(nullptr),
87        _valueChangedFinder(*this, &sc_signal_inout_if<T>::value_changed_event)
88    {}
89    sc_inout(const char *name, sc_port<sc_signal_inout_if<T>, 1> &parent) :
90        sc_port<sc_signal_inout_if<T>, 1>(name, parent), initValue(nullptr),
91        _valueChangedFinder(*this, &sc_signal_inout_if<T>::value_changed_event)
92    {}
93
94    void
95    initialize(const T &t)
96    {
97        if (this->size()) {
98            (*this)->write(t);
99        } else {
100            if (!initValue)
101                initValue = new T;
102            *initValue = t;
103        }
104    }
105    void initialize(const sc_signal_in_if<T> &i) { initialize(i.read()); }
106
107    virtual void
108    end_of_elaboration()
109    {
110        if (initValue) {
111            write(*initValue);
112            delete initValue;
113            initValue = nullptr;
114        }
115
116        for (auto params: traceParamsVec)
117            sc_trace(params->tf, (*this)->read(), params->name);
118
119        traceParamsVec.clear();
120    }
121
122    const T &read() const { return (*this)->read(); }
123    operator const T& () const { return (*this)->read(); }
124
125    void write(const T &t) { (*this)->write(t); }
126    sc_inout<T> &
127    operator = (const T &t)
128    {
129        (*this)->write(t);
130        return *this;
131    }
132    sc_inout<T> &
133    operator = (const sc_signal_in_if<T> &i)
134    {
135        (*this)->write(i.read());
136        return *this;
137    }
138    sc_inout<T> &
139    operator = (const sc_port<sc_signal_in_if<T>, 1> &p)
140    {
141        (*this)->write(p->read());
142        return *this;
143    }
144    sc_inout<T> &
145    operator = (const sc_port<sc_signal_inout_if<T>, 1> &p)
146    {
147        (*this)->write(p->read());
148        return *this;
149    }
150    sc_inout<T> &
151    operator = (const sc_inout<T> &p)
152    {
153        (*this)->write(p->read());
154        return *this;
155    }
156
157    const sc_event &default_event() const { return (*this)->default_event(); }
158    const sc_event &
159    value_changed_event() const
160    {
161        return (*this)->value_changed_event();
162    }
163    bool event() const { return (*this)->event(); }
164    sc_event_finder &value_changed() const { return _valueChangedFinder; }
165
166    virtual const char *kind() const { return "sc_inout"; }
167
168    void
169    add_trace(sc_trace_file *tf, const std::string &name) const
170    {
171        traceParamsVec.push_back(new sc_trace_params(tf, name));
172    }
173
174  private:
175    T *initValue;
176    mutable sc_event_finder_t<sc_signal_inout_if<T> > _valueChangedFinder;
177
178    mutable sc_trace_params_vec traceParamsVec;
179
180    // Disabled
181    sc_inout(const sc_inout<T> &);
182};
183
184template <class T>
185inline void
186sc_trace(sc_trace_file *tf, const sc_inout<T> &i, const std::string &name)
187{
188    if (::sc_core::sc_get_status() < ::sc_core::SC_START_OF_SIMULATION)
189        i.add_trace(tf, name);
190    else
191        sc_trace(tf, i->read(), name);
192}
193
194template <>
195class sc_inout<bool> : public sc_port<sc_signal_inout_if<bool>, 1>
196{
197  public:
198    sc_inout() : sc_port<sc_signal_inout_if<bool>, 1>(), initValue(nullptr),
199        _valueChangedFinder(*this,
200                &sc_signal_inout_if<bool>::value_changed_event),
201        _posFinder(*this, &sc_signal_inout_if<bool>::posedge_event),
202        _negFinder(*this, &sc_signal_inout_if<bool>::negedge_event)
203    {}
204    explicit sc_inout(const char *name) :
205            sc_port<sc_signal_inout_if<bool>, 1>(name), initValue(nullptr),
206        _valueChangedFinder(*this,
207                &sc_signal_inout_if<bool>::value_changed_event),
208        _posFinder(*this, &sc_signal_inout_if<bool>::posedge_event),
209        _negFinder(*this, &sc_signal_inout_if<bool>::negedge_event)
210    {}
211    virtual ~sc_inout() { delete initValue; }
212
213    // Deprecated binding constructors.
214    explicit sc_inout(const sc_signal_inout_if<bool> &interface) :
215        sc_port<sc_signal_inout_if<bool>, 1>(interface), initValue(nullptr),
216        _valueChangedFinder(*this,
217                &sc_signal_inout_if<bool>::value_changed_event),
218        _posFinder(*this, &sc_signal_inout_if<bool>::posedge_event),
219        _negFinder(*this, &sc_signal_inout_if<bool>::negedge_event)
220    {}
221    sc_inout(const char *name, const sc_signal_inout_if<bool> &interface) :
222        sc_port<sc_signal_inout_if<bool>, 1>(name, interface),
223        initValue(nullptr),
224        _valueChangedFinder(*this,
225                &sc_signal_inout_if<bool>::value_changed_event),
226        _posFinder(*this, &sc_signal_inout_if<bool>::posedge_event),
227        _negFinder(*this, &sc_signal_inout_if<bool>::negedge_event)
228    {}
229    explicit sc_inout(sc_port_b<sc_signal_inout_if<bool> > &parent) :
230        sc_port<sc_signal_inout_if<bool>, 1>(parent), initValue(nullptr),
231        _valueChangedFinder(*this,
232                &sc_signal_inout_if<bool>::value_changed_event),
233        _posFinder(*this, &sc_signal_inout_if<bool>::posedge_event),
234        _negFinder(*this, &sc_signal_inout_if<bool>::negedge_event)
235    {}
236    sc_inout(const char *name, sc_port_b<sc_signal_inout_if<bool> > &parent) :
237        sc_port<sc_signal_inout_if<bool>, 1>(name, parent), initValue(nullptr),
238        _valueChangedFinder(*this,
239                &sc_signal_inout_if<bool>::value_changed_event),
240        _posFinder(*this, &sc_signal_inout_if<bool>::posedge_event),
241        _negFinder(*this, &sc_signal_inout_if<bool>::negedge_event)
242    {}
243    explicit sc_inout(sc_port<sc_signal_inout_if<bool>, 1> &parent) :
244        sc_port<sc_signal_inout_if<bool>, 1>(parent), initValue(nullptr),
245        _valueChangedFinder(*this,
246                &sc_signal_inout_if<bool>::value_changed_event),
247        _posFinder(*this, &sc_signal_inout_if<bool>::posedge_event),
248        _negFinder(*this, &sc_signal_inout_if<bool>::negedge_event)
249    {}
250    sc_inout(const char *name, sc_port<sc_signal_inout_if<bool>, 1> &parent) :
251        sc_port<sc_signal_inout_if<bool>, 1>(name, parent), initValue(nullptr),
252        _valueChangedFinder(*this,
253                &sc_signal_inout_if<bool>::value_changed_event),
254        _posFinder(*this, &sc_signal_inout_if<bool>::posedge_event),
255        _negFinder(*this, &sc_signal_inout_if<bool>::negedge_event)
256    {}
257
258    void
259    initialize(const bool &b)
260    {
261        if (this->size()) {
262            (*this)->write(b);
263        } else {
264            if (!initValue)
265                initValue = new bool;
266            *initValue = b;
267        }
268    }
269    void initialize(const sc_signal_in_if<bool> &i) { initialize(i.read()); }
270
271    virtual void
272    end_of_elaboration()
273    {
274        if (initValue) {
275            write(*initValue);
276            delete initValue;
277            initValue = nullptr;
278        }
279
280        for (auto params: traceParamsVec)
281            sc_trace(params->tf, (*this)->read(), params->name);
282
283        traceParamsVec.clear();
284    }
285
286    const bool &read() const { return (*this)->read(); }
287    operator const bool& () const { return (*this)->read(); }
288
289    void write(const bool &b) { (*this)->write(b); }
290    sc_inout<bool> &
291    operator = (const bool &b)
292    {
293        (*this)->write(b);
294        return *this;
295    }
296    sc_inout<bool> &
297    operator = (const sc_signal_in_if<bool> &i)
298    {
299        (*this)->write(i.read());
300        return *this;
301    }
302    sc_inout<bool> &
303    operator = (const sc_port<sc_signal_in_if<bool>, 1> &p)
304    {
305        (*this)->write(p->read());
306        return *this;
307    }
308    sc_inout<bool> &
309    operator = (const sc_port<sc_signal_inout_if<bool>, 1> &p)
310    {
311        (*this)->write(p->read());
312        return *this;
313    }
314    sc_inout<bool> &
315    operator = (const sc_inout<bool> &p)
316    {
317        (*this)->write(p->read());
318        return *this;
319    }
320
321    const sc_event &default_event() const { return (*this)->default_event(); }
322    const sc_event &
323    value_changed_event() const
324    {
325        return (*this)->value_changed_event();
326    }
327    const sc_event &posedge_event() const { return (*this)->posedge_event(); }
328    const sc_event &negedge_event() const { return (*this)->negedge_event(); }
329    bool event() const { return (*this)->event(); }
330    bool posedge() const { return (*this)->posedge(); }
331    bool negedge() const { return (*this)->negedge(); }
332
333    sc_event_finder &value_changed() const { return _valueChangedFinder; }
334    sc_event_finder &pos() const { return _posFinder; }
335    sc_event_finder &neg() const { return _negFinder; }
336
337    virtual const char *kind() const { return "sc_inout"; }
338
339    void
340    add_trace(sc_trace_file *tf, const std::string &name) const
341    {
342        traceParamsVec.push_back(new sc_trace_params(tf, name));
343    }
344
345  private:
346    bool *initValue;
347    mutable sc_event_finder_t<sc_signal_inout_if<bool> > _valueChangedFinder;
348    mutable sc_event_finder_t<sc_signal_inout_if<bool> > _posFinder;
349    mutable sc_event_finder_t<sc_signal_inout_if<bool> > _negFinder;
350
351    mutable sc_trace_params_vec traceParamsVec;
352
353    // Disabled
354    sc_inout(const sc_inout<bool> &);
355};
356
357template <>
358inline void sc_trace<bool>(
359        sc_trace_file *tf, const sc_inout<bool> &i, const std::string &name)
360{
361    if (::sc_core::sc_get_status() < ::sc_core::SC_START_OF_SIMULATION)
362        i.add_trace(tf, name);
363    else
364        sc_trace(tf, i->read(), name);
365}
366
367template <>
368class sc_inout<sc_dt::sc_logic> :
369        public sc_port<sc_signal_inout_if<sc_dt::sc_logic>, 1>
370{
371  public:
372    sc_inout() : sc_port<sc_signal_inout_if<sc_dt::sc_logic>, 1>(),
373        initValue(nullptr),
374        _valueChangedFinder(*this,
375                &sc_signal_inout_if<sc_dt::sc_logic>::value_changed_event),
376        _posFinder(*this, &sc_signal_inout_if<sc_dt::sc_logic>::posedge_event),
377        _negFinder(*this, &sc_signal_inout_if<sc_dt::sc_logic>::negedge_event)
378    {}
379    explicit sc_inout(const char *name) :
380            sc_port<sc_signal_inout_if<sc_dt::sc_logic>, 1>(name),
381        initValue(nullptr),
382        _valueChangedFinder(*this,
383                &sc_signal_inout_if<sc_dt::sc_logic>::value_changed_event),
384        _posFinder(*this, &sc_signal_inout_if<sc_dt::sc_logic>::posedge_event),
385        _negFinder(*this, &sc_signal_inout_if<sc_dt::sc_logic>::negedge_event)
386    {}
387    virtual ~sc_inout() { delete initValue; }
388
389    // Deprecated binding constructors.
390    explicit sc_inout(const sc_signal_inout_if<sc_dt::sc_logic> &interface) :
391        sc_port<sc_signal_inout_if<sc_dt::sc_logic>, 1>(interface),
392        initValue(nullptr),
393        _valueChangedFinder(*this,
394                &sc_signal_inout_if<sc_dt::sc_logic>::value_changed_event),
395        _posFinder(*this, &sc_signal_inout_if<sc_dt::sc_logic>::posedge_event),
396        _negFinder(*this, &sc_signal_inout_if<sc_dt::sc_logic>::negedge_event)
397    {}
398    sc_inout(const char *name,
399            const sc_signal_inout_if<sc_dt::sc_logic> &interface) :
400        sc_port<sc_signal_inout_if<sc_dt::sc_logic>, 1>(name, interface),
401        initValue(nullptr),
402        _valueChangedFinder(*this,
403                &sc_signal_inout_if<sc_dt::sc_logic>::value_changed_event),
404        _posFinder(*this, &sc_signal_inout_if<sc_dt::sc_logic>::posedge_event),
405        _negFinder(*this, &sc_signal_inout_if<sc_dt::sc_logic>::negedge_event)
406    {}
407    explicit sc_inout(
408            sc_port_b<sc_signal_inout_if<sc_dt::sc_logic> > &parent) :
409        sc_port<sc_signal_inout_if<sc_dt::sc_logic>, 1>(parent),
410        initValue(nullptr),
411        _valueChangedFinder(*this,
412                &sc_signal_inout_if<sc_dt::sc_logic>::value_changed_event),
413        _posFinder(*this, &sc_signal_inout_if<sc_dt::sc_logic>::posedge_event),
414        _negFinder(*this, &sc_signal_inout_if<sc_dt::sc_logic>::negedge_event)
415    {}
416    sc_inout(const char *name,
417            sc_port_b<sc_signal_inout_if<sc_dt::sc_logic> > &parent) :
418        sc_port<sc_signal_inout_if<sc_dt::sc_logic>, 1>(name, parent),
419        initValue(nullptr),
420        _valueChangedFinder(*this,
421                &sc_signal_inout_if<sc_dt::sc_logic>::value_changed_event),
422        _posFinder(*this, &sc_signal_inout_if<sc_dt::sc_logic>::posedge_event),
423        _negFinder(*this, &sc_signal_inout_if<sc_dt::sc_logic>::negedge_event)
424    {}
425    explicit sc_inout(
426            sc_port<sc_signal_inout_if<sc_dt::sc_logic>, 1> &parent) :
427        sc_port<sc_signal_inout_if<sc_dt::sc_logic>, 1>(parent),
428        initValue(nullptr),
429        _valueChangedFinder(*this,
430                &sc_signal_inout_if<sc_dt::sc_logic>::value_changed_event),
431        _posFinder(*this, &sc_signal_inout_if<sc_dt::sc_logic>::posedge_event),
432        _negFinder(*this, &sc_signal_inout_if<sc_dt::sc_logic>::negedge_event)
433    {}
434    sc_inout(const char *name,
435            sc_port<sc_signal_inout_if<sc_dt::sc_logic>, 1> &parent) :
436        sc_port<sc_signal_inout_if<sc_dt::sc_logic>, 1>(name, parent),
437        initValue(nullptr),
438        _valueChangedFinder(*this,
439                &sc_signal_inout_if<sc_dt::sc_logic>::value_changed_event),
440        _posFinder(*this, &sc_signal_inout_if<sc_dt::sc_logic>::posedge_event),
441        _negFinder(*this, &sc_signal_inout_if<sc_dt::sc_logic>::negedge_event)
442    {}
443
444    void
445    initialize(const sc_dt::sc_logic &l)
446    {
447        if (this->size()) {
448            (*this)->write(l);
449        } else {
450            if (!initValue)
451                initValue = new sc_dt::sc_logic;
452            *initValue = l;
453        }
454    }
455    void
456    initialize(const sc_signal_in_if<sc_dt::sc_logic> &i)
457    {
458        initialize(i.read());
459    }
460
461    virtual void
462    end_of_elaboration()
463    {
464        if (initValue) {
465            write(*initValue);
466            delete initValue;
467            initValue = nullptr;
468        }
469
470        for (auto params: traceParamsVec)
471            sc_trace(params->tf, (*this)->read(), params->name);
472
473        traceParamsVec.clear();
474    }
475
476    const sc_dt::sc_logic &read() const { return (*this)->read(); }
477    operator const sc_dt::sc_logic& () const { return (*this)->read(); }
478
479    void write(const sc_dt::sc_logic &l) { (*this)->write(l); }
480    sc_inout<sc_dt::sc_logic> &
481    operator = (const sc_dt::sc_logic &l)
482    {
483        (*this)->write(l);
484        return *this;
485    }
486    sc_inout<sc_dt::sc_logic> &
487    operator = (const sc_signal_in_if<sc_dt::sc_logic> &i)
488    {
489        (*this)->write(i.read());
490        return *this;
491    }
492    sc_inout<sc_dt::sc_logic> &
493    operator = (const sc_port<sc_signal_in_if<sc_dt::sc_logic>, 1> &p)
494    {
495        (*this)->write(p->read());
496        return *this;
497    }
498    sc_inout<sc_dt::sc_logic> &
499    operator = (const sc_port<sc_signal_inout_if<sc_dt::sc_logic>, 1> &p)
500    {
501        (*this)->write(p->read());
502        return *this;
503    }
504    sc_inout<sc_dt::sc_logic> &
505    operator = (const sc_inout<sc_dt::sc_logic> &p)
506    {
507        (*this)->write(p->read());
508        return *this;
509    }
510
511    const sc_event &default_event() const { return (*this)->default_event(); }
512    const sc_event &
513    value_changed_event() const
514    {
515        return (*this)->value_changed_event();
516    }
517    const sc_event &posedge_event() const { return (*this)->posedge_event(); }
518    const sc_event &negedge_event() const { return (*this)->negedge_event(); }
519    bool event() const { return (*this)->event(); }
520    bool posedge() const { return (*this)->posedge(); }
521    bool negedge() const { return (*this)->negedge(); }
522
523    sc_event_finder &value_changed() const { return _valueChangedFinder; }
524    sc_event_finder &pos() const { return _posFinder; }
525    sc_event_finder &neg() const { return _negFinder; }
526
527    virtual const char *kind() const { return "sc_inout"; }
528
529    void
530    add_trace(sc_trace_file *tf, const std::string &name) const
531    {
532        traceParamsVec.push_back(new sc_trace_params(tf, name));
533    }
534
535  private:
536    sc_dt::sc_logic *initValue;
537    mutable sc_event_finder_t<
538        sc_signal_inout_if<sc_dt::sc_logic> > _valueChangedFinder;
539    mutable sc_event_finder_t<sc_signal_inout_if<sc_dt::sc_logic> > _posFinder;
540    mutable sc_event_finder_t<sc_signal_inout_if<sc_dt::sc_logic> > _negFinder;
541
542    mutable sc_trace_params_vec traceParamsVec;
543
544    // Disabled
545    sc_inout(const sc_inout<sc_dt::sc_logic> &);
546};
547
548template <>
549inline void
550sc_trace<sc_dt::sc_logic>(sc_trace_file *tf,
551        const sc_inout<sc_dt::sc_logic> &i, const std::string &name)
552{
553    if (::sc_core::sc_get_status() < ::sc_core::SC_START_OF_SIMULATION)
554        i.add_trace(tf, name);
555    else
556        sc_trace(tf, i->read(), name);
557}
558
559} // namespace sc_core
560
561#endif  //__SYSTEMC_EXT_CHANNEL_SC_INOUT_HH__
562