systemc: Implement writer policies.

This includes the nonstandard SC_NO_WRITE_CHECK #define which the
Accellera tests use and depend on.

Change-Id: I106c4c16160325725a00d5c337047251817dca32
Reviewed-on: https://gem5-review.googlesource.com/c/13203
Reviewed-by: Gabe Black <gabeblack@google.com>
Maintainer: Gabe Black <gabeblack@google.com>
diff --git a/src/systemc/channel/SConscript b/src/systemc/channel/SConscript
index c83c233..fe79737 100644
--- a/src/systemc/channel/SConscript
+++ b/src/systemc/channel/SConscript
@@ -35,4 +35,5 @@
     Source('sc_out_resolved.cc')
     Source('sc_mutex.cc')
     Source('sc_semaphore.cc')
+    Source('sc_signal.cc')
     Source('sc_signal_resolved.cc')
diff --git a/src/systemc/channel/sc_signal.cc b/src/systemc/channel/sc_signal.cc
new file mode 100644
index 0000000..e2c9bdf
--- /dev/null
+++ b/src/systemc/channel/sc_signal.cc
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2018 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#include <sstream>
+
+#include "systemc/core/scheduler.hh"
+#include "systemc/ext/channel/sc_signal.hh"
+#include "systemc/ext/core/sc_main.hh"
+
+namespace sc_gem5
+{
+
+ScSignalBase::ScSignalBase(const char *name) :
+    sc_core::sc_prim_channel(name), _changeStamp(~0ULL),
+    _gem5WriterPort(nullptr)
+{}
+
+ScSignalBase::~ScSignalBase() {}
+
+const sc_core::sc_event &
+ScSignalBase::defaultEvent() const
+{
+    return valueChangedEvent();
+}
+
+const sc_core::sc_event &
+ScSignalBase::valueChangedEvent() const
+{
+    return _valueChangedEvent;
+}
+
+bool
+ScSignalBase::event() const
+{
+    return _changeStamp == getChangeStamp();
+}
+
+void
+ScSignalBase::_signalChange()
+{
+    _changeStamp = getChangeStamp();
+    _valueChangedEvent.notify(sc_core::SC_ZERO_TIME);
+}
+
+namespace
+{
+
+void
+reportSignalError(ScSignalBase *sig, sc_core::sc_object *first,
+        sc_core::sc_object *second, bool delta_conflict=false)
+{
+    std::ostringstream ss;
+    ss << "\n signal " << "`" << sig->name() << "' (" << sig->kind() << ")";
+    ss << "\n first driver `" << first->name() << "'  (" <<
+        first->kind() << ")";
+    ss << "\n second driver `" << second->name() << "' (" <<
+        second->kind() << ")";
+    if (delta_conflict) {
+        ss << "\n conflicting write in delta cycle " <<
+            sc_core::sc_delta_count();
+    }
+    SC_REPORT_ERROR(
+            "(E115) sc_signal<T> cannot have more than one driver",
+            ss.str().c_str());
+}
+
+} // anonymous namespace
+
+WriteChecker<sc_core::SC_ONE_WRITER>::WriteChecker(ScSignalBase *_sig) :
+    sig(_sig), firstPort(nullptr), proc(nullptr), writeStamp(~0ULL)
+{}
+
+void
+WriteChecker<sc_core::SC_ONE_WRITER>::checkPort(sc_core::sc_port_base &port,
+        std::string iface_type_name, std::string out_name)
+{
+    if (iface_type_name == out_name) {
+        if (firstPort)
+            reportSignalError(sig, firstPort, &port);
+        firstPort = &port;
+    }
+}
+
+void
+WriteChecker<sc_core::SC_ONE_WRITER>::checkWriter()
+{
+    Process *p = scheduler.current();
+    if (!p)
+        return;
+    uint64_t stamp = getChangeStamp();
+    if (proc && proc != p)
+        reportSignalError(sig, proc, p);
+    proc = p;
+    writeStamp = stamp;
+}
+
+WriteChecker<sc_core::SC_MANY_WRITERS>::WriteChecker(ScSignalBase *_sig) :
+    sig(_sig), proc(nullptr), writeStamp(~0ULL)
+{}
+
+void
+WriteChecker<sc_core::SC_MANY_WRITERS>::checkPort(sc_core::sc_port_base &port,
+        std::string iface_type_name, std::string out_name)
+{
+    return;
+}
+
+void
+WriteChecker<sc_core::SC_MANY_WRITERS>::checkWriter()
+{
+    Process *p = scheduler.current();
+    if (!p)
+        return;
+    uint64_t stamp = getChangeStamp();
+    if (writeStamp == stamp && proc && proc != p)
+        reportSignalError(sig, proc, p, writeStamp == stamp);
+    proc = p;
+    writeStamp = stamp;
+}
+
+ScSignalBaseBinary::ScSignalBaseBinary(const char *_name) :
+    ScSignalBase(_name), _posStamp(~0ULL), _negStamp(~0ULL)
+{}
+
+const sc_core::sc_event &
+ScSignalBaseBinary::posedgeEvent() const
+{
+    return _posedgeEvent;
+}
+
+const sc_core::sc_event &
+ScSignalBaseBinary::negedgeEvent() const
+{
+    return _negedgeEvent;
+}
+
+bool
+ScSignalBaseBinary::posedge() const
+{
+    return _posStamp == getChangeStamp();
+}
+bool
+
+ScSignalBaseBinary::negedge() const
+{
+    return _negStamp == getChangeStamp();
+}
+
+} // namespace sc_gem5
diff --git a/src/systemc/ext/channel/sc_buffer.hh b/src/systemc/ext/channel/sc_buffer.hh
index 21dc52b..c0ad710 100644
--- a/src/systemc/ext/channel/sc_buffer.hh
+++ b/src/systemc/ext/channel/sc_buffer.hh
@@ -50,6 +50,11 @@
     virtual void
     write(const T &t)
     {
+#       if !defined(SC_NO_WRITE_CHECK)
+        {
+            this->_checker.checkWriter();
+        }
+#       endif
         this->m_new_val = t;
         this->request_update();
     }
diff --git a/src/systemc/ext/channel/sc_signal.hh b/src/systemc/ext/channel/sc_signal.hh
index 672eef5..e430034 100644
--- a/src/systemc/ext/channel/sc_signal.hh
+++ b/src/systemc/ext/channel/sc_signal.hh
@@ -31,7 +31,6 @@
 #define __SYSTEMC_EXT_CHANNEL_SC_SIGNAL_HH__
 
 #include <iostream>
-#include <sstream>
 #include <string>
 #include <vector>
 
@@ -46,141 +45,265 @@
 
 class sc_port_base;
 
-template <class T, sc_writer_policy WRITER_POLICY=SC_ONE_WRITER>
-class sc_signal : public sc_signal_inout_if<T>,
-                  public sc_prim_channel
+} // namespace sc_core
+
+namespace sc_gem5
+{
+
+class Process;
+
+class ScSignalBase : public sc_core::sc_prim_channel
 {
   public:
-    sc_signal() : sc_signal_inout_if<T>(),
-                  sc_prim_channel(sc_gen_unique_name("signal")),
-                  m_cur_val(T()), m_new_val(T()), _changeStamp(~0ULL),
-                  _gem5Writer(NULL)
+    virtual const char *kind() const { return "sc_signal"; }
+
+  protected:
+    ScSignalBase(const char *_name);
+    virtual ~ScSignalBase();
+
+    const sc_core::sc_event &defaultEvent() const;
+    const sc_core::sc_event &valueChangedEvent() const;
+
+    bool event() const;
+
+    void _signalChange();
+
+    virtual sc_core::sc_writer_policy get_writer_policy() const = 0;
+
+    sc_core::sc_event _valueChangedEvent;
+    uint64_t _changeStamp;
+    sc_core::sc_port_base *_gem5WriterPort;
+};
+
+class ScSignalBaseBinary : public ScSignalBase
+{
+  protected:
+    ScSignalBaseBinary(const char *_name);
+
+    const sc_core::sc_event &posedgeEvent() const;
+    const sc_core::sc_event &negedgeEvent() const;
+
+    bool posedge() const;
+    bool negedge() const;
+
+    sc_core::sc_event _posedgeEvent;
+    sc_core::sc_event _negedgeEvent;
+
+    uint64_t _posStamp;
+    uint64_t _negStamp;
+};
+
+template <class T>
+class ScSignalBasePicker : public ScSignalBase
+{
+  protected:
+    ScSignalBasePicker(const char *_name) : ScSignalBase(_name) {}
+};
+
+template <>
+class ScSignalBasePicker<bool> : public ScSignalBaseBinary
+{
+  protected:
+    ScSignalBasePicker(const char *_name) : ScSignalBaseBinary(_name) {}
+};
+
+template <>
+class ScSignalBasePicker<sc_dt::sc_logic> : public ScSignalBaseBinary
+{
+  protected:
+    ScSignalBasePicker(const char *_name) : ScSignalBaseBinary(_name) {}
+};
+
+template <sc_core::sc_writer_policy WRITER_POLICY>
+class WriteChecker;
+
+template <>
+class WriteChecker<sc_core::SC_ONE_WRITER>
+{
+  public:
+    WriteChecker(ScSignalBase *_sig);
+
+    void checkPort(sc_core::sc_port_base &port,
+            std::string iface_type_name, std::string out_name);
+    void checkWriter();
+
+  private:
+    ScSignalBase *sig;
+    sc_core::sc_port_base *firstPort;
+    Process *proc;
+    uint64_t writeStamp;
+};
+
+template <>
+class WriteChecker<sc_core::SC_MANY_WRITERS>
+{
+  public:
+    WriteChecker(ScSignalBase *_sig);
+
+    void checkPort(sc_core::sc_port_base &port,
+            std::string iface_type_name, std::string out_name);
+    void checkWriter();
+
+  private:
+    ScSignalBase *sig;
+    Process *proc;
+    uint64_t writeStamp;
+};
+
+template <class T, sc_core::sc_writer_policy WRITER_POLICY>
+class ScSignalBaseT :
+    public ScSignalBasePicker<T>, public sc_core::sc_signal_inout_if<T>
+{
+  public:
+    ScSignalBaseT(const char *_name) :
+        ScSignalBasePicker<T>(_name), m_cur_val(T()), m_new_val(T()),
+        _checker(this)
     {}
-    explicit sc_signal(const char *name) :
-        sc_signal_inout_if<T>(), sc_prim_channel(name),
-        m_cur_val(T()), m_new_val(T()), _changeStamp(~0ULL),
-        _gem5Writer(NULL)
+    ScSignalBaseT(const char *_name, const T &initial_value) :
+        ScSignalBasePicker<T>(_name), m_cur_val(initial_value),
+        m_new_val(initial_value), _checker(this)
     {}
-    explicit sc_signal(const char *name, const T &initial_value) :
-        sc_signal_inout_if<T>(), sc_prim_channel(name),
-        m_cur_val(initial_value), m_new_val(initial_value),
-        _changeStamp(~0ULL), _gem5Writer(NULL)
-    {}
-    virtual ~sc_signal() {}
+    virtual ~ScSignalBaseT() {}
 
     virtual void
-    register_port(sc_port_base &port, const char *iface_type_name)
+    register_port(sc_core::sc_port_base &port, const char *iface_type_name)
     {
-        if (WRITER_POLICY == SC_ONE_WRITER &&
-                std::string(iface_type_name) ==
-                typeid(sc_signal_inout_if<T>).name()) {
-            if (_gem5Writer) {
-                std::ostringstream ss;
-                ss << "\n signal " << "`" << name() << "' (" <<
-                    kind() << ")";
-                ss << "\n first driver `" << _gem5Writer->name() << "'  (" <<
-                    _gem5Writer->kind() << ")";
-                ss << "\n second driver `" << port.name() << "' (" <<
-                    port.kind() << ")";
-                SC_REPORT_ERROR(
-                        "(E115) sc_signal<T> cannot have more than one driver",
-                        ss.str().c_str());
-            }
-            _gem5Writer = &port;
+#       if !defined(SC_NO_WRITE_CHECK)
+        {
+            _checker.checkPort(port, iface_type_name,
+                typeid(sc_core::sc_signal_inout_if<T>).name());
         }
+#       endif
     }
 
     virtual const T &read() const { return m_cur_val; }
     operator const T&() const { return read(); }
 
-    virtual sc_writer_policy
-    get_writer_policy() const
-    {
-        return WRITER_POLICY;
-    }
     virtual void
     write(const T &t)
     {
+#       if !defined(SC_NO_WRITE_CHECK)
+        {
+            _checker.checkWriter();
+        }
+#       endif
         m_new_val = t;
         bool changed = !(m_cur_val == m_new_val);
-        //TODO check whether this write follows the write policy.
         if (changed)
-            request_update();
-    }
-    sc_signal<T, WRITER_POLICY> &
-    operator = (const T &t)
-    {
-        write(t);
-        return *this;
-    }
-    sc_signal<T, WRITER_POLICY> &
-    operator = (const sc_signal<T, WRITER_POLICY> &s)
-    {
-        write(s.read());
-        return *this;
+            this->request_update();
     }
 
-    virtual const sc_event &
+    virtual const sc_core::sc_event &
     default_event() const
     {
-        return value_changed_event();
+        return ScSignalBase::defaultEvent();
     }
-    virtual const sc_event &
+
+    virtual const sc_core::sc_event &
     value_changed_event() const
     {
-        return _valueChangedEvent;
-    }
-    virtual bool
-    event() const
-    {
-        return _changeStamp == ::sc_gem5::getChangeStamp();
+        return ScSignalBase::valueChangedEvent();
     }
 
     virtual void print(std::ostream &os=std::cout) const { os << m_cur_val; }
     virtual void
     dump(std::ostream &os=std::cout) const
     {
-        os << "     name = " << name() << ::std::endl;
+        os << "     name = " << this->name() << ::std::endl;
         os << "    value = " << m_cur_val << ::std::endl;
         os << "new value = " << m_new_val << ::std::endl;
     }
-    virtual const char *kind() const { return "sc_signal"; }
+
+    virtual bool event() const { return ScSignalBase::event(); }
+
+    virtual sc_core::sc_writer_policy
+    get_writer_policy() const
+    {
+        return WRITER_POLICY;
+    }
 
   protected:
-    virtual void
-    update()
-    {
-        if (m_new_val == m_cur_val)
-            return;
-
-        m_cur_val = m_new_val;
-        _signalChange();
-        _changeStamp = ::sc_gem5::getChangeStamp();
-        _valueChangedEvent.notify(SC_ZERO_TIME);
-    }
-
-    void
-    _signalChange()
-    {
-        _changeStamp = ::sc_gem5::getChangeStamp();
-        _valueChangedEvent.notify(SC_ZERO_TIME);
-    }
-
     // These members which store the current and future value of the signal
     // are not specified in the standard but are referred to directly by one
     // of the tests.
     T m_cur_val;
     T m_new_val;
 
-  private:
-    sc_event _valueChangedEvent;
-    uint64_t _changeStamp;
-    sc_port_base *_gem5Writer;
+    WriteChecker<WRITER_POLICY> _checker;
+};
 
-    // Disabled
-    sc_signal(const sc_signal<T, WRITER_POLICY> &) :
-            sc_signal_inout_if<T>(), sc_prim_channel("")
+template <typename T, sc_core::sc_writer_policy WRITER_POLICY>
+class ScSignalBinary : public ScSignalBaseT<T, WRITER_POLICY>
+{
+  public:
+    ScSignalBinary(const char *_name) : ScSignalBaseT<T, WRITER_POLICY>(_name)
     {}
+    ScSignalBinary(const char *_name, const T& initial_value) :
+        ScSignalBaseT<T, WRITER_POLICY>(_name, initial_value)
+    {}
+
+    const sc_core::sc_event &
+    posedge_event() const
+    {
+        return ScSignalBaseBinary::posedgeEvent();
+    }
+    const sc_core::sc_event &
+    negedge_event() const
+    {
+        return ScSignalBaseBinary::negedgeEvent();
+    }
+
+    bool posedge() const { return ScSignalBaseBinary::posedge(); }
+    bool negedge() const { return ScSignalBaseBinary::negedge(); }
+};
+
+} // namespace sc_gem5
+
+namespace sc_core
+{
+
+template <class T, sc_writer_policy WRITER_POLICY=SC_ONE_WRITER>
+class sc_signal : public sc_gem5::ScSignalBaseT<T, WRITER_POLICY>
+{
+  public:
+    sc_signal() : sc_gem5::ScSignalBaseT<T, WRITER_POLICY>(
+            sc_gen_unique_name("signal"))
+    {}
+    explicit sc_signal(const char *name) :
+        sc_gem5::ScSignalBaseT<T, WRITER_POLICY>(name)
+    {}
+    explicit sc_signal(const char *name, const T &initial_value) :
+        sc_gem5::ScSignalBaseT<T, WRITER_POLICY>(name, initial_value)
+    {}
+    virtual ~sc_signal() {}
+
+    sc_signal<T, WRITER_POLICY> &
+    operator = (const T &t)
+    {
+        this->write(t);
+        return *this;
+    }
+    sc_signal<T, WRITER_POLICY> &
+    operator = (const sc_signal<T, WRITER_POLICY> &s)
+    {
+        this->write(s.read());
+        return *this;
+    }
+
+  protected:
+    virtual void
+    update()
+    {
+        if (this->m_new_val == this->m_cur_val)
+            return;
+
+        this->m_cur_val = this->m_new_val;
+        this->_signalChange();
+    }
+
+  private:
+    // Disabled
+    sc_signal(const sc_signal<T, WRITER_POLICY> &);
 };
 
 template <class T, sc_writer_policy WRITER_POLICY>
@@ -193,343 +316,110 @@
 
 template <sc_writer_policy WRITER_POLICY>
 class sc_signal<bool, WRITER_POLICY> :
-    public sc_signal_inout_if<bool>, public sc_prim_channel
+    public sc_gem5::ScSignalBinary<bool, WRITER_POLICY>
 {
   public:
-    sc_signal() : sc_signal_inout_if<bool>(),
-                  sc_prim_channel(sc_gen_unique_name("signal")),
-                  m_cur_val(bool()), m_new_val(bool()),
-                  _changeStamp(~0ULL), _posStamp(~0ULL), _negStamp(~0ULL),
-                  _gem5Writer(NULL)
+    sc_signal() :
+        sc_gem5::ScSignalBinary<bool, WRITER_POLICY>(
+                sc_gen_unique_name("signal"))
     {}
     explicit sc_signal(const char *name) :
-        sc_signal_inout_if<bool>(), sc_prim_channel(name),
-        m_cur_val(bool()), m_new_val(bool()),
-        _changeStamp(~0ULL), _posStamp(~0ULL), _negStamp(~0ULL),
-        _gem5Writer(NULL)
+        sc_gem5::ScSignalBinary<bool, WRITER_POLICY>(name)
     {}
     explicit sc_signal(const char *name, const bool &initial_value) :
-        sc_signal_inout_if<bool>(), sc_prim_channel(name),
-        m_cur_val(initial_value), m_new_val(initial_value),
-        _changeStamp(~0ULL), _posStamp(~0ULL), _negStamp(~0ULL),
-        _gem5Writer(NULL)
+        sc_gem5::ScSignalBinary<bool, WRITER_POLICY>(name, initial_value)
     {}
     virtual ~sc_signal() {}
 
-    virtual void
-    register_port(sc_port_base &port, const char *iface_type_name)
-    {
-        if (WRITER_POLICY == SC_ONE_WRITER &&
-                std::string(iface_type_name) ==
-                typeid(sc_signal_inout_if<bool>).name()) {
-            if (_gem5Writer) {
-                std::ostringstream ss;
-                ss << "\n signal " << "`" << name() << "' (" <<
-                    kind() << ")";
-                ss << "\n first driver `" << _gem5Writer->name() << "'  (" <<
-                    _gem5Writer->kind() << ")";
-                ss << "\n second driver `" << port.name() << "' (" <<
-                    port.kind() << ")";
-                SC_REPORT_ERROR(
-                        "(E115) sc_signal<T> cannot have more than one driver",
-                        ss.str().c_str());
-            }
-            _gem5Writer = &port;
-        }
-    }
-
-    virtual const bool &read() const { return m_cur_val; }
-    operator const bool &() const { return read(); }
-
-    virtual sc_writer_policy
-    get_writer_policy() const
-    {
-        return WRITER_POLICY;
-    }
-    virtual void
-    write(const bool &b)
-    {
-        m_new_val = b;
-        bool changed = !(m_cur_val == m_new_val);
-        //TODO check whether this write follows the write policy.
-        if (changed)
-            request_update();
-    }
     sc_signal<bool, WRITER_POLICY> &
     operator = (const bool &b)
     {
-        write(b);
+        this->write(b);
         return *this;
     }
     sc_signal<bool, WRITER_POLICY> &
     operator = (const sc_signal<bool, WRITER_POLICY> &s)
     {
-        write(s.read());
+        this->write(s.read());
         return *this;
     }
 
-    virtual const sc_event &
-    default_event() const
-    {
-        return value_changed_event();
-    }
-
-    virtual const sc_event &
-    value_changed_event() const
-    {
-        return _valueChangedEvent;
-    }
-    virtual const sc_event &
-    posedge_event() const
-    {
-        return _posedgeEvent;
-    }
-    virtual const sc_event &
-    negedge_event() const
-    {
-        return _negedgeEvent;
-    }
-
-    virtual bool
-    event() const
-    {
-        return _changeStamp == ::sc_gem5::getChangeStamp();
-    }
-    virtual bool
-    posedge() const
-    {
-        return _posStamp == ::sc_gem5::getChangeStamp();
-    }
-    virtual bool
-    negedge() const
-    {
-        return _negStamp == ::sc_gem5::getChangeStamp();
-    }
-
-    virtual void print(std::ostream &os=std::cout) const { os << m_cur_val; }
-    virtual void
-    dump(std::ostream &os=std::cout) const
-    {
-        os << "     name = " << name() << ::std::endl;
-        os << "    value = " << m_cur_val << ::std::endl;
-        os << "new value = " << m_new_val << ::std::endl;
-    }
-    virtual const char *kind() const { return "sc_signal"; }
-
   protected:
     virtual void
     update()
     {
-        if (m_new_val == m_cur_val)
+        if (this->m_new_val == this->m_cur_val)
             return;
 
-        m_cur_val = m_new_val;
-        _signalChange();
-        if (m_cur_val) {
-            _posStamp = ::sc_gem5::getChangeStamp();
-            _posedgeEvent.notify(SC_ZERO_TIME);
+        this->m_cur_val = this->m_new_val;
+        this->_signalChange();
+        if (this->m_cur_val) {
+            this->_posStamp = ::sc_gem5::getChangeStamp();
+            this->_posedgeEvent.notify(SC_ZERO_TIME);
         } else {
-            _negStamp = ::sc_gem5::getChangeStamp();
-            _negedgeEvent.notify(SC_ZERO_TIME);
+            this->_negStamp = ::sc_gem5::getChangeStamp();
+            this->_negedgeEvent.notify(SC_ZERO_TIME);
         }
     }
 
-    void
-    _signalChange()
-    {
-        _changeStamp = ::sc_gem5::getChangeStamp();
-        _valueChangedEvent.notify(SC_ZERO_TIME);
-    }
-
-    bool m_cur_val;
-    bool m_new_val;
-
   private:
-    sc_event _valueChangedEvent;
-    sc_event _posedgeEvent;
-    sc_event _negedgeEvent;
-
-    uint64_t _changeStamp;
-    uint64_t _posStamp;
-    uint64_t _negStamp;
-
-    sc_port_base *_gem5Writer;
-
     // Disabled
-    sc_signal(const sc_signal<bool, WRITER_POLICY> &) :
-            sc_signal_inout_if<bool>(), sc_prim_channel("")
-    {}
+    sc_signal(const sc_signal<bool, WRITER_POLICY> &);
 };
 
 template <sc_writer_policy WRITER_POLICY>
 class sc_signal<sc_dt::sc_logic, WRITER_POLICY> :
-    public sc_signal_inout_if<sc_dt::sc_logic>, public sc_prim_channel
+    public sc_gem5::ScSignalBinary<sc_dt::sc_logic, WRITER_POLICY>
 {
   public:
-    sc_signal() : sc_signal_inout_if<sc_dt::sc_logic>(),
-                  sc_prim_channel(sc_gen_unique_name("signal")),
-                  m_cur_val(sc_dt::sc_logic()), m_new_val(sc_dt::sc_logic()),
-                  _changeStamp(~0ULL), _posStamp(~0ULL), _negStamp(~0ULL),
-                  _gem5Writer(NULL)
+    sc_signal() :
+        sc_gem5::ScSignalBinary<sc_dt::sc_logic, WRITER_POLICY>(
+                sc_gen_unique_name("signal"))
     {}
     explicit sc_signal(const char *name) :
-        sc_signal_inout_if<sc_dt::sc_logic>(), sc_prim_channel(name),
-        m_cur_val(sc_dt::sc_logic()), m_new_val(sc_dt::sc_logic()),
-        _changeStamp(~0ULL), _posStamp(~0ULL), _negStamp(~0ULL),
-        _gem5Writer(NULL)
+        sc_gem5::ScSignalBinary<sc_dt::sc_logic, WRITER_POLICY>(name)
     {}
     explicit sc_signal(const char *name,
             const sc_dt::sc_logic &initial_value) :
-        sc_signal_inout_if<sc_dt::sc_logic>(), sc_prim_channel(name),
-        m_cur_val(initial_value), m_new_val(initial_value),
-        _changeStamp(~0ULL), _posStamp(~0ULL), _negStamp(~0ULL),
-        _gem5Writer(NULL)
+        sc_gem5::ScSignalBinary<sc_dt::sc_logic, WRITER_POLICY>(
+                name, initial_value)
     {}
     virtual ~sc_signal() {}
 
-    virtual void
-    register_port(sc_port_base &port, const char *iface_type_name)
-    {
-        if (WRITER_POLICY == SC_ONE_WRITER &&
-                std::string(iface_type_name) ==
-                typeid(sc_signal_inout_if<sc_dt::sc_logic>).name()) {
-            if (_gem5Writer) {
-                std::ostringstream ss;
-                ss << "\n signal " << "`" << name() << "' (" <<
-                    kind() << ")";
-                ss << "\n first driver `" << _gem5Writer->name() << "'  (" <<
-                    _gem5Writer->kind() << ")";
-                ss << "\n second driver `" << port.name() << "' (" <<
-                    port.kind() << ")";
-                SC_REPORT_ERROR(
-                        "(E115) sc_signal<T> cannot have more than one driver",
-                        ss.str().c_str());
-            }
-            _gem5Writer = &port;
-        }
-    }
-
-    virtual const sc_dt::sc_logic &read() const { return m_cur_val; }
-    operator const sc_dt::sc_logic &() const { return read(); }
-
-    virtual sc_writer_policy
-    get_writer_policy() const
-    {
-        return WRITER_POLICY;
-    }
-    virtual void
-    write(const sc_dt::sc_logic &l)
-    {
-        m_new_val = l;
-        bool changed = !(m_cur_val == m_new_val);
-        //TODO check whether this write follows the write policy.
-        if (changed)
-            request_update();
-    }
     sc_signal<sc_dt::sc_logic, WRITER_POLICY> &
     operator = (const sc_dt::sc_logic &l)
     {
-        write(l);
+        this->write(l);
         return *this;
     }
     sc_signal<sc_dt::sc_logic, WRITER_POLICY> &
     operator = (const sc_signal<sc_dt::sc_logic, WRITER_POLICY> &s)
     {
-        write(s.read());
+        this->write(s.read());
         return *this;
     }
 
-    virtual const sc_event &
-    default_event() const
-    {
-        return value_changed_event();
-    }
-
-    virtual const sc_event &
-    value_changed_event() const
-    {
-        return _valueChangedEvent;
-    }
-    virtual const sc_event &
-    posedge_event() const
-    {
-        return _posedgeEvent;
-    }
-    virtual const sc_event &
-    negedge_event() const
-    {
-        return _negedgeEvent;
-    }
-
-    virtual bool
-    event() const
-    {
-        return _changeStamp == ::sc_gem5::getChangeStamp();
-    }
-    virtual bool
-    posedge() const
-    {
-        return _posStamp == ::sc_gem5::getChangeStamp();
-    }
-    virtual bool
-    negedge() const
-    {
-        return _negStamp == ::sc_gem5::getChangeStamp();
-    }
-
-    virtual void print(std::ostream &os=std::cout) const { os << m_cur_val; }
-    virtual void
-    dump(std::ostream &os=std::cout) const
-    {
-        os << "     name = " << name() << ::std::endl;
-        os << "    value = " << m_cur_val << ::std::endl;
-        os << "new value = " << m_new_val << ::std::endl;
-    }
-    virtual const char *kind() const { return "sc_signal"; }
-
   protected:
     virtual void
     update()
     {
-        if (m_new_val == m_cur_val)
+        if (this->m_new_val == this->m_cur_val)
             return;
 
-        m_cur_val = m_new_val;
-        _signalChange();
-        if (m_cur_val == sc_dt::SC_LOGIC_1) {
-            _posStamp = ::sc_gem5::getChangeStamp();
-            _posedgeEvent.notify(SC_ZERO_TIME);
-        } else if (m_cur_val == sc_dt::SC_LOGIC_0) {
-            _negStamp = ::sc_gem5::getChangeStamp();
-            _negedgeEvent.notify(SC_ZERO_TIME);
+        this->m_cur_val = this->m_new_val;
+        this->_signalChange();
+        if (this->m_cur_val == sc_dt::SC_LOGIC_1) {
+            this->_posStamp = ::sc_gem5::getChangeStamp();
+            this->_posedgeEvent.notify(SC_ZERO_TIME);
+        } else if (this->m_cur_val == sc_dt::SC_LOGIC_0) {
+            this->_negStamp = ::sc_gem5::getChangeStamp();
+            this->_negedgeEvent.notify(SC_ZERO_TIME);
         }
     }
 
-    void
-    _signalChange()
-    {
-        _changeStamp = ::sc_gem5::getChangeStamp();
-        _valueChangedEvent.notify(SC_ZERO_TIME);
-    }
-
-    sc_dt::sc_logic m_cur_val;
-    sc_dt::sc_logic m_new_val;
-
   private:
-    sc_event _valueChangedEvent;
-    sc_event _posedgeEvent;
-    sc_event _negedgeEvent;
-
-    uint64_t _changeStamp;
-    uint64_t _posStamp;
-    uint64_t _negStamp;
-
-    sc_port_base *_gem5Writer;
-
     // Disabled
-    sc_signal(const sc_signal<sc_dt::sc_logic, WRITER_POLICY> &) :
-            sc_signal_inout_if<sc_dt::sc_logic>(), sc_prim_channel("")
-    {}
+    sc_signal(const sc_signal<sc_dt::sc_logic, WRITER_POLICY> &);
 };
 
 } // namespace sc_core
diff --git a/src/systemc/tests/systemc/communication/sc_signal/check_writer/test01/expected_returncode b/src/systemc/tests/systemc/communication/sc_signal/check_writer/test01/expected_returncode
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/systemc/tests/systemc/communication/sc_signal/check_writer/test01/expected_returncode
@@ -0,0 +1 @@
+1
diff --git a/src/systemc/tests/systemc/communication/sc_signal/check_writer/test02/expected_returncode b/src/systemc/tests/systemc/communication/sc_signal/check_writer/test02/expected_returncode
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/systemc/tests/systemc/communication/sc_signal/check_writer/test02/expected_returncode
@@ -0,0 +1 @@
+1
diff --git a/src/systemc/tests/systemc/communication/sc_signal/check_writer/test03/expected_returncode b/src/systemc/tests/systemc/communication/sc_signal/check_writer/test03/expected_returncode
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/systemc/tests/systemc/communication/sc_signal/check_writer/test03/expected_returncode
@@ -0,0 +1 @@
+1
diff --git a/src/systemc/tests/systemc/communication/sc_signal/check_writer/test04/expected_returncode b/src/systemc/tests/systemc/communication/sc_signal/check_writer/test04/expected_returncode
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/systemc/tests/systemc/communication/sc_signal/check_writer/test04/expected_returncode
@@ -0,0 +1 @@
+1
diff --git a/src/systemc/tests/systemc/communication/sc_signal/check_writer/test05/expected_returncode b/src/systemc/tests/systemc/communication/sc_signal/check_writer/test05/expected_returncode
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/systemc/tests/systemc/communication/sc_signal/check_writer/test05/expected_returncode
@@ -0,0 +1 @@
+1
diff --git a/src/systemc/tests/systemc/communication/sc_signal/check_writer/test07/expected_returncode b/src/systemc/tests/systemc/communication/sc_signal/check_writer/test07/expected_returncode
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/systemc/tests/systemc/communication/sc_signal/check_writer/test07/expected_returncode
@@ -0,0 +1 @@
+1
diff --git a/src/systemc/tests/systemc/communication/sc_signal/check_writer/test14/expected_returncode b/src/systemc/tests/systemc/communication/sc_signal/check_writer/test14/expected_returncode
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/systemc/tests/systemc/communication/sc_signal/check_writer/test14/expected_returncode
@@ -0,0 +1 @@
+1
diff --git a/src/systemc/tests/systemc/communication/sc_signal/check_writer/test16/expected_returncode b/src/systemc/tests/systemc/communication/sc_signal/check_writer/test16/expected_returncode
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/src/systemc/tests/systemc/communication/sc_signal/check_writer/test16/expected_returncode
@@ -0,0 +1 @@
+1