summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Reinhardt <stever@eecs.umich.edu>2006-08-30 16:24:26 -0700
committerSteve Reinhardt <stever@eecs.umich.edu>2006-08-30 16:24:26 -0700
commitf9ae0dcf1065454ca3d08512cd36a2dad9f08b2d (patch)
tree37e20bde0e0098eca99969f975c055d50cb65914
parenta8a7ce2b886ca2571f9470a48a4f12302f9cc830 (diff)
downloadgem5-f9ae0dcf1065454ca3d08512cd36a2dad9f08b2d.tar.xz
Move more common functionality into SimpleTimingPort,
allowing derived classes to be simplified. --HG-- extra : convert_revision : c980d3aec5e6c044d8f41e96252726fe9a256605
-rw-r--r--src/dev/io_device.cc24
-rw-r--r--src/dev/io_device.hh22
-rw-r--r--src/dev/pcidev.cc32
-rw-r--r--src/dev/pcidev.hh14
-rw-r--r--src/mem/physical.cc21
-rw-r--r--src/mem/physical.hh2
-rw-r--r--src/mem/port.hh2
-rw-r--r--src/mem/tport.cc61
-rw-r--r--src/mem/tport.hh89
9 files changed, 103 insertions, 164 deletions
diff --git a/src/dev/io_device.cc b/src/dev/io_device.cc
index b06e8b85d..408d8de3e 100644
--- a/src/dev/io_device.cc
+++ b/src/dev/io_device.cc
@@ -37,20 +37,14 @@
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)
diff --git a/src/dev/io_device.hh b/src/dev/io_device.hh
index d91304301..df4f494cb 100644
--- a/src/dev/io_device.hh
+++ b/src/dev/io_device.hh
@@ -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
diff --git a/src/dev/pcidev.cc b/src/dev/pcidev.cc
index a8fb44c39..8ea22cb24 100644
--- a/src/dev/pcidev.cc
+++ b/src/dev/pcidev.cc
@@ -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),
diff --git a/src/dev/pcidev.hh b/src/dev/pcidev.hh
index 8e4f003b0..22dd6296e 100644
--- a/src/dev/pcidev.hh
+++ b/src/dev/pcidev.hh
@@ -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
diff --git a/src/mem/physical.cc b/src/mem/physical.cc
index f4fbd2fb1..8fea733ec 100644
--- a/src/mem/physical.cc
+++ b/src/mem/physical.cc
@@ -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);
}
diff --git a/src/mem/physical.hh b/src/mem/physical.hh
index 1489e6700..02308b2ef 100644
--- a/src/mem/physical.hh
+++ b/src/mem/physical.hh
@@ -57,8 +57,6 @@ class PhysicalMemory : public MemObject
protected:
- virtual bool recvTiming(Packet *pkt);
-
virtual Tick recvAtomic(Packet *pkt);
virtual void recvFunctional(Packet *pkt);
diff --git a/src/mem/port.hh b/src/mem/port.hh
index 80c591f82..6b4184043 100644
--- a/src/mem/port.hh
+++ b/src/mem/port.hh
@@ -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);
diff --git a/src/mem/tport.cc b/src/mem/tport.cc
index 90cf68f02..55c301c87 100644
--- a/src/mem/tport.cc
+++ b/src/mem/tport.cc
@@ -31,18 +31,41 @@
#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
diff --git a/src/mem/tport.hh b/src/mem/tport.hh
index 4d5c4599d..df6d48196 100644
--- a/src/mem/tport.hh
+++ b/src/mem/tport.hh
@@ -28,57 +28,40 @@
* 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);
};