From f9ae0dcf1065454ca3d08512cd36a2dad9f08b2d Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Wed, 30 Aug 2006 16:24:26 -0700 Subject: [PATCH] Move more common functionality into SimpleTimingPort, allowing derived classes to be simplified. --HG-- extra : convert_revision : c980d3aec5e6c044d8f41e96252726fe9a256605 --- src/dev/io_device.cc | 24 +----------- src/dev/io_device.hh | 22 +---------- src/dev/pcidev.cc | 32 ++-------------- src/dev/pcidev.hh | 14 +------ src/mem/physical.cc | 21 +++-------- src/mem/physical.hh | 2 - src/mem/port.hh | 2 + src/mem/tport.cc | 61 ++++++++++++++++++------------ src/mem/tport.hh | 89 +++++++++++++++++++++++++------------------- 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 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 @@ -30,19 +30,42 @@ #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 #include +/** + * 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 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); }; -- 2.30.2