mem, sim, systemc: Reorganize Port and co.s bind, unbind slightly.

The base Port class can keep track of its peer, and also whether it's
connected. This is partially delegated away from the port subclasses
which still keep track of a cast version of their peer pointer for
their own conveneince, so that it can be used by generic code. Even
with the Port mechanism's new flexibility, each port still has
exactly one peer and is either connected or not based on whether there
is a peer currently.

Change-Id: Id3228617dd1604d196814254a1aadeac5ade7cde
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/20232
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Gabe Black <gabeblack@google.com>
diff --git a/src/mem/port.cc b/src/mem/port.cc
index 40481b0..303d1bc 100644
--- a/src/mem/port.cc
+++ b/src/mem/port.cc
@@ -70,6 +70,22 @@
     return *_baseSlavePort;
 }
 
+void
+BaseMasterPort::bind(Port &peer)
+{
+    _baseSlavePort = dynamic_cast<BaseSlavePort *>(&peer);
+    fatal_if(!_baseSlavePort, "Attempt to bind port %s to non-master port %s.",
+             name(), peer.name());
+    Port::bind(peer);
+}
+
+void
+BaseMasterPort::unbind()
+{
+    _baseSlavePort = nullptr;
+    Port::unbind();
+}
+
 BaseSlavePort::BaseSlavePort(const std::string &name, PortID _id)
     : Port(name, _id), _baseMasterPort(NULL)
 {
@@ -89,6 +105,22 @@
     return *_baseMasterPort;
 }
 
+void
+BaseSlavePort::bind(Port &peer)
+{
+    _baseMasterPort = dynamic_cast<BaseMasterPort *>(&peer);
+    fatal_if(!_baseMasterPort, "Attempt to bind port %s to non-slave port %s.",
+             name(), peer.name());
+    Port::bind(peer);
+}
+
+void
+BaseSlavePort::unbind()
+{
+    _baseMasterPort = nullptr;
+    Port::unbind();
+}
+
 /**
  * Master port
  */
@@ -109,12 +141,9 @@
         fatal("Attempt to bind port %s to non-slave port %s.",
                 name(), peer.name());
     }
-    // bind on the level of the base ports
-    _baseSlavePort = slave_port;
-
     // master port keeps track of the slave port
     _slavePort = slave_port;
-    _connected = true;
+    BaseMasterPort::bind(peer);
     // slave port also keeps track of master port
     _slavePort->slaveBind(*this);
 }
@@ -126,9 +155,8 @@
         panic("Attempting to unbind master port %s that is not connected\n",
               name());
     _slavePort->slaveUnbind();
-    _slavePort = NULL;
-    _connected = false;
-    _baseSlavePort = NULL;
+    _slavePort = nullptr;
+    BaseMasterPort::unbind();
 }
 
 AddrRangeList
@@ -166,17 +194,15 @@
 void
 SlavePort::slaveUnbind()
 {
-    _baseMasterPort = NULL;
     _masterPort = NULL;
-    _connected = false;
+    BaseSlavePort::unbind();
 }
 
 void
 SlavePort::slaveBind(MasterPort& master_port)
 {
-    _baseMasterPort = &master_port;
     _masterPort = &master_port;
-    _connected = true;
+    BaseSlavePort::bind(master_port);
 }
 
 Tick
diff --git a/src/mem/port.hh b/src/mem/port.hh
index 847bd1e..0b589da 100644
--- a/src/mem/port.hh
+++ b/src/mem/port.hh
@@ -78,6 +78,8 @@
 
   public:
     BaseSlavePort& getSlavePort() const;
+    void bind(Port &peer) override;
+    void unbind() override;
 };
 
 /**
@@ -94,6 +96,8 @@
 
   public:
     BaseMasterPort& getMasterPort() const;
+    void bind(Port &peer) override;
+    void unbind() override;
 };
 
 /** Forward declaration */
diff --git a/src/sim/port.cc b/src/sim/port.cc
index b3139a6..fa7df18 100644
--- a/src/sim/port.cc
+++ b/src/sim/port.cc
@@ -50,6 +50,6 @@
 #include "sim/port.hh"
 
 Port::Port(const std::string& _name, PortID _id) :
-    portName(_name), id(_id), _connected(false)
+    portName(_name), id(_id), _peer(nullptr), _connected(false)
 {}
 Port::~Port() {}
diff --git a/src/sim/port.hh b/src/sim/port.hh
index e181164..ee4b548 100644
--- a/src/sim/port.hh
+++ b/src/sim/port.hh
@@ -72,6 +72,13 @@
      * to InvalidPortID in case this port is not part of a vector.
      */
     const PortID id;
+
+    /**
+     * A pointer to this port's peer.
+     */
+    Port *_peer;
+
+
     /**
      * Whether this port is currently connected to a peer port.
      */
@@ -92,6 +99,9 @@
 
   public:
 
+    /** Return a reference to this port's peer. */
+    Port &getPeer() { return *_peer; }
+
     /** Return port name (for DPRINTF). */
     const std::string name() const { return portName; }
 
@@ -99,10 +109,20 @@
     PortID getId() const { return id; }
 
     /** Attach to a peer port. */
-    virtual void bind(Port &peer) = 0;
+    virtual void
+    bind(Port &peer)
+    {
+        _peer = &peer;
+        _connected = true;
+    }
 
     /** Dettach from a peer port. */
-    virtual void unbind() = 0;
+    virtual void
+    unbind()
+    {
+        _peer = nullptr;
+        _connected = false;
+    }
 
     /** Is this port currently connected to a peer? */
     bool isConnected() const { return _connected; }
diff --git a/src/systemc/sc_port_wrapper.hh b/src/systemc/sc_port_wrapper.hh
index b6f6f85..9f7d80d 100644
--- a/src/systemc/sc_port_wrapper.hh
+++ b/src/systemc/sc_port_wrapper.hh
@@ -85,6 +85,7 @@
             fatal("Attempt to bind sc_port %s to incompatible port %s.",
                   name(), peer.name());
         }
+        Port::bind(peer);
     }
 
   private:
@@ -123,6 +124,7 @@
         // Don't bind to peer otherwise we may have error messages saying that
         // this interface has already be bound since the peer may already did
         // that. Just let sc_port or sc_export do the binding
+        Port::bind(peer);
     }
 
   private:
@@ -160,6 +162,7 @@
                  name(), peer.name());
 
         port_.bind(iface->interface());
+        Port::bind(peer);
     }
 
   private:
diff --git a/src/systemc/tlm_port_wrapper.hh b/src/systemc/tlm_port_wrapper.hh
index 0553a18..59f8d9f 100644
--- a/src/systemc/tlm_port_wrapper.hh
+++ b/src/systemc/tlm_port_wrapper.hh
@@ -74,6 +74,7 @@
                 "incompatible port %s.", name(), peer.name());
 
         initiator().bind(target->target());
+        Port::bind(peer);
     }
 
     void
@@ -107,6 +108,7 @@
     {
         // Ignore attempts to bind a target socket. The initiator will
         // handle it.
+        Port::bind(peer);
     }
 
     void