mem: Make PortProxy use a delegate for a sendFunctional function.

The only part of the MaserPort the PortProxy uses is the sendFunctional
function which is part of the functional protocol. Rather than require
a MasterPort which comes along with a lot of other mechanisms, this
change slightly adjusts the PortProxy to only require that function
through the use of a delegate. That allows lots of flexibility in how
the actual packet gets sent and what sends it.

In cases where code constructs a PortProxy and passes its constructor
an unbound MasterPort, the PortProxy will create a delegate to the
sendFunctional method on its own.

This should also make it easier for objects which don't have
traditional gem5 style ports, for instance systemc models, to implement
just the little bit of the protocol they need, rather than having to
stub out a whole port class, most of which will be ignored.

Change-Id: I234b42ce050f12313b551a61736186ddf2c9e2c7
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/20229
Maintainer: Gabe Black <gabeblack@google.com>
Reviewed-by: Gabe Black <gabeblack@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
diff --git a/src/mem/fs_translating_port_proxy.cc b/src/mem/fs_translating_port_proxy.cc
index 6a25d11..d12af13 100644
--- a/src/mem/fs_translating_port_proxy.cc
+++ b/src/mem/fs_translating_port_proxy.cc
@@ -60,8 +60,14 @@
 {
 }
 
-FSTranslatingPortProxy::FSTranslatingPortProxy(MasterPort &port,
-                                               unsigned int cacheLineSize)
+FSTranslatingPortProxy::FSTranslatingPortProxy(
+        SendFunctionalFunc func, unsigned int cacheLineSize)
+    : PortProxy(func, cacheLineSize), _tc(NULL)
+{
+}
+
+FSTranslatingPortProxy::FSTranslatingPortProxy(
+        MasterPort &port, unsigned int cacheLineSize)
     : PortProxy(port, cacheLineSize), _tc(NULL)
 {
 }
diff --git a/src/mem/fs_translating_port_proxy.hh b/src/mem/fs_translating_port_proxy.hh
index 410eb7d..2ecd742 100644
--- a/src/mem/fs_translating_port_proxy.hh
+++ b/src/mem/fs_translating_port_proxy.hh
@@ -79,7 +79,10 @@
 
     FSTranslatingPortProxy(ThreadContext* tc);
 
-    FSTranslatingPortProxy(MasterPort &port, unsigned int cacheLineSize);
+    FSTranslatingPortProxy(SendFunctionalFunc func,
+                           unsigned int cacheLineSize);
+    FSTranslatingPortProxy(MasterPort &port,
+                           unsigned int cacheLineSize);
 
     ~FSTranslatingPortProxy() {}
 
diff --git a/src/mem/port_proxy.cc b/src/mem/port_proxy.cc
index 60f79e3..b630d31 100644
--- a/src/mem/port_proxy.cc
+++ b/src/mem/port_proxy.cc
@@ -53,7 +53,7 @@
 
         Packet pkt(req, MemCmd::ReadReq);
         pkt.dataStatic(static_cast<uint8_t *>(p));
-        _port.sendFunctional(&pkt);
+        sendFunctional(&pkt);
         p = static_cast<uint8_t *>(p) + gen.size();
     }
 }
@@ -70,7 +70,7 @@
 
         Packet pkt(req, MemCmd::WriteReq);
         pkt.dataStaticConst(static_cast<const uint8_t *>(p));
-        _port.sendFunctional(&pkt);
+        sendFunctional(&pkt);
         p = static_cast<const uint8_t *>(p) + gen.size();
     }
 }
diff --git a/src/mem/port_proxy.hh b/src/mem/port_proxy.hh
index 61a2071..31ac3e9 100644
--- a/src/mem/port_proxy.hh
+++ b/src/mem/port_proxy.hh
@@ -59,38 +59,53 @@
 #ifndef __MEM_PORT_PROXY_HH__
 #define __MEM_PORT_PROXY_HH__
 
+#include <functional>
 #include <limits>
 
 #include "mem/port.hh"
 #include "sim/byteswap.hh"
 
 /**
- * This object is a proxy for a structural port, to be used for debug
- * accesses.
+ * This object is a proxy for a port or other object which implements the
+ * functional response protocol, to be used for debug accesses.
  *
  * This proxy object is used when non structural entities
  * (e.g. thread contexts, object file loaders) need access to the
  * memory system. It calls the corresponding functions on the underlying
- * structural port, and provides templatized convenience access functions.
+ * protocol, and provides templatized convenience access functions.
  *
  * The addresses are interpreted as physical addresses.
  *
  * @sa SETranslatingProxy
  * @sa FSTranslatingProxy
  */
-class PortProxy
+class PortProxy : FunctionalRequestProtocol
 {
-  private:
+  public:
+    typedef std::function<void(PacketPtr pkt)> SendFunctionalFunc;
 
-    /** The actual physical port used by this proxy. */
-    MasterPort &_port;
+  private:
+    SendFunctionalFunc sendFunctional;
 
     /** Granularity of any transactions issued through this proxy. */
     const unsigned int _cacheLineSize;
 
+    void
+    recvFunctionalSnoop(PacketPtr pkt) override
+    {
+        // Since port proxies aren't anyone else's peer, they should never
+        // receive snoops.
+        panic("Port proxies should never receive snoops.");
+    }
+
   public:
-    PortProxy(MasterPort &port, unsigned int cacheLineSize) :
-        _port(port), _cacheLineSize(cacheLineSize)
+    PortProxy(SendFunctionalFunc func, unsigned int cacheLineSize) :
+        sendFunctional(func), _cacheLineSize(cacheLineSize)
+    {}
+    PortProxy(const MasterPort &port, unsigned int cacheLineSize) :
+        sendFunctional([&port](PacketPtr pkt)->void {
+                port.sendFunctional(pkt);
+            }), _cacheLineSize(cacheLineSize)
     {}
     virtual ~PortProxy() { }
 
diff --git a/src/mem/se_translating_port_proxy.cc b/src/mem/se_translating_port_proxy.cc
index c5f38f1..94d2ab3 100644
--- a/src/mem/se_translating_port_proxy.cc
+++ b/src/mem/se_translating_port_proxy.cc
@@ -55,8 +55,13 @@
 
 using namespace TheISA;
 
-SETranslatingPortProxy::SETranslatingPortProxy(MasterPort& port, Process *p,
-                                           AllocType alloc)
+SETranslatingPortProxy::SETranslatingPortProxy(
+        SendFunctionalFunc func, Process *p, AllocType alloc)
+    : PortProxy(func, p->system->cacheLineSize()), pTable(p->pTable),
+      process(p), allocating(alloc)
+{ }
+SETranslatingPortProxy::SETranslatingPortProxy(MasterPort &port,
+                                               Process *p, AllocType alloc)
     : PortProxy(port, p->system->cacheLineSize()), pTable(p->pTable),
       process(p), allocating(alloc)
 { }
diff --git a/src/mem/se_translating_port_proxy.hh b/src/mem/se_translating_port_proxy.hh
index 718e44a..e32f1d0 100644
--- a/src/mem/se_translating_port_proxy.hh
+++ b/src/mem/se_translating_port_proxy.hh
@@ -80,7 +80,9 @@
     AllocType allocating;
 
   public:
-    SETranslatingPortProxy(MasterPort& port, Process* p, AllocType alloc);
+    SETranslatingPortProxy(SendFunctionalFunc func,
+                           Process* p, AllocType alloc);
+    SETranslatingPortProxy(MasterPort &port, Process* p, AllocType alloc);
     ~SETranslatingPortProxy() {}
 
     void setPageTable(EmulationPageTable *p) { pTable = p; }
diff --git a/src/mem/secure_port_proxy.hh b/src/mem/secure_port_proxy.hh
index 9a2200c..5ce0c29 100644
--- a/src/mem/secure_port_proxy.hh
+++ b/src/mem/secure_port_proxy.hh
@@ -70,8 +70,7 @@
 class SecurePortProxy : public PortProxy
 {
   public:
-    SecurePortProxy(MasterPort &port, unsigned int cache_line_size)
-        : PortProxy(port, cache_line_size) {}
+    using PortProxy::PortProxy;
 
     bool tryReadBlob(Addr addr, void *p, int size) const override;
     bool tryWriteBlob(Addr addr, const void *p, int size) const override;