Move more common functionality into SimpleTimingPort,
authorSteve Reinhardt <stever@eecs.umich.edu>
Wed, 30 Aug 2006 23:24:26 +0000 (16:24 -0700)
committerSteve Reinhardt <stever@eecs.umich.edu>
Wed, 30 Aug 2006 23:24:26 +0000 (16:24 -0700)
allowing derived classes to be simplified.

--HG--
extra : convert_revision : c980d3aec5e6c044d8f41e96252726fe9a256605

src/dev/io_device.cc
src/dev/io_device.hh
src/dev/pcidev.cc
src/dev/pcidev.hh
src/mem/physical.cc
src/mem/physical.hh
src/mem/port.hh
src/mem/tport.cc
src/mem/tport.hh

index b06e8b85d4580ffc8e0e5f15e9c8e52198fc166a..408d8de3edd6e09034ad50f1c9d7529db44cd10e 100644 (file)
 
 
 PioPort::PioPort(PioDevice *dev, System *s, std::string pname)
-    : SimpleTimingPort(dev->name() + pname), device(dev), sys(s)
+    : SimpleTimingPort(dev->name() + pname), device(dev)
 { }
 
 
 Tick
 PioPort::recvAtomic(Packet *pkt)
 {
-    return device->recvAtomic(pkt);
-}
-
-void
-PioPort::recvFunctional(Packet *pkt)
-{
-    device->recvAtomic(pkt);
+    return pkt->isRead() ? device->read(pkt) : device->write(pkt);
 }
 
 void
@@ -61,20 +55,6 @@ PioPort::getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
 }
 
 
-bool
-PioPort::recvTiming(Packet *pkt)
-{
-    if (pkt->result == Packet::Nacked) {
-        resendNacked(pkt);
-    } else {
-        Tick latency = device->recvAtomic(pkt);
-        // turn packet around to go back to requester
-        pkt->makeTimingResponse();
-        sendTiming(pkt, latency);
-    }
-    return true;
-}
-
 PioDevice::~PioDevice()
 {
     if (pioPort)
index d91304301138c2322a93c7b369fcc842384a4927..df4f494cb2c9588b7e6243461e417bca09858d5b 100644 (file)
@@ -56,28 +56,14 @@ class PioPort : public SimpleTimingPort
     /** The device that this port serves. */
     PioDevice *device;
 
-    /** The system that device/port are in. This is used to select which mode
-     * we are currently operating in. */
-    System *sys;
-
-    /** The current status of the peer(bus) that we are connected to. */
-    Status peerStatus;
-
-    virtual bool recvTiming(Packet *pkt);
-
     virtual Tick recvAtomic(Packet *pkt);
 
-    virtual void recvFunctional(Packet *pkt) ;
-
-    virtual void recvStatusChange(Status status)
-    { peerStatus = status; }
-
     virtual void getDeviceAddressRanges(AddrRangeList &resp,
                                         AddrRangeList &snoop);
 
   public:
-    PioPort(PioDevice *dev, System *s, std::string pname = "-pioport");
 
+    PioPort(PioDevice *dev, System *s, std::string pname = "-pioport");
 };
 
 
@@ -172,12 +158,6 @@ class PioDevice : public MemObject
 
     virtual void addressRanges(AddrRangeList &range_list) = 0;
 
-    /** As far as the devices are concerned they only accept atomic
-     * transactions which are converted to either a write or a
-     * read. */
-    Tick recvAtomic(Packet *pkt)
-    { return pkt->isRead() ? this->read(pkt) : this->write(pkt); }
-
     /** Pure virtual function that the device must implement. Called
      * when a read command is recieved by the port.
      * @param pkt Packet describing this request
index a8fb44c39d5f8c4aa113829a39e87111f0681f69..8ea22cb247d0b927cc326e9e3ebdb3e140990eff 100644 (file)
@@ -57,8 +57,8 @@ using namespace std;
 
 PciDev::PciConfigPort::PciConfigPort(PciDev *dev, int busid, int devid,
         int funcid, Platform *p)
-        : PioPort(dev,p->system,"-pciconf"), device(dev), platform(p),
-          busId(busid), deviceId(devid), functionId(funcid)
+    : SimpleTimingPort(dev->name() + "-pciconf"), device(dev), platform(p),
+      busId(busid), deviceId(devid), functionId(funcid)
 {
     configAddr = platform->calcConfigAddr(busId, deviceId, functionId);
 }
@@ -70,16 +70,7 @@ PciDev::PciConfigPort::recvAtomic(Packet *pkt)
     assert(pkt->result == Packet::Unknown);
     assert(pkt->getAddr() >= configAddr &&
            pkt->getAddr() < configAddr + PCI_CONFIG_SIZE);
-    return device->recvConfig(pkt);
-}
-
-void
-PciDev::PciConfigPort::recvFunctional(Packet *pkt)
-{
-    assert(pkt->result == Packet::Unknown);
-    assert(pkt->getAddr() >= configAddr &&
-           pkt->getAddr() < configAddr + PCI_CONFIG_SIZE);
-    device->recvConfig(pkt);
+    return pkt->isRead() ? device->readConfig(pkt) : device->writeConfig(pkt);
 }
 
 void
@@ -91,23 +82,6 @@ PciDev::PciConfigPort::getDeviceAddressRanges(AddrRangeList &resp,
 }
 
 
-bool
-PciDev::PciConfigPort::recvTiming(Packet *pkt)
-{
-    if (pkt->result == Packet::Nacked) {
-        resendNacked(pkt);
-    } else {
-        assert(pkt->result == Packet::Unknown);
-        assert(pkt->getAddr() >= configAddr &&
-               pkt->getAddr() < configAddr + PCI_CONFIG_SIZE);
-        Tick latency = device->recvConfig(pkt);
-        // turn packet around to go back to requester
-        pkt->makeTimingResponse();
-        sendTiming(pkt, latency);
-    }
-    return true;
-}
-
 PciDev::PciDev(Params *p)
     : DmaDevice(p), plat(p->platform), configData(p->configData),
       pioDelay(p->pio_delay), configDelay(p->config_delay),
index 8e4f003b022fb09ee9ed551c72a7bf6415133200..22dd6296e630b452f5268285ff7fc0efb4fb4af6 100644 (file)
@@ -78,17 +78,13 @@ class PciConfigData : public SimObject
  */
 class PciDev : public DmaDevice
 {
-    class PciConfigPort : public PioPort
+    class PciConfigPort : public SimpleTimingPort
     {
       protected:
         PciDev *device;
 
-        virtual bool recvTiming(Packet *pkt);
-
         virtual Tick recvAtomic(Packet *pkt);
 
-        virtual void recvFunctional(Packet *pkt) ;
-
         virtual void getDeviceAddressRanges(AddrRangeList &resp,
                                             AddrRangeList &snoop);
 
@@ -102,9 +98,7 @@ class PciDev : public DmaDevice
 
       public:
         PciConfigPort(PciDev *dev, int busid, int devid, int funcid,
-                Platform *p);
-
-        friend class PioPort::SendEvent;
+                      Platform *p);
     };
 
   public:
@@ -239,10 +233,6 @@ class PciDev : public DmaDevice
      */
     void addressRanges(AddrRangeList &range_list);
 
-    /** Do a PCI Configspace memory access. */
-    Tick recvConfig(Packet *pkt)
-    { return pkt->isRead() ? readConfig(pkt) : writeConfig(pkt); }
-
     /**
      * Constructor for PCI Dev. This function copies data from the
      * config file object PCIConfigData and registers the device with
index f4fbd2fb19cadea83f597fa8fdb65350cc717e35..8fea733ec37ef443cdf146aa701baa38478f04e6 100644 (file)
@@ -182,7 +182,8 @@ PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
 {
     snoop.clear();
     resp.clear();
-    resp.push_back(RangeSize(params()->addrRange.start, params()->addrRange.size()));
+    resp.push_back(RangeSize(params()->addrRange.start,
+                             params()->addrRange.size()));
 }
 
 int
@@ -191,21 +192,6 @@ PhysicalMemory::MemoryPort::deviceBlockSize()
     return memory->deviceBlockSize();
 }
 
-bool
-PhysicalMemory::MemoryPort::recvTiming(Packet *pkt)
-{
-    assert(pkt->result != Packet::Nacked);
-
-    Tick latency = memory->calculateLatency(pkt);
-
-    memory->doFunctionalAccess(pkt);
-
-    pkt->makeTimingResponse();
-    sendTiming(pkt, latency);
-
-    return true;
-}
-
 Tick
 PhysicalMemory::MemoryPort::recvAtomic(Packet *pkt)
 {
@@ -216,6 +202,9 @@ PhysicalMemory::MemoryPort::recvAtomic(Packet *pkt)
 void
 PhysicalMemory::MemoryPort::recvFunctional(Packet *pkt)
 {
+    // Default implementation of SimpleTimingPort::recvFunctional()
+    // calls recvAtomic() and throws away the latency; we can save a
+    // little here by just not calculating the latency.
     memory->doFunctionalAccess(pkt);
 }
 
index 1489e67002ae6684a89c9ba4f6cc512d4edd122e..02308b2ef90355ddf9a24676429b94acf52f952b 100644 (file)
@@ -57,8 +57,6 @@ class PhysicalMemory : public MemObject
 
       protected:
 
-        virtual bool recvTiming(Packet *pkt);
-
         virtual Tick recvAtomic(Packet *pkt);
 
         virtual void recvFunctional(Packet *pkt);
index 80c591f82923609db18f2b40a62cbbca558525ee..6b4184043f5a31870eb7d5b78c68abcd478294d5 100644 (file)
@@ -252,11 +252,13 @@ class FunctionalPort : public Port
         : Port(_name)
     {}
 
+  protected:
     virtual bool recvTiming(Packet *pkt) { panic("FuncPort is UniDir"); }
     virtual Tick recvAtomic(Packet *pkt) { panic("FuncPort is UniDir"); }
     virtual void recvFunctional(Packet *pkt) { panic("FuncPort is UniDir"); }
     virtual void recvStatusChange(Status status) {}
 
+  public:
     /** a write function that also does an endian conversion. */
     template <typename T>
     inline void writeHtoG(Addr addr, T d);
index 90cf68f02a0d142e4c0fd33a1821689258350486..55c301c87f9c2e185ddc83fb83c9fdb2aebe50d3 100644 (file)
 
 #include "mem/tport.hh"
 
+void
+SimpleTimingPort::recvFunctional(Packet *pkt)
+{
+    // just do an atomic access and throw away the returned latency
+    recvAtomic(pkt);
+}
+
+bool
+SimpleTimingPort::recvTiming(Packet *pkt)
+{
+    // If the device is only a slave, it should only be sending
+    // responses, which should never get nacked.  There used to be
+    // code to hanldle nacks here, but I'm pretty sure it didn't work
+    // correctly with the drain code, so that would need to be fixed
+    // if we ever added it back.
+    assert(pkt->result != Packet::Nacked);
+    Tick latency = recvAtomic(pkt);
+    // turn packet around to go back to requester
+    pkt->makeTimingResponse();
+    sendTimingLater(pkt, latency);
+    return true;
+}
+
 void
 SimpleTimingPort::recvRetry()
 {
     bool result = true;
     while (result && transmitList.size()) {
-        result = Port::sendTiming(transmitList.front());
+        result = sendTiming(transmitList.front());
         if (result)
             transmitList.pop_front();
     }
-   if (transmitList.size() == 0 && drainEvent) {
-       drainEvent->process();
-       drainEvent = NULL;
-   }
+    if (transmitList.size() == 0 && drainEvent) {
+        drainEvent->process();
+        drainEvent = NULL;
+    }
 }
 
 void
@@ -50,26 +73,18 @@ SimpleTimingPort::SendEvent::process()
 {
     port->outTiming--;
     assert(port->outTiming >= 0);
-    if (port->Port::sendTiming(packet))
-       if (port->transmitList.size() == 0 && port->drainEvent) {
-           port->drainEvent->process();
-           port->drainEvent = NULL;
-       }
-       return;
-
-    port->transmitList.push_back(packet);
-}
-
-void
-SimpleTimingPort::resendNacked(Packet *pkt) {
-    pkt->reinitNacked();
-    if (transmitList.size()) {
-         transmitList.push_front(pkt);
+    if (port->sendTiming(packet)) {
+        // send successfule
+        if (port->transmitList.size() == 0 && port->drainEvent) {
+            port->drainEvent->process();
+            port->drainEvent = NULL;
+        }
     } else {
-        if (!Port::sendTiming(pkt))
-            transmitList.push_front(pkt);
+        // send unsuccessful (due to flow control).  Will get retry
+        // callback later; save for then.
+        port->transmitList.push_back(packet);
     }
-};
+}
 
 
 unsigned int
index 4d5c4599dce01c6e1634e4687ec244f887b92ba2..df6d481962cca3e32c25bdaa43ca86c9467dae74 100644 (file)
  * Authors: Ali Saidi
  */
 
+#ifndef __MEM_TPORT_HH__
+#define __MEM_TPORT_HH__
+
 /**
  * @file
- * Implement a port which adds simple support of a sendTiming() function that
- * takes a delay. In this way the * device can immediatly call
- * sendTiming(pkt, time) after processing a request and the request will be
- * handled by the port even if the port bus the device connects to is blocked.
+ *
+ * Declaration of SimpleTimingPort.
  */
 
-/** recvTiming and drain should be implemented something like this when this
- * class is used.
-
-bool
-PioPort::recvTiming(Packet *pkt)
-{
-    if (pkt->result == Packet::Nacked) {
-        resendNacked(pkt);
-    } else {
-        Tick latency = device->recvAtomic(pkt);
-        // turn packet around to go back to requester
-        pkt->makeTimingResponse();
-        sendTiming(pkt, latency);
-    }
-    return true;
-}
-
-PioDevice::drain(Event *de)
-{
-    unsigned int count;
-    count = SimpleTimingPort->drain(de);
-    if (count)
-        changeState(Draining);
-    else
-        changeState(Drained);
-    return count;
-}
-*/
-
-#ifndef __MEM_TPORT_HH__
-#define __MEM_TPORT_HH__
-
 #include "mem/port.hh"
 #include "sim/eventq.hh"
 #include <list>
 #include <string>
 
+/**
+ * A simple port for interfacing objects that basically have only
+ * functional memory behavior (e.g. I/O devices) to the memory system.
+ * Both timing and functional accesses are implemented in terms of
+ * atomic accesses.  A derived port class thus only needs to provide
+ * recvAtomic() to support all memory access modes.
+ *
+ * The tricky part is handling recvTiming(), where the response must
+ * be scheduled separately via a later call to sendTiming().  This
+ * feature is handled by scheduling an internal event that calls
+ * sendTiming() after a delay, and optionally rescheduling the
+ * response if it is nacked.
+ */
 class SimpleTimingPort : public Port
 {
   protected:
     /** A list of outgoing timing response packets that haven't been
      * serviced yet. */
     std::list<Packet*> transmitList;
+
     /**
      * This class is used to implemented sendTiming() with a delay. When
      * a delay is requested a new event is created. When the event time
@@ -112,20 +95,48 @@ class SimpleTimingPort : public Port
     Event *drainEvent;
 
     /** Schedule a sendTiming() event to be called in the future. */
-    void sendTiming(Packet *pkt, Tick time)
-    { outTiming++; new SimpleTimingPort::SendEvent(this, pkt, time); }
+    void sendTimingLater(Packet *pkt, Tick time)
+    { outTiming++; new SendEvent(this, pkt, time); }
 
     /** This function is notification that the device should attempt to send a
      * packet again. */
     virtual void recvRetry();
 
-    void resendNacked(Packet *pkt);
+    /** Implemented using recvAtomic(). */
+    void recvFunctional(Packet *pkt);
+
+    /** Implemented using recvAtomic(). */
+    bool recvTiming(Packet *pkt);
+
+    /**
+     * Simple ports generally don't care about any status
+     * changes... can always override this in cases where that's not
+     * true. */
+    virtual void recvStatusChange(Status status) { }
+
+
   public:
 
     SimpleTimingPort(std::string pname)
         : Port(pname), outTiming(0), drainEvent(NULL)
     {}
 
+    /** Hook for draining timing accesses from the system.  The
+     * associated SimObject's drain() functions should be implemented
+     * something like this when this class is used:
+     \code
+          PioDevice::drain(Event *de)
+          {
+              unsigned int count;
+              count = SimpleTimingPort->drain(de);
+              if (count)
+                  changeState(Draining);
+              else
+                  changeState(Drained);
+              return count;
+          }
+     \endcode
+    */
     unsigned int drain(Event *de);
 };