dev: Templatize PioPort.
authorGabe Black <gabeblack@google.com>
Tue, 3 Sep 2019 04:41:53 +0000 (21:41 -0700)
committerGabe Black <gabeblack@google.com>
Wed, 4 Sep 2019 02:30:01 +0000 (02:30 +0000)
When creating a base class which needs to be a SimObject, it's
necessary to decide ahead of time whether to use PioDevice or
BasicPioDevice in the hierarchy because they inherit from SimObject. If
they were added into the hierarchy later, then the original class would
inherit from SimObject, as would PioDevice. That would create a diamond
inheritance structure which would require virtual inheritance, and
that's a can of worms we'd rather not get into.

A big part of the PioPort mechanism is the PioPort itself which holds
a pointer to its parent device and delegates reads/writes to it. It
does that with a PioDevice pointer, and PioDevice declares virtual
functions for all the callbacks the port can call into.

Instead of that, this change templatizes PioPort based on the class of
the device that holds it. That will let you use a PioPort on *any*
class, as long as it has the methods PioPort depends on. That removes
the need to create an inheritance diamond to add a PioPort down the
line since PioDevice is no longer strictly required.

The PioDevice and BasicPioDevice classes are still around since they
still provide some additional functionality and there are existing
classes which depend on them.

Change-Id: I753afc1e0fa54b91217d54c1f8743c150537e960
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/20568
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Maintainer: Jason Lowe-Power <jason@lowepower.com>
Tested-by: kokoro <noreply+kokoro@google.com>
src/dev/io_device.cc
src/dev/io_device.hh

index 425c2f41f7748abba3e52b9b1c7078f778f7b548..64550eadea80da822dd4bef35ee8aa473649d26a 100644 (file)
 #include "debug/AddrRanges.hh"
 #include "sim/system.hh"
 
-PioPort::PioPort(PioDevice *dev)
-    : SimpleTimingPort(dev->name() + ".pio", dev), device(dev)
-{
-}
-
-Tick
-PioPort::recvAtomic(PacketPtr pkt)
-{
-    // technically the packet only reaches us after the header delay,
-    // and typically we also need to deserialise any payload
-    Tick receive_delay = pkt->headerDelay + pkt->payloadDelay;
-    pkt->headerDelay = pkt->payloadDelay = 0;
-
-    const Tick delay(pkt->isRead() ? device->read(pkt) : device->write(pkt));
-    assert(pkt->isResponse() || pkt->isError());
-    return delay + receive_delay;
-}
-
-AddrRangeList
-PioPort::getAddrRanges() const
-{
-    return device->getAddrRanges();
-}
-
 PioDevice::PioDevice(const Params *p)
     : ClockedObject(p), sys(p->system), pioPort(this)
 {}
index c9e25d224ac6c949df20c6e69a430ffbb111fa17..804133893275e694d81c5c5186c6501546efc158 100644 (file)
@@ -59,19 +59,37 @@ class System;
  * must respond to. The device must also provide getAddrRanges() function
  * with which it returns the address ranges it is interested in.
  */
+template <class Device>
 class PioPort : public SimpleTimingPort
 {
   protected:
     /** The device that this port serves. */
-    PioDevice *device;
+    Device *device;
 
-    virtual Tick recvAtomic(PacketPtr pkt);
+    Tick
+    recvAtomic(PacketPtr pkt) override
+    {
+        // Technically the packet only reaches us after the header delay,
+        // and typically we also need to deserialise any payload.
+        Tick receive_delay = pkt->headerDelay + pkt->payloadDelay;
+        pkt->headerDelay = pkt->payloadDelay = 0;
+
+        const Tick delay =
+            pkt->isRead() ? device->read(pkt) : device->write(pkt);
+        assert(pkt->isResponse() || pkt->isError());
+        return delay + receive_delay;
+    }
 
-    virtual AddrRangeList getAddrRanges() const;
+    AddrRangeList
+    getAddrRanges() const override
+    {
+        return device->getAddrRanges();
+    }
 
   public:
-
-    PioPort(PioDevice *dev);
+    PioPort(Device *dev) :
+        SimpleTimingPort(dev->name() + ".pio", dev), device(dev)
+    {}
 };
 
 /**
@@ -88,7 +106,7 @@ class PioDevice : public ClockedObject
 
     /** The pioPort that handles the requests for us and provides us requests
      * that it sees. */
-    PioPort pioPort;
+    PioPort<PioDevice> pioPort;
 
     /**
      * Every PIO device is obliged to provide an implementation that
@@ -128,7 +146,7 @@ class PioDevice : public ClockedObject
     Port &getPort(const std::string &if_name,
             PortID idx=InvalidPortID) override;
 
-    friend class PioPort;
+    friend class PioPort<PioDevice>;
 
 };
 
@@ -159,8 +177,7 @@ class BasicPioDevice : public PioDevice
      *
      * @return a list of non-overlapping address ranges
      */
-    virtual AddrRangeList getAddrRanges() const;
-
+    AddrRangeList getAddrRanges() const override;
 };
 
 #endif // __DEV_IO_DEVICE_HH__